From b725671dffa6fadb00d1f219bcc7f263812d6d75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 19:24:21 +0000 Subject: [PATCH 01/17] Initial plan From d8d8a8750acd62f41d66cb22308dc137fa16fa9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 19:26:10 +0000 Subject: [PATCH 02/17] Make drawEnemyResistanceIndicator resilient to missing resistance fields Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com> --- js/systems/RenderSystem.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/js/systems/RenderSystem.js b/js/systems/RenderSystem.js index 9285e1c..30be335 100644 --- a/js/systems/RenderSystem.js +++ b/js/systems/RenderSystem.js @@ -318,21 +318,33 @@ class RenderSystem { let layerCount = 0; if (defense.shield.current > 0) { - const base = defense.shield.baseResistances[damageType] || 0; - const bonus = defense.shield.bonusResistances && defense.shield.bonusResistances[damageType] || 0; - totalResist += base + bonus; + const layerData = defense.shield; + const baseRes = layerData.baseResistances || layerData.resistances || {}; + const bonusRes = layerData.bonusResistances || {}; + const base = baseRes[damageType] || 0; + const bonus = bonusRes[damageType] || 0; + const total = base + bonus; + totalResist += total; layerCount++; } if (defense.armor.current > 0) { - const base = defense.armor.baseResistances[damageType] || 0; - const bonus = defense.armor.bonusResistances && defense.armor.bonusResistances[damageType] || 0; - totalResist += base + bonus; + const layerData = defense.armor; + const baseRes = layerData.baseResistances || layerData.resistances || {}; + const bonusRes = layerData.bonusResistances || {}; + const base = baseRes[damageType] || 0; + const bonus = bonusRes[damageType] || 0; + const total = base + bonus; + totalResist += total; layerCount++; } if (defense.structure.current > 0) { - const base = defense.structure.baseResistances[damageType] || 0; - const bonus = defense.structure.bonusResistances && defense.structure.bonusResistances[damageType] || 0; - totalResist += base + bonus; + const layerData = defense.structure; + const baseRes = layerData.baseResistances || layerData.resistances || {}; + const bonusRes = layerData.bonusResistances || {}; + const base = baseRes[damageType] || 0; + const bonus = bonusRes[damageType] || 0; + const total = base + bonus; + totalResist += total; layerCount++; } From f76a9461a4bca3f5f452193f458650d46546df0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 19:28:07 +0000 Subject: [PATCH 03/17] Apply code review feedback: remove unnecessary total variable Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com> --- js/systems/RenderSystem.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/js/systems/RenderSystem.js b/js/systems/RenderSystem.js index 30be335..3e84b3e 100644 --- a/js/systems/RenderSystem.js +++ b/js/systems/RenderSystem.js @@ -323,8 +323,7 @@ class RenderSystem { const bonusRes = layerData.bonusResistances || {}; const base = baseRes[damageType] || 0; const bonus = bonusRes[damageType] || 0; - const total = base + bonus; - totalResist += total; + totalResist += base + bonus; layerCount++; } if (defense.armor.current > 0) { @@ -333,8 +332,7 @@ class RenderSystem { const bonusRes = layerData.bonusResistances || {}; const base = baseRes[damageType] || 0; const bonus = bonusRes[damageType] || 0; - const total = base + bonus; - totalResist += total; + totalResist += base + bonus; layerCount++; } if (defense.structure.current > 0) { @@ -343,8 +341,7 @@ class RenderSystem { const bonusRes = layerData.bonusResistances || {}; const base = baseRes[damageType] || 0; const bonus = bonusRes[damageType] || 0; - const total = base + bonus; - totalResist += total; + totalResist += base + bonus; layerCount++; } From 9740fde512e37327db0220444dc20ce390bf0dc9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 19:45:37 +0000 Subject: [PATCH 04/17] Gate all debug logs behind COLLISION_DEBUG flag Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com> --- js/systems/CollisionSystem.js | 193 +++++++++++++++++++++------------- 1 file changed, 119 insertions(+), 74 deletions(-) diff --git a/js/systems/CollisionSystem.js b/js/systems/CollisionSystem.js index 0c3db4e..bdff7a6 100644 --- a/js/systems/CollisionSystem.js +++ b/js/systems/CollisionSystem.js @@ -3,6 +3,9 @@ * @description Handles collision detection between entities */ +// Debug flag to control collision debug logging +const COLLISION_DEBUG = false; + // Hit cooldown constant (200ms to prevent instant melt from tick collisions) const HIT_COOLDOWN_MS = 200; @@ -238,7 +241,9 @@ class CollisionSystem { const projectiles = this.world.getEntitiesByType('projectile'); // 🔍 DEBUG: Log player and projectile counts - console.log(`[DEBUG COLLISION] Players found: ${players.length}, Projectiles found: ${projectiles.length}`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] Players found: ${players.length}, Projectiles found: ${projectiles.length}`); + } for (const player of players) { const playerPos = player.getComponent('position'); @@ -246,27 +251,35 @@ class CollisionSystem { const playerHealth = player.getComponent('health'); const playerDefense = player.getComponent('defense'); - console.log(`[DEBUG COLLISION] Player entity:`, { - id: player.id, - type: player.type, - hasPos: !!playerPos, - hasCol: !!playerCol, - hasHealth: !!playerHealth, - hasDefense: !!playerDefense - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] Player entity:`, { + id: player.id, + type: player.type, + hasPos: !!playerPos, + hasCol: !!playerCol, + hasHealth: !!playerHealth, + hasDefense: !!playerDefense + }); + } if (!playerPos || !playerCol || (!playerHealth && !playerDefense)) { - console.log(`[DEBUG COLLISION] ❌ Player missing required components, skipping`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ❌ Player missing required components, skipping`); + } continue; } // BUG FIX: Check invulnerability on defense component (player uses defense, not health) if (playerDefense && (playerDefense.invulnerable || playerDefense.godMode)) { - console.log(`[DEBUG COLLISION] ❌ Player invulnerable (defense), skipping all projectiles`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ❌ Player invulnerable (defense), skipping all projectiles`); + } continue; } if (playerHealth && (playerHealth.invulnerable || playerHealth.godMode)) { - console.log(`[DEBUG COLLISION] ❌ Player invulnerable (health), skipping all projectiles`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ❌ Player invulnerable (health), skipping all projectiles`); + } continue; } @@ -276,41 +289,51 @@ class CollisionSystem { const projComp = projectile.getComponent('projectile'); if (!projPos || !projCol || !projComp) { - console.log(`[DEBUG COLLISION] ⚠️ Projectile ${projectile.id} missing components`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ⚠️ Projectile ${projectile.id} missing components`); + } continue; } // 🔍 REQUESTED DEBUG: Log collision check details BEFORE ANY filtering - console.log( - "[DEBUG COLLISION CHECK]", - { - projectileId: projectile.id, - projectileOwner: projComp.owner, - projectileTag: projectile.type, - playerId: player.id, - playerTags: player.type, - projectilePos: { x: projPos.x, y: projPos.y }, - playerPos: { x: playerPos.x, y: playerPos.y } - } - ); + if (COLLISION_DEBUG) { + console.log( + "[DEBUG COLLISION CHECK]", + { + projectileId: projectile.id, + projectileOwner: projComp.owner, + projectileTag: projectile.type, + playerId: player.id, + playerTags: player.type, + projectilePos: { x: projPos.x, y: projPos.y }, + playerPos: { x: playerPos.x, y: playerPos.y } + } + ); + } // 🔍 DEBUG: Log projectile details BEFORE owner check - console.log(`[DEBUG COLLISION] Checking projectile ${projectile.id}:`, { - owner: projComp.owner, - damage: projComp.damage, - damageType: projComp.damageType, - pos: { x: projPos.x.toFixed(1), y: projPos.y.toFixed(1) } - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] Checking projectile ${projectile.id}:`, { + owner: projComp.owner, + damage: projComp.damage, + damageType: projComp.damageType, + pos: { x: projPos.x.toFixed(1), y: projPos.y.toFixed(1) } + }); + } // Check if projectile is from enemy (owner is an enemy entity or 'enemy' string) const ownerEntity = this.world.getEntity(projComp.owner); - console.log(`[DEBUG COLLISION] Owner entity lookup for ${projComp.owner}:`, { - found: !!ownerEntity, - type: ownerEntity?.type - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] Owner entity lookup for ${projComp.owner}:`, { + found: !!ownerEntity, + type: ownerEntity?.type + }); + } if (!ownerEntity || ownerEntity.type !== 'enemy') { - console.log(`[DEBUG COLLISION] ❌ Projectile ${projectile.id} not from enemy, skipping`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ❌ Projectile ${projectile.id} not from enemy, skipping`); + } continue; } @@ -321,26 +344,32 @@ class CollisionSystem { const collisionThreshold = playerCol.radius + projCol.radius; // 🔍 REQUESTED DEBUG: Log distance and radius details - console.log( - "[DEBUG DISTANCE]", - { - distance: distance, - projectileRadius: projCol.radius, - playerRadius: playerCol.radius, - sum: projCol.radius + playerCol.radius - } - ); + if (COLLISION_DEBUG) { + console.log( + "[DEBUG DISTANCE]", + { + distance: distance, + projectileRadius: projCol.radius, + playerRadius: playerCol.radius, + sum: projCol.radius + playerCol.radius + } + ); + } - console.log(`[DEBUG COLLISION] Distance check:`, { - distance: distance.toFixed(1), - threshold: collisionThreshold.toFixed(1), - willCollide: distance <= collisionThreshold - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] Distance check:`, { + distance: distance.toFixed(1), + threshold: collisionThreshold.toFixed(1), + willCollide: distance <= collisionThreshold + }); + } // FIX: Check hit cooldown for this projectile const sourceId = `projectile_${projectile.id}`; if (this.hitCooldowns.has(sourceId)) { - console.log(`[DEBUG COLLISION] ❌ Projectile ${projectile.id} on cooldown, skipping`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ❌ Projectile ${projectile.id} on cooldown, skipping`); + } continue; // Still on cooldown } @@ -348,8 +377,10 @@ class CollisionSystem { playerPos.x, playerPos.y, playerCol.radius, projPos.x, projPos.y, projCol.radius )) { - console.log(`[DEBUG COLLISION] ✅ COLLISION DETECTED! Projectile ${projectile.id} hit player ${player.id}`); - console.log(`[DEBUG COLLISION] ✅ COLLISION DETECTED! Projectile ${projectile.id} hit player ${player.id}`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ✅ COLLISION DETECTED! Projectile ${projectile.id} hit player ${player.id}`); + console.log(`[DEBUG COLLISION] ✅ COLLISION DETECTED! Projectile ${projectile.id} hit player ${player.id}`); + } // Check hit cooldown to prevent instant melt from tick collisions const now = performance.now(); @@ -360,20 +391,26 @@ class CollisionSystem { const lastHitTime = this.hitCooldowns.get(cooldownKey) || 0; const timeSinceLastHit = now - lastHitTime; - console.log(`[DEBUG COLLISION] Hit cooldown check:`, { - cooldownKey, - timeSinceLastHit: timeSinceLastHit.toFixed(0), - cooldownThreshold: HIT_COOLDOWN_MS, - willDamage: timeSinceLastHit >= HIT_COOLDOWN_MS - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] Hit cooldown check:`, { + cooldownKey, + timeSinceLastHit: timeSinceLastHit.toFixed(0), + cooldownThreshold: HIT_COOLDOWN_MS, + willDamage: timeSinceLastHit >= HIT_COOLDOWN_MS + }); + } if (timeSinceLastHit < HIT_COOLDOWN_MS) { // Still in cooldown, ignore this hit - console.log(`[DEBUG COLLISION] ❌ Hit cooldown active, ignoring damage`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ❌ Hit cooldown active, ignoring damage`); + } logger.debug('Collision', `Hit cooldown active (${timeSinceLastHit.toFixed(0)}ms < ${HIT_COOLDOWN_MS}ms) - ignoring damage`); } else { // Cooldown expired or first hit, deal damage - console.log(`[DEBUG COLLISION] ✅ Calling damagePlayer() with damage: ${projComp.damage}, type: ${damageType}`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG COLLISION] ✅ Calling damagePlayer() with damage: ${projComp.damage}, type: ${damageType}`); + } this.damagePlayer(player, projComp.damage, damageType); // Update cooldown timestamp @@ -470,22 +507,26 @@ class CollisionSystem { } damagePlayer(player, damage, damageType = 'kinetic') { - console.log(`[DEBUG DAMAGE] damagePlayer() called:`, { - playerId: player?.id, - damage, - damageType - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG DAMAGE] damagePlayer() called:`, { + playerId: player?.id, + damage, + damageType + }); + } const playerComp = player.getComponent('player'); const defense = player.getComponent('defense'); const health = player.getComponent('health'); - console.log(`[DEBUG DAMAGE] Player components:`, { - hasPlayerComp: !!playerComp, - hasDefense: !!defense, - hasHealth: !!health, - defenseSystemExists: !!(this.world && this.world.defenseSystem) - }); + if (COLLISION_DEBUG) { + console.log(`[DEBUG DAMAGE] Player components:`, { + hasPlayerComp: !!playerComp, + hasDefense: !!defense, + hasHealth: !!health, + defenseSystemExists: !!(this.world && this.world.defenseSystem) + }); + } if (!playerComp) { console.error('[CollisionSystem] damagePlayer: Missing player component'); @@ -503,11 +544,15 @@ class CollisionSystem { // Apply damage through DefenseSystem (the only authority for defense modifications) // Use DamagePacket for proper structure if (defense && this.world && this.world.defenseSystem) { - console.log(`[DEBUG DAMAGE] Calling DefenseSystem.applyDamage()...`); + if (COLLISION_DEBUG) { + console.log(`[DEBUG DAMAGE] Calling DefenseSystem.applyDamage()...`); + } const damagePacket = DamagePacket.simple(damage, damageType); const result = this.world.defenseSystem.applyDamage(player, damagePacket); - console.log(`[DEBUG DAMAGE] DefenseSystem.applyDamage() result:`, result); + if (COLLISION_DEBUG) { + console.log(`[DEBUG DAMAGE] DefenseSystem.applyDamage() result:`, result); + } // Validate result if (!result || typeof result.dealt !== 'number') { From cd11c4a87838c4f66e173a532079745c678ad53f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 20:07:56 +0000 Subject: [PATCH 05/17] Add Combat Dev Sandbox page for testing combat mechanics Co-authored-by: Linkatplug <36280686+Linkatplug@users.noreply.github.com> --- dev/test-combat-sandbox.html | 749 +++++++++++++++++++++++++++++++++++ 1 file changed, 749 insertions(+) create mode 100644 dev/test-combat-sandbox.html diff --git a/dev/test-combat-sandbox.html b/dev/test-combat-sandbox.html new file mode 100644 index 0000000..5ef5fe0 --- /dev/null +++ b/dev/test-combat-sandbox.html @@ -0,0 +1,749 @@ + + +
+ + +