diff --git a/dev/combat-sandbox-clean.html b/dev/combat-sandbox-clean.html
new file mode 100644
index 0000000..b0e1788
--- /dev/null
+++ b/dev/combat-sandbox-clean.html
@@ -0,0 +1,593 @@
+
+
+
+
+
+ Combat Sandbox - Clean (No Game Class)
+
+
+
+
+
+
+
+
System Toggles
+
+ Movement
+
+
+
+ AI
+
+
+
+ Combat
+
+
+
+ Defense
+
+
+
+ Collision
+
+
+
+
+
+
Spawn Control
+
+
+
+
+
+
+
+
+
Live Stats
+
+ Total Enemies:
+ 0
+
+
+ Shield:
+ 0/0
+
+
+ Armor:
+ 0/0
+
+
+ Structure:
+ 0/0
+
+
+ Total HP:
+ 0/0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/combat-sandbox-pro.html b/dev/combat-sandbox-pro.html
new file mode 100644
index 0000000..190d218
--- /dev/null
+++ b/dev/combat-sandbox-pro.html
@@ -0,0 +1,805 @@
+
+
+
+
+
+ Combat Dev Sandbox - Professional
+
+
+
+ Combat Dev Sandbox - Professional
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
System Toggles
+
+ AI System
+
+
+
+ Enemy Fire
+
+
+
+ Player Fire
+
+
+
+ Collision
+
+
+
+ Defense Update
+
+
+
+ Movement
+
+
+
+
+
+
Spawn Control
+
+
+
+
+
+
+
+
+
Runtime Modifiers
+
+
+ Player Damage
+ 1.0x
+
+
+
+
+
+ Enemy Damage
+ 1.0x
+
+
+
+
+
+ Enemy Fire Cooldown
+ 1.0x
+
+
+
+
+
+
+
Live Stats
+
+ Total Enemies
+ 0
+
+
+ Damage/sec
+ 0
+
+
+ Shots/sec
+ 0
+
+
+
+ Shield:
+ 0/0
+
+
+ Armor:
+ 0/0
+
+
+ Structure:
+ 0/0
+
+
+ Total HP:
+ 0/0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/combat-sandbox.html b/dev/combat-sandbox.html
new file mode 100644
index 0000000..f7ce4fb
--- /dev/null
+++ b/dev/combat-sandbox.html
@@ -0,0 +1,460 @@
+
+
+
+
+
+ Combat Sandbox - Real Game Class
+
+
+
+
+
+
+
+
Combat Sandbox
+
+ Using Real Game Class
+ WaveSystem: Disabled
+ UISystem: Disabled
+ AudioManager: Disabled
+
+
+
+
+
Spawn Control
+
+
+
+
+
+
+
+
+
Live Stats
+
+ Enemies:
+ 0
+
+
+ Shield:
+ ---
+
+
+ Armor:
+ ---
+
+
+ Structure:
+ ---
+
+
+ Total HP:
+ ---
+
+
+
+
+
Info
+
+ • WASD to move
+ • Weapons fire automatically
+ • No wave system
+ • Manual spawn only
+ • Real Game architecture
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/test-combat-sandbox.html b/dev/test-combat-sandbox.html
new file mode 100644
index 0000000..b9b67d7
--- /dev/null
+++ b/dev/test-combat-sandbox.html
@@ -0,0 +1,769 @@
+
+
+
+
+
+ Combat Dev Sandbox
+
+
+
+
+
⚔️ Combat Dev Sandbox
+
Press WASD to move • Click to fire
+
+
+
+
+
+
+
+
+
Spawn Controls
+
+
+
+
+
+
+
+
+
+
+
Player Status
+
+
+ Shield:
+ 0/0
+
+
+ Armor:
+ 0/0
+
+
+ Structure:
+ 0/0
+
+
+ Total HP:
+ 0/0
+
+
+ Enemies:
+ 0
+
+
+
+
+
+
Combat Stats & Debug
+
+ Shots/sec:
+ 0
+
+
+ Damage/sec:
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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') {
diff --git a/js/systems/RenderSystem.js b/js/systems/RenderSystem.js
index 9285e1c..3e84b3e 100644
--- a/js/systems/RenderSystem.js
+++ b/js/systems/RenderSystem.js
@@ -318,20 +318,29 @@ 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;
+ const layerData = defense.shield;
+ const baseRes = layerData.baseResistances || layerData.resistances || {};
+ const bonusRes = layerData.bonusResistances || {};
+ const base = baseRes[damageType] || 0;
+ const bonus = bonusRes[damageType] || 0;
totalResist += base + bonus;
layerCount++;
}
if (defense.armor.current > 0) {
- const base = defense.armor.baseResistances[damageType] || 0;
- const bonus = defense.armor.bonusResistances && defense.armor.bonusResistances[damageType] || 0;
+ const layerData = defense.armor;
+ const baseRes = layerData.baseResistances || layerData.resistances || {};
+ const bonusRes = layerData.bonusResistances || {};
+ const base = baseRes[damageType] || 0;
+ const bonus = bonusRes[damageType] || 0;
totalResist += base + bonus;
layerCount++;
}
if (defense.structure.current > 0) {
- const base = defense.structure.baseResistances[damageType] || 0;
- const bonus = defense.structure.bonusResistances && defense.structure.bonusResistances[damageType] || 0;
+ const layerData = defense.structure;
+ const baseRes = layerData.baseResistances || layerData.resistances || {};
+ const bonusRes = layerData.bonusResistances || {};
+ const base = baseRes[damageType] || 0;
+ const bonus = bonusRes[damageType] || 0;
totalResist += base + bonus;
layerCount++;
}