# 🔧 Quick Fixes for Critical Gameplay Issues ## Fix 1: Attack System Implementation ### Backend (app.py) Add after line 420: ```python # Add to handle_command method elif cmd_type == "attack_unit": attacker_ids = command.get("attacker_ids", []) target_id = command.get("target_id") if target_id in self.game_state.units: target = self.game_state.units[target_id] for uid in attacker_ids: if uid in self.game_state.units: attacker = self.game_state.units[uid] # Set target for attack attacker.target = Position(target.position.x, target.position.y) attacker.target_unit_id = target_id # Add this field to Unit class # Add combat logic to game_loop (after line 348) def update_combat(self): """Handle unit combat""" for unit in list(self.game_state.units.values()): if hasattr(unit, 'target_unit_id') and unit.target_unit_id: target_id = unit.target_unit_id if target_id in self.game_state.units: target = self.game_state.units[target_id] # Check range distance = unit.position.distance_to(target.position) if distance <= unit.range: # In range - attack! unit.target = None # Stop moving # Apply damage (simplified - no cooldown for now) target.health -= unit.damage / 20 # Damage over time if target.health <= 0: # Target destroyed del self.game_state.units[target_id] unit.target_unit_id = None else: # Move closer unit.target = Position(target.position.x, target.position.y) else: # Target no longer exists unit.target_unit_id = None ``` ### Frontend (static/game.js) Replace `onRightClick` method around line 220: ```javascript onRightClick(e) { e.preventDefault(); if (this.selectedUnits.size === 0) return; const rect = this.canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; // Convert to world coordinates const worldX = (x / this.camera.zoom) + this.camera.x; const worldY = (y / this.camera.zoom) + this.camera.y; // Check if clicking on an enemy unit const clickedUnit = this.getUnitAtPosition(worldX, worldY); if (clickedUnit && clickedUnit.player_id !== 0) { // ATTACK ENEMY UNIT this.attackUnit(clickedUnit.id); this.showNotification(`🎯 Attacking enemy ${clickedUnit.type}!`, 'warning'); } else { // MOVE TO POSITION this.moveSelectedUnits(worldX, worldY); } } // Add new methods getUnitAtPosition(worldX, worldY) { if (!this.gameState || !this.gameState.units) return null; const CLICK_TOLERANCE = CONFIG.TILE_SIZE; for (const [id, unit] of Object.entries(this.gameState.units)) { const dx = worldX - (unit.position.x + CONFIG.TILE_SIZE / 2); const dy = worldY - (unit.position.y + CONFIG.TILE_SIZE / 2); const distance = Math.sqrt(dx * dx + dy * dy); if (distance < CLICK_TOLERANCE) { return { id, ...unit }; } } return null; } attackUnit(targetId) { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; this.ws.send(JSON.stringify({ type: 'attack_unit', attacker_ids: Array.from(this.selectedUnits), target_id: targetId })); } ``` --- ## Fix 2: Production Requirements ### Backend (app.py) Add near top of file after imports: ```python # Production requirements mapping PRODUCTION_REQUIREMENTS = { UnitType.INFANTRY: BuildingType.BARRACKS, UnitType.TANK: BuildingType.WAR_FACTORY, UnitType.ARTILLERY: BuildingType.WAR_FACTORY, UnitType.HELICOPTER: BuildingType.WAR_FACTORY, UnitType.HARVESTER: BuildingType.HQ # ← CRITICAL: Harvester needs HQ! } ``` Replace `build_unit` handler in `handle_command`: ```python elif cmd_type == "build_unit": unit_type_str = command.get("unit_type") player_id = command.get("player_id", 0) if not unit_type_str: return try: unit_type = UnitType(unit_type_str) except ValueError: return # Find required building type required_building = PRODUCTION_REQUIREMENTS.get(unit_type) if not required_building: return # Find a suitable building owned by player suitable_building = None for building in self.game_state.buildings.values(): if (building.player_id == player_id and building.type == required_building): suitable_building = building break if suitable_building: # Add to production queue suitable_building.production_queue.append(unit_type_str) # Notify client await self.broadcast({ "type": "notification", "message": f"Training {unit_type_str} at {required_building.value}", "level": "success" }) else: # Send error await self.broadcast({ "type": "notification", "message": f"⚠️ Requires {required_building.value} to train {unit_type_str}!", "level": "error" }) ``` ### Frontend (static/game.js) Update train unit methods around line 540: ```javascript trainUnit(unitType) { // Check requirements const requirements = { 'infantry': 'barracks', 'tank': 'war_factory', 'artillery': 'war_factory', 'helicopter': 'war_factory', 'harvester': 'hq' // ← CRITICAL! }; const requiredBuilding = requirements[unitType]; if (!this.hasBuilding(requiredBuilding)) { this.showNotification( `⚠️ Need ${requiredBuilding.replace('_', ' ').toUpperCase()} to train ${unitType}!`, 'error' ); return; } if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; this.ws.send(JSON.stringify({ type: 'build_unit', unit_type: unitType, player_id: 0 })); } hasBuilding(buildingType) { if (!this.gameState || !this.gameState.buildings) return false; for (const building of Object.values(this.gameState.buildings)) { if (building.player_id === 0 && building.type === buildingType) { return true; } } return false; } // Update setupBuildMenu to show requirements setupBuildMenu() { document.getElementById('train-infantry').addEventListener('click', () => { this.trainUnit('infantry'); }); document.getElementById('train-tank').addEventListener('click', () => { this.trainUnit('tank'); }); document.getElementById('train-harvester').addEventListener('click', () => { this.trainUnit('harvester'); }); document.getElementById('train-helicopter').addEventListener('click', () => { this.trainUnit('helicopter'); }); document.getElementById('train-artillery').addEventListener('click', () => { this.trainUnit('artillery'); }); // Add tooltips document.getElementById('train-infantry').title = 'Requires: Barracks'; document.getElementById('train-tank').title = 'Requires: War Factory'; document.getElementById('train-harvester').title = 'Requires: HQ (Command Center)'; document.getElementById('train-helicopter').title = 'Requires: War Factory'; document.getElementById('train-artillery').title = 'Requires: War Factory'; } ``` --- ## Fix 3: Add Unit Range Field ### Backend (app.py) Update Unit dataclass around line 68: ```python @dataclass class Unit: id: str type: UnitType player_id: int position: Position health: int max_health: int speed: float damage: int range: float = 100.0 # Add range field target_unit_id: Optional[str] = None # Add target tracking # ... rest of methods ``` Update `create_unit` method around line 185 to set range: ```python def create_unit(self, unit_type: UnitType, player_id: int, position: Position) -> Unit: """Create a new unit""" unit_stats = { UnitType.INFANTRY: {"health": 100, "speed": 2.0, "damage": 10, "range": 80}, UnitType.TANK: {"health": 200, "speed": 1.5, "damage": 30, "range": 120}, UnitType.HARVESTER: {"health": 150, "speed": 1.0, "damage": 0, "range": 0}, UnitType.HELICOPTER: {"health": 120, "speed": 3.0, "damage": 25, "range": 150}, UnitType.ARTILLERY: {"health": 100, "speed": 1.0, "damage": 50, "range": 200}, } stats = unit_stats[unit_type] unit_id = str(uuid.uuid4()) unit = Unit( id=unit_id, type=unit_type, player_id=player_id, position=position, health=stats["health"], max_health=stats["health"], speed=stats["speed"], damage=stats["damage"], range=stats["range"], # Add range target=None ) self.units[unit_id] = unit return unit ``` --- ## Testing Checklist After applying fixes: 1. **Test Attack:** - [ ] Select friendly unit - [ ] Right-click on enemy unit - [ ] Unit should move toward enemy and attack when in range - [ ] Enemy health should decrease - [ ] Enemy should be destroyed when health reaches 0 2. **Test Production:** - [ ] Try to train Harvester WITHOUT HQ → Should show error - [ ] Build HQ - [ ] Try to train Harvester WITH HQ → Should work - [ ] Try to train Infantry without Barracks → Should show error - [ ] Build Barracks - [ ] Train Infantry → Should work 3. **Test Requirements:** - [ ] Hover over unit buttons → Should show tooltip with requirements - [ ] Click button without building → Should show error notification --- ## Quick Apply Commands ```bash # Backup current files cd /home/luigi/rts/web cp app.py app.py.backup cp static/game.js static/game.js.backup # Apply fixes manually or use sed/patch # Then rebuild Docker: docker stop rts-game docker rm rts-game docker build -t rts-game-web . docker run -d --name rts-game -p 7860:7860 rts-game-web ``` --- ## Summary These fixes add: 1. ✅ **Attack System** - Right-click enemies to attack 2. ✅ **Production Requirements** - Harvester needs HQ (not Refinery!) 3. ✅ **Error Messages** - Clear feedback when requirements not met 4. ✅ **Tooltips** - Shows what building is required **Impact:** Game becomes **playable** and **faithful** to original mechanics!