aether-shards/test/systems/EnvironmentalHazards.test.js
Matthew Mone f04905044d Implement EffectProcessor and related systems for enhanced game mechanics
Introduce the EffectProcessor class to manage game state changes through various effects, including damage, healing, and status application. Define type specifications for effects, conditions, and passive abilities in Effects.d.ts. Add a comprehensive JSON registry for passive skills and item effects, enhancing gameplay dynamics. Update the GameLoop and TurnSystem to integrate the EffectProcessor, ensuring proper handling of environmental hazards and passive effects during combat. Enhance testing coverage for the EffectProcessor and environmental interactions to validate functionality and performance.
2025-12-30 20:50:11 -08:00

168 lines
5.4 KiB
JavaScript

import { expect } from "@esm-bundle/chai";
import { TurnSystem } from "../../src/systems/TurnSystem.js";
import { VoxelGrid } from "../../src/grid/VoxelGrid.js";
import { UnitManager } from "../../src/managers/UnitManager.js";
import { EffectProcessor } from "../../src/systems/EffectProcessor.js";
describe("Systems: Environmental Hazards", function () {
let turnSystem;
let grid;
let unitManager;
let effectProcessor;
let unit;
let mockRegistry;
beforeEach(() => {
// Create mock registry
mockRegistry = new Map();
mockRegistry.set("CLASS_VANGUARD", {
id: "CLASS_VANGUARD",
name: "Vanguard",
type: "EXPLORER",
base_stats: {
health: 100,
attack: 10,
defense: 5,
speed: 10,
movement: 4,
},
});
unitManager = new UnitManager(mockRegistry);
grid = new VoxelGrid(20, 5, 20);
// Create walkable floor
for (let x = 0; x < 20; x++) {
for (let z = 0; z < 20; z++) {
grid.setCell(x, 0, z, 1); // Floor
grid.setCell(x, 1, z, 0); // Air (walkable)
grid.setCell(x, 2, z, 0); // Headroom
}
}
effectProcessor = new EffectProcessor(grid, unitManager);
turnSystem = new TurnSystem(unitManager);
turnSystem.setHazardContext(grid, effectProcessor);
// Create test unit
unit = unitManager.createUnit("CLASS_VANGUARD", "PLAYER");
unit.position = { x: 5, y: 1, z: 5 };
unit.currentHealth = 100;
unit.maxHealth = 100;
grid.placeUnit(unit, unit.position);
});
describe("Integration Point 3: Environmental Hazards", () => {
it("should apply fire hazard damage when unit starts turn on fire", () => {
// Place fire hazard at unit's position
grid.addHazard(unit.position, "HAZARD_FIRE", 3);
const initialHP = unit.currentHealth;
const defense = unit.baseStats.defense || 0;
const expectedDamage = Math.max(0, 5 - defense); // 5 fire damage - defense
// Start turn (should process hazards)
turnSystem.startTurn(unit);
// Unit should have taken fire damage (reduced by defense)
expect(unit.currentHealth).to.be.lessThanOrEqual(initialHP);
expect(unit.currentHealth).to.equal(initialHP - expectedDamage);
});
it("should apply acid hazard damage when unit starts turn on acid", () => {
// Place acid hazard at unit's position
grid.addHazard(unit.position, "HAZARD_ACID", 2);
const initialHP = unit.currentHealth;
const defense = unit.baseStats.defense || 0;
const expectedDamage = Math.max(0, 5 - defense); // 5 acid damage - defense
// Start turn
turnSystem.startTurn(unit);
// Unit should have taken acid damage (reduced by defense)
expect(unit.currentHealth).to.be.lessThanOrEqual(initialHP);
expect(unit.currentHealth).to.equal(initialHP - expectedDamage);
});
it("should decrement hazard duration after processing", () => {
// Place hazard with duration 2
grid.addHazard(unit.position, "HAZARD_FIRE", 2);
const hazard = grid.getHazardAt(unit.position);
expect(hazard.duration).to.equal(2);
// Start turn (should decrement duration)
turnSystem.startTurn(unit);
const hazardAfter = grid.getHazardAt(unit.position);
expect(hazardAfter.duration).to.equal(1);
});
it("should remove hazard when duration reaches 0", () => {
// Place hazard with duration 1
grid.addHazard(unit.position, "HAZARD_FIRE", 1);
expect(grid.getHazardAt(unit.position)).to.exist;
// Start turn (should remove hazard)
turnSystem.startTurn(unit);
// Hazard should be removed
expect(grid.getHazardAt(unit.position)).to.be.undefined;
});
it("should not process hazards if unit is not on a hazard tile", () => {
const initialHP = unit.currentHealth;
// Start turn without any hazard
turnSystem.startTurn(unit);
// Health should be unchanged (except for status effects if any)
expect(unit.currentHealth).to.equal(initialHP);
});
it("should handle unknown hazard types with default damage", () => {
// Place unknown hazard type
grid.addHazard(unit.position, "HAZARD_UNKNOWN", 1);
const initialHP = unit.currentHealth;
const defense = unit.baseStats.defense || 0;
const expectedDamage = Math.max(0, 5 - defense); // Default 5 damage - defense
// Start turn
turnSystem.startTurn(unit);
// Unit should still take damage (default 5, reduced by defense)
if (expectedDamage > 0) {
expect(unit.currentHealth).to.be.lessThan(initialHP);
}
expect(unit.currentHealth).to.equal(initialHP - expectedDamage);
});
it("should process hazards before status effects in turn order", () => {
// Add hazard and status effect
grid.addHazard(unit.position, "HAZARD_FIRE", 1);
unit.statusEffects = [
{
id: "poison",
type: "DOT",
damage: 3,
duration: 1,
},
];
const initialHP = unit.currentHealth;
const defense = unit.baseStats.defense || 0;
const hazardDamage = Math.max(0, 5 - defense); // 5 fire damage - defense
const poisonDamage = 3; // Poison damage (not reduced by defense in current implementation)
// Start turn
turnSystem.startTurn(unit);
// Should have taken both hazard damage and poison damage
expect(unit.currentHealth).to.equal(initialHP - hazardDamage - poisonDamage);
});
});
});