Shot trap status/damage of affected entity rather then just player

This commit is contained in:
Peter Stockings
2026-01-27 14:14:27 +11:00
parent ef7d85750f
commit a15bb3675b
2 changed files with 117 additions and 6 deletions

View File

@@ -608,7 +608,6 @@ export class GameScene extends Phaser.Scene {
}
// Process traps and status effects
console.log(`[GameScene] Processing traps. Player Pos: ${player.pos.x},${player.pos.y}`);
this.ecsRegistry.updateAll();
// Handle trap events from ECS
@@ -618,17 +617,19 @@ export class GameScene extends Phaser.Scene {
}
for (const ev of trapEvents) {
if (ev.type === "trigger_activated") {
// Get trap trigger data for status effect display
const activator = this.entityAccessor.getActor(ev.activatorId);
const trapTrigger = this.ecsWorld.getComponent(ev.triggerId, "trigger");
if (trapTrigger?.effect) {
if (trapTrigger?.effect && activator) {
const color = getEffectColor(trapTrigger.effect);
const text = getEffectName(trapTrigger.effect);
this.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, text, color);
this.dungeonRenderer.showFloatingText(activator.pos.x, activator.pos.y, text, color);
}
} else if (ev.type === "damage") {
// Show damage number from trap
this.dungeonRenderer.showDamage(player.pos.x, player.pos.y, ev.amount);
const victim = this.entityAccessor.getActor(ev.entityId);
if (victim) {
this.dungeonRenderer.showDamage(victim.pos.x, victim.pos.y, ev.amount);
}
} else if (ev.type === "status_applied") {
// Already handled above via trigger_activated
} else if (ev.type === "status_tick" && ev.entityId) {

View File

@@ -146,6 +146,70 @@ vi.mock('../../engine/ecs/systems/StatusEffectSystem', () => ({
StatusEffectSystem: class {},
}));
vi.mock('../systems/TargetingSystem', () => ({
TargetingSystem: class {
isActive = false;
itemId = null;
cursorPos = null;
startTargeting = vi.fn();
cancel = vi.fn();
updateCursor = vi.fn();
executeThrow = vi.fn();
},
}));
vi.mock('../systems/CameraController', () => ({
CameraController: class {
constructor() {}
handleWheel = vi.fn();
handlePan = vi.fn();
enableFollowMode = vi.fn();
setBounds = vi.fn();
centerOnTile = vi.fn();
},
}));
vi.mock('../systems/ItemManager', () => ({
ItemManager: class {
constructor() {}
updateWorld = vi.fn();
setEntityAccessor = vi.fn();
handleUse = vi.fn(() => ({ success: true, consumed: false }));
removeFromInventory = vi.fn(() => true);
spawnItem = vi.fn();
tryPickup = vi.fn();
getItem = vi.fn(() => ({ id: 'test', name: 'Test' }));
},
}));
vi.mock('../../engine/ProgressionManager', () => ({
ProgressionManager: class {
allocateStat = vi.fn();
allocatePassive = vi.fn();
},
}));
vi.mock('../../engine/systems/UpgradeManager', () => ({
UpgradeManager: {
applyUpgrade: vi.fn(),
},
}));
vi.mock('../../engine/systems/EquipmentService', () => ({
equipItem: vi.fn(),
deEquipItem: vi.fn(),
}));
vi.mock('../../engine/systems/LootSystem', () => ({
generateLoot: vi.fn(),
}));
vi.mock('../systems/EventRenderer', () => ({
renderSimEvents: vi.fn(),
getEffectColor: vi.fn((e) => e === 'poison' ? '#00ff00' : "#ffffff"),
getEffectName: vi.fn((e) => e === 'poison' ? 'Poisoned!' : e),
}));
vi.mock('../../engine/world/world-logic', () => ({
inBounds: vi.fn(function() { return true; }),
isBlocked: vi.fn(function() { return false; }),
@@ -231,4 +295,50 @@ describe('GameScene', () => {
expect(mockUI.showDeathScreen).toHaveBeenCalled();
});
it('should show damage text at the entity position when a trap damages a non-player entity', () => {
const enemyActor = {
id: 5,
pos: { x: 5, y: 5 },
category: 'combatant',
};
// Setup mocks
(scene as any).entityAccessor.getActor = vi.fn((id) => (id === 5 ? enemyActor : null));
(scene as any).ecsEventBus.drain = vi.fn(() => [
{ type: 'damage', entityId: 5, amount: 10 }
]);
// Trigger action that processes traps (like move)
(simulation.applyAction as any).mockReturnValue([{ type: 'move', targetId: 1, dx: 1, dy: 0 }]);
(scene as any).commitPlayerAction({ type: 'move', dx: 1, dy: 0 });
// Verify
expect((scene as any).dungeonRenderer.showDamage).toHaveBeenCalledWith(5, 5, 10);
});
it('should show effect text at the entity position when a trap triggers an effect on a non-player entity', () => {
const enemyActor = {
id: 7,
pos: { x: 7, y: 7 },
category: 'combatant',
};
// Setup mocks
(scene as any).entityAccessor.getActor = vi.fn((id) => (id === 7 ? enemyActor : null));
(scene as any).ecsEventBus.drain = vi.fn(() => [
{ type: 'trigger_activated', triggerId: 10, activatorId: 7 }
]);
(scene as any).ecsWorld.getComponent = vi.fn((id, type) => {
if (id === 10 && type === 'trigger') return { effect: 'poison' };
return null;
});
// Trigger action
(simulation.applyAction as any).mockReturnValue([{ type: 'move', targetId: 1, dx: 1, dy: 0 }]);
(scene as any).commitPlayerAction({ type: 'move', dx: 1, dy: 0 });
// Verify
expect((scene as any).dungeonRenderer.showFloatingText).toHaveBeenCalledWith(7, 7, 'Poisoned!', '#00ff00');
});
});