diff options
Diffstat (limited to 'html/XCOM/game.js')
-rw-r--r-- | html/XCOM/game.js | 72 |
1 files changed, 63 insertions, 9 deletions
diff --git a/html/XCOM/game.js b/html/XCOM/game.js index e4d39c8..6c4e256 100644 --- a/html/XCOM/game.js +++ b/html/XCOM/game.js @@ -69,6 +69,7 @@ const TILE_SIZE = 40; const UNIT_RADIUS = 15; const OBSTACLE_MAX_HEALTH = 20; +const MAX_VISIBILITY_RANGE = 6; // Maximum distance units can see const ENEMY_TURN_SPEED = 0.3; // Enemy turns are 3x faster than player turns const ENEMY_ACTION_FEEDBACK_DURATION = 800; // How long to show enemy action feedback const AI_BEHAVIORS = ['aggressive', 'patrol', 'stationary']; @@ -1304,9 +1305,9 @@ function createPlayerUnit(id, x, y) { owner: 'player', x, y, - maxMovement: generateStat(2, 10), + maxMovement: generateStat(2, 6), // Reduced from 2-10 to 2-6 movementRange: 0, // Will be set to maxMovement - shootRange: generateStat(4, 15), + shootRange: generateStat(3, 8), // Reduced from 4-15 to 3-8 damage: generateStat(5, 20), maxHp: generateStat(30, 60), currentHp: 0, // Will be set to maxHp @@ -1390,9 +1391,9 @@ function createEnemyUnit(id, x, y) { owner: 'enemy', x, y, - maxMovement: generateStat(2, 10), + maxMovement: generateStat(2, 6), // Reduced from 2-10 to 2-6 movementRange: 0, // Will be set to maxMovement - shootRange: generateStat(4, 15), + shootRange: generateStat(3, 8), // Reduced from 4-15 to 3-8 damage: generateStat(5, 10), maxHp: generateStat(10, 20), currentHp: 0, // Will be set to maxHp @@ -2371,6 +2372,7 @@ function view(model, canvas, ctx) { drawUnits(model, ctx); drawFogOfWar(model, ctx); // Add fog of war effect drawStatusMessage(model, ctx); // Add status message + drawVisibilityRanges(model, ctx); // Add visibility ranges // Post-condition: canvas displays the current model state. } @@ -2406,6 +2408,31 @@ function drawStatusMessage(model, ctx) { } } +/** + * Draws visibility range indicators around player units + * @param {Model} model + * @param {CanvasRenderingContext2D} ctx + */ +function drawVisibilityRanges(model, ctx) { + model.units.forEach(unit => { + if (unit.owner === 'player' && !unit.isDead) { + const centerX = unit.x * TILE_SIZE + TILE_SIZE / 2; + const centerY = unit.y * TILE_SIZE + TILE_SIZE / 2; + + // Draw visibility range circle + ctx.strokeStyle = 'rgba(0, 255, 255, 0.3)'; // Cyan with transparency + ctx.lineWidth = 1; + ctx.setLineDash([3, 3]); // Dashed line + + ctx.beginPath(); + ctx.arc(centerX, centerY, MAX_VISIBILITY_RANGE * TILE_SIZE, 0, Math.PI * 2); + ctx.stroke(); + + ctx.setLineDash([]); // Reset line dash + } + }); +} + // ------------------------------------------------ // 4. MAIN APPLICATION LOOP // ------------------------------------------------ @@ -2660,8 +2687,22 @@ function checkLineOfSight(startX, startY, endX, endY, grid, units) { const dy = endY - startY; const distance = Math.sqrt(dx * dx + dy * dy); + // Add maximum visibility range - units can't see beyond this distance + const MAX_VISIBILITY_RANGE = 6; // Reduced from unlimited to 6 tiles + if (distance === 0) return { blocked: false, blocker: null, obstacleX: null, obstacleY: null }; + // If target is beyond visibility range, it's blocked + if (distance > MAX_VISIBILITY_RANGE) { + return { + blocked: true, + blocker: null, + obstacleX: null, + obstacleY: null, + reason: 'beyond_visibility_range' + }; + } + // Use Bresenham's line algorithm to check each tile along the path const steps = Math.max(Math.abs(dx), Math.abs(dy)); const xStep = dx / steps; @@ -2682,7 +2723,8 @@ function checkLineOfSight(startX, startY, endX, endY, grid, units) { blocked: true, blocker: null, obstacleX: checkX, - obstacleY: checkY + obstacleY: checkY, + reason: 'obstacle' }; } @@ -2696,12 +2738,13 @@ function checkLineOfSight(startX, startY, endX, endY, grid, units) { blocked: true, blocker: blockingUnit, obstacleX: null, - obstacleY: null + obstacleY: null, + reason: 'unit' }; } } - return { blocked: false, blocker: null, obstacleX: null, obstacleY: null }; + return { blocked: false, blocker: null, obstacleX: null, obstacleY: null, reason: 'clear' }; } /** @@ -2843,8 +2886,19 @@ function drawFogOfWar(model, ctx) { * @returns {Unit[]} Units with turn order assigned */ function generateTurnOrder(units) { - const shuffledUnits = [...units].sort(() => Math.random() - 0.5); - return shuffledUnits.map((unit, index) => ({ + // Separate player and enemy units + const playerUnits = units.filter(u => u.owner === 'player'); + const enemyUnits = units.filter(u => u.owner === 'enemy'); + + // Shuffle each group separately + const shuffledPlayers = [...playerUnits].sort(() => Math.random() - 0.5); + const shuffledEnemies = [...enemyUnits].sort(() => Math.random() - 0.5); + + // Combine: players first, then enemies + const orderedUnits = [...shuffledPlayers, ...shuffledEnemies]; + + // Assign turn order + return orderedUnits.map((unit, index) => ({ ...unit, turnOrder: index })); |