User prompt
Machine gun of Jeep is different from the one of the Gatling Gunner: it fires bullets every 0.567 seconds
User prompt
Add a new unit: Jeep! A veichle with high health armed with a machine gun (type: ranged, faction: modern era)
User prompt
Add a new unit: Jeep! A veichle with high health armed with a machine gun (faction: modern era)
Code edit (1 edits merged)
Please save this source code
User prompt
Add a new unit: Jeep! A veichle with high health armed with a machine gun (type: ranged, faction: modern era)
User prompt
Add a new unit: Jeep! A fast veichle with high health armed with a machine gun that shoots really fast (type: ranged, faction: modern era)
User prompt
Add a new unit: Santa! Every 3 seconds he places gifts that can spawn a COMPLETELY RANDOM UNIT! (faction: farm, type: melee)
User prompt
Add a new unit: Santa! Every 3 seconds he places gifts that can spawn a COMPLETELY RANDOM UNIT! (faction: farm, type: melee)
User prompt
Now the sniper, rifleman, Gatling gunner, pirate crew and Pirate captain use the Shoot sound when attacking
User prompt
Pirate captain and pirate crew now have a longer range
User prompt
Add new unit: Pirate captain! Has a stronger flintnock than the ones from the pirate crew and a strong swashbuckle when enemies are close! (Faction: pirates)
User prompt
Add new unit: Pirate crew! Has a flintnick that deals low damage, but attacks fast (type: ranged, faction: pirates)
User prompt
Swashbucklee attacks once every 0.1 seconds
User prompt
Add a new unit: Swashbuckler! Has a Swashbuckle that lets it attack very fast
User prompt
Please fix the bug: 'Unit.extend is not a function' in or related to this line: 'var Swashbuckler = Unit.extend({' Line Number: 1117
User prompt
Please fix the bug: 'Unit.extend is not a function' in or related to this line: 'var PirateCrew = Unit.extend({' Line Number: 1093
User prompt
Please fix the bug: 'Unit.extend is not a function' in or related to this line: 'var PirateCaptain = Unit.extend({' Line Number: 1062
User prompt
Add new units: Swashbuckler: attacks with a swashbuckle really fast, but dies easily (type: melee, faction: pirates); Pirate crew: Its 3 units at once that are armed with flintnocks that deal weak single damage (type: ranged, faction: pirates); Pirate captain: has a gun that shoots 5 bullets at once like a shotgun and, when it has an enemy nearby, it uses a swashbuckle to attack reallg fast (type: ranged, faction: pirates)
User prompt
Add a new faction called "Pirates"; for now it hasn't got any units
User prompt
Please fix the bug: 'Uncaught TypeError: storage.set is not a function' in or related to this line: 'storage.set('savedFormation', formation);' Line Number: 1087 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add a multiplayer mode where you place a formation of 10 units and then fight other player's formations! You can save your formation by tapping the "save" button
User prompt
Add a multiplayer mode where you place a formation of 10 units and then fight other player's formations! You can save your formation by tapping the "save" button
User prompt
Add new units: ballista: has a great range (not infinite) and throws big arrows that cant be reflected (type: ranged, faction: rome); Yarl: AN unit with massive damage that Has a 20% chance that, when attacking, stuns the enemy for 0.4 seconds (type: melee, faction: vikings); Santa: an unit with 500 HP that when moving, every 5 seconds Santa places a gift that can spawn any unit in the game! (Type: melee, faction: farm); use Container.expand
User prompt
Add new units: ballista: has a great range (not infinite) and throws big arrows that cant be reflected (type: ranged, faction: rome); Yarl: AN unit with massive damage that Has a 20% chance that, when attacking, stuns the enemy for 0.4 seconds (type: melee, faction: vikings); Santa: dosent attack and moves on random locations; when moving, every 5 seconds Santa places a gift that can spawn any unit in the game! (Type: melee, faction: farm); use Container.expand
User prompt
New units arent doin anything
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Battlefield = Container.expand(function () { var self = Container.call(this); self.width = 2048; self.height = 1366; self.initialized = false; // Create background var bg = self.attachAsset('background', { anchorX: 0, anchorY: 0 }); self.projectiles = []; self.createProjectile = function (source, target, type) { var projectile = new Projectile(source, target, type); projectile.x = source.x; projectile.y = source.y; self.addChild(projectile); self.projectiles.push(projectile); }; self.removeUnit = function (unit) { var index = units.indexOf(unit); if (index !== -1) { units.splice(index, 1); } // Check win condition self.checkWinCondition(); }; self.checkWinCondition = function () { var redTeamUnits = 0; var blueTeamUnits = 0; for (var i = 0; i < units.length; i++) { if (units[i].active) { if (units[i].team === 'red') { redTeamUnits++; } else { blueTeamUnits++; } } } if (self.initialized && (redTeamUnits === 0 || blueTeamUnits === 0)) { var winningTeam = redTeamUnits > 0 ? "Red" : "Blue"; if (winText) { winText.setText(winningTeam + " Team Wins!"); winText.visible = true; } LK.getSound('victory').play(); // Create reset button if (!resetButton) { resetButton = new ResetButton(); resetButton.x = self.width / 2; resetButton.y = self.height / 2 + 100; game.addChild(resetButton); } } }; self.update = function () { // Update all projectiles for (var i = self.projectiles.length - 1; i >= 0; i--) { self.projectiles[i].update(); // Remove destroyed projectiles if (!self.projectiles[i].parent) { self.projectiles.splice(i, 1); } } }; return self; }); var EndlessModeButton = Container.expand(function () { var self = Container.call(this); var buttonShape = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2("Endless Mode", { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { endlessMode.start(); self.visible = false; instructions.visible = false; LK.playMusic('battleMusic'); }; return self; }); var EndlessModeInstructionsButton = Container.expand(function () { var self = Container.call(this); var buttonShape = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2("Instructions for Endless Mode", { size: 30, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { endlessModeInstructions.visible = !endlessModeInstructions.visible; if (endlessModeInstructions.visible) { // Create a black opaque overlay var overlay = new Container(); var overlayShape = overlay.attachAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732, color: 0x000000, alpha: 0.7 }); overlay.x = 2048 / 2; overlay.y = 2732 / 2; game.addChild(overlay); // Create a custom popup for Endless Mode Instructions var popupText = new Text2("Endless Mode Instructions:\n- Place units on the battlefield.\n- Survive waves of enemies.\n- Unlock new units as you progress.\n- Win by unlocking all units.", { size: 30, fill: 0xFFFFFF }); popupText.anchor.set(0.5, 0.5); popupText.x = 2048 / 2; popupText.y = 2732 / 2; game.addChild(popupText); // Remove popup and overlay when tapping anywhere overlay.down = function (x, y, obj) { if (popupText.parent) { popupText.destroy(); } if (overlay.parent) { overlay.destroy(); } endlessModeInstructions.visible = false; // Hide the instructions text }; } if (endlessModeInstructions.visible) { // Create a custom popup for Endless Mode Instructions var popupText = new Text2("Endless Mode Instructions:\n- Place units on the battlefield.\n- Survive waves of enemies.\n- Unlock new units as you progress.\n- Win by unlocking all units.", { size: 30, fill: 0xFFFFFF }); popupText.anchor.set(0.5, 0.5); popupText.x = 2048 / 2; popupText.y = 2732 / 2; game.addChild(popupText); } }; return self; }); var FactionButton = Container.expand(function (team, faction, x, y) { var self = Container.call(this); self.team = team; self.faction = faction; self.x = x; self.y = y; // Create button appearance var buttonShape = self.attachAsset('button' + team.charAt(0).toUpperCase() + team.slice(1), { anchorX: 0.5, anchorY: 0.5, width: 150, height: 80 }); // Add faction name text var nameText = new Text2(faction.charAt(0).toUpperCase() + faction.slice(1), { size: 24, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = 30; self.addChild(nameText); self.down = function (x, y, obj) { // When button is pressed, create unit buttons for the faction var xOffset = 120; for (var i = 0; i < factions[faction].length; i++) { var unitButton = new UnitButton(self.team, factions[faction][i], 2048 - xOffset, self.y); game.addChild(unitButton); xOffset += 180; } // Highlight button LK.effects.flashObject(self, 0xffffff, 300); }; return self; }); var Jeep = Container.expand(function () { var self = Container.call(this); self.attackRange = 500; self.attackDamage = 10; self.moveSpeed = 1.0; self.health = 200; self.maxHealth = 200; self.attackCooldown = 20; // Fast attack with machine gun self.special = "high health, machine gun"; // Create unit appearance var unitShape = self.attachAsset('jeep', { anchorX: 0.5, anchorY: 0.5 }); // Add team color indicator on top var teamIndicator = self.attachAsset('character' + self.team.charAt(0).toUpperCase() + self.team.slice(1), { anchorX: 0.5, anchorY: 0.5, width: 20, height: 20 }); teamIndicator.y = -40; // Add health bar self.healthBarBg = self.attachAsset('healthBarBackground', { anchorX: 0.5, anchorY: 0.5 }); self.healthBarBg.y = 40; self.healthBarFill = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0.5 }); self.healthBarFill.x = -35; // Half the width self.healthBarFill.y = 40; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; self.healthBarFill.scaleX = healthPercent; }; self.takeDamage = function (amount, attacker) { if (!self.active) { return; } if (amount > 0) { self.health -= amount; } self.updateHealthBar(); LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { self.die(); } }; self.die = function () { self.active = false; LK.getSound('Destroyed').play(); tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { battlefield.removeUnit(self); self.destroy(); } }); }; self.findNearestEnemy = function () { var closestDist = Infinity; var closestEnemy = null; for (var i = 0; i < units.length; i++) { var unit = units[i]; if (unit.active && unit.team !== self.team) { var dist = getDistance(self.x, self.y, unit.x, unit.y); if (dist < closestDist) { closestDist = dist; closestEnemy = unit; } } } return closestEnemy; }; self.moveTowardsTarget = function () { if (!self.target || !self.target.active) { self.target = self.findNearestEnemy(); if (!self.target) { return; } } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist <= self.attackRange) { if (self.attackCooldown === 0) { self.attack(); } return; } var moveX = dx / dist * self.moveSpeed; var moveY = dy / dist * self.moveSpeed; self.x += moveX; self.y += moveY; }; self.attack = function () { if (!self.target || !self.target.active) { self.target = self.findNearestEnemy(); if (!self.target) { return; } } if (self.attackCooldown === 0) { self.attackCooldown = 20; // Reset cooldown for machine gun var dist = getDistance(self.x, self.y, self.target.x, self.target.y); if (dist <= self.attackRange) { if (self.target && self.target.team !== self.team) { self.target.takeDamage(self.attackDamage, self); } battlefield.createProjectile(self, self.target, 'bullet'); LK.getSound('Shoot').play(); } } }; self.update = function () { if (!self.active) { return; } self.updateHealthBar(); if (self.attackCooldown > 0) { self.attackCooldown--; } self.moveTowardsTarget(); if (self.attackCooldown === 0 && battlefield.initialized) { self.attack(); } }; return self; }); var Projectile = Container.expand(function (source, target, type) { var self = Container.call(this); self.source = source; self.target = target; self.speed = type === 'arrow' ? 12 : 6; self.damage = source.attackDamage; var projectileAsset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (!self.target || !self.target.active) { self.destroy(); return; } // Calculate direction to target if (!self.target) { self.destroy(); return; } if (self.target) { if (self.target) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); } else { self.destroy(); return; } } else { self.destroy(); return; } // Rotate projectile to face target self.rotation = Math.atan2(dy, dx); // Move towards target if (dist > self.speed) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } else { // Hit target if (type === 'arrow') { if (self.target.type === 'mirrorShield' && Math.random() < 0.5) { // 50% chance to reflect // Reflect the projectile back to the source self.target = self.source; self.source = null; // No longer has a source LK.getSound('Defend').play(); // Play 'Defend' sound } else { self.target.takeDamage(self.damage, self.source); } } else if (type === 'rock') { // Deal damage to the target self.target.takeDamage(self.damage, self.source); // Split into smaller rocks for (var i = 0; i < 3; i++) { var smallRock = new Projectile(self, self.target, 'smallRock'); smallRock.x = self.x; smallRock.y = self.y; smallRock.speed = 4; // Smaller rocks move slower battlefield.addChild(smallRock); battlefield.projectiles.push(smallRock); } } else if (type === 'javelin') { var piercedEnemies = 0; for (var i = 0; i < units.length; i++) { var unit = units[i]; if (unit.active && unit.team !== self.source.team) { var distToUnit = getDistance(self.x, self.y, unit.x, unit.y); if (distToUnit < 50) { // Assuming a small radius for piercing unit.takeDamage(self.damage, self.source); piercedEnemies++; if (piercedEnemies >= 3) { break; } // Stop after piercing 3 enemies } } } } self.destroy(); } }; return self; }); var ResetButton = Container.expand(function () { var self = Container.call(this); var buttonShape = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2("Reset Battle", { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { // Reset the battle resetBattle(); }; return self; }); var StartButton = Container.expand(function () { var self = Container.call(this); var buttonShape = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2("Start Battle!", { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { // Start the battle (mark battlefield as initialized) if (units.length > 0) { battlefield.initialized = true; self.visible = false; instructions.visible = false; LK.playMusic('battleMusic'); } }; return self; }); var Unit = Container.expand(function (team, type, x, y) { var self = Container.call(this); self.team = team; self.type = type; self.x = x; self.y = y; self.active = true; self.target = null; self.attackCooldown = 0; self.attackRange = 0; self.attackDamage = 0; self.moveSpeed = 0; self.health = 100; self.maxHealth = 100; self.special = ""; // Default properties based on unit type switch (type) { case 'gatlingGunner': self.attackRange = Infinity; // Infinite range self.attackDamage = 8; // Increased damage per bullet self.moveSpeed = 0; // Stands still self.health = 80; self.maxHealth = 80; self.attackCooldown = 10; // Very fast shooting self.special = "fast but inaccurate shooting"; break; case 'valkyrie': self.attackRange = 100; self.attackDamage = 20; self.moveSpeed = 1.5; self.health = 100; self.maxHealth = 100; self.attackCooldown = 60; self.special = "immune to melee attacks"; break; case 'mortar': self.attackRange = Infinity; self.attackDamage = 30; self.moveSpeed = 0; // Mortar cannot move self.health = 50; // Fragile self.maxHealth = 50; self.attackCooldown = 150; self.special = "high area damage, infinite range"; break; case 'wobbler': self.attackRange = 50; self.attackDamage = 15; self.moveSpeed = 1.5; self.attackCooldowsn = 40; break; case 'farmer': self.attackRange = 70; self.attackDamage = 25; // High first hit self.moveSpeed = 1.2; self.attackCooldown = 60; self.special = "extra damage on first hit"; break; case 'skeleton': self.attackRange = 70; self.attackDamage = 25; self.moveSpeed = 1.2; self.attackCooldown = 60; self.special = "extra damage on first hit"; break; case 'archer': self.attackRange = 400; self.attackDamage = 12; self.moveSpeed = 1.0; self.attackCooldown = 80; self.special = "ranged"; break; case 'shield': self.attackRange = 60; self.attackDamage = 8; self.moveSpeed = 0.8; self.health = 150; self.maxHealth = 150; self.attackCooldown = 50; self.special = "resistant to arrow"; break; case 'sword': self.attackRange = 80; self.attackDamage = 20; self.moveSpeed = 1.3; self.attackCooldown = 45; break; case 'romanLegionnaire': self.attackRange = 80; self.attackDamage = 20; self.moveSpeed = 1.0; self.health = 150; self.maxHealth = 150; self.attackCooldown = 50; self.special = "invincibility for 1 second every 5 seconds"; // Add special ability description break; case 'wizard': self.attackRange = 300; self.attackDamage = 10; self.moveSpeed = 0.9; self.attackCooldown = 100; self.special = "splash damage"; break; case 'witch': self.attackRange = 400; self.attackDamage = 25; self.moveSpeed = 0.8; self.attackCooldown = 120; self.special = "magic ball"; break; case 'necromancer': self.attackRange = 100; self.attackDamage = 5; self.moveSpeed = 0.7; self.health = 80; self.maxHealth = 80; self.attackCooldown = 90; self.special = "summons skeletons"; break; case 'berserker': self.attackRange = 70; self.attackDamage = 20; self.moveSpeed = 1.5; self.attackCooldown = 50; self.special = "double damage at half health"; break; case 'spearman': self.attackRange = 100; self.attackDamage = 18; self.moveSpeed = 1.2; self.attackCooldown = 60; self.special = "chance to throw spear"; break; case 'mirrorShield': self.attackRange = 60; self.attackDamage = 5; self.moveSpeed = 0.8; self.health = 120; self.maxHealth = 120; self.attackCooldown = 50; self.special = "chance to reflect projectiles"; break; case 'king': self.attackRange = 80; self.attackDamage = 50; self.moveSpeed = 0.5; self.health = 300; self.maxHealth = 300; self.attackCooldown = 100; self.special = "massive damage and health"; break; case 'crossbowMan': self.attackRange = 400; self.attackDamage = 15; self.moveSpeed = 1.0; self.attackCooldown = 60; self.special = "fast firing, chance for critical damage"; break; case 'sniper': self.attackRange = Infinity; self.attackDamage = 20; self.moveSpeed = 1.0; self.attackCooldown = 100; self.special = "ranged"; break; case 'rifleman': self.attackRange = 500; self.attackDamage = 15; self.moveSpeed = 1.0; self.attackCooldown = 30; // 0.5 seconds at 60 FPS self.special = "ranged"; break; case 'hammer': self.attackRange = 50; self.attackDamage = 30; self.moveSpeed = 1.0; self.attackCooldown = 70; self.special = "aoe"; break; case 'retarius': self.attackRange = 100; self.attackDamage = 18; self.moveSpeed = 1.2; self.attackCooldown = 60; self.special = "stun every 3 attacks"; break; case 'appleThrower': self.attackRange = 300; self.attackDamage = -10; // Negative damage for healing self.moveSpeed = 1.0; self.attackCooldown = 100; self.special = "heals allies"; break; case 'scarecrow': self.attackRange = 250; self.attackDamage = 15; self.moveSpeed = 0.8; self.attackCooldown = 70; self.special = "curses enemies with crows"; break; case 'warMachine': self.attackRange = 500; self.attackDamage = 30; self.moveSpeed = 0.5; self.health = 300; self.maxHealth = 300; self.attackCooldown = 120; self.special = "area damage, immune to negative effects"; break; case 'axeThrower': self.attackRange = 500; self.attackDamage = 20; self.moveSpeed = 1.0; self.attackCooldown = 80; self.special = "boomerang attack"; break; case 'cannon': self.attackRange = 600; self.attackDamage = 50; self.moveSpeed = 0.4; self.health = 100; self.maxHealth = 100; self.attackCooldown = 150; self.special = "bomb explosion"; break; case 'catapult': self.attackRange = 700; self.attackDamage = 40; self.moveSpeed = 0.3; self.health = 120; self.maxHealth = 120; self.attackCooldown = 200; self.special = "splits into smaller rocks"; break; case 'romanJavelinThrower': self.attackRange = 400; self.attackDamage = 15; self.moveSpeed = 1.0; self.attackCooldown = 80; self.special = "pierces through 3 enemies"; break; case 'queen': self.attackRange = 300; self.attackDamage = 10; self.moveSpeed = 0.8; self.attackCooldown = 100; self.special = "seduces enemies"; break; case 'swashbuckler': self.attackRange = 60; self.attackDamage = 10; self.moveSpeed = 1.8; self.attackCooldown = 6; // Attack every 0.1 seconds (6 frames at 60 FPS) self.special = "fast attack"; break; case 'pirateCrew': self.attackRange = 400; // Increased range for Pirate Crew self.attackDamage = 8; self.moveSpeed = 1.0; self.attackCooldown = 30; // Fast attack self.special = "ranged"; break; case 'pirateCaptain': self.attackRange = 500; // Increased range for Pirate Captain self.attackDamage = 15; // Stronger flintnock self.moveSpeed = 1.0; self.attackCooldown = 30; // Fast attack self.special = "stronger flintnock and swashbuckle"; break; } // Create unit appearance var unitShape = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); // Add team color indicator on top var teamIndicator = self.attachAsset('character' + team.charAt(0).toUpperCase() + team.slice(1), { anchorX: 0.5, anchorY: 0.5, width: 20, height: 20 }); teamIndicator.y = -40; // Add health bar self.healthBarBg = self.attachAsset('healthBarBackground', { anchorX: 0.5, anchorY: 0.5 }); self.healthBarBg.y = 40; self.healthBarFill = self.attachAsset('healthBar', { anchorX: 0, // Left anchored for easy scaling anchorY: 0.5 }); self.healthBarFill.x = -35; // Half the width self.healthBarFill.y = 40; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; self.healthBarFill.scaleX = healthPercent; }; self.takeDamage = function (amount, attacker) { if (!self.active || self.type === 'romanLegionnaire' && self.invincible || self.type === 'valkyrie' && attacker && attacker.attackType === 'melee') { return; } // Shield units take less damage from archers if (self.type === 'shield' && attacker && attacker.type === 'archer') { amount = Math.floor(amount * 0.5); } // Ensure Rifleman, Roman Legionnaire, and Witch lose health if (self.type === 'rifleman' || self.type === 'romanLegionnaire' || self.type === 'witch') { self.health -= amount; } // Wizards do extra damage to shields if (attacker && attacker.type === 'wizard' && self.type === 'shield') { amount = Math.floor(amount * 1.5); } if (amount > 0) { self.health -= amount; } self.updateHealthBar(); // Flash unit when hit LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { self.die(); } }; self.die = function () { self.active = false; if (self.type === 'warMachine' || self.type === 'cannon' || self.type === 'catapult') { LK.getSound('Destroyed').play(); } else if (self.type === 'queen' || self.type === 'valkyrie' || self.type === 'witch') { LK.getSound('Girldeath').play(); } else { LK.getSound('death').play(); } // Fade out and remove from battlefield tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { battlefield.removeUnit(self); self.destroy(); } }); }; self.findNearestEnemy = function () { var closestDist = Infinity; var closestEnemy = null; for (var i = 0; i < units.length; i++) { var unit = units[i]; if (unit.active && unit.team !== self.team) { var dist = getDistance(self.x, self.y, unit.x, unit.y); if (dist < closestDist) { closestDist = dist; closestEnemy = unit; } } } return closestEnemy; }; self.moveTowardsTarget = function () { if (!self.target || !self.target.active) { if (self.type === 'spearman' && Math.random() < 0.3) { // 30% chance to throw spear self.target = self.findNearestEnemy(); if (self.target) { battlefield.createProjectile(self, self.target, 'javelin'); self.attackCooldown = 60; // Reset cooldown after throwing spear return; } } self.target = self.findNearestEnemy(); if (!self.target) { return; } } if (!self.target) { return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); // If in attack range, stop moving if (dist <= self.attackRange) { if (self.attackCooldown === 0) { self.attack(); } return; } // Normalize direction and move var moveX = dx / dist * self.moveSpeed; var moveY = dy / dist * self.moveSpeed; self.x += moveX; self.y += moveY; }; self.attack = function () { // Track number of attacks for Retarius if (self.type === 'retarius') { if (!self.attackCount) { self.attackCount = 0; } self.attackCount++; // Stun effect every 3 attacks if (self.attackCount % 3 === 0 && self.target && self.target.type !== 'warMachine') { self.target.stunned = true; LK.setTimeout(function () { if (self.target) { self.target.stunned = false; } }, 2000); // Stun duration of 2 seconds } } if (!self.target || !self.target.active) { self.target = self.findNearestEnemy(); if (!self.target) { return; } } if (self.attackCooldown === 0) { // Ensure attack is only called once per cooldown cycle self.attackCooldown = self.type === 'wobbler' ? 40 : self.type === 'farmer' ? 60 : self.type === 'archer' ? 80 : self.type === 'shield' ? 50 : self.type === 'sword' ? 45 : 100; self.attack(); } var dist = getDistance(self.x, self.y, self.target.x, self.target.y); if (dist <= self.attackRange) { // Ensure all units deal damage to enemies if (self.target && self.target.team !== self.team) { self.target.takeDamage(self.attackDamage, self); } // Reset attack cooldown self.attackCooldown = self.type === 'wobbler' ? 40 : self.type === 'farmer' ? 60 : self.type === 'archer' ? 80 : self.type === 'shield' ? 50 : self.type === 'sword' ? 45 : 100; // Handle special attacks if (self.special === "ranged") { if (self.type === 'pirateCaptain') { LK.getSound('Shoot').play(); } if (self.type === 'pirateCrew') { LK.getSound('Shoot').play(); } if (self.type === 'rifleman') { LK.getSound('Shoot').play(); } if (self.type === 'sniper') { LK.getSound('Shoot').play(); } // Create arrow projectile battlefield.createProjectile(self, self.target, 'arrow'); LK.getSound('arrow').play(); LK.getSound('Shoot').play(); } else if (self.special === "fast but inaccurate shooting") { // Gatling Gunner shoots 25 bullets per second aiming at the target with a chance to miss for (var i = 0; i < 25; i++) { var angleToTarget = Math.atan2(self.target.y - self.y, self.target.x - self.x); var missChance = Math.random() * 0.2 - 0.1; // Random miss angle between -0.1 and 0.1 radians var bullet = new Projectile(self, null, 'bullet'); bullet.x = self.x; bullet.y = self.y; bullet.rotation = angleToTarget + missChance; bullet.speed = 12; // Set bullet speed bullet.update = function () { this.x += Math.cos(this.rotation) * this.speed; this.y += Math.sin(this.rotation) * this.speed; // Check if bullet is out of bounds if (this.x < 0 || this.x > 2048 || this.y < 0 || this.y > 2732) { this.destroy(); } }; battlefield.addChild(bullet); battlefield.projectiles.push(bullet); } LK.getSound('attack').play(); } else if (self.special === "bomb explosion") { // Cannon bomb explosion battlefield.createProjectile(self, self.target, 'bomb'); LK.getSound('Explosion').play(); var damage = self.attackDamage; for (var i = 0; i < units.length; i++) { var unit = units[i]; if (unit.active && unit.team !== self.team) { var aoeDistance = getDistance(self.target.x, self.target.y, unit.x, unit.y); if (aoeDistance < 200) { var aoeDamage = Math.floor(damage * (1 - aoeDistance / 200)); if (aoeDamage > 0) { unit.takeDamage(aoeDamage, self); } } } } } else if (self.special === "splits into smaller rocks") { // Catapult attack logic battlefield.createProjectile(self, self.target, 'rock'); LK.getSound('Explosion').play(); } else if (self.special === "pierces through 3 enemies") { battlefield.createProjectile(self, self.target, 'javelin'); LK.getSound('arrow').play(); } else if (self.special === "magic ball") { battlefield.createProjectile(self, self.target, 'spell'); LK.getSound('spell').play(); } else if (self.special === "seduces enemies") { // Queen's seduction ability if (Math.random() < 0.1 && self.target.type !== 'warMachine' && self.target.type !== 'king') { self.target.team = 'blue'; // Change team to blue self.target.updateHealthBar(); // Update health bar to reflect team change self.target.findNearestEnemy(); // Reassign target to find new enemies self.target.target = null; // Stop attacking the Queen self.target = null; // Queen stops attacking the seduced enemy LK.getSound('Kiss').play(); // Play 'Kiss' sound when Queen seduces an enemy } // Wizard AOE attack battlefield.createProjectile(self, self.target, 'spell'); if (self.type === 'wizard') { LK.getSound('spell').play(); } else { LK.getSound('Explosion').play(); } // Damage the target and nearby enemies var damage = self.attackDamage; for (var i = 0; i < units.length; i++) { var unit = units[i]; if (unit.active && unit.team !== self.team) { if (self.target) { var aoeDistance = getDistance(self.target.x, self.target.y, unit.x, unit.y); } if (aoeDistance < 150) { // Damage falls off with distance var aoeDamage = Math.floor(damage * (1 - aoeDistance / 150)); if (aoeDamage > 0) { unit.takeDamage(aoeDamage, self); } } } } } else if (self.special === "curses enemies with crows") { if (!self.attackCount) { self.attackCount = 0; } self.attackCount++; if (self.attackCount % 3 === 0) { // Scarecrow shoots crows every 3 attacks battlefield.createProjectile(self, self.target, 'crow'); LK.getSound('Gnehehe').play(); // Reduce target's attack by 5 points if (self.target) { self.target.attackDamage = Math.max(0, self.target.attackDamage - 5); } } // Melee attack LK.getSound('attack').play(); var damage = self.attackDamage; // Double damage if Berserker is enraged (health is at or below half) if (self.type === 'berserker' && self.health <= self.maxHealth / 2) { damage *= 2; self.moveSpeed = 2.0; // Increase move speed when enraged } // Implement critical hit chance for Crossbowman if (self.type === 'crossbowMan' && Math.random() < 0.2) { // 20% chance for critical hit damage *= 2; // Double damage for critical hit } // First strike bonus for farmers if (self.special === "firstStrike" && !self.hasAttacked) { damage *= 1.5; // 50% bonus on first hit self.hasAttacked = true; } self.target.takeDamage(damage, self); } } }; self.showStats = function () { var statsText = "Type: " + self.type.charAt(0).toUpperCase() + self.type.slice(1) + "\n" + "Health: " + self.health + "/" + self.maxHealth + "\n" + "Attack Damage: " + self.attackDamage + "\n" + "Attack Range: " + self.attackRange + "\n" + "Special: " + (self.special ? self.special : "None"); var statsDisplay = new Text2(statsText, { size: 30, fill: 0xFFFFFF }); statsDisplay.anchor.set(0.5, 0.5); statsDisplay.x = self.x; statsDisplay.y = self.y - 100; game.addChild(statsDisplay); // Remove stats display after 3 seconds LK.setTimeout(function () { if (statsDisplay.parent) { statsDisplay.destroy(); } }, 3000); }; self.down = function (x, y, obj) { if (self.lastTap && Date.now() - self.lastTap < 300) { self.showStats(); } self.lastTap = Date.now(); }; self.update = function () { if (!self.active || self.stunned) { return; } // Roman Legionnaire invincibility logic if (self.type === 'romanLegionnaire') { if (!self.invincibilityCooldown) { self.invincibilityCooldown = 300; // 5 seconds at 60 FPS } if (self.invincibilityCooldown > 0) { self.invincibilityCooldown--; } if (self.invincibilityCooldown === 0) { self.invincible = true; LK.getSound('Defend').play(); // Play 'Defend' sound LK.setTimeout(function () { self.invincible = false; self.invincibilityCooldown = 300; // Reset cooldown }, 1000); // Invincibility duration of 1 second } } // Update health bar position to follow unit self.updateHealthBar(); // Decrease attack cooldown if (self.attackCooldown > 0) { self.attackCooldown--; } // Find and move towards target self.moveTowardsTarget(); // Attack if cooldown is ready if (self.attackCooldown === 0 && battlefield.initialized) { // Necromancer summons skeletons every 1.5 seconds if battle has started if (self.type === 'necromancer' && battlefield.initialized && LK.ticks % 150 === 0) { // Count current skeletons on the battlefield var skeletonCount = units.filter(function (unit) { return unit.type === 'skeleton' && unit.active; }).length; if (skeletonCount < 3) { var skeleton = new Unit(self.team, 'skeleton', self.x, self.y); units.push(skeleton); game.addChild(skeleton); LK.getSound('Gnehehe').play(); } } self.attack(); } }; return self; }); var UnitButton = Container.expand(function (team, type, x, y) { var self = Container.call(this); self.team = team; self.type = type; self.x = x; self.y = y; // Create button appearance var buttonShape = self.attachAsset('button' + team.charAt(0).toUpperCase() + team.slice(1), { anchorX: 0.5, anchorY: 0.5, width: 150, height: 80 }); // Add unit icon var unitIcon = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); // Add lock icon if unit is locked var lockIcon = null; if (endlessMode.active && !endlessMode.unlockedUnits.includes(self.type)) { lockIcon = new Text2("🔒", { size: 24, fill: 0xFF0000 }); lockIcon.anchor.set(0.5, 0.5); lockIcon.y = -30; self.addChild(lockIcon); } // Remove lock icon if unit is unlocked self.updateLockIcon = function () { if (endlessMode.unlockedUnits.includes(self.type) && lockIcon && lockIcon.parent) { lockIcon.destroy(); lockIcon = null; } }; self.updateLockIcon(); // Add unit name text var nameText = new Text2(type.charAt(0).toUpperCase() + type.slice(1), { size: 24, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = 30; self.addChild(nameText); self.down = function (x, y, obj) { // When button is pressed, start dragging a new unit if (endlessMode.active && !endlessMode.unlockedUnits.includes(self.type)) { return; // Prevent adding locked units } var unit = new Unit(self.team, self.type, x, y); // Mark as dragging unit draggingUnit = unit; game.addChild(unit); // Highlight button LK.effects.flashObject(self, 0xffffff, 300); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Define factions and their respective units var endlessModeInstructions = new Text2("Endless Mode Instructions:\n- Place units on the battlefield.\n- Survive waves of enemies.\n- Unlock new units as you progress.\n- Win by unlocking all units.", { size: 30, fill: 0xFFFFFF }); endlessModeInstructions.anchor.set(0.5, 0.5); endlessModeInstructions.x = 2048 / 2; endlessModeInstructions.y = 2732 / 2 - 200; endlessModeInstructions.visible = false; game.addChild(endlessModeInstructions); var endlessMode = { active: false, currentWave: 0, unlockedUnits: ['wobbler'], enemyUnits: ['farmer', 'archer', 'sword', 'shield', 'berserker', 'spearman', 'retarius', 'romanJavelinThrower', 'romanLegionnaire', 'wizard', 'witch', 'necromancer', 'skeleton', 'mirrorShield', 'crossbowMan', 'sniper', 'warMachine', 'rifleman', 'hammer', 'axeThrower', 'cannon', 'catapult', 'queen'], start: function start() { var _this2 = this; this.active = true; this.currentWave = 0; this.unlockedUnits = ['wobbler']; this.lockedUnits = Object.keys(factions).reduce(function (acc, faction) { return acc.concat(factions[faction].filter(function (unit) { return !_this2.unlockedUnits.includes(unit); })); }, []); this.spawnNextWave(); }, spawnNextWave: function spawnNextWave() { this.currentWave++; var numEnemies = this.currentWave * 2; // Increase number of enemies with each wave for (var i = 0; i < numEnemies; i++) { var enemyType = this.enemyUnits[Math.floor(Math.random() * this.enemyUnits.length)]; // Count current units of the same type on the battlefield var currentUnitCount = units.filter(function (unit) { return unit.type === enemyType && unit.team === 'red' && unit.active; }).length; // Limit the number of units based on type var maxUnits = enemyType === 'wobbler' ? 5 : 3; if (currentUnitCount < maxUnits) { var enemy = new Unit('red', enemyType, Math.random() * 2048, Math.random() * 1366); units.push(enemy); game.addChild(enemy); } } if (units.filter(function (unit) { return unit.team === 'red' && unit.active; }).length === 0) { this.unlockUnit(); } else { return; // Exit if there are still active red units } }, unlockUnit: function unlockUnit() { var _this = this; if (this.lockedUnits.length > 0) { var nextUnit = this.lockedUnits[Math.floor(Math.random() * this.lockedUnits.length)]; if (nextUnit) { this.unlockedUnits.push(nextUnit); this.lockedUnits = this.lockedUnits.filter(function (unit) { return unit !== nextUnit; }); // Display popup for unlocked unit var popupText = new Text2("Unlocked: " + nextUnit.charAt(0).toUpperCase() + nextUnit.slice(1), { size: 50, fill: 0xFFFFFF }); popupText.anchor.set(0.5, 0.5); popupText.x = 2048 / 2; popupText.y = 2732 / 2; game.addChild(popupText); // Remove popup after 2 seconds LK.setTimeout(function () { if (popupText.parent) { popupText.destroy(); } }, 2000); } } }, checkWinCondition: function checkWinCondition() { if (this.unlockedUnits.length === Object.keys(factions).reduce(function (acc, faction) { return acc.concat(factions[faction]); }, []).length) { LK.showYouWin(); this.active = false; this.unlockedUnits = Object.keys(factions).reduce(function (acc, faction) { return acc.concat(factions[faction]); }, []); } } }; function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _defineProperty3(e, r, t) { return (r = _toPropertyKey2(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey2(t) { var i = _toPrimitive2(t, "string"); return "symbol" == _typeof2(i) ? i : i + ""; } function _toPrimitive2(t, r) { if ("object" != _typeof2(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof2(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var factions = _defineProperty(_defineProperty(_defineProperty3({ farm: ['wobbler', 'farmer', 'appleThrower', 'scarecrow'], medieval: ['sword', 'archer', 'crossbowMan', 'king', 'shield', 'cannon', 'queen', 'catapult'], rome: ['spearman', 'retarius', 'romanJavelinThrower', 'romanLegionnaire'], magic: ['mirrorShield', 'wizard', 'necromancer', 'skeleton', 'witch'], vikings: ['berserker', 'valkyrie'], modern: ['sniper', 'warMachine', 'rifleman', 'mortar', 'gatlingGunner', 'Jeep'], pirates: ['swashbuckler', 'pirateCrew', 'pirateCaptain'] // New faction 'Pirates' with Swashbuckler, Pirate Crew, and Pirate Captain units }, "rome", ['spearman', 'retarius', 'romanJavelinThrower', 'romanLegionnaire']), "vikings", ['berserker', 'hammer', 'axeThrower', 'valkyrie']), "modern", ['sniper', 'warMachine', 'rifleman', 'mortar', 'gatlingGunner'], "farm", ['wobbler', 'farmer', 'appleThrower', 'scarecrow']); // Game state variables var units = []; var draggingUnit = null; var battlefield = null; var resetButton = null; // Create the battlefield battlefield = new Battlefield(); battlefield.x = 0; battlefield.y = 0; game.addChild(battlefield); // Create faction buttons for red team var redFactionButtons = []; var factionNames = Object.keys(factions); var factionYOffset = 80; for (var i = 0; i < factionNames.length; i++) { var factionButton = new FactionButton('red', factionNames[i], 2048 - 300, factionYOffset); factionButton.x = 2048 - 300; // Adjusted position even further to the left factionButton.y = factionYOffset; redFactionButtons.push(factionButton); game.addChild(factionButton); factionYOffset += 100; } // Create faction buttons for blue team var blueFactionButtons = []; factionYOffset = 2732 - 80; for (var i = 0; i < factionNames.length; i++) { var factionButton = new FactionButton('blue', factionNames[i], 60, factionYOffset); blueFactionButtons.push(factionButton); game.addChild(factionButton); factionYOffset -= 100; } // Start button var startButton = new StartButton(); startButton.x = 2048 / 2; startButton.y = 2732 / 2; game.addChild(startButton); // Endless mode button var endlessModeButton = new EndlessModeButton(); endlessModeButton.x = 2048 / 2; endlessModeButton.y = 2732 / 2 + 100; game.addChild(endlessModeButton); // Endless mode instructions button var endlessModeInstructionsButton = new EndlessModeInstructionsButton(); endlessModeInstructionsButton.x = 2048 / 2; endlessModeInstructionsButton.y = 2732 / 2 + 200; game.addChild(endlessModeInstructionsButton); // Win text var winText = new Text2("", { size: 80, fill: 0xFFFF00 }); winText.anchor.set(0.5, 0.5); winText.x = 2048 / 2; winText.y = 2732 / 2 - 100; winText.visible = false; game.addChild(winText); // Instructions text var instructions = new Text2("Place units on the battlefield\nand press Start Battle!", { size: 40, fill: 0xFFFFFF }); instructions.anchor.set(0.5, 0.5); instructions.x = 2048 / 2; instructions.y = 2732 / 2 - 100; game.addChild(instructions); // Helper function to calculate distance between two points function getDistance(x1, y1, x2, y2) { var dx = x2 - x1; var dy = y2 - y1; return Math.sqrt(dx * dx + dy * dy); } // Reset the battle function resetBattle() { // Remove all units for (var i = units.length - 1; i >= 0; i--) { if (units[i].parent) { units[i].destroy(); } } units = []; // Clear projectiles for (var i = battlefield.projectiles.length - 1; i >= 0; i--) { if (battlefield.projectiles[i].parent) { battlefield.projectiles[i].destroy(); } } battlefield.projectiles = []; // Reset battlefield state battlefield.initialized = false; // Show start button, endless mode button, and instructions again if (startButton) { startButton.visible = true; } if (endlessModeButton) { endlessModeButton.visible = true; } if (instructions) { instructions.visible = true; } // Hide win text and reset button if (winText) { winText.visible = false; } if (resetButton && resetButton.parent) { resetButton.destroy(); resetButton = null; } // Stop music LK.stopMusic(); } // Handle dragging game.move = function (x, y, obj) { if (draggingUnit) { draggingUnit.x = x; draggingUnit.y = y; } }; game.up = function (x, y, obj) { if (draggingUnit) { // Check if unit is placed on the battlefield (not on buttons) var validPlacement = y > 150 && y < 2732 - 150; if (validPlacement) { // Add to units array units.push(draggingUnit); } else { // Not valid placement, destroy the unit draggingUnit.destroy(); } draggingUnit = null; } }; // Game update loop game.update = function () { // Update all units if battle has started if (battlefield.initialized) { for (var i = 0; i < units.length; i++) { if (units[i].active) { units[i].update(); } } if (endlessMode.active) { var redTeamUnits = units.filter(function (unit) { return unit.team === 'red' && unit.active; }).length; if (redTeamUnits === 0) { endlessMode.spawnNextWave(); endlessMode.unlockUnit(); } endlessMode.checkWinCondition(); } } // Update projectiles battlefield.update(); };
===================================================================
--- original.js
+++ change.js
@@ -1325,9 +1325,9 @@
medieval: ['sword', 'archer', 'crossbowMan', 'king', 'shield', 'cannon', 'queen', 'catapult'],
rome: ['spearman', 'retarius', 'romanJavelinThrower', 'romanLegionnaire'],
magic: ['mirrorShield', 'wizard', 'necromancer', 'skeleton', 'witch'],
vikings: ['berserker', 'valkyrie'],
- modern: ['sniper', 'warMachine', 'rifleman', 'mortar', 'gatlingGunner', 'jeep'],
+ modern: ['sniper', 'warMachine', 'rifleman', 'mortar', 'gatlingGunner', 'Jeep'],
pirates: ['swashbuckler', 'pirateCrew', 'pirateCaptain'] // New faction 'Pirates' with Swashbuckler, Pirate Crew, and Pirate Captain units
}, "rome", ['spearman', 'retarius', 'romanJavelinThrower', 'romanLegionnaire']), "vikings", ['berserker', 'hammer', 'axeThrower', 'valkyrie']), "modern", ['sniper', 'warMachine', 'rifleman', 'mortar', 'gatlingGunner'], "farm", ['wobbler', 'farmer', 'appleThrower', 'scarecrow']);
// Game state variables
var units = [];
victory
Sound effect
battleMusic
Music
death
Sound effect
arrow
Sound effect
spell
Sound effect
attack
Sound effect
Explosion
Sound effect
Destroyed
Sound effect
Kiss
Sound effect
Gnehehe
Sound effect
Defend
Sound effect
Girldeath
Sound effect
Shoot
Sound effect
RAWR
Sound effect
Malfunction
Sound effect
Blaster
Sound effect
Holy
Sound effect