diff --git a/assets/sprites/textures/coal.png b/assets/sprites/textures/coal.png new file mode 100644 index 0000000..6a72f69 Binary files /dev/null and b/assets/sprites/textures/coal.png differ diff --git a/assets/sprites/textures/furnace.png b/assets/sprites/textures/furnace.png new file mode 100644 index 0000000..447beb7 Binary files /dev/null and b/assets/sprites/textures/furnace.png differ diff --git a/client/gui/gui_furnace.ts b/client/gui/gui_furnace.ts new file mode 100644 index 0000000..e968835 --- /dev/null +++ b/client/gui/gui_furnace.ts @@ -0,0 +1,129 @@ +import { Inventory, PlayerInventory } from "../inventory.ts"; +import { add_player_hotbar, add_player_inventory, GuiScreen, Slot } from "./gui_screen.ts"; +import { canvas, draw_rect, draw_text, Texture } from "$/client/renderer.ts"; +import { AssetManager } from "../assets.ts"; +import { SLOT_SIZE } from "../../common/constants.ts"; +import { draw_nine_slice } from "../systems/rendering/render_utils.ts"; + +const PADDING = 10; + +export class GuiFurnace extends GuiScreen { + override inventory_width = PADDING * 2 + SLOT_SIZE * 9; + override inventory_height = PADDING * 4 + SLOT_SIZE * 7; + + constructor( + inventory: Inventory, + player_inventory: PlayerInventory, + properties: { fuel: number; progress: number }, + ) { + super(inventory, player_inventory, properties); + + add_player_hotbar(this, player_inventory, PADDING, PADDING); + add_player_inventory(this, player_inventory, PADDING, PADDING * 2 + SLOT_SIZE); + + const furnace_y = PADDING * 3 + SLOT_SIZE * 4; + + this.slots.push( + new Slot( + this.inventory, + 0, + this.inventory_width / 2 - SLOT_SIZE, + furnace_y, + ), + ); + this.slots.push( + new Slot( + this.inventory, + 1, + this.inventory_width / 2 - SLOT_SIZE, + furnace_y + SLOT_SIZE * 2, + ), + ); + this.slots.push( + new Slot( + this.inventory, + 2, + this.inventory_width / 2 + SLOT_SIZE, + furnace_y + SLOT_SIZE, + ), + ); + } + + override on_render(): void { + draw_rect(0, 0, canvas.width, canvas.height, [0, 0, 0, 0.8]); + + const ui = AssetManager.instance.get("bworld:ui"); + + draw_nine_slice( + ui, + 160, + 0, + 16, + 16, + 4, + 4, + 4, + 4, + this.x, + this.y, + this.inventory_width, + this.inventory_height, + ); + + const furnace_y = PADDING * 3 + SLOT_SIZE * 4; + draw_text( + String(this.properties.fuel), + this.x + this.inventory_width / 2 - SLOT_SIZE, + this.y + furnace_y + SLOT_SIZE, + 1, + [0, 0, 0, 1], + ); + draw_text( + String(this.properties.progress), + this.x + this.inventory_width / 2, + this.y + furnace_y + SLOT_SIZE, + 1, + [0, 0, 0, 1], + ); + + super.on_render(); + } + + override handle_left_click(slot: Slot): void { + if (slot.inventory === this.inventory && slot.index === 2) { + if (this.inventory.container.get_item(2)) { + this.pickup(); + } + } else { + super.handle_left_click(slot); + } + } + + override handle_right_click(slot: Slot): void { + if (slot.inventory === this.inventory && slot.index === 2) { + if (this.inventory.container.get_item(2)) { + this.pickup(); + } + } else { + super.handle_right_click(slot); + } + } + + pickup() { + const holding_item = this.player_inventory.holding_item; + const item = this.inventory.container.get_item(2)!; + + if (holding_item) { + if (holding_item.type_id === item.type_id) { + const items_left = holding_item.max_amount - holding_item.amount; + if (items_left >= item.amount) { + holding_item.amount += item.amount; + this.inventory.container.set_item(2, undefined); + } + } + } else { + this.player_inventory.holding_item = item; + this.inventory.container.set_item(2, undefined); + } + } +} diff --git a/client/player.ts b/client/player.ts index 08310b3..36c1a5c 100644 --- a/client/player.ts +++ b/client/player.ts @@ -53,10 +53,11 @@ export function create_player(world: ClientWorld) { player_inventory.container.add_item(new ItemStack("bworld:axe", 1, 1)); // player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:sword", 1, 1)); // player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:bomb", 64)); - player_inventory.container.add_item(new ItemStack("bworld:tomato_seeds", 64)); - player_inventory.container.add_item(new ItemStack("bworld:potato_seeds", 64)); - player_inventory.container.add_item(new ItemStack("bworld:pumpkin_seeds", 64)); - player_inventory.container.add_item(new ItemStack("bworld:carrot_seeds", 64)); + // player_inventory.container.add_item(new ItemStack("bworld:tomato_seeds", 64)); + // player_inventory.container.add_item(new ItemStack("bworld:potato_seeds", 64)); + // player_inventory.container.add_item(new ItemStack("bworld:pumpkin_seeds", 64)); + // player_inventory.container.add_item(new ItemStack("bworld:carrot_seeds", 64)); + player_inventory.container.add_item(new ItemStack("bworld:furnace", 1)); player.add(new Camera(-100, -100)); world.add_entity(player); diff --git a/client/tiles/furnace.ts b/client/tiles/furnace.ts new file mode 100644 index 0000000..15a1020 --- /dev/null +++ b/client/tiles/furnace.ts @@ -0,0 +1,115 @@ +import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; +import { Container, Inventory, ItemStack } from "../inventory.ts"; +import { PlayerComponent } from "../player.ts"; +import { GuiFurnace } from "$/client/gui/gui_furnace.ts"; + +function can_craft(container: Container) { + const input = container.get_item(0); + const output = container.get_item(2); + + if (!input) { + return false; + } + + if (["bworld:log"].includes(input.type_id)) { + return true; + } + + if (!output) { + return true; + } + + if (output.amount >= output.max_amount) { + return false; + } + + return true; +} + +function has_fuel(container: Container) { + const fuel = container.get_item(1); + + if (!fuel) { + return false; + } + + if (["bworld:coal", "bworld:log"].includes(fuel.type_id)) { + return true; + } + + return false; +} + +function consume_fuel(container: Container) { + const fuel = container.get_item(1)!; + fuel.amount -= 1; + container.set_item(1, fuel); +} + +function craft(container: Container, item: ItemStack) { + const input = container.get_item(0)!; + const output = container.get_item(2); + + if (!output) { + container.set_item(2, item); + } else { + output.amount += item.amount; + } + + input.amount -= 1; + container.set_item(0, input); +} + +interface TileChestData { + inventory: Inventory; + progress: number; + fuel: number; +} + +EverythingRegistry.register>("tiles", "bworld:furnace", { + texture_id: "bworld:furnace", + has_collision: false, + + on_interact(world, tile) { + const [player] = world.get_tag("player")!; + const player_component = player.get(PlayerComponent)!; + if (tile.data && tile.data.inventory) { + const gui = new GuiFurnace(tile.data.inventory, player_component.player_inventory, tile.data); + player_component.screens.push(gui); + } + }, + on_create(_, tile) { + tile.data = { + inventory: new Inventory(new Container(3)), + progress: 0, + fuel: 0, + }; + }, + on_tick(_, tile) { + if (!tile.data) { + return; + } + + if (tile.data.fuel > 0) { + tile.data.fuel -= 1; + } + + const container = tile.data.inventory.container; + + if (can_craft(container)) { + if (tile.data.fuel === 0 && has_fuel(container)) { + consume_fuel(container); + tile.data.fuel = 200; + } + + if (tile.data.fuel > 0) { + tile.data.progress += 1; + + if (tile.data.progress >= 100) { + tile.data.progress = 0; + craft(container, new ItemStack("bworld:coal")); + } + } + } + }, +}); diff --git a/client/tiles/grass.ts b/client/tiles/grass.ts index 4d5c1b8..2eb7cd8 100644 --- a/client/tiles/grass.ts +++ b/client/tiles/grass.ts @@ -13,6 +13,8 @@ EverythingRegistry.register("tiles", "bworld:grass", { tile.id = "bworld:hoed_dirt"; } else if (item?.type_id === "bworld:chest") { world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:chest" }); + } else if (item?.type_id === "bworld:furnace") { + world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:furnace", tickable: true }); } }, }); diff --git a/client/tiles/mod.ts b/client/tiles/mod.ts index 5820251..5eb7f89 100644 --- a/client/tiles/mod.ts +++ b/client/tiles/mod.ts @@ -4,3 +4,4 @@ import "./tree.ts"; import "./crops.ts"; import "./water.ts"; import "./chest.ts"; +import "./furnace.ts";