diff options
Diffstat (limited to 'html/tower/docs/mechanics.js.html')
-rw-r--r-- | html/tower/docs/mechanics.js.html | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/html/tower/docs/mechanics.js.html b/html/tower/docs/mechanics.js.html new file mode 100644 index 0000000..d629a87 --- /dev/null +++ b/html/tower/docs/mechanics.js.html @@ -0,0 +1,480 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>JSDoc: Source: mechanics.js</title> + + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> +</head> + +<body> + +<div id="main"> + + <h1 class="page-title">Source: mechanics.js</h1> + + + + + + + <section> + <article> + <pre class="prettyprint source linenums"><code>/** + * Combat Mechanics Module + * + * This module handles all combat-related game mechanics including: + * 1. Enemy movement and behavior + * 2. Tower attacks and targeting + * 3. Projectile and particle systems + * 4. Status effects and special abilities + * + * @module mechanics + */ + +/** + * Updates all enemy states including movement, health, and status effects + * Implements core game loop mechanics for enemy behavior + * + * Key features: + * - Path following + * - Health management + * - Status effect processing + * - Collision detection + * + * @returns {void} + */ +function updateEnemies() { + const cellSize = canvas.width / 20; + + gameState.enemies = gameState.enemies.filter(enemy => { + // Initialize progress tracking for new enemies + if (typeof enemy.progress === 'undefined') { + enemy.progress = 0; + } + + // Update movement progress + enemy.progress += enemy.speed * 0.001; + + // Handle path completion + if (enemy.progress >= 1) { + gameState.enemiesEscaped++; + // Deduct currency when enemy escapes + gameState.currency = Math.max(0, gameState.currency - 10); + // Check for game over + if (gameState.currency <= 0) { + handleGameOver(); + } + return false; + } + + // Projectile collision detection and damage application + const hitByProjectile = gameState.projectiles.some(projectile => { + // Calculate current projectile position based on lifetime + const age = performance.now() - projectile.createdAt; + const progress = Math.min(age / projectile.lifetime, 1); + + const currentX = projectile.startPos.x + (projectile.targetPos.x - projectile.startPos.x) * progress; + const currentY = projectile.startPos.y + (projectile.targetPos.y - projectile.startPos.y) * progress; + + const distance = Math.hypot( + enemy.position.x - currentX, + enemy.position.y - currentY + ); + + if (distance < 0.5) { + // Apply damage when projectile hits + enemy.currentHealth -= projectile.damage; + return true; + } + return false; + }); + + if (enemy.currentHealth <= 0) { + gameState.awardEnemyDestroyed(); + // Create death particles + gameState.particles.push(...createDeathParticles(enemy, cellSize)); + return false; + } + + // Update position based on path progress + const pathPosition = getPathPosition(enemy.progress, gameState.path); + enemy.position.x = pathPosition.x; + enemy.position.y = pathPosition.y; + + // Process slow effect expiration + if (enemy.slowed && performance.now() > enemy.slowExpiry) { + enemy.slowed = false; + enemy.slowStacks = 0; + enemy.currentSlowAmount = 0; + enemy.speed = enemy.originalSpeed; + } + + // Visual feedback for slowed status + if (enemy.slowed && Math.random() < 0.2 + (enemy.slowStacks * 0.05)) { + gameState.particles.push(createSlimeTrail(enemy, cellSize)); + } + + return true; + }); + + // Remove projectiles that hit enemies + gameState.projectiles = gameState.projectiles.filter(projectile => { + const age = performance.now() - projectile.createdAt; + if (age >= projectile.lifetime) return false; + + const progress = age / projectile.lifetime; + const currentX = projectile.startPos.x + (projectile.targetPos.x - projectile.startPos.x) * progress; + const currentY = projectile.startPos.y + (projectile.targetPos.y - projectile.startPos.y) * progress; + + const hitEnemy = gameState.enemies.some(enemy => { + const distance = Math.hypot( + enemy.position.x - currentX, + enemy.position.y - currentY + ); + return distance < 0.5; + }); + + return !hitEnemy; + }); +} + +/** + * Updates particle effects with time-based animation + * Implements particle system lifecycle management + * + * @param {Array<Object>} particles - Array of particle objects + * @param {number} timestamp - Current game timestamp + * @param {number} deltaTime - Time elapsed since last frame + * @returns {Array<Object>} Updated particles array + */ +function updateParticles(particles, timestamp, deltaTime) { + return particles.filter(particle => { + const age = timestamp - particle.createdAt; + if (age > particle.lifetime) return false; + + if (particle.velocity) { + particle.position.x += particle.velocity.x * deltaTime; + particle.position.y += particle.velocity.y * deltaTime; + } + + return true; + }); +} + +/** + * Creates death effect particles for defeated entities + * Implements visual feedback system + * + * @param {Object} target - The defeated entity + * @param {number} cellSize - Size of grid cell for scaling + * @returns {Array<Object>} Array of particle objects + */ +function createDeathParticles(target, cellSize) { + const particles = []; + const centerX = (target.position.x + 0.5) * cellSize; + const centerY = (target.position.y + 0.5) * cellSize; + + const particleCount = 8 + Math.floor(Math.random() * 8); + for (let i = 0; i < particleCount; i++) { + const baseAngle = (Math.PI * 2 * i) / particleCount; + const randomAngle = baseAngle + (Math.random() - 0.5) * 1.5; + const speedMultiplier = 0.7 + Math.random() * 0.6; + const startOffset = Math.random() * 5; + + particles.push(createParticle( + { + ...ParticleTypes.DEATH_PARTICLE, + speed: ParticleTypes.DEATH_PARTICLE.speed * speedMultiplier, + lifetime: ParticleTypes.DEATH_PARTICLE.lifetime * (0.8 + Math.random() * 0.4) + }, + { + x: centerX + Math.cos(randomAngle) * startOffset, + y: centerY + Math.sin(randomAngle) * startOffset + }, + randomAngle + )); + } + return particles; +} + +/** + * Processes tower attacks and targeting + * Implements combat mechanics and special abilities + * + * @param {Array<Object>} towers - Array of tower objects + * @param {Array<Object>} enemies - Array of enemy objects + * @param {Array<Object>} projectiles - Array of projectile objects + * @param {Array<Object>} particles - Array of particle objects + * @param {number} timestamp - Current game timestamp + * @param {number} cellSize - Size of grid cell for scaling + */ +function processTowerAttacks(towers, enemies, projectiles, particles, timestamp, cellSize) { + towers.forEach(tower => { + if (timestamp - tower.lastAttackTime > 1000 / tower.attackSpeed) { + const enemiesInRange = findEnemiesInRange(tower, enemies); + + if (enemiesInRange.length > 0 && tower.ammo > 0) { + const target = enemiesInRange[0]; + handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize); + } + } + }); +} + +function findEnemiesInRange(tower, enemies) { + return enemies.filter(enemy => { + const dx = enemy.position.x - tower.position.x; + const dy = enemy.position.y - tower.position.y; + return Math.sqrt(dx * dx + dy * dy) <= tower.range; + }); +} + +function createAOEExplosion(position, cellSize) { + return { + position: { + x: (position.x + 0.5) * cellSize, + y: (position.y + 0.5) * cellSize + }, + createdAt: performance.now(), + type: 'AOE_EXPLOSION', + ...ParticleTypes.AOE_EXPLOSION + }; +} + +function createSlimeTrail(enemy, cellSize) { + return { + position: { + x: (enemy.position.x + 0.5) * cellSize, + y: (enemy.position.y + 0.5) * cellSize + }, + createdAt: performance.now(), + type: 'SLIME_TRAIL', + ...ParticleTypes.SLIME_TRAIL + }; +} + +/** + * Handles individual tower attack logic including special effects + * Implements tower ability system + * + * @param {Object} tower - Attacking tower + * @param {Object} target - Target enemy + * @param {Array<Object>} projectiles - Projectile array + * @param {Array<Object>} particles - Particle array + * @param {number} timestamp - Current game timestamp + * @param {number} cellSize - Grid cell size + */ +function handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize) { + // Only attack if we have ammo + if (tower.ammo <= 0) return; + + // Decrease ammo (already checked it's > 0) + tower.ammo--; + + // Create projectile + projectiles.push({ + startPos: { ...tower.position }, + targetPos: { ...target.position }, + createdAt: timestamp, + lifetime: 300, + towerType: tower.type, + damage: tower.damage + }); + + // Process special abilities + if (tower.special === 'slow') { + handleSlowEffect(target, tower, timestamp, particles, cellSize); + } else if (tower.special === 'aoe') { + handleAOEEffect(target, tower, gameState.enemies, particles, cellSize); + } + + tower.lastAttackTime = timestamp; +} + +/** + * Processes enemy attack behaviors and targeting + * Implements enemy combat AI + * + * @param {Array<Object>} enemies - Array of enemy objects + * @param {Array<Object>} towers - Array of tower objects + * @param {Array<Object>} particles - Particle effect array + * @param {number} timestamp - Current game timestamp + * @param {number} cellSize - Grid cell size + */ +function processEnemyAttacks(enemies, towers, particles, timestamp, cellSize) { + enemies.forEach(enemy => { + if (!EnemyTypes[enemy.type].isRanged) return; + + if (timestamp - enemy.lastAttackTime > 1000 / EnemyTypes[enemy.type].attackSpeed) { + const towersInRange = findTowersInRange(enemy, towers); + + if (towersInRange.length > 0) { + const target = towersInRange[0]; + handleEnemyAttack(enemy, target, particles, timestamp, cellSize); + } + } + }); +} + +/** + * Finds towers within enemy attack range + * Implements targeting system for enemies + * + * @param {Object} enemy - Enemy doing the targeting + * @param {Array<Object>} towers - Array of potential tower targets + * @returns {Array<Object>} Array of towers in range + */ +function findTowersInRange(enemy, towers) { + return towers.filter(tower => { + const dx = tower.position.x - enemy.position.x; + const dy = tower.position.y - enemy.position.y; + return Math.sqrt(dx * dx + dy * dy) <= EnemyTypes[enemy.type].attackRange; + }); +} + +/** + * Handles enemy attack execution and effects + * Implements enemy combat mechanics + * + * @param {Object} enemy - Attacking enemy + * @param {Object} tower - Target tower + * @param {Array<Object>} particles - Particle array for effects + * @param {number} timestamp - Current game timestamp + * @param {number} cellSize - Grid cell size + */ +function handleEnemyAttack(enemy, tower, particles, timestamp, cellSize) { + // Create projectile effect + particles.push(createParticle( + { + ...ParticleTypes.PROJECTILE, + color: '#8e44ad80', // Semi-transparent purple + lifetime: 500 + }, + { + x: (enemy.position.x + 0.5) * cellSize, + y: (enemy.position.y + 0.5) * cellSize + }, + Math.atan2( + tower.position.y - enemy.position.y, + tower.position.x - enemy.position.x + ) + )); + + // Apply damage and update tower state + tower.currentHealth -= enemy.damage; + enemy.lastAttackTime = timestamp; + + // Dynamic damage reduction based on tower health + tower.damage = TowerTypes[tower.type].damage * (tower.currentHealth / tower.maxHealth); +} + +/** + * Handles slow effect application and stacking + * Implements status effect system + * + * @param {Object} target - Enemy to apply slow to + * @param {Object} tower - Tower applying the effect + * @param {number} timestamp - Current game timestamp + * @param {Array<Object>} particles - Particle array for effects + * @param {number} cellSize - Grid cell size + */ +function handleSlowEffect(target, tower, timestamp, particles, cellSize) { + // Initialize slow effect tracking + if (!target.slowStacks) { + target.slowStacks = 0; + } + + const maxStacks = 5; // Maximum 5 stacks + if (target.slowStacks < maxStacks) { + target.slowStacks++; + // Each stack slows by an additional 10% (multiplicative) + const newSlowAmount = 1 - Math.pow(0.9, target.slowStacks); + + // Only update if new slow is stronger + if (!target.slowed || newSlowAmount > target.currentSlowAmount) { + const originalSpeed = target.originalSpeed || target.speed; + target.originalSpeed = originalSpeed; + target.speed = originalSpeed * (1 - newSlowAmount); + target.currentSlowAmount = newSlowAmount; + target.slowed = true; + } + + // Visual feedback particles + for (let i = 0; i < 4 + target.slowStacks; i++) { + particles.push(createSlimeTrail(target, cellSize)); + } + } + + // Refresh effect duration + target.slowExpiry = timestamp + 2000; // 2 second duration +} + +/** + * Handles AOE (Area of Effect) damage and visual effects + * Implements area damage system + * + * @param {Object} target - Primary target + * @param {Object} tower - Tower dealing AOE damage + * @param {Array<Object>} enemies - All enemies for AOE calculation + * @param {Array<Object>} particles - Particle array for effects + * @param {number} cellSize - Grid cell size + */ +function handleAOEEffect(target, tower, enemies, particles, cellSize) { + // Find all enemies in AOE radius + const enemiesInAOE = enemies.filter(enemy => { + const dx = enemy.position.x - target.position.x; + const dy = enemy.position.y - target.position.y; + return Math.sqrt(dx * dx + dy * dy) <= tower.aoeRadius; + }); + + // Create explosion effect + particles.push(createAOEExplosion(target.position, cellSize)); + + // Apply AOE damage + enemiesInAOE.forEach(enemy => { + enemy.currentHealth -= tower.damage; + if (enemy.currentHealth <= 0) { + particles.push(...createDeathParticles(enemy, cellSize)); + } + }); +} + +// Update createEnemy to track original speed +function createEnemy(startPosition) { + const enemy = { + // ... existing enemy properties ... + slowStacks: 0, + currentSlowAmount: 0 + }; + enemy.originalSpeed = enemy.speed; // Store original speed + return enemy; +} </code></pre> + </article> + </section> + + + + +</div> + +<nav> + <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-game.html">game</a></li><li><a href="module-gameState.html">gameState</a></li><li><a href="module-mechanics.html">mechanics</a></li><li><a href="module-path.html">path</a></li><li><a href="module-renderer.html">renderer</a></li><li><a href="module-uiHandlers.html">uiHandlers</a></li></ul> +</nav> + +<br class="clear"> + +<footer> + Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.3</a> on Mon Feb 17 2025 09:19:19 GMT-0500 (Eastern Standard Time) +</footer> + +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html> |