about summary refs log tree commit diff stats
path: root/html/XCOM/game.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/XCOM/game.js')
-rw-r--r--html/XCOM/game.js72
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
     }));