Shot trap status/damage of affected entity rather then just player
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user