diff --git a/src/components/game/BattleSimulatorPanel.tsx b/src/components/game/BattleSimulatorPanel.tsx index e608401f..4d2d387a 100644 --- a/src/components/game/BattleSimulatorPanel.tsx +++ b/src/components/game/BattleSimulatorPanel.tsx @@ -210,21 +210,13 @@ export const BattleSimulatorPanel = memo(function BattleSimulatorPanel() { }, [selectedUnit, selectedTeam, spawnQuantity]); const handleFight = useCallback(() => { - console.log('[BattleSimulator] handleFight called'); const bridge = getWorkerBridge(); const worldAdapter = RenderStateWorldAdapter.getInstance(); - if (!worldAdapter) { - console.warn('[BattleSimulator] No world adapter available'); + if (!worldAdapter || !bridge) { return; } - if (!bridge) { - console.warn('[BattleSimulator] No worker bridge available'); - return; - } - - console.log('[BattleSimulator] Registering AI for both players'); // Register both players as AI-controlled so the AI takes over and fights const player1Faction = playerSlots[0]?.faction ?? 'dominion'; const player2Faction = playerSlots[1]?.faction ?? 'dominion'; @@ -232,18 +224,9 @@ export const BattleSimulatorPanel = memo(function BattleSimulatorPanel() { bridge.registerAI('player2', player2Faction, 'medium'); const currentTick = bridge.currentTick; - console.log('[BattleSimulator] Current tick:', currentTick); // Get all units from render state adapter const entities = worldAdapter.getEntitiesWith('Unit', 'Selectable', 'Transform', 'Health'); - console.log('[BattleSimulator] Found entities:', entities.length); - - let skippedNoComponents = 0; - let skippedDead = 0; - let skippedWorker = 0; - let skippedWrongPlayer = 0; - let attackCommands = 0; - let moveCommands = 0; for (const entity of entities) { const selectable = entity.get<{ playerId: string }>('Selectable'); @@ -259,29 +242,16 @@ export const BattleSimulatorPanel = memo(function BattleSimulatorPanel() { const transform = entity.get<{ x: number; y: number }>('Transform'); const health = entity.get<{ isDead: () => boolean }>('Health'); - if (!selectable || !unit || !transform || !health) { - skippedNoComponents++; - continue; - } - if (health.isDead()) { - skippedDead++; - continue; - } - if (unit.isWorker) { - skippedWorker++; - continue; - } + if (!selectable || !unit || !transform || !health) continue; + if (health.isDead()) continue; + if (unit.isWorker) continue; const playerId = selectable.playerId; - if (playerId !== 'player1' && playerId !== 'player2') { - skippedWrongPlayer++; - continue; - } + if (playerId !== 'player1' && playerId !== 'player2') continue; const targetId = findValidTarget(worldAdapter, entity.id, unit, transform, playerId); if (targetId !== null) { - attackCommands++; const attackCommand: GameCommand = { tick: currentTick, playerId, @@ -293,7 +263,6 @@ export const BattleSimulatorPanel = memo(function BattleSimulatorPanel() { } else { const enemyCenter = findEnemyCenter(worldAdapter, unit, playerId); if (enemyCenter) { - moveCommands++; const moveCommand: GameCommand = { tick: currentTick, playerId, @@ -306,21 +275,9 @@ export const BattleSimulatorPanel = memo(function BattleSimulatorPanel() { } } - console.log('[BattleSimulator] Entity processing stats:', { - total: entities.length, - skippedNoComponents, - skippedDead, - skippedWorker, - skippedWrongPlayer, - attackCommands, - moveCommands, - }); - - console.log('[BattleSimulator] Calling bridge.resume()'); bridge.resume(); setIsPaused(false); setSelectedUnit(null); - console.log('[BattleSimulator] handleFight completed'); }, [playerSlots]); const handlePauseToggle = useCallback(() => { diff --git a/src/engine/workers/GameWorker.ts b/src/engine/workers/GameWorker.ts index db23b4f1..9954b63c 100644 --- a/src/engine/workers/GameWorker.ts +++ b/src/engine/workers/GameWorker.ts @@ -835,6 +835,10 @@ export class WorkerGame extends GameCore { // Combat stats for range overlays attackRange: unit.attackRange, sightRange: unit.sightRange, + // Targeting capabilities + isNaval: unit.isNaval, + canAttackGround: unit.canAttackGround, + canAttackAir: unit.canAttackAir, // Selection properties for hit detection selectionRadius: selectable.selectionRadius, selectionPriority: selectable.selectionPriority, diff --git a/src/engine/workers/RenderStateAdapter.ts b/src/engine/workers/RenderStateAdapter.ts index cca38f02..d1c87db4 100644 --- a/src/engine/workers/RenderStateAdapter.ts +++ b/src/engine/workers/RenderStateAdapter.ts @@ -128,10 +128,19 @@ class UnitAdapter { public targetY: number | null; public speed: number; // Command queue for shift-click visualization - public commandQueue: Array<{ type: string; targetX?: number; targetY?: number; targetEntityId?: number }>; + public commandQueue: Array<{ + type: string; + targetX?: number; + targetY?: number; + targetEntityId?: number; + }>; // Combat stats for range overlays public attackRange: number; public sightRange: number; + // Targeting capabilities + public isNaval: boolean; + public canAttackGround: boolean; + public canAttackAir: boolean; constructor(data: UnitRenderState) { this.unitId = data.unitId; @@ -153,6 +162,9 @@ class UnitAdapter { this.commandQueue = data.commandQueue; this.attackRange = data.attackRange; this.sightRange = data.sightRange; + this.isNaval = data.isNaval; + this.canAttackGround = data.canAttackGround; + this.canAttackAir = data.canAttackAir; } public update(data: UnitRenderState): void { @@ -175,6 +187,9 @@ class UnitAdapter { this.commandQueue = data.commandQueue; this.attackRange = data.attackRange; this.sightRange = data.sightRange; + this.isNaval = data.isNaval; + this.canAttackGround = data.canAttackGround; + this.canAttackAir = data.canAttackAir; } public isSelected(): boolean { @@ -371,9 +386,7 @@ class BuildingComponentAdapter { this.isFlying = data.isFlying; this.liftProgress = data.liftProgress; // Simulate productionQueue for renderer compatibility - this.productionQueue = data.hasProductionQueue - ? [{ progress: data.productionProgress }] - : []; + this.productionQueue = data.hasProductionQueue ? [{ progress: data.productionProgress }] : []; this.attackRange = data.attackRange; this.sightRange = data.sightRange; } @@ -389,9 +402,7 @@ class BuildingComponentAdapter { this.isFlying = data.isFlying; this.liftProgress = data.liftProgress; // Simulate productionQueue for renderer compatibility - this.productionQueue = data.hasProductionQueue - ? [{ progress: data.productionProgress }] - : []; + this.productionQueue = data.hasProductionQueue ? [{ progress: data.productionProgress }] : []; this.attackRange = data.attackRange; this.sightRange = data.sightRange; } @@ -576,7 +587,7 @@ class ResourceComponentAdapter { } public getDepletionPercent(): number { - return this.maxAmount > 0 ? 1 - (this.amount / this.maxAmount) : 0; + return this.maxAmount > 0 ? 1 - this.amount / this.maxAmount : 0; } public getCurrentGatherers(): number { @@ -622,7 +633,9 @@ export class RenderStateWorldAdapter implements IWorldProvider { if (!instance) { instance = new RenderStateWorldAdapter(); global[RENDER_STATE_ADAPTER_KEY] = instance; - debugInitialization.log('[RenderStateWorldAdapter] Created new singleton instance on globalThis'); + debugInitialization.log( + '[RenderStateWorldAdapter] Created new singleton instance on globalThis' + ); } return instance; } @@ -683,9 +696,11 @@ export class RenderStateWorldAdapter implements IWorldProvider { try { this._updateCount++; - // Debug: log first significant update - if (!this.hasLoggedFirstUpdate && (state.units.length > 0 || state.buildings.length > 0 || state.resources.length > 0)) { + if ( + !this.hasLoggedFirstUpdate && + (state.units.length > 0 || state.buildings.length > 0 || state.resources.length > 0) + ) { debugInitialization.log('[RenderStateWorldAdapter] First update with entities:', { tick: state.tick, units: state.units.length, @@ -753,7 +768,12 @@ export class RenderStateWorldAdapter implements IWorldProvider { } // Mark as ready once we have entities - if (!this._isReady && (this.unitEntities.size > 0 || this.buildingEntities.size > 0 || this.resourceEntities.size > 0)) { + if ( + !this._isReady && + (this.unitEntities.size > 0 || + this.buildingEntities.size > 0 || + this.resourceEntities.size > 0) + ) { this._isReady = true; debugInitialization.log('[RenderStateWorldAdapter] Adapter is now ready with entities:', { units: this.unitEntities.size, @@ -762,7 +782,10 @@ export class RenderStateWorldAdapter implements IWorldProvider { }); } } catch (error) { - debugInitialization.error('[RenderStateWorldAdapter] Error updating from render state:', error); + debugInitialization.error( + '[RenderStateWorldAdapter] Error updating from render state:', + error + ); } } @@ -786,13 +809,13 @@ export class RenderStateWorldAdapter implements IWorldProvider { // Units: return when querying for Unit, Selectable (without Building/Resource filter), // or Transform alone (legacy) - const includeUnits = hasUnit || - (hasSelectable && !hasBuilding && !hasResource) || - (hasTransform && componentTypes.length === 1); + const includeUnits = + hasUnit || + (hasSelectable && !hasBuilding && !hasResource) || + (hasTransform && componentTypes.length === 1); // Buildings: return when querying for Building, or Selectable (without Unit/Resource filter) - const includeBuildings = hasBuilding || - (hasSelectable && !hasUnit && !hasResource); + const includeBuildings = hasBuilding || (hasSelectable && !hasUnit && !hasResource); // Resources: return when querying for Resource const includeResources = hasResource; @@ -822,10 +845,12 @@ export class RenderStateWorldAdapter implements IWorldProvider { * Get entity by ID */ public getEntity(entityId: number): IEntity | null { - return this.unitEntities.get(entityId) - ?? this.buildingEntities.get(entityId) - ?? this.resourceEntities.get(entityId) - ?? null; + return ( + this.unitEntities.get(entityId) ?? + this.buildingEntities.get(entityId) ?? + this.resourceEntities.get(entityId) ?? + null + ); } /** diff --git a/src/engine/workers/types.ts b/src/engine/workers/types.ts index 5789e7ea..8a65d9e8 100644 --- a/src/engine/workers/types.ts +++ b/src/engine/workers/types.ts @@ -80,6 +80,10 @@ export interface UnitRenderState { // Combat stats for range overlays attackRange: number; sightRange: number; + // Targeting capabilities + isNaval: boolean; + canAttackGround: boolean; + canAttackAir: boolean; // Selection properties for hit detection selectionRadius: number; selectionPriority: number;