Crafting and chest
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1,60 @@
|
|||||||
|
import { Inventory, PlayerInventory } from "../inventory.ts";
|
||||||
|
import { add_player_hotbar, add_player_inventory, GuiScreen, Slot } from "./gui_screen.ts";
|
||||||
|
import { canvas, draw_rect, 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 GuiChest extends GuiScreen {
|
||||||
|
override inventory_width = PADDING * 2 + SLOT_SIZE * 9;
|
||||||
|
override inventory_height = PADDING * 3 + SLOT_SIZE * 7;
|
||||||
|
|
||||||
|
constructor(inventory: Inventory, player_inventory: PlayerInventory) {
|
||||||
|
super(inventory, player_inventory, undefined);
|
||||||
|
|
||||||
|
add_player_hotbar(this, player_inventory, PADDING, PADDING);
|
||||||
|
add_player_inventory(this, player_inventory, PADDING, PADDING * 2 + SLOT_SIZE);
|
||||||
|
|
||||||
|
const chest_x = PADDING;
|
||||||
|
const chest_y = PADDING * 3 + SLOT_SIZE * 4;
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; ++i) {
|
||||||
|
for (let l = 0; l < 9; ++l) {
|
||||||
|
this.slots.push(
|
||||||
|
new Slot(
|
||||||
|
this.inventory,
|
||||||
|
l + i * 9 + 9,
|
||||||
|
chest_x + l * SLOT_SIZE,
|
||||||
|
chest_y + i * SLOT_SIZE,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override on_render(): void {
|
||||||
|
draw_rect(0, 0, canvas.width, canvas.height, [0, 0, 0, 0.8]);
|
||||||
|
|
||||||
|
const ui = AssetManager.instance.get<Texture>("bworld:ui");
|
||||||
|
|
||||||
|
draw_nine_slice(
|
||||||
|
ui,
|
||||||
|
160,
|
||||||
|
0,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
this.x,
|
||||||
|
this.y,
|
||||||
|
this.inventory_width,
|
||||||
|
this.inventory_height,
|
||||||
|
);
|
||||||
|
|
||||||
|
super.on_render();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,36 @@
|
|||||||
import { Container, Inventory, PlayerInventory } from "../inventory.ts";
|
import { Container, Inventory, ItemStack, PlayerInventory } from "../inventory.ts";
|
||||||
import { add_player_hotbar, add_player_inventory, GuiScreen, Slot } from "./gui_screen.ts";
|
import { add_player_hotbar, add_player_inventory, GuiScreen, Slot } from "./gui_screen.ts";
|
||||||
import { canvas, draw_rect, Texture } from "$/client/renderer.ts";
|
import { canvas, draw_rect, Texture } from "$/client/renderer.ts";
|
||||||
import { AssetManager } from "../assets.ts";
|
import { AssetManager } from "../assets.ts";
|
||||||
import { SLOT_SIZE } from "../../common/constants.ts";
|
import { SLOT_SIZE } from "../../common/constants.ts";
|
||||||
import { draw_nine_slice } from "../systems/rendering/render_utils.ts";
|
import { draw_nine_slice } from "../systems/rendering/render_utils.ts";
|
||||||
|
|
||||||
|
export interface CraftingRecipe {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
pattern: (string | undefined)[];
|
||||||
|
result: ItemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recipes: CraftingRecipe[] = [
|
||||||
|
{
|
||||||
|
width: 3,
|
||||||
|
height: 3,
|
||||||
|
pattern: [
|
||||||
|
"bworld:log",
|
||||||
|
"bworld:log",
|
||||||
|
"bworld:log",
|
||||||
|
"bworld:log",
|
||||||
|
undefined,
|
||||||
|
"bworld:log",
|
||||||
|
"bworld:log",
|
||||||
|
"bworld:log",
|
||||||
|
"bworld:log",
|
||||||
|
],
|
||||||
|
result: new ItemStack("bworld:chest", 1),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const PADDING = 10;
|
const PADDING = 10;
|
||||||
|
|
||||||
export class GuiPlayerInventory extends GuiScreen {
|
export class GuiPlayerInventory extends GuiScreen {
|
||||||
@@ -31,6 +57,11 @@ export class GuiPlayerInventory extends GuiScreen {
|
|||||||
this.slots.push(new Slot(this.inventory, 9, crafting_x + 5 * SLOT_SIZE, crafting_y + 1 * SLOT_SIZE));
|
this.slots.push(new Slot(this.inventory, 9, crafting_x + 5 * SLOT_SIZE, crafting_y + 1 * SLOT_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override on_tick(delta: number): void {
|
||||||
|
super.on_tick(delta);
|
||||||
|
this.update_crafting_result();
|
||||||
|
}
|
||||||
|
|
||||||
override on_render(): void {
|
override on_render(): void {
|
||||||
draw_rect(0, 0, canvas.width, canvas.height, [0, 0, 0, 0.8]);
|
draw_rect(0, 0, canvas.width, canvas.height, [0, 0, 0, 0.8]);
|
||||||
|
|
||||||
@@ -56,11 +87,118 @@ export class GuiPlayerInventory extends GuiScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override on_close(): void {
|
override on_close(): void {
|
||||||
for (let i = 0; i < this.inventory.container.size; i += 1) {
|
for (let i = 0; i < 8; i += 1) {
|
||||||
const item = this.inventory.container.get_item(i);
|
const item = this.inventory.container.get_item(i);
|
||||||
if (item) {
|
if (item) {
|
||||||
this.player_inventory.container.add_item(item);
|
this.player_inventory.container.add_item(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_crafting_grid(): (string | undefined)[] {
|
||||||
|
const grid: (string | undefined)[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
const item = this.inventory.container.get_item(i);
|
||||||
|
grid.push(item?.type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches_recipe(
|
||||||
|
grid: (string | undefined)[],
|
||||||
|
recipe: CraftingRecipe,
|
||||||
|
): boolean {
|
||||||
|
for (let y = 0; y <= 3 - recipe.height; y++) {
|
||||||
|
for (let x = 0; x <= 3 - recipe.width; x++) {
|
||||||
|
let match = true;
|
||||||
|
|
||||||
|
for (let ry = 0; ry < recipe.height; ry++) {
|
||||||
|
for (let rx = 0; rx < recipe.width; rx++) {
|
||||||
|
const grid_index = (y + ry) * 3 + (x + rx);
|
||||||
|
const recipe_index = ry * recipe.width + rx;
|
||||||
|
|
||||||
|
if (grid[grid_index] !== recipe.pattern[recipe_index]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_crafting_result() {
|
||||||
|
const grid = this.get_crafting_grid();
|
||||||
|
|
||||||
|
for (const recipe of recipes) {
|
||||||
|
if (this.matches_recipe(grid, recipe)) {
|
||||||
|
this.inventory.container.set_item(
|
||||||
|
9,
|
||||||
|
recipe.result.clone(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inventory.container.set_item(9, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
consume_recipe_items() {
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
const item = this.inventory.container.get_item(i);
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.amount -= 1;
|
||||||
|
|
||||||
|
if (item.amount <= 0) {
|
||||||
|
this.inventory.container.set_item(i, undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override handle_left_click(slot: Slot): void {
|
||||||
|
if (slot.inventory === this.inventory && slot.index === 9) {
|
||||||
|
if (this.inventory.container.get_item(9)) {
|
||||||
|
this.craft();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.handle_left_click(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override handle_right_click(slot: Slot): void {
|
||||||
|
if (slot.inventory === this.inventory && slot.index === 9) {
|
||||||
|
if (this.inventory.container.get_item(9)) {
|
||||||
|
this.craft();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.handle_right_click(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
craft() {
|
||||||
|
const holding_item = this.player_inventory.holding_item;
|
||||||
|
const item = this.inventory.container.get_item(9)!;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
this.consume_recipe_items();
|
||||||
|
holding_item.amount += item.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.player_inventory.holding_item = item;
|
||||||
|
this.consume_recipe_items();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -88,14 +88,14 @@ export class Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_item(slot: number): ItemStack | undefined {
|
get_item(slot: number): ItemStack | undefined {
|
||||||
return this.#slots[slot].get_item();
|
return this.#slots[slot]?.get_item();
|
||||||
}
|
}
|
||||||
|
|
||||||
get_slot(slot: number): ContainerSlot {
|
get_slot(slot: number): ContainerSlot {
|
||||||
return this.#slots[slot];
|
return this.#slots[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
set_item(slot: number, item: ItemStack) {
|
set_item(slot: number, item: ItemStack | undefined) {
|
||||||
this.#slots[slot].set_item(item);
|
this.#slots[slot].set_item(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { EverythingRegistry } from "../common/everything_registry.ts";
|
|
||||||
import { AssetManager } from "./assets.ts";
|
import { AssetManager } from "./assets.ts";
|
||||||
import { ClientWorld } from "./client_world.ts";
|
import { ClientWorld } from "./client_world.ts";
|
||||||
import { InputManager } from "./input_manager.ts";
|
import { InputManager } from "./input_manager.ts";
|
||||||
import { begin_drawing, end_drawing, init_font, init_window } from "./renderer.ts";
|
import { begin_drawing, end_drawing, init_font, init_window } from "./renderer.ts";
|
||||||
|
|
||||||
EverythingRegistry.add_registry("tiles");
|
|
||||||
await import("./tiles/mod.ts");
|
await import("./tiles/mod.ts");
|
||||||
EverythingRegistry.add_registry("items");
|
|
||||||
await import("./items/mod.ts");
|
await import("./items/mod.ts");
|
||||||
|
|
||||||
export class ClientLoop {
|
export class ClientLoop {
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
|
||||||
|
import { Container, Inventory } from "../inventory.ts";
|
||||||
|
import { PlayerComponent } from "../player.ts";
|
||||||
|
import { GuiChest } from "$/client/gui/gui_chest.ts";
|
||||||
|
|
||||||
|
interface TileChestData {
|
||||||
|
inventory: Inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
EverythingRegistry.register<TileRegistry<TileChestData>>("tiles", "bworld:chest", {
|
||||||
|
texture_id: "bworld:chest",
|
||||||
|
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) {
|
||||||
|
player_component.screens.push(new GuiChest(tile.data.inventory, player_component.player_inventory));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
on_create(_, tile) {
|
||||||
|
tile.data = { inventory: new Inventory(new Container(9 * 3)) };
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -10,7 +10,6 @@ interface CropsRegistry {
|
|||||||
regrowable: boolean;
|
regrowable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
EverythingRegistry.add_registry("crops");
|
|
||||||
EverythingRegistry.register<CropsRegistry>("crops", "bworld:carrot", {
|
EverythingRegistry.register<CropsRegistry>("crops", "bworld:carrot", {
|
||||||
total_stages: 5,
|
total_stages: 5,
|
||||||
time_to_grow: [60, 60 * 3, 60 * 3, 60 * 3],
|
time_to_grow: [60, 60 * 3, 60 * 3, 60 * 3],
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ EverythingRegistry.register<TileRegistry>("tiles", "bworld:grass", {
|
|||||||
on_interact(world, tile) {
|
on_interact(world, tile) {
|
||||||
const [player] = world.get_tag("player")!;
|
const [player] = world.get_tag("player")!;
|
||||||
const player_inventory = player.get(PlayerComponent)!.player_inventory;
|
const player_inventory = player.get(PlayerComponent)!.player_inventory;
|
||||||
const maybe_item = player_inventory.container.get_item(player_inventory.hotbar_selected);
|
const item = player_inventory.container.get_item(player_inventory.hotbar_selected);
|
||||||
if (maybe_item && maybe_item.type_id === "bworld:hoe") {
|
if (item?.type_id === "bworld:hoe") {
|
||||||
tile.id = "bworld:hoed_dirt";
|
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" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ import "./dirt.ts";
|
|||||||
import "./tree.ts";
|
import "./tree.ts";
|
||||||
import "./crops.ts";
|
import "./crops.ts";
|
||||||
import "./water.ts";
|
import "./water.ts";
|
||||||
|
import "./chest.ts";
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import { EverythingRegistry } from "../everything_registry.ts";
|
|
||||||
|
|
||||||
EverythingRegistry.add_registry("components");
|
|
||||||
|
|
||||||
export abstract class Component {
|
export abstract class Component {
|
||||||
__component = true;
|
__component = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,14 @@ import { Tile } from "../client/components/dimension.ts";
|
|||||||
import { ItemStack } from "../client/inventory.ts";
|
import { ItemStack } from "../client/inventory.ts";
|
||||||
|
|
||||||
export class EverythingRegistry {
|
export class EverythingRegistry {
|
||||||
static #registries = new Map<string, Map<string, unknown>>();
|
static #registries = new Map<string, unknown>();
|
||||||
|
|
||||||
static add_registry(name: string) {
|
|
||||||
this.#registries.set(name, new Map());
|
|
||||||
}
|
|
||||||
|
|
||||||
static register<T>(registry_name: string, key: string, value: T) {
|
static register<T>(registry_name: string, key: string, value: T) {
|
||||||
this.#registries.get(registry_name)?.set(key, value);
|
this.#registries.set(`${registry_name}__${key}`, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get<T>(registry_name: string, key: string): T {
|
static get<T>(registry_name: string, key: string): T {
|
||||||
return this.#registries.get(registry_name)?.get(key) as T;
|
return this.#registries.get(`${registry_name}__${key}`) as T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user