Further refactoring

This commit is contained in:
Peter Stockings
2026-01-07 09:19:38 +11:00
parent f9b1abee6e
commit fcd31cce68
11 changed files with 910 additions and 220 deletions

View File

@@ -0,0 +1,151 @@
import type { World, CombatantActor, Item, ItemDropActor, Vec2 } from "../../core/types";
import { EntityManager } from "../../engine/EntityManager";
/**
* Result of attempting to use an item
*/
export interface ItemUseResult {
success: boolean;
consumed: boolean;
message?: string;
}
/**
* Manages item-related operations including spawning, pickup, and usage.
* Extracted from GameScene to centralize item logic and reduce complexity.
*/
export class ItemManager {
private world: World;
private entityManager: EntityManager;
constructor(world: World, entityManager: EntityManager) {
this.world = world;
this.entityManager = entityManager;
}
/**
* Update references when world changes (e.g., new floor)
*/
updateWorld(world: World, entityManager: EntityManager): void {
this.world = world;
this.entityManager = entityManager;
}
/**
* Spawn an item drop at the specified position
*/
spawnItem(item: Item, pos: Vec2): void {
if (!this.world || !this.entityManager) return;
const id = this.entityManager.getNextId();
const drop: ItemDropActor = {
id,
pos: { x: pos.x, y: pos.y },
category: "item_drop",
item: { ...item } // Clone item
};
this.entityManager.addActor(drop);
}
/**
* Try to pickup an item at the player's position
* @returns The picked up item, or null if nothing to pick up
*/
tryPickup(player: CombatantActor): Item | null {
if (!player || !player.inventory) return null;
const actors = this.entityManager.getActorsAt(player.pos.x, player.pos.y);
const itemActor = actors.find((a): a is ItemDropActor => a.category === "item_drop");
if (itemActor) {
const item = itemActor.item;
// Add to inventory
player.inventory.items.push(item);
// Remove from world
this.entityManager.removeActor(itemActor.id);
console.log("Picked up:", item.name);
return item;
}
return null;
}
/**
* Handle using an item from inventory
* Returns information about what happened
*/
handleUse(itemId: string, player: CombatantActor): ItemUseResult {
if (!player || !player.inventory) {
return { success: false, consumed: false, message: "Invalid player state" };
}
const itemIdx = player.inventory.items.findIndex(it => it.id === itemId);
if (itemIdx === -1) {
return { success: false, consumed: false, message: "Item not found" };
}
const item = player.inventory.items[itemIdx];
// Check if item is a healing consumable
if (item.stats && item.stats.hp && item.stats.hp > 0) {
const healAmount = item.stats.hp;
if (player.stats.hp >= player.stats.maxHp) {
return { success: false, consumed: false, message: "Already at full health" };
}
player.stats.hp = Math.min(player.stats.hp + healAmount, player.stats.maxHp);
// Remove item after use
player.inventory.items.splice(itemIdx, 1);
return {
success: true,
consumed: true,
message: `Healed for ${healAmount} HP`
};
}
// Throwable items are handled by TargetingSystem, not here
if (item.throwable) {
return {
success: true,
consumed: false,
message: "Throwable item - use targeting"
};
}
return {
success: false,
consumed: false,
message: "Item has no effect"
};
}
/**
* Remove an item from player inventory by ID
*/
removeFromInventory(player: CombatantActor, itemId: string): boolean {
if (!player || !player.inventory) return false;
const itemIdx = player.inventory.items.findIndex(it => it.id === itemId);
if (itemIdx === -1) return false;
player.inventory.items.splice(itemIdx, 1);
return true;
}
/**
* Get an item from player inventory by ID
*/
getItem(player: CombatantActor, itemId: string): Item | null {
if (!player || !player.inventory) return null;
const item = player.inventory.items.find(it => it.id === itemId);
return item || null;
}
}