inventory types

This commit is contained in:
Boki 2026-02-12 12:00:29 -05:00
parent cf5d944fd1
commit 3d7a8aafdf
9 changed files with 532 additions and 369 deletions

View file

@ -1,13 +1,15 @@
import { logger } from '../util/logger.js';
import type { PostAction } from '../types.js';
const ROWS = 5;
const COLS = 12;
interface PlacedItem {
export interface PlacedItem {
row: number;
col: number;
w: number;
h: number;
postAction: PostAction;
}
export class InventoryTracker {
@ -19,7 +21,11 @@ export class InventoryTracker {
}
/** Initialize from a grid scan result (occupied cells + detected items). */
initFromScan(cells: boolean[][], items: { row: number; col: number; w: number; h: number }[]): void {
initFromScan(
cells: boolean[][],
items: { row: number; col: number; w: number; h: number }[],
defaultAction: PostAction = 'stash',
): void {
// Reset
for (let r = 0; r < ROWS; r++) {
this.grid[r].fill(false);
@ -35,19 +41,19 @@ export class InventoryTracker {
// Record detected items
for (const item of items) {
this.items.push({ row: item.row, col: item.col, w: item.w, h: item.h });
this.items.push({ row: item.row, col: item.col, w: item.w, h: item.h, postAction: defaultAction });
}
logger.info({ occupied: ROWS * COLS - this.freeCells, items: this.items.length, free: this.freeCells }, 'Inventory initialized from scan');
}
/** Try to place an item of size w×h. Column-first to match game's left-priority placement. */
tryPlace(w: number, h: number): { row: number; col: number } | null {
tryPlace(w: number, h: number, postAction: PostAction = 'stash'): { row: number; col: number } | null {
for (let col = 0; col <= COLS - w; col++) {
for (let row = 0; row <= ROWS - h; row++) {
if (this.fits(row, col, w, h)) {
this.place(row, col, w, h);
logger.info({ row, col, w, h, free: this.freeCells }, 'Item placed in inventory');
this.place(row, col, w, h, postAction);
logger.info({ row, col, w, h, postAction, free: this.freeCells }, 'Item placed in inventory');
return { row, col };
}
}
@ -70,6 +76,38 @@ export class InventoryTracker {
return [...this.items];
}
/** Get items with a specific postAction. */
getItemsByAction(action: PostAction): PlacedItem[] {
return this.items.filter(i => i.postAction === action);
}
/** Check if any items have a specific postAction. */
hasItemsWithAction(action: PostAction): boolean {
return this.items.some(i => i.postAction === action);
}
/** Remove a specific item from tracking and unmark its grid cells. */
removeItem(item: PlacedItem): void {
const idx = this.items.indexOf(item);
if (idx === -1) return;
// Unmark grid cells
for (let r = item.row; r < item.row + item.h; r++) {
for (let c = item.col; c < item.col + item.w; c++) {
this.grid[r][c] = false;
}
}
this.items.splice(idx, 1);
}
/** Remove all items with a specific postAction. */
removeItemsByAction(action: PostAction): void {
const toRemove = this.items.filter(i => i.postAction === action);
for (const item of toRemove) {
this.removeItem(item);
}
logger.info({ action, removed: toRemove.length, remaining: this.items.length }, 'Removed items by action');
}
/** Get a copy of the occupancy grid. */
getGrid(): boolean[][] {
return this.grid.map(row => [...row]);
@ -104,12 +142,12 @@ export class InventoryTracker {
return true;
}
private place(row: number, col: number, w: number, h: number): void {
private place(row: number, col: number, w: number, h: number, postAction: PostAction): void {
for (let r = row; r < row + h; r++) {
for (let c = col; c < col + w; c++) {
this.grid[r][c] = true;
}
}
this.items.push({ row, col, w, h });
this.items.push({ row, col, w, h, postAction });
}
}