Implement main game as a mod

This commit is contained in:
2026-09-24 23:49:34 -03:00
parent bb42dd662e
commit 6458bc0440
131 changed files with 1810 additions and 786 deletions
+39 -59
View File
@@ -1,5 +1,7 @@
import { Container, ItemStack } from "$/common/inventory.ts";
import { ScreenLayout } from "$/common/protocol.ts";
import { EverythingRegistry, ItemRegistry } from "$/common/everything_registry.ts";
import type { RecipeBook } from "$/common/mod_loader.ts";
import type { GameServer } from "./game_server.ts";
import type { ServerPlayer } from "./player.ts";
import type { Tile } from "./world.ts";
@@ -80,50 +82,6 @@ BLOCK_BEHAVIORS["bworld:chest"] = {
// furnace
export interface FurnaceRecipe {
input: string;
output: ItemStack;
cook_time: number;
}
export const FURNACE_RECIPES: FurnaceRecipe[] = [
{
input: "bworld:log",
output: new ItemStack("bworld:coal", 1),
cook_time: 100,
},
{
input: "bworld:coal_ore",
output: new ItemStack("bworld:coal", 1),
cook_time: 100,
},
{
input: "bworld:iron_ore",
output: new ItemStack("bworld:iron_ingot", 1),
cook_time: 200,
},
{
input: "bworld:tin_ore",
output: new ItemStack("bworld:tin_ingot", 1),
cook_time: 200,
},
{
input: "bworld:copper_ore",
output: new ItemStack("bworld:copper_ingot", 1),
cook_time: 200,
},
{
input: "bworld:gold_ore",
output: new ItemStack("bworld:gold_ingot", 1),
cook_time: 200,
},
];
export const FUEL_VALUES: Record<string, number> = {
"bworld:coal": 1000,
"bworld:log": 100,
};
interface FurnaceData {
progress: number;
progress_max: number;
@@ -131,12 +89,17 @@ interface FurnaceData {
fuel_max: number;
}
function get_recipe(input?: ItemStack | undefined): FurnaceRecipe | undefined {
interface FurnaceRecipe {
output: { id: string; count: number };
cook_time: number;
}
function get_recipe(recipes: RecipeBook, input?: ItemStack | undefined): FurnaceRecipe | undefined {
if (!input) {
return;
}
return FURNACE_RECIPES.find((r) => r.input === input.type_id);
return recipes.furnace.get(input.type_id);
}
function can_craft(container: Container, recipe?: FurnaceRecipe) {
@@ -150,27 +113,27 @@ function can_craft(container: Container, recipe?: FurnaceRecipe) {
return true;
}
if (output.type_id !== recipe.output.type_id) {
if (output.type_id !== recipe.output.id) {
return false;
}
return output.amount < output.max_amount;
}
function get_fuel_value(item?: ItemStack | undefined): number {
function get_fuel_value(recipes: RecipeBook, item?: ItemStack | undefined): number {
if (!item) {
return 0;
}
return FUEL_VALUES[item.type_id] ?? 0;
return recipes.fuel.get(item.type_id) ?? 0;
}
function has_fuel(container: Container) {
return get_fuel_value(container.get_item(1)) > 0;
function has_fuel(recipes: RecipeBook, container: Container) {
return get_fuel_value(recipes, container.get_item(1)) > 0;
}
function consume_fuel(container: Container): number {
function consume_fuel(recipes: RecipeBook, container: Container): number {
const fuel = container.get_slot(1)!;
const value = get_fuel_value(fuel.get_item());
const value = get_fuel_value(recipes, fuel.get_item());
if (fuel.has_item()) {
fuel.amount! -= 1;
@@ -184,9 +147,9 @@ function craft(container: Container, recipe: FurnaceRecipe) {
const output = container.get_item(2);
if (!output) {
container.set_item(2, recipe.output.clone());
container.set_item(2, new ItemStack(recipe.output.id, recipe.output.count));
} else {
output.amount += recipe.output.amount;
output.amount += recipe.output.count;
}
input.amount -= 1;
@@ -241,12 +204,12 @@ BLOCK_BEHAVIORS["bworld:furnace"] = {
on_break(_game, tile, player) {
give_container_contents(tile, player);
},
on_tick(_game, tile) {
on_tick(game, tile) {
const data = tile.data as unknown as FurnaceData;
const container = tile.containers.main;
const input = container.get_item(0);
const recipe = get_recipe(input);
const recipe = get_recipe(game.recipes, input);
// burn fuel
if (data.fuel > 0) {
@@ -259,8 +222,8 @@ BLOCK_BEHAVIORS["bworld:furnace"] = {
}
// refuel
if (data.fuel === 0 && has_fuel(container)) {
data.fuel = consume_fuel(container);
if (data.fuel === 0 && has_fuel(game.recipes, container)) {
data.fuel = consume_fuel(game.recipes, container);
data.fuel_max = data.fuel;
}
@@ -276,3 +239,20 @@ BLOCK_BEHAVIORS["bworld:furnace"] = {
}
},
};
// items that still need code, until they're components in mods/bworld (phase 2 in MODS.md)
export interface WateringCanData {
water: number;
max_water: number;
}
export function add_base_item_hooks() {
const watering_can = EverythingRegistry.get<ItemRegistry<WateringCanData>>("items", "bworld:watering_can");
if (watering_can) {
watering_can.on_create = (item) => {
item.data = { water: 0, max_water: 32 };
};
watering_can.get_lore = (item) => `Water: ${item.data?.water}/${item.data?.max_water}`;
}
}