import type { GameScene } from "../GameScene"; import { UpgradeManager } from "../../engine/systems/UpgradeManager"; import { InventoryOverlay } from "../../ui/components/InventoryOverlay"; import { equipItem, deEquipItem } from "../../engine/systems/EquipmentService"; import { inBounds, isBlocked } from "../../engine/world/world-logic"; import GameUI from "../../ui/GameUI"; export class GameEventHandler { private scene: GameScene; constructor(scene: GameScene) { this.scene = scene; } public registerListeners() { const events = this.scene.events; events.on("menu-toggled", (isOpen: boolean) => { this.scene.isMenuOpen = isOpen; }); events.on("inventory-toggled", (isOpen: boolean) => { this.scene.isInventoryOpen = isOpen; }); events.on("character-toggled", (isOpen: boolean) => { this.scene.isCharacterOpen = isOpen; }); events.on("toggle-minimap", () => { this.scene.dungeonRenderer.toggleMinimap(); }); events.on("request-ui-update", () => { this.scene.emitUIUpdate(); }); events.on("restart-game", () => { this.scene.restartGame(); }); events.on("allocate-stat", (statName: string) => { const player = this.scene.entityAccessor.getPlayer(); if (player) { this.scene.progressionManager.allocateStat(player, statName); this.scene.emitUIUpdate(); } }); events.on("allocate-passive", (nodeId: string) => { const player = this.scene.entityAccessor.getPlayer(); if (player) { this.scene.progressionManager.allocatePassive(player, nodeId); this.scene.emitUIUpdate(); } }); events.on("player-wait", () => { if (!this.scene.awaitingPlayer) return; if (this.scene.isMenuOpen || this.scene.isInventoryOpen || this.scene.dungeonRenderer.isMinimapVisible()) return; this.scene.commitPlayerAction({ type: "wait" }); }); events.on("player-search", () => { if (!this.scene.awaitingPlayer) return; if (this.scene.isMenuOpen || this.scene.isInventoryOpen || this.scene.dungeonRenderer.isMinimapVisible()) return; console.log("Player searching..."); this.scene.commitPlayerAction({ type: "wait" }); }); events.on("use-item", (data: { itemId: string }) => { this.handleUseItem(data.itemId); }); events.on("drop-item", (data: { itemId: string, pointerX: number, pointerY: number }) => { this.handleDropItem(data); }); events.on("equip-item", (data: { itemId: string, slotKey: string }) => { this.handleEquipItem(data); }); events.on("de-equip-item", (data: { slotKey: string }) => { this.handleDeEquipItem(data); }); } private handleUseItem(itemId: string) { if (!this.scene.awaitingPlayer) return; const player = this.scene.entityAccessor.getPlayer(); if (!player || !player.inventory) return; const itemIdx = player.inventory.items.findIndex(it => it.id === itemId); if (itemIdx === -1) return; const item = player.inventory.items[itemIdx]; // Ranged Weapon Logic if (item.type === "Weapon" && (item.weaponType === "ranged" || item.weaponType === "flamethrower")) { if (item.weaponType === "ranged") { // Check Ammo if (item.currentAmmo <= 0) { if (item.reloadingTurnsLeft > 0) { this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, "Reloading...", "#aaaaaa"); return; } // Try Reload this.scene.startReload(player, item as any); return; } // Is it already reloading? if (item.reloadingTurnsLeft > 0) { this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, "Reloading...", "#aaaaaa"); return; } } else if (item.weaponType === "flamethrower") { // Check Charges if (item.charges <= 0) { this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, "No charges!", "#ff6600"); return; } } // Has ammo/charges, start targeting if (this.scene.targetingSystem.isActive && this.scene.targetingSystem.itemId === item.id) { // Already targeting - execute action if (this.scene.targetingSystem.cursorPos) { this.scene.executeThrow(); } return; } const { x: tx, y: ty } = this.scene.getPointerTilePos(this.scene.input.activePointer); this.scene.targetingSystem.startTargeting( item.id, player.pos, this.scene.world, this.scene.entityAccessor, this.scene.playerId, this.scene.dungeonRenderer.seenArray, this.scene.world.width, { x: tx, y: ty } ); this.scene.emitUIUpdate(); return; } // Upgrade Scroll Logic if (item.id === "upgrade_scroll") { const uiScene = this.scene.scene.get("GameUI") as GameUI; // Access the public inventory component const inventoryOverlay = uiScene.inventory; if (inventoryOverlay && inventoryOverlay instanceof InventoryOverlay) { // Trigger upgrade mode inventoryOverlay.enterUpgradeMode((targetItem: any) => { const success = UpgradeManager.applyUpgrade(targetItem); if (success) { // Consume scroll logic handling stacking const scrollItem = player.inventory?.items.find(it => it.id === "upgrade_scroll"); if (scrollItem) { if (scrollItem.stackable && scrollItem.quantity && scrollItem.quantity > 1) { scrollItem.quantity--; } else { this.scene.itemManager.removeFromInventory(player, "upgrade_scroll"); } this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, "Upgraded!", "#ffd700"); } inventoryOverlay.cancelUpgradeMode(); this.scene.emitUIUpdate(); this.scene.commitPlayerAction({ type: "wait" }); } else { // Should technically be prevented by UI highlights, but safety check this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, "Cannot upgrade!", "#ff0000"); inventoryOverlay.cancelUpgradeMode(); this.scene.emitUIUpdate(); } }); this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, "Select Item to Upgrade", "#ffffff"); } return; } const result = this.scene.itemManager.handleUse(itemId, player); if (result.success && result.consumed) { const healAmount = player.stats.maxHp - player.stats.hp; // Already healed by manager const actualHeal = Math.min(healAmount, player.stats.hp); this.scene.dungeonRenderer.showHeal(player.pos.x, player.pos.y, actualHeal); this.scene.commitPlayerAction({ type: "wait" }); this.scene.emitUIUpdate(); } else if (result.success && !result.consumed) { // Throwable item - start targeting if (this.scene.targetingSystem.isActive && this.scene.targetingSystem.itemId === item.id) { // Already targeting - execute throw if (this.scene.targetingSystem.cursorPos) { this.scene.executeThrow(); } return; } const { x: tx, y: ty } = this.scene.getPointerTilePos(this.scene.input.activePointer); this.scene.targetingSystem.startTargeting( item.id, player.pos, this.scene.world, this.scene.entityAccessor, this.scene.playerId, this.scene.dungeonRenderer.seenArray, this.scene.world.width, { x: tx, y: ty } ); this.scene.emitUIUpdate(); } } private handleDropItem(data: { itemId: string, pointerX: number, pointerY: number }) { if (!this.scene.awaitingPlayer) return; const player = this.scene.entityAccessor.getPlayer(); if (!player || !player.inventory) return; const item = this.scene.itemManager.getItem(player, data.itemId); if (!item) return; // Determine drop position based on pointer or player pos let dropPos = { x: player.pos.x, y: player.pos.y }; if (data.pointerX !== undefined && data.pointerY !== undefined) { const tilePos = this.scene.getPointerTilePos({ x: data.pointerX, y: data.pointerY } as Phaser.Input.Pointer); // Limit drop distance to 1 tile from player for balance/fairness const dx = Math.sign(tilePos.x - player.pos.x); const dy = Math.sign(tilePos.y - player.pos.y); const targetX = player.pos.x + dx; const targetY = player.pos.y + dy; if (inBounds(this.scene.world, targetX, targetY) && !isBlocked(this.scene.world, targetX, targetY, this.scene.entityAccessor)) { dropPos = { x: targetX, y: targetY }; } } // Remove from inventory and spawn in world if (this.scene.itemManager.removeFromInventory(player, data.itemId)) { this.scene.itemManager.spawnItem(item, dropPos); const quantityText = (item.quantity && item.quantity > 1) ? ` x${item.quantity}` : ""; this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, `Dropped ${item.name}${quantityText}`, "#aaaaaa"); this.scene.emitUIUpdate(); } } private handleEquipItem(data: { itemId: string, slotKey: string }) { const player = this.scene.entityAccessor.getPlayer(); if (!player || !player.inventory) return; const item = player.inventory.items.find(it => it.id === data.itemId); if (!item) return; const result = equipItem(player, item, data.slotKey as any); if (!result.success) { this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, result.message ?? "Cannot equip!", "#ff0000"); return; } this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, `Equipped ${item.name}`, "#d4af37"); this.scene.emitUIUpdate(); } private handleDeEquipItem(data: { slotKey: string }) { const player = this.scene.entityAccessor.getPlayer(); if (!player || !player.equipment) return; const removedItem = deEquipItem(player, data.slotKey as any); if (removedItem) { this.scene.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, `De-equipped ${removedItem.name}`, "#aaaaaa"); this.scene.emitUIUpdate(); } } }