import { expect } from "@esm-bundle/chai"; import { GameLoop } from "../../../src/core/GameLoop.js"; import { createGameLoopSetup, cleanupGameLoop, createRunData, createMockGameStateManagerForCombat, setupCombatUnits, cleanupTurnSystem, } from "./helpers.js"; describe("Core: GameLoop - Combat Turn System", function () { this.timeout(30000); let gameLoop; let container; let mockGameStateManager; let playerUnit; let enemyUnit; beforeEach(async () => { const setup = createGameLoopSetup(); gameLoop = setup.gameLoop; container = setup.container; gameLoop.stop(); if ( gameLoop.turnSystem && typeof gameLoop.turnSystem.reset === "function" ) { gameLoop.turnSystem.reset(); } gameLoop.init(container); mockGameStateManager = createMockGameStateManagerForCombat(); gameLoop.gameStateManager = mockGameStateManager; const runData = createRunData({ squad: [{ id: "u1", classId: "CLASS_VANGUARD" }], }); await gameLoop.startLevel(runData, { startAnimation: false }); const units = setupCombatUnits(gameLoop); playerUnit = units.playerUnit; enemyUnit = units.enemyUnit; }); afterEach(() => { gameLoop.clearMovementHighlights(); gameLoop.clearSpawnZoneHighlights(); cleanupTurnSystem(gameLoop); cleanupGameLoop(gameLoop, container); }); it("CoA 12: should end turn and advance turn queue", () => { const allUnits = [playerUnit, enemyUnit]; gameLoop.turnSystem.startCombat(allUnits); const activeUnit = gameLoop.turnSystem.getActiveUnit(); expect(activeUnit).to.exist; const initialCharge = activeUnit.chargeMeter; expect(initialCharge).to.be.greaterThanOrEqual(100); gameLoop.endTurn(); expect(activeUnit.chargeMeter).to.be.a("number"); expect(activeUnit.chargeMeter).to.be.at.least(0); const minExpectedAfterSubtraction = Math.max(0, initialCharge - 100); expect(activeUnit.chargeMeter).to.be.at.least(minExpectedAfterSubtraction); const nextUnit = gameLoop.turnSystem?.getActiveUnit(); expect(nextUnit).to.exist; expect(nextUnit.chargeMeter).to.be.greaterThanOrEqual(100); }); it("CoA 13: should restore AP for units when their turn starts (via TurnSystem)", () => { enemyUnit.currentAP = 0; playerUnit.baseStats.speed = 10; enemyUnit.baseStats.speed = 10; const allUnits = [playerUnit, enemyUnit]; gameLoop.turnSystem.startCombat(allUnits); let attempts = 0; while ( gameLoop.turnSystem.getActiveUnit() !== playerUnit && attempts < 10 ) { const current = gameLoop.turnSystem.getActiveUnit(); if (current) { gameLoop.turnSystem.endTurn(current); } else { break; } attempts++; } expect(gameLoop.turnSystem.getActiveUnit()).to.equal(playerUnit); gameLoop.endTurn(); attempts = 0; while (gameLoop.turnSystem.getActiveUnit() !== enemyUnit && attempts < 10) { const current = gameLoop.turnSystem.getActiveUnit(); if (current && current !== enemyUnit) { gameLoop.endTurn(); } else { break; } attempts++; } const activeUnit = gameLoop.turnSystem.getActiveUnit(); expect(activeUnit).to.equal(enemyUnit); expect(enemyUnit.currentAP).to.equal(5); }); it("CoA 16: should initialize all units with full AP when combat starts", () => { const fastUnit = gameLoop.unitManager.createUnit( "CLASS_VANGUARD", "PLAYER" ); fastUnit.baseStats.speed = 20; fastUnit.position = { x: 3, y: 1, z: 3 }; gameLoop.grid.placeUnit(fastUnit, fastUnit.position); const slowUnit = gameLoop.unitManager.createUnit( "CLASS_VANGUARD", "PLAYER" ); slowUnit.baseStats.speed = 5; slowUnit.position = { x: 4, y: 1, z: 4 }; gameLoop.grid.placeUnit(slowUnit, slowUnit.position); const enemyUnit2 = gameLoop.unitManager.createUnit( "ENEMY_DEFAULT", "ENEMY" ); enemyUnit2.baseStats.speed = 8; enemyUnit2.position = { x: 10, y: 1, z: 10 }; gameLoop.grid.placeUnit(enemyUnit2, enemyUnit2.position); gameLoop.initializeCombatUnits(); expect(fastUnit.currentAP).to.equal(10); expect(slowUnit.currentAP).to.equal(10); expect(enemyUnit2.currentAP).to.equal(10); expect(fastUnit.chargeMeter).to.be.greaterThan(slowUnit.chargeMeter); }); });