refactor game scene
This commit is contained in:
278
src/scenes/systems/GameEventHandler.ts
Normal file
278
src/scenes/systems/GameEventHandler.ts
Normal file
@@ -0,0 +1,278 @@
|
||||
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") {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Has ammo, start targeting
|
||||
if (this.scene.targetingSystem.isActive && this.scene.targetingSystem.itemId === item.id) {
|
||||
// Already targeting - execute shoot
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user