User prompt
Add a Canadian Goose in treasure hoarder outfit wtih ability to make a fake emden goose to charm Emden Goose ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a Pyro Catalyst Canadian Goose and he can summon fire magic! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add pie flavour assets with effects on enemies and healing on Canadian Geese ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a Pie Shooter Canadian Goose armed with a Spoon shooting different flavoured piece of pie into Emden Geese and she can heal Canadian Geese ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
add anti virus Goose ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fix errors PLS!
User prompt
Add main menu
User prompt
Add a new bros in to the game: Canadian Geese: Sun Shooter - Canadian Goose in Sun Warrior Outfit with Sun Crossbow and Sun Arrows (Type of Attack: Shoot Attack) Moonlight Sleeper - Canadian Goose in Moonlight Magician Outfit with Magic Staff of Moon and Moonlight Magic (Type of Attack: Moonlight Magic Shoot!) New Enemies: Red Moon Treasure Hoarder Emden Goose with Red Moon Magic Staff and Blue Sun Emden Goose with Long Sword) (In the Sun World Sun Shooter bro is strong and weak in Mua World and Moonlight bro is Strong in Mua world but weak in Sun world!) (2 New worlds: Sun World - Episode 2 and Mua World - Episode 3!) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (5 edits merged)
Please save this source code
User prompt
Pls make unlimited money to buy geese! (and new enemy: treasure hoarder emden goose "Hydro Arrow" with blue hydro battle bow)
User prompt
Time to add new canadian goose: A Canadian goose in electro purple armor with electro purple hammer! (this bro can stun emden geese by hammer) (in game he named Hammer Goose) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'canadianBtn.style.fill = "#FFD700";' Line Number: 460
User prompt
Add a Ameno Emden Potioneer Emden Goose Enemy and fix the errors
Code edit (1 edits merged)
Please save this source code
User prompt
Goose Guard: Ice Defense
Initial prompt
Make a Tower Defense game but all towers and player are canadian geese! (this game have a special Canadian goose: Ice Magic Canadian Goose with his ability: Canadian goose freeze ability!) (enemies are treasure hoarder Emden geese) (no bosses!)
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AmenoEmdenGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('amenoGoose', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 150;
self.speed = 1.2;
self.pathIndex = 0;
self.reward = 20;
self.frozen = false;
self.freezeTimer = 0;
self.destroyed = false;
self.potionTimer = 0;
self.potionRate = 240; // 4 seconds at 60fps
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff513a, 200);
if (self.health <= 0) {
resources += self.reward;
updateResourceDisplay();
LK.getSound('defeat').play();
self.destroyed = true;
self.destroy();
}
};
self.freeze = function (duration) {
self.frozen = true;
self.freezeTimer = duration;
graphics.tint = 0xAADDFF;
var iceEffect = new IceEffect();
iceEffect.x = self.x;
iceEffect.y = self.y;
game.addChild(iceEffect);
};
self.stunned = false;
self.stunTimer = 0;
self.stun = function (duration) {
self.stunned = true;
self.stunTimer = duration;
graphics.tint = 0x9932CC; // Purple tint for stun
var stunEffect = new StunEffect();
stunEffect.x = self.x;
stunEffect.y = self.y;
game.addChild(stunEffect);
};
self.throwPotion = function () {
var nearestTower = findNearestTower(self.x, self.y, 200);
if (nearestTower) {
var potion = new PoisonPotion();
potion.x = self.x;
potion.y = self.y;
potion.target = nearestTower;
potions.push(potion);
game.addChild(potion);
LK.getSound('potion').play();
}
};
self.update = function () {
if (self.freezeTimer > 0) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
graphics.tint = 0xFFFFFF;
}
}
// Handle stun timer
if (self.stunTimer > 0) {
self.stunTimer--;
if (self.stunTimer <= 0) {
self.stunned = false;
graphics.tint = 0xFFFFFF;
}
}
// Potion throwing ability
self.potionTimer++;
if (self.potionTimer >= self.potionRate && !self.frozen && !self.stunned) {
self.throwPotion();
self.potionTimer = 0;
}
if (!self.frozen && !self.stunned && self.pathIndex < pathPoints.length - 1) {
var target = pathPoints[self.pathIndex + 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= pathPoints.length - 1) {
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.destroyed = true;
self.destroy();
return;
}
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
};
return self;
});
var AntiVirusGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('antiVirusGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x00FF00; // Green anti-virus color
self.range = 160;
self.cleanseRate = 120; // 2 seconds at 60fps
self.cleanseTimer = 0;
self.cost = 150;
self.disabled = false;
self.disableTimer = 0;
self.worldModifier = 1.0;
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.cleanseTimer++;
if (self.cleanseTimer >= self.cleanseRate) {
// Find all towers in range that are disabled
var towersInRange = [];
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
if (!tower.destroyed && tower.disabled) {
var dx = tower.x - self.x;
var dy = tower.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.range) {
towersInRange.push(tower);
}
}
}
// Cleanse all disabled towers in range
for (var j = 0; j < towersInRange.length; j++) {
var tower = towersInRange[j];
tower.disabled = false;
tower.disableTimer = 0;
// Visual cleansing effect
LK.effects.flashObject(tower, 0x00FF00, 800);
tween(tower, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(tower, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
if (towersInRange.length > 0) {
// Visual effect for anti-virus goose
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(graphics, {
tint: 0x00FF00
}, {
duration: 300,
easing: tween.easeIn
});
}
});
LK.getSound('antiVirus').play();
}
self.cleanseTimer = 0;
}
}
};
return self;
});
var BlueSunEmdenGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('blueSunGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x4169E1; // Royal blue color
self.health = 200;
self.maxHealth = 200;
self.speed = 1.3;
self.pathIndex = 0;
self.reward = 35;
self.frozen = false;
self.freezeTimer = 0;
self.destroyed = false;
self.swordTimer = 0;
self.swordRate = 150; // 2.5 seconds at 60fps
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff1e00, 200);
if (self.health <= 0) {
resources += self.reward;
updateResourceDisplay();
LK.getSound('defeat').play();
self.destroyed = true;
self.destroy();
}
};
self.freeze = function (duration) {
self.frozen = true;
self.freezeTimer = duration;
graphics.tint = 0xAADDFF;
var iceEffect = new IceEffect();
iceEffect.x = self.x;
iceEffect.y = self.y;
game.addChild(iceEffect);
};
self.stunned = false;
self.stunTimer = 0;
self.stun = function (duration) {
self.stunned = true;
self.stunTimer = duration;
graphics.tint = 0x9932CC;
var stunEffect = new StunEffect();
stunEffect.x = self.x;
stunEffect.y = self.y;
game.addChild(stunEffect);
};
self.swordSlash = function () {
var nearestTower = findNearestTower(self.x, self.y, 180);
if (nearestTower) {
var slash = new BlueSunSlash();
slash.x = self.x;
slash.y = self.y;
slash.target = nearestTower;
potions.push(slash);
game.addChild(slash);
LK.getSound('blueSunSword').play();
}
};
self.update = function () {
if (self.freezeTimer > 0) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
graphics.tint = 0x4169E1;
}
}
if (self.stunTimer > 0) {
self.stunTimer--;
if (self.stunTimer <= 0) {
self.stunned = false;
graphics.tint = 0x4169E1;
}
}
self.swordTimer++;
if (self.swordTimer >= self.swordRate && !self.frozen && !self.stunned) {
self.swordSlash();
self.swordTimer = 0;
}
if (!self.frozen && !self.stunned && self.pathIndex < pathPoints.length - 1) {
var target = pathPoints[self.pathIndex + 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= pathPoints.length - 1) {
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.destroyed = true;
self.destroy();
return;
}
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
};
return self;
});
var BlueSunSlash = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x4169E1; // Royal blue color
self.speed = 8;
self.target = null;
self.destroyed = false;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 25) {
// Blue sun slash disables tower for 4 seconds
self.target.disabled = true;
self.target.disableTimer = 240; // 4 seconds at 60fps
LK.effects.flashObject(self.target, 0x4169E1, 700);
// Apply world modifier weakness
if (self.target.worldModifier) {
self.target.worldModifier = 0.5; // Weakened in wrong world
LK.setTimeout(function () {
if (self.target && !self.target.destroyed) {
self.target.worldModifier = 1.0;
}
}, 2500);
}
self.destroyed = true;
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroyed = true;
self.destroy();
}
};
return self;
});
var CanadianGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('canadianGoose', {
anchorX: 0.5,
anchorY: 0.5
});
self.range = 150;
self.damage = 25;
self.fireRate = 60; // 1 second at 60fps
self.fireTimer = 0;
self.cost = 50;
self.disabled = false;
self.disableTimer = 0;
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.target = target;
projectile.damage = self.damage;
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('honk').play();
self.fireTimer = 0;
}
}
}
};
return self;
});
var EmdenGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('emdenGoose', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.speed = 1.5;
self.pathIndex = 0;
self.reward = 10;
self.frozen = false;
self.freezeTimer = 0;
self.destroyed = false;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
resources += self.reward;
updateResourceDisplay();
LK.getSound('defeat').play();
self.destroyed = true;
self.destroy();
}
};
self.freeze = function (duration) {
self.frozen = true;
self.freezeTimer = duration;
graphics.tint = 0xAADDFF;
var iceEffect = new IceEffect();
iceEffect.x = self.x;
iceEffect.y = self.y;
game.addChild(iceEffect);
};
self.stunned = false;
self.stunTimer = 0;
self.stun = function (duration) {
self.stunned = true;
self.stunTimer = duration;
graphics.tint = 0x9932CC; // Purple tint for stun
var stunEffect = new StunEffect();
stunEffect.x = self.x;
stunEffect.y = self.y;
game.addChild(stunEffect);
};
// Charm state variables
self.charmed = false;
self.charmTimer = 0;
self.originalSpeed = self.speed;
self.update = function () {
if (self.freezeTimer > 0) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
graphics.tint = 0xFFFFFF;
}
}
// Handle stun timer
if (self.stunTimer > 0) {
self.stunTimer--;
if (self.stunTimer <= 0) {
self.stunned = false;
graphics.tint = 0xFFFFFF;
}
}
// Handle charm timer - charmed enemies move backwards
if (self.charmed && self.charmTimer > 0) {
self.charmTimer--;
if (self.charmTimer <= 0) {
self.charmed = false;
self.speed = self.originalSpeed;
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
}
}
if (!self.frozen && !self.stunned && self.pathIndex < pathPoints.length - 1) {
var target;
// If charmed, move towards previous path point (backwards)
if (self.charmed && self.pathIndex > 0) {
target = pathPoints[self.pathIndex - 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex--;
if (self.pathIndex <= 0) {
// If charmed enemy reaches start, remove it and give bonus resources
resources += self.reward * 2;
updateResourceDisplay();
self.destroyed = true;
self.destroy();
return;
}
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * Math.abs(self.speed);
self.y += Math.sin(angle) * Math.abs(self.speed);
}
} else {
// Normal forward movement
target = pathPoints[self.pathIndex + 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= pathPoints.length - 1) {
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.destroyed = true;
self.destroy();
return;
}
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
}
};
return self;
});
var FakeEmdenGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('emdenGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFD700; // Golden tint to show it's fake
self.charmRange = 100;
self.lifetime = 600; // 10 seconds at 60fps
self.timer = 0;
self.charmedEnemies = [];
self.update = function () {
self.timer++;
// Pulsing effect to show it's fake
graphics.alpha = 0.7 + Math.sin(self.timer * 0.1) * 0.3;
graphics.rotation += 0.02;
// Find nearby real enemies to charm
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.destroyed && self.charmedEnemies.indexOf(enemy) === -1) {
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.charmRange) {
// Charm the enemy - make it move backwards on path
self.charmedEnemies.push(enemy);
enemy.charmed = true;
enemy.charmTimer = 300; // 5 seconds charm duration
enemy.originalSpeed = enemy.speed;
enemy.speed = -enemy.speed * 0.5; // Move backwards slower
// Visual charm effect
tween(enemy, {
tint: 0xFFB6C1
}, {
duration: 500,
easing: tween.easeOut
});
LK.effects.flashObject(enemy, 0xFFD700, 800);
}
}
}
// Remove charm from enemies over time
for (var j = self.charmedEnemies.length - 1; j >= 0; j--) {
var charmedEnemy = self.charmedEnemies[j];
if (charmedEnemy.destroyed || !charmedEnemy.charmed) {
self.charmedEnemies.splice(j, 1);
} else if (charmedEnemy.charmTimer <= 0) {
charmedEnemy.charmed = false;
charmedEnemy.speed = charmedEnemy.originalSpeed;
charmedEnemy.charmTimer = 0;
tween(charmedEnemy, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
self.charmedEnemies.splice(j, 1);
} else {
charmedEnemy.charmTimer--;
}
}
// Destroy fake goose after lifetime
if (self.timer >= self.lifetime) {
// Remove charm from all enemies when fake goose dies
for (var k = 0; k < self.charmedEnemies.length; k++) {
var enemy = self.charmedEnemies[k];
if (!enemy.destroyed) {
enemy.charmed = false;
enemy.speed = enemy.originalSpeed;
enemy.charmTimer = 0;
tween(enemy, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
}
}
self.destroy();
}
};
return self;
});
var FireMagic = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF4500; // Orange-red fire color
self.speed = 6;
self.target = null;
self.damage = 45;
self.destroyed = false;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
// Primary fire damage
self.target.takeDamage(self.damage);
LK.effects.flashObject(self.target, 0xFF4500, 400);
// Burning damage over time - 6 ticks of burn damage
var burnDamage = 12;
var burnTicks = 6;
for (var bt = 1; bt <= burnTicks; bt++) {
LK.setTimeout(function () {
if (self.target && !self.target.destroyed) {
self.target.takeDamage(burnDamage);
LK.effects.flashObject(self.target, 0xFF6600, 150);
}
}, bt * 500);
}
// Fire spreads to nearby enemies with area damage
var nearbyEnemies = [];
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.destroyed && enemy !== self.target) {
var edx = enemy.x - self.target.x;
var edy = enemy.y - self.target.y;
var edist = Math.sqrt(edx * edx + edy * edy);
if (edist < 90) {
nearbyEnemies.push(enemy);
}
}
}
for (var j = 0; j < nearbyEnemies.length; j++) {
var splashDamage = Math.floor(self.damage * 0.6);
nearbyEnemies[j].takeDamage(splashDamage);
LK.effects.flashObject(nearbyEnemies[j], 0xFF4500, 300);
// Reduced burning effect on nearby enemies
var nearbyBurnDamage = 8;
var nearbyBurnTicks = 3;
for (var nbt = 1; nbt <= nearbyBurnTicks; nbt++) {
LK.setTimeout(function () {
if (nearbyEnemies[j] && !nearbyEnemies[j].destroyed) {
nearbyEnemies[j].takeDamage(nearbyBurnDamage);
LK.effects.flashObject(nearbyEnemies[j], 0xFF6600, 100);
}
}, nbt * 600);
}
}
self.destroyed = true;
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroyed = true;
self.destroy();
}
};
return self;
});
var HammerGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('hammerGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x9932CC; // Electro purple color
self.range = 100;
self.stunDuration = 180; // 3 seconds at 60fps
self.fireRate = 90; // 1.5 seconds at 60fps
self.fireTimer = 0;
self.cost = 120;
self.disabled = false;
self.disableTimer = 0;
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target && !target.stunned) {
// Hammer swing animation
tween(graphics, {
rotation: graphics.rotation + Math.PI / 4
}, {
duration: 150,
easing: tween.easeOut
});
tween(graphics, {
rotation: graphics.rotation
}, {
duration: 150,
easing: tween.easeIn
});
// Stun the enemy
target.stun(self.stunDuration);
LK.getSound('hammer').play();
self.fireTimer = 0;
}
}
}
};
return self;
});
var HydroArrow = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x0066CC; // Blue hydro color
self.speed = 7;
self.target = null;
self.destroyed = false;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 25) {
// Disable tower for 4 seconds and deal damage
self.target.disabled = true;
self.target.disableTimer = 240; // 4 seconds at 60fps
LK.effects.flashObject(self.target, 0x0066CC, 600);
self.destroyed = true;
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroyed = true;
self.destroy();
}
};
return self;
});
var HydroArrowEmdenGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('hydroGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x0066CC; // Blue hydro color
self.health = 150;
self.maxHealth = 150;
self.speed = 1.0;
self.pathIndex = 0;
self.reward = 30;
self.frozen = false;
self.freezeTimer = 0;
self.destroyed = false;
self.arrowTimer = 0;
self.arrowRate = 180; // 3 seconds at 60fps
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff1e00, 200);
if (self.health <= 0) {
resources += self.reward;
updateResourceDisplay();
LK.getSound('defeat').play();
self.destroyed = true;
self.destroy();
}
};
self.freeze = function (duration) {
self.frozen = true;
self.freezeTimer = duration;
graphics.tint = 0xAADDFF;
var iceEffect = new IceEffect();
iceEffect.x = self.x;
iceEffect.y = self.y;
game.addChild(iceEffect);
};
self.stunned = false;
self.stunTimer = 0;
self.stun = function (duration) {
self.stunned = true;
self.stunTimer = duration;
graphics.tint = 0x9932CC; // Purple tint for stun
var stunEffect = new StunEffect();
stunEffect.x = self.x;
stunEffect.y = self.y;
game.addChild(stunEffect);
};
self.shootArrow = function () {
var nearestTower = findNearestTower(self.x, self.y, 250);
if (nearestTower) {
var arrow = new HydroArrow();
arrow.x = self.x;
arrow.y = self.y;
arrow.target = nearestTower;
potions.push(arrow);
game.addChild(arrow);
LK.getSound('hydroArrow').play();
}
};
self.update = function () {
if (self.freezeTimer > 0) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
graphics.tint = 0x0066CC; // Return to blue hydro color
}
}
// Handle stun timer
if (self.stunTimer > 0) {
self.stunTimer--;
if (self.stunTimer <= 0) {
self.stunned = false;
graphics.tint = 0x0066CC; // Return to blue hydro color
}
}
// Hydro arrow shooting ability
self.arrowTimer++;
if (self.arrowTimer >= self.arrowRate && !self.frozen && !self.stunned) {
self.shootArrow();
self.arrowTimer = 0;
}
if (!self.frozen && !self.stunned && self.pathIndex < pathPoints.length - 1) {
var target = pathPoints[self.pathIndex + 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= pathPoints.length - 1) {
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.destroyed = true;
self.destroy();
return;
}
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
};
return self;
});
var IceEffect = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('iceEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.duration = 180; // 3 seconds at 60fps
self.timer = 0;
self.update = function () {
self.timer++;
graphics.rotation += 0.1;
if (self.timer >= self.duration) {
self.destroy();
}
};
return self;
});
var IceGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('iceGoose', {
anchorX: 0.5,
anchorY: 0.5
});
self.range = 120;
self.freezeDuration = 120; // 2 seconds at 60fps
self.fireRate = 180; // 3 seconds at 60fps
self.fireTimer = 0;
self.cost = 80;
self.disabled = false;
self.disableTimer = 0;
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target && !target.frozen) {
target.freeze(self.freezeDuration);
LK.getSound('freeze').play();
self.fireTimer = 0;
}
}
}
};
return self;
});
var MoonMagic = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x9370DB; // Purple moonlight color
self.speed = 7;
self.target = null;
self.damage = 40;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
self.target.takeDamage(self.damage);
LK.effects.flashObject(self.target, 0x9370DB, 400);
// Moonlight magic spreads to nearby enemies
var nearbyEnemies = [];
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.destroyed && enemy !== self.target) {
var edx = enemy.x - self.target.x;
var edy = enemy.y - self.target.y;
var edist = Math.sqrt(edx * edx + edy * edy);
if (edist < 80) {
nearbyEnemies.push(enemy);
}
}
}
for (var j = 0; j < nearbyEnemies.length; j++) {
nearbyEnemies[j].takeDamage(Math.floor(self.damage * 0.5));
LK.effects.flashObject(nearbyEnemies[j], 0x9370DB, 200);
}
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroy();
}
};
return self;
});
var MoonlightSleeper = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('moonlightSleeper', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x9370DB; // Purple moonlight color
self.range = 200;
self.damage = 40;
self.fireRate = 90; // Slower but powerful magic
self.fireTimer = 0;
self.cost = 120;
self.disabled = false;
self.disableTimer = 0;
self.worldModifier = 1.0; // Damage modifier based on world
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target) {
var projectile = new MoonMagic();
projectile.x = self.x;
projectile.y = self.y;
projectile.target = target;
projectile.damage = Math.floor(self.damage * self.worldModifier);
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('moonMagic').play();
self.fireTimer = 0;
}
}
}
};
return self;
});
var PieProjectile = Container.expand(function () {
var self = Container.call(this);
self.pieType = 'apple'; // 'apple', 'cherry', 'blueberry'
self.speed = 6;
self.target = null;
self.damage = 30;
self.destroyed = false;
// Use appropriate pie asset based on type
var assetId = 'applePie';
if (self.pieType === 'cherry') assetId = 'cherryPie';
if (self.pieType === 'blueberry') assetId = 'blueberryPie';
var graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
// Apply pie-specific effects on enemies
if (self.pieType === 'apple') {
// Apple pie: slow enemy for 3 seconds
self.target.takeDamage(self.damage);
if (!self.target.frozen && !self.target.stunned) {
var originalSpeed = self.target.speed;
self.target.speed = originalSpeed * 0.5;
tween(self.target, {
tint: 0x90EE90
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.target, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
}
});
LK.setTimeout(function () {
if (self.target && !self.target.destroyed) {
self.target.speed = originalSpeed;
}
}, 3000);
}
} else if (self.pieType === 'cherry') {
// Cherry pie: burning damage over time
self.target.takeDamage(self.damage);
var burnDamage = 8;
var burnTicks = 5;
for (var bt = 1; bt <= burnTicks; bt++) {
LK.setTimeout(function () {
if (self.target && !self.target.destroyed) {
self.target.takeDamage(burnDamage);
LK.effects.flashObject(self.target, 0xFF6B6B, 200);
}
}, bt * 600);
}
} else if (self.pieType === 'blueberry') {
// Blueberry pie: chance to freeze enemy
self.target.takeDamage(self.damage);
if (Math.random() < 0.4 && !self.target.frozen) {
self.target.freeze(120); // 2 seconds freeze
}
}
// Pie splash effect with flavor-specific colors
var splashColor = 0x90EE90;
if (self.pieType === 'cherry') splashColor = 0xFF6B6B;
if (self.pieType === 'blueberry') splashColor = 0x4169E1;
LK.effects.flashObject(self.target, splashColor, 400);
// Area damage to nearby enemies
var nearbyEnemies = [];
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.destroyed && enemy !== self.target) {
var edx = enemy.x - self.target.x;
var edy = enemy.y - self.target.y;
var edist = Math.sqrt(edx * edx + edy * edy);
if (edist < 60) {
nearbyEnemies.push(enemy);
}
}
}
for (var j = 0; j < nearbyEnemies.length; j++) {
var splashDamage = Math.floor(self.damage * 0.4);
nearbyEnemies[j].takeDamage(splashDamage);
LK.effects.flashObject(nearbyEnemies[j], splashColor, 200);
// Apply reduced pie effects to nearby enemies
if (self.pieType === 'apple' && !nearbyEnemies[j].frozen && !nearbyEnemies[j].stunned) {
var enemySpeed = nearbyEnemies[j].speed;
nearbyEnemies[j].speed = enemySpeed * 0.7;
LK.setTimeout(function () {
if (nearbyEnemies[j] && !nearbyEnemies[j].destroyed) {
nearbyEnemies[j].speed = enemySpeed;
}
}, 1500);
} else if (self.pieType === 'blueberry' && Math.random() < 0.2 && !nearbyEnemies[j].frozen) {
nearbyEnemies[j].freeze(60);
}
}
self.destroyed = true;
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroyed = true;
self.destroy();
}
};
return self;
});
var PieShooterGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pieShooterGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFB6C1; // Light pink color for pie shooter
self.range = 160;
self.damage = 30;
self.fireRate = 75; // Moderate shooting speed
self.fireTimer = 0;
self.cost = 110;
self.disabled = false;
self.disableTimer = 0;
self.worldModifier = 1.0;
self.healRange = 120;
self.healRate = 180; // 3 seconds at 60fps
self.healTimer = 0;
self.healAmount = 15;
self.lastPieType = 'apple'; // Track last pie type for healing effects
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
self.healTimer++;
// Shooting pies at enemies
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target) {
var projectile = new PieProjectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.target = target;
projectile.damage = Math.floor(self.damage * self.worldModifier);
// Randomly select pie type
var pieTypes = ['apple', 'cherry', 'blueberry'];
projectile.pieType = pieTypes[Math.floor(Math.random() * pieTypes.length)];
self.lastPieType = projectile.pieType; // Track for healing effects
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('pieShot').play();
self.fireTimer = 0;
}
}
// Healing nearby Canadian Geese towers
if (self.healTimer >= self.healRate) {
var towersInRange = [];
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
if (!tower.destroyed && (tower.constructor === CanadianGoose || tower.constructor === PieShooterGoose)) {
var dx = tower.x - self.x;
var dy = tower.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.healRange && tower !== self) {
towersInRange.push(tower);
}
}
}
// Heal all Canadian Geese in range with different pie healing effects
for (var j = 0; j < towersInRange.length; j++) {
var tower = towersInRange[j];
// Determine healing type based on what pie flavor was last shot
var currentPieType = 'apple'; // default
if (self.lastPieType) {
currentPieType = self.lastPieType;
}
// Apply different healing effects based on pie flavor
if (currentPieType === 'apple') {
// Apple healing: boost fire rate temporarily
if (tower.fireRate && !tower.appleBoosted) {
tower.appleBoosted = true;
var originalFireRate = tower.fireRate;
tower.fireRate = Math.floor(originalFireRate * 0.7); // 30% faster
tween(tower, {
tint: 0x90EE90
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(tower, {
tint: 0xFFFFFF
}, {
duration: 400,
easing: tween.easeIn
});
}
});
LK.setTimeout(function () {
if (tower && !tower.destroyed) {
tower.fireRate = originalFireRate;
tower.appleBoosted = false;
}
}, 5000);
}
} else if (currentPieType === 'cherry') {
// Cherry healing: boost damage temporarily
if (tower.damage && !tower.cherryBoosted) {
tower.cherryBoosted = true;
var originalDamage = tower.damage;
tower.damage = Math.floor(originalDamage * 1.3); // 30% more damage
tween(tower, {
tint: 0xFF6B6B
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(tower, {
tint: 0xFFFFFF
}, {
duration: 400,
easing: tween.easeIn
});
}
});
LK.setTimeout(function () {
if (tower && !tower.destroyed) {
tower.damage = originalDamage;
tower.cherryBoosted = false;
}
}, 5000);
}
} else if (currentPieType === 'blueberry') {
// Blueberry healing: boost range temporarily
if (tower.range && !tower.blueberryBoosted) {
tower.blueberryBoosted = true;
var originalRange = tower.range;
tower.range = Math.floor(originalRange * 1.25); // 25% more range
tween(tower, {
tint: 0x4169E1
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(tower, {
tint: 0xFFFFFF
}, {
duration: 400,
easing: tween.easeIn
});
}
});
LK.setTimeout(function () {
if (tower && !tower.destroyed) {
tower.range = originalRange;
tower.blueberryBoosted = false;
}
}, 5000);
}
}
// Base visual healing effect
LK.effects.flashObject(tower, 0x00FF7F, 600);
tween(tower, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(tower, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 250,
easing: tween.easeIn
});
}
});
}
if (towersInRange.length > 0) {
// Visual effect for pie shooter goose healing
tween(graphics, {
tint: 0x00FF7F
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(graphics, {
tint: 0xFFB6C1
}, {
duration: 400,
easing: tween.easeIn
});
}
});
}
self.healTimer = 0;
}
}
};
return self;
});
var PoisonPotion = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x9932CC; // Purple color for poison
self.speed = 6;
self.target = null;
self.destroyed = false;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 25) {
// Disable tower for 3 seconds
self.target.disabled = true;
self.target.disableTimer = 180; // 3 seconds at 60fps
LK.effects.flashObject(self.target, 0x9932CC, 500);
self.destroyed = true;
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroyed = true;
self.destroy();
}
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.target = null;
self.damage = 25;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
self.target.takeDamage(self.damage);
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroy();
}
};
return self;
});
var PyroCatalystGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pyroCatalystGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF4500; // Orange-red fire color
self.range = 170;
self.damage = 45;
self.fireRate = 80; // Moderate casting speed
self.fireTimer = 0;
self.cost = 140;
self.disabled = false;
self.disableTimer = 0;
self.worldModifier = 1.0;
// Fire magic charging effect
self.chargingEffect = false;
self.chargeTimer = 0;
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
// Charging effect before casting
if (self.fireTimer >= self.fireRate - 20 && !self.chargingEffect) {
self.chargingEffect = true;
tween(graphics, {
tint: 0xFFFF00,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
}
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target) {
var projectile = new FireMagic();
projectile.x = self.x;
projectile.y = self.y;
projectile.target = target;
projectile.damage = Math.floor(self.damage * self.worldModifier);
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('fireMagic').play();
// Fire casting animation
tween(graphics, {
rotation: graphics.rotation + Math.PI / 6
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(graphics, {
rotation: graphics.rotation,
tint: 0xFF4500,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
self.fireTimer = 0;
self.chargingEffect = false;
}
}
}
};
return self;
});
var RedMoonEmdenGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('redMoonGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x8B0000; // Dark red color
self.health = 180;
self.maxHealth = 180;
self.speed = 1.1;
self.pathIndex = 0;
self.reward = 40;
self.frozen = false;
self.freezeTimer = 0;
self.destroyed = false;
self.magicTimer = 0;
self.magicRate = 200; // 3.3 seconds at 60fps
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff1e00, 200);
if (self.health <= 0) {
resources += self.reward;
updateResourceDisplay();
LK.getSound('defeat').play();
self.destroyed = true;
self.destroy();
}
};
self.freeze = function (duration) {
self.frozen = true;
self.freezeTimer = duration;
graphics.tint = 0xAADDFF;
var iceEffect = new IceEffect();
iceEffect.x = self.x;
iceEffect.y = self.y;
game.addChild(iceEffect);
};
self.stunned = false;
self.stunTimer = 0;
self.stun = function (duration) {
self.stunned = true;
self.stunTimer = duration;
graphics.tint = 0x9932CC;
var stunEffect = new StunEffect();
stunEffect.x = self.x;
stunEffect.y = self.y;
game.addChild(stunEffect);
};
self.castRedMoonMagic = function () {
var nearestTower = findNearestTower(self.x, self.y, 220);
if (nearestTower) {
var magic = new RedMoonMagic();
magic.x = self.x;
magic.y = self.y;
magic.target = nearestTower;
potions.push(magic);
game.addChild(magic);
LK.getSound('redMoonMagic').play();
}
};
self.update = function () {
if (self.freezeTimer > 0) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
graphics.tint = 0x8B0000;
}
}
if (self.stunTimer > 0) {
self.stunTimer--;
if (self.stunTimer <= 0) {
self.stunned = false;
graphics.tint = 0x8B0000;
}
}
self.magicTimer++;
if (self.magicTimer >= self.magicRate && !self.frozen && !self.stunned) {
self.castRedMoonMagic();
self.magicTimer = 0;
}
if (!self.frozen && !self.stunned && self.pathIndex < pathPoints.length - 1) {
var target = pathPoints[self.pathIndex + 1];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= pathPoints.length - 1) {
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.destroyed = true;
self.destroy();
return;
}
} else {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
};
return self;
});
var RedMoonMagic = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x8B0000; // Dark red color
self.speed = 6;
self.target = null;
self.destroyed = false;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 25) {
// Red moon magic disables tower for 5 seconds and deals damage
self.target.disabled = true;
self.target.disableTimer = 300; // 5 seconds at 60fps
LK.effects.flashObject(self.target, 0x8B0000, 800);
// Apply world modifier weakness
if (self.target.worldModifier) {
self.target.worldModifier = 0.5; // Weakened in wrong world
LK.setTimeout(function () {
if (self.target && !self.target.destroyed) {
self.target.worldModifier = 1.0;
}
}, 3000);
}
self.destroyed = true;
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroyed = true;
self.destroy();
}
};
return self;
});
var StunEffect = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('stunEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
graphics.tint = 0x9932CC; // Purple color for stun effect
self.duration = 120; // 2 seconds at 60fps
self.timer = 0;
self.update = function () {
self.timer++;
graphics.rotation += 0.15;
graphics.scaleX = 1 + Math.sin(self.timer * 0.2) * 0.1;
graphics.scaleY = 1 + Math.sin(self.timer * 0.2) * 0.1;
if (self.timer >= self.duration) {
self.destroy();
}
};
return self;
});
var SunArrow = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFD700; // Golden sun color
self.speed = 9;
self.target = null;
self.damage = 35;
self.update = function () {
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
self.target.takeDamage(self.damage);
LK.effects.flashObject(self.target, 0xFFD700, 300);
self.destroy();
return;
}
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
self.destroy();
}
};
return self;
});
var SunShooter = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('sunShooter', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFD700; // Golden sun color
self.range = 180;
self.damage = 35;
self.fireRate = 45; // Fast shooting
self.fireTimer = 0;
self.cost = 100;
self.disabled = false;
self.disableTimer = 0;
self.worldModifier = 1.0; // Damage modifier based on world
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fireTimer++;
if (self.fireTimer >= self.fireRate) {
var target = findNearestEnemy(self.x, self.y, self.range);
if (target) {
var projectile = new SunArrow();
projectile.x = self.x;
projectile.y = self.y;
projectile.target = target;
projectile.damage = Math.floor(self.damage * self.worldModifier);
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('sunArrow').play();
self.fireTimer = 0;
}
}
}
};
return self;
});
var TreasureHoarderGoose = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('treasureHoarderGoose', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFD700; // Golden treasure color
self.range = 200;
self.fakeGooseRate = 480; // 8 seconds at 60fps
self.fakeGooseTimer = 0;
self.cost = 200;
self.disabled = false;
self.disableTimer = 0;
self.worldModifier = 1.0;
// Treasure collection ability - gains resources over time
self.treasureRate = 300; // 5 seconds at 60fps
self.treasureTimer = 0;
self.treasureAmount = 15;
self.update = function () {
// Handle disable timer
if (self.disableTimer > 0) {
self.disableTimer--;
if (self.disableTimer <= 0) {
self.disabled = false;
}
}
if (!self.disabled) {
self.fakeGooseTimer++;
self.treasureTimer++;
// Treasure hoarding - generate resources
if (self.treasureTimer >= self.treasureRate) {
resources += self.treasureAmount;
updateResourceDisplay();
// Treasure collection visual effect
tween(graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0x00FF00
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(graphics, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeIn
});
}
});
self.treasureTimer = 0;
}
// Create fake Emden goose to charm enemies
if (self.fakeGooseTimer >= self.fakeGooseRate) {
var nearestEnemy = findNearestEnemy(self.x, self.y, self.range);
if (nearestEnemy) {
var fakeGoose = new FakeEmdenGoose();
// Position fake goose strategically near enemy path
var targetPathPoint = pathPoints[Math.min(nearestEnemy.pathIndex + 1, pathPoints.length - 1)];
fakeGoose.x = targetPathPoint.x + (Math.random() - 0.5) * 120;
fakeGoose.y = targetPathPoint.y + (Math.random() - 0.5) * 120;
game.addChild(fakeGoose);
// Summoning visual effect
tween(graphics, {
rotation: graphics.rotation + Math.PI / 3
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(graphics, {
rotation: graphics.rotation
}, {
duration: 300,
easing: tween.easeIn
});
}
});
LK.effects.flashObject(self, 0xFFD700, 600);
LK.getSound('charm').play();
}
self.fakeGooseTimer = 0;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Game state variables
var gameState = 'menu'; // 'menu', 'playing', 'paused'
var mainMenu;
var gameInitialized = false;
// Game variables
var resources = 999999;
var lives = 20;
var wave = 1;
var enemies = [];
var towers = [];
var projectiles = [];
var potions = [];
var waveTimer = 0;
var waveDelay = 300; // 5 seconds between waves
var enemiesPerWave = 5;
var selectedTowerType = 'canadian';
var currentWorld = 'normal'; // 'normal', 'sun', 'moon'
var episode = 1;
// UI Elements - declare globally to be accessible
var resourceTxt;
var livesTxt;
var waveTxt;
var canadianBtn;
var iceBtn;
var hammerBtn;
var sunBtn;
var moonBtn;
var antiVirusBtn;
var pieShooterBtn;
var pyroCatalystBtn;
var treasureHoarderBtn;
// Path points for enemies to follow
var pathPoints = [{
x: 0,
y: 400
}, {
x: 300,
y: 400
}, {
x: 300,
y: 800
}, {
x: 700,
y: 800
}, {
x: 700,
y: 1200
}, {
x: 1100,
y: 1200
}, {
x: 1100,
y: 1600
}, {
x: 1500,
y: 1600
}, {
x: 1500,
y: 2000
}, {
x: 2048,
y: 2000
}];
// Initialize Main Menu
function createMainMenu() {
mainMenu = new Container();
// Title
var titleText = new Text2('Canadian Geese Tower Defense', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
mainMenu.addChild(titleText);
// Subtitle
var subtitleText = new Text2('Defend Against the Emden Invasion!', {
size: 80,
fill: 0xFFD700
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 550;
mainMenu.addChild(subtitleText);
// Play Button
var playButton = new Text2('START GAME', {
size: 100,
fill: 0x00FF00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 1024;
playButton.y = 800;
playButton.down = function () {
startGame();
};
mainMenu.addChild(playButton);
// Instructions
var instructText = new Text2('Tap to place towers and defend your treasure!', {
size: 60,
fill: 0xCCCCCC
});
instructText.anchor.set(0.5, 0.5);
instructText.x = 1024;
instructText.y = 1000;
mainMenu.addChild(instructText);
// Episode info
var episodeText = new Text2('3 Episodes: Normal → Sun World → Moon World', {
size: 50,
fill: 0x87CEEB
});
episodeText.anchor.set(0.5, 0.5);
episodeText.x = 1024;
episodeText.y = 1150;
mainMenu.addChild(episodeText);
// Animation for title
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
yoyo: true,
repeat: -1
});
// Animation for play button
tween(playButton, {
alpha: 0.7
}, {
duration: 800,
easing: tween.easeInOut,
yoyo: true,
repeat: -1
});
game.addChild(mainMenu);
}
function startGame() {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
gameState = 'playing';
if (!gameInitialized) {
initializeGame();
gameInitialized = true;
}
}
function initializeGame() {
// Create path visuals
for (var i = 0; i < pathPoints.length - 1; i++) {
var start = pathPoints[i];
var end = pathPoints[i + 1];
var segments = Math.ceil(Math.sqrt((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / 100);
for (var j = 0; j < segments; j++) {
var t = j / segments;
var pathSegment = game.addChild(LK.getAsset('path', {
anchorX: 0.5,
anchorY: 0.5,
x: start.x + (end.x - start.x) * t,
y: start.y + (end.y - start.y) * t,
alpha: 0.3
}));
}
}
// Create treasure at end
var treasure = game.addChild(LK.getAsset('treasure', {
anchorX: 0.5,
anchorY: 0.5,
x: pathPoints[pathPoints.length - 1].x - 100,
y: pathPoints[pathPoints.length - 1].y
}));
// UI Elements
resourceTxt = new Text2('Resources: ' + resources, {
size: 60,
fill: 0xFFFFFF
});
resourceTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(resourceTxt);
resourceTxt.x = -300;
resourceTxt.y = 50;
livesTxt = new Text2('Lives: ' + lives, {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(livesTxt);
livesTxt.x = -300;
livesTxt.y = 120;
waveTxt = new Text2('Wave: ' + wave, {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(waveTxt);
waveTxt.x = 120;
waveTxt.y = 50;
// Tower selection buttons
canadianBtn = new Text2('Canadian Goose (50)', {
size: 50,
fill: 0x8B4513
});
canadianBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(canadianBtn);
canadianBtn.y = -200;
canadianBtn.x = -200;
iceBtn = new Text2('Ice Goose (80)', {
size: 50,
fill: 0x87CEEB
});
iceBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(iceBtn);
iceBtn.y = -200;
iceBtn.x = 0;
hammerBtn = new Text2('Hammer Goose (120)', {
size: 50,
fill: 0x9932CC
});
hammerBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(hammerBtn);
hammerBtn.y = -200;
hammerBtn.x = 200;
sunBtn = new Text2('Sun Shooter (100)', {
size: 50,
fill: 0xFFD700
});
sunBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(sunBtn);
sunBtn.y = -140;
sunBtn.x = -200;
moonBtn = new Text2('Moonlight Sleeper (120)', {
size: 50,
fill: 0x9370DB
});
moonBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(moonBtn);
moonBtn.y = -140;
moonBtn.x = 200;
antiVirusBtn = new Text2('Anti Virus (150)', {
size: 50,
fill: 0x00FF00
});
antiVirusBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(antiVirusBtn);
antiVirusBtn.y = -80;
antiVirusBtn.x = -100;
pieShooterBtn = new Text2('Pie Shooter (110)', {
size: 50,
fill: 0xFFB6C1
});
pieShooterBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(pieShooterBtn);
pieShooterBtn.y = -80;
pieShooterBtn.x = 50;
pyroCatalystBtn = new Text2('Pyro Catalyst (140)', {
size: 50,
fill: 0xFF4500
});
pyroCatalystBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(pyroCatalystBtn);
pyroCatalystBtn.y = -80;
pyroCatalystBtn.x = 150;
treasureHoarderBtn = new Text2('Treasure Hoarder (200)', {
size: 50,
fill: 0xFFD700
});
treasureHoarderBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(treasureHoarderBtn);
treasureHoarderBtn.y = -20;
treasureHoarderBtn.x = 0;
// Button interactions
canadianBtn.down = function () {
selectedTowerType = 'canadian';
canadianBtn.fill = 0xFFD700;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
treasureHoarderBtn.fill = 0xFFD700;
};
pieShooterBtn.down = function () {
selectedTowerType = 'pieShooter';
pieShooterBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pyroCatalystBtn.fill = 0xFF4500;
};
iceBtn.down = function () {
selectedTowerType = 'ice';
iceBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
};
hammerBtn.down = function () {
selectedTowerType = 'hammer';
hammerBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
};
sunBtn.down = function () {
selectedTowerType = 'sun';
sunBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
};
moonBtn.down = function () {
selectedTowerType = 'moon';
moonBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
};
antiVirusBtn.down = function () {
selectedTowerType = 'antiVirus';
antiVirusBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
};
pyroCatalystBtn.down = function () {
selectedTowerType = 'pyroCatalyst';
pyroCatalystBtn.fill = 0xFFD700;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
treasureHoarderBtn.fill = 0xFFD700;
};
treasureHoarderBtn.down = function () {
selectedTowerType = 'treasureHoarder';
treasureHoarderBtn.fill = 0x00FF00;
canadianBtn.fill = 0x8B4513;
iceBtn.fill = 0x87CEEB;
hammerBtn.fill = 0x9932CC;
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
};
// Initialize first wave
spawnWave();
}
// Helper functions
function updateResourceDisplay() {
resourceTxt.setText('Resources: ' + resources);
}
function updateLivesDisplay() {
livesTxt.setText('Lives: ' + lives);
}
function updateWaveDisplay() {
var worldName = 'Normal';
if (currentWorld === 'sun') {
worldName = 'Sun World';
}
if (currentWorld === 'moon') {
worldName = 'Moon World';
}
waveTxt.setText('Episode ' + episode + ' - Wave: ' + wave + ' (' + worldName + ')');
}
function findNearestEnemy(x, y, range) {
var nearest = null;
var nearestDistance = range;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.destroyed) {
var dx = enemy.x - x;
var dy = enemy.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearest = enemy;
nearestDistance = distance;
}
}
}
return nearest;
}
function findNearestTower(x, y, range) {
var nearest = null;
var nearestDistance = range;
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
if (!tower.destroyed) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearest = tower;
nearestDistance = distance;
}
}
}
return nearest;
}
function spawnWave() {
for (var i = 0; i < enemiesPerWave + Math.floor(wave / 3); i++) {
LK.setTimeout(function () {
var enemy;
var rand = Math.random();
// Episode-based enemy spawning
if (episode >= 3 && rand < 0.15) {
// Moon World - Red Moon enemies
enemy = new RedMoonEmdenGoose();
} else if (episode >= 2 && rand < 0.15) {
// Sun World - Blue Sun enemies
enemy = new BlueSunEmdenGoose();
} else if (wave >= 3 && rand < 0.2) {
// Hydro Arrow Emden
enemy = new HydroArrowEmdenGoose();
} else if (wave >= 2 && rand < 0.45) {
// Ameno Emden Potioneer
enemy = new AmenoEmdenGoose();
} else {
enemy = new EmdenGoose();
}
enemy.x = pathPoints[0].x;
enemy.y = pathPoints[0].y;
enemy.health = enemy.maxHealth + (wave - 1) * 20;
enemy.maxHealth = enemy.health;
enemies.push(enemy);
game.addChild(enemy);
}, i * 1000);
}
}
// Game interaction
game.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
// Check if clicking on path (don't allow tower placement)
var onPath = false;
for (var i = 0; i < pathPoints.length - 1; i++) {
var start = pathPoints[i];
var end = pathPoints[i + 1];
var dx = end.x - start.x;
var dy = end.y - start.y;
var length = Math.sqrt(dx * dx + dy * dy);
var nx = dx / length;
var ny = dy / length;
var px = x - start.x;
var py = y - start.y;
var dot = px * nx + py * ny;
if (dot >= 0 && dot <= length) {
var distance = Math.abs(px * ny - py * nx);
if (distance < 60) {
onPath = true;
break;
}
}
}
if (!onPath) {
var tower = null;
var cost = 0;
if (selectedTowerType === 'canadian') {
tower = new CanadianGoose();
cost = tower.cost;
} else if (selectedTowerType === 'ice') {
tower = new IceGoose();
cost = tower.cost;
} else if (selectedTowerType === 'hammer') {
tower = new HammerGoose();
cost = tower.cost;
} else if (selectedTowerType === 'sun') {
tower = new SunShooter();
cost = tower.cost;
} else if (selectedTowerType === 'moon') {
tower = new MoonlightSleeper();
cost = tower.cost;
} else if (selectedTowerType === 'antiVirus') {
tower = new AntiVirusGoose();
cost = tower.cost;
} else if (selectedTowerType === 'pieShooter') {
tower = new PieShooterGoose();
cost = tower.cost;
} else if (selectedTowerType === 'pyroCatalyst') {
tower = new PyroCatalystGoose();
cost = tower.cost;
} else if (selectedTowerType === 'treasureHoarder') {
tower = new TreasureHoarderGoose();
cost = tower.cost;
}
if (tower && resources >= cost) {
tower.x = x;
tower.y = y;
// Apply world modifiers
if (tower.worldModifier !== undefined) {
if (currentWorld === 'sun' && selectedTowerType === 'sun') {
tower.worldModifier = 1.5; // Strong in Sun World
} else if (currentWorld === 'moon' && selectedTowerType === 'moon') {
tower.worldModifier = 1.5; // Strong in Moon World
} else if (currentWorld === 'sun' && selectedTowerType === 'moon') {
tower.worldModifier = 0.7; // Weak in wrong world
} else if (currentWorld === 'moon' && selectedTowerType === 'sun') {
tower.worldModifier = 0.7; // Weak in wrong world
}
}
towers.push(tower);
game.addChild(tower);
resources -= cost;
updateResourceDisplay();
}
}
};
// Show main menu on startup
createMainMenu();
// Main game loop
game.update = function () {
if (gameState !== 'playing') {
return;
}
waveTimer++;
// Clean up destroyed enemies
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i].destroyed) {
enemies.splice(i, 1);
}
}
// Clean up destroyed projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
if (projectiles[i].destroyed) {
projectiles.splice(i, 1);
}
}
// Clean up destroyed potions
for (var i = potions.length - 1; i >= 0; i--) {
if (potions[i].destroyed) {
potions.splice(i, 1);
}
}
// Check if wave is complete and spawn next wave
if (enemies.length === 0 && waveTimer >= waveDelay) {
wave++;
// Episode progression logic
if (wave > 10 && episode === 1) {
episode = 2;
currentWorld = 'sun';
wave = 1;
game.setBackgroundColor(0xFFD700); // Golden sun background
// Update all Sun Shooter towers to be strong
for (var t = 0; t < towers.length; t++) {
if (towers[t].worldModifier !== undefined) {
if (towers[t].attachedAsset === 'sunShooter') {
towers[t].worldModifier = 1.5;
tween(towers[t], {
tint: 0xFFD700
}, {
duration: 1000
});
} else if (towers[t].attachedAsset === 'moonlightSleeper') {
towers[t].worldModifier = 0.7;
tween(towers[t], {
tint: 0x666666
}, {
duration: 1000
});
}
}
}
} else if (wave > 10 && episode === 2) {
episode = 3;
currentWorld = 'moon';
wave = 1;
game.setBackgroundColor(0x191970); // Dark blue moon background
// Update all Moonlight Sleeper towers to be strong
for (var t = 0; t < towers.length; t++) {
if (towers[t].worldModifier !== undefined) {
if (towers[t].attachedAsset === 'moonlightSleeper') {
towers[t].worldModifier = 1.5;
tween(towers[t], {
tint: 0x9370DB
}, {
duration: 1000
});
} else if (towers[t].attachedAsset === 'sunShooter') {
towers[t].worldModifier = 0.7;
tween(towers[t], {
tint: 0x666666
}, {
duration: 1000
});
}
}
}
} else if (wave > 10 && episode === 3) {
LK.showYouWin();
}
updateWaveDisplay();
waveTimer = 0;
spawnWave();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -433,8 +433,12 @@
stunEffect.x = self.x;
stunEffect.y = self.y;
game.addChild(stunEffect);
};
+ // Charm state variables
+ self.charmed = false;
+ self.charmTimer = 0;
+ self.originalSpeed = self.speed;
self.update = function () {
if (self.freezeTimer > 0) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
@@ -449,34 +453,156 @@
self.stunned = false;
graphics.tint = 0xFFFFFF;
}
}
+ // Handle charm timer - charmed enemies move backwards
+ if (self.charmed && self.charmTimer > 0) {
+ self.charmTimer--;
+ if (self.charmTimer <= 0) {
+ self.charmed = false;
+ self.speed = self.originalSpeed;
+ tween(graphics, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 500,
+ easing: tween.easeIn
+ });
+ }
+ }
if (!self.frozen && !self.stunned && self.pathIndex < pathPoints.length - 1) {
- var target = pathPoints[self.pathIndex + 1];
- var dx = target.x - self.x;
- var dy = target.y - self.y;
- var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance < 10) {
- self.pathIndex++;
- if (self.pathIndex >= pathPoints.length - 1) {
- lives--;
- updateLivesDisplay();
- if (lives <= 0) {
- LK.showGameOver();
+ var target;
+ // If charmed, move towards previous path point (backwards)
+ if (self.charmed && self.pathIndex > 0) {
+ target = pathPoints[self.pathIndex - 1];
+ var dx = target.x - self.x;
+ var dy = target.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 10) {
+ self.pathIndex--;
+ if (self.pathIndex <= 0) {
+ // If charmed enemy reaches start, remove it and give bonus resources
+ resources += self.reward * 2;
+ updateResourceDisplay();
+ self.destroyed = true;
+ self.destroy();
+ return;
}
- self.destroyed = true;
- self.destroy();
- return;
+ } else {
+ var angle = Math.atan2(dy, dx);
+ self.x += Math.cos(angle) * Math.abs(self.speed);
+ self.y += Math.sin(angle) * Math.abs(self.speed);
}
} else {
- var angle = Math.atan2(dy, dx);
- self.x += Math.cos(angle) * self.speed;
- self.y += Math.sin(angle) * self.speed;
+ // Normal forward movement
+ target = pathPoints[self.pathIndex + 1];
+ var dx = target.x - self.x;
+ var dy = target.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 10) {
+ self.pathIndex++;
+ if (self.pathIndex >= pathPoints.length - 1) {
+ lives--;
+ updateLivesDisplay();
+ if (lives <= 0) {
+ LK.showGameOver();
+ }
+ self.destroyed = true;
+ self.destroy();
+ return;
+ }
+ } else {
+ var angle = Math.atan2(dy, dx);
+ self.x += Math.cos(angle) * self.speed;
+ self.y += Math.sin(angle) * self.speed;
+ }
}
}
};
return self;
});
+var FakeEmdenGoose = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('emdenGoose', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ graphics.tint = 0xFFD700; // Golden tint to show it's fake
+ self.charmRange = 100;
+ self.lifetime = 600; // 10 seconds at 60fps
+ self.timer = 0;
+ self.charmedEnemies = [];
+ self.update = function () {
+ self.timer++;
+ // Pulsing effect to show it's fake
+ graphics.alpha = 0.7 + Math.sin(self.timer * 0.1) * 0.3;
+ graphics.rotation += 0.02;
+ // Find nearby real enemies to charm
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ if (!enemy.destroyed && self.charmedEnemies.indexOf(enemy) === -1) {
+ var dx = enemy.x - self.x;
+ var dy = enemy.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.charmRange) {
+ // Charm the enemy - make it move backwards on path
+ self.charmedEnemies.push(enemy);
+ enemy.charmed = true;
+ enemy.charmTimer = 300; // 5 seconds charm duration
+ enemy.originalSpeed = enemy.speed;
+ enemy.speed = -enemy.speed * 0.5; // Move backwards slower
+ // Visual charm effect
+ tween(enemy, {
+ tint: 0xFFB6C1
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ LK.effects.flashObject(enemy, 0xFFD700, 800);
+ }
+ }
+ }
+ // Remove charm from enemies over time
+ for (var j = self.charmedEnemies.length - 1; j >= 0; j--) {
+ var charmedEnemy = self.charmedEnemies[j];
+ if (charmedEnemy.destroyed || !charmedEnemy.charmed) {
+ self.charmedEnemies.splice(j, 1);
+ } else if (charmedEnemy.charmTimer <= 0) {
+ charmedEnemy.charmed = false;
+ charmedEnemy.speed = charmedEnemy.originalSpeed;
+ charmedEnemy.charmTimer = 0;
+ tween(charmedEnemy, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 500,
+ easing: tween.easeIn
+ });
+ self.charmedEnemies.splice(j, 1);
+ } else {
+ charmedEnemy.charmTimer--;
+ }
+ }
+ // Destroy fake goose after lifetime
+ if (self.timer >= self.lifetime) {
+ // Remove charm from all enemies when fake goose dies
+ for (var k = 0; k < self.charmedEnemies.length; k++) {
+ var enemy = self.charmedEnemies[k];
+ if (!enemy.destroyed) {
+ enemy.charmed = false;
+ enemy.speed = enemy.originalSpeed;
+ enemy.charmTimer = 0;
+ tween(enemy, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 500,
+ easing: tween.easeIn
+ });
+ }
+ }
+ self.destroy();
+ }
+ };
+ return self;
+});
var FireMagic = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
@@ -1580,8 +1706,96 @@
}
};
return self;
});
+var TreasureHoarderGoose = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('treasureHoarderGoose', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ graphics.tint = 0xFFD700; // Golden treasure color
+ self.range = 200;
+ self.fakeGooseRate = 480; // 8 seconds at 60fps
+ self.fakeGooseTimer = 0;
+ self.cost = 200;
+ self.disabled = false;
+ self.disableTimer = 0;
+ self.worldModifier = 1.0;
+ // Treasure collection ability - gains resources over time
+ self.treasureRate = 300; // 5 seconds at 60fps
+ self.treasureTimer = 0;
+ self.treasureAmount = 15;
+ self.update = function () {
+ // Handle disable timer
+ if (self.disableTimer > 0) {
+ self.disableTimer--;
+ if (self.disableTimer <= 0) {
+ self.disabled = false;
+ }
+ }
+ if (!self.disabled) {
+ self.fakeGooseTimer++;
+ self.treasureTimer++;
+ // Treasure hoarding - generate resources
+ if (self.treasureTimer >= self.treasureRate) {
+ resources += self.treasureAmount;
+ updateResourceDisplay();
+ // Treasure collection visual effect
+ tween(graphics, {
+ scaleX: 1.3,
+ scaleY: 1.3,
+ tint: 0x00FF00
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(graphics, {
+ scaleX: 1.0,
+ scaleY: 1.0,
+ tint: 0xFFD700
+ }, {
+ duration: 200,
+ easing: tween.easeIn
+ });
+ }
+ });
+ self.treasureTimer = 0;
+ }
+ // Create fake Emden goose to charm enemies
+ if (self.fakeGooseTimer >= self.fakeGooseRate) {
+ var nearestEnemy = findNearestEnemy(self.x, self.y, self.range);
+ if (nearestEnemy) {
+ var fakeGoose = new FakeEmdenGoose();
+ // Position fake goose strategically near enemy path
+ var targetPathPoint = pathPoints[Math.min(nearestEnemy.pathIndex + 1, pathPoints.length - 1)];
+ fakeGoose.x = targetPathPoint.x + (Math.random() - 0.5) * 120;
+ fakeGoose.y = targetPathPoint.y + (Math.random() - 0.5) * 120;
+ game.addChild(fakeGoose);
+ // Summoning visual effect
+ tween(graphics, {
+ rotation: graphics.rotation + Math.PI / 3
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(graphics, {
+ rotation: graphics.rotation
+ }, {
+ duration: 300,
+ easing: tween.easeIn
+ });
+ }
+ });
+ LK.effects.flashObject(self, 0xFFD700, 600);
+ LK.getSound('charm').play();
+ }
+ self.fakeGooseTimer = 0;
+ }
+ }
+ };
+ return self;
+});
/****
* Initialize Game
****/
@@ -1621,8 +1835,9 @@
var moonBtn;
var antiVirusBtn;
var pieShooterBtn;
var pyroCatalystBtn;
+var treasureHoarderBtn;
// Path points for enemies to follow
var pathPoints = [{
x: 0,
y: 400
@@ -1849,9 +2064,17 @@
});
pyroCatalystBtn.anchor.set(0.5, 0);
LK.gui.bottom.addChild(pyroCatalystBtn);
pyroCatalystBtn.y = -80;
- pyroCatalystBtn.x = 200;
+ pyroCatalystBtn.x = 150;
+ treasureHoarderBtn = new Text2('Treasure Hoarder (200)', {
+ size: 50,
+ fill: 0xFFD700
+ });
+ treasureHoarderBtn.anchor.set(0.5, 0);
+ LK.gui.bottom.addChild(treasureHoarderBtn);
+ treasureHoarderBtn.y = -20;
+ treasureHoarderBtn.x = 0;
// Button interactions
canadianBtn.down = function () {
selectedTowerType = 'canadian';
canadianBtn.fill = 0xFFD700;
@@ -1861,8 +2084,9 @@
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
pyroCatalystBtn.fill = 0xFF4500;
+ treasureHoarderBtn.fill = 0xFFD700;
};
pieShooterBtn.down = function () {
selectedTowerType = 'pieShooter';
pieShooterBtn.fill = 0xFFD700;
@@ -1938,9 +2162,22 @@
sunBtn.fill = 0xFFD700;
moonBtn.fill = 0x9370DB;
antiVirusBtn.fill = 0x00FF00;
pieShooterBtn.fill = 0xFFB6C1;
+ treasureHoarderBtn.fill = 0xFFD700;
};
+ treasureHoarderBtn.down = function () {
+ selectedTowerType = 'treasureHoarder';
+ treasureHoarderBtn.fill = 0x00FF00;
+ canadianBtn.fill = 0x8B4513;
+ iceBtn.fill = 0x87CEEB;
+ hammerBtn.fill = 0x9932CC;
+ sunBtn.fill = 0xFFD700;
+ moonBtn.fill = 0x9370DB;
+ antiVirusBtn.fill = 0x00FF00;
+ pieShooterBtn.fill = 0xFFB6C1;
+ pyroCatalystBtn.fill = 0xFF4500;
+ };
// Initialize first wave
spawnWave();
}
// Helper functions
@@ -2076,8 +2313,11 @@
cost = tower.cost;
} else if (selectedTowerType === 'pyroCatalyst') {
tower = new PyroCatalystGoose();
cost = tower.cost;
+ } else if (selectedTowerType === 'treasureHoarder') {
+ tower = new TreasureHoarderGoose();
+ cost = tower.cost;
}
if (tower && resources >= cost) {
tower.x = x;
tower.y = y;
Canadian Goose in robe with sword. In-Game asset. 2d. High contrast. No shadows
Emden Goose in Outfit of Treasure Hoarders. In-Game asset. 2d. High contrast. No shadows
A Canadian Goose in Magic Ice Mage Outfit armed with a magic ice staff. In-Game asset. 2d. High contrast. No shadows
Emden Goose in Cyan Outfit of Treasure Hoarders armed with cyan anemo potion. In-Game asset. 2d. High contrast. No shadows
Ice magic effect. In-Game asset. 2d. High contrast. No shadows
A emden goose in blue treasure hoarders outfit with blue hydro battle bow. In-Game asset. 2d. High contrast. No shadows
Treasure with canadian geese as guard No text on image!!. In-Game asset. 2d. High contrast. No shadows
A Canadian goose in armor armed electro purple battle hammer.. In-Game asset. 2d. No shadows
A Canadian Goose in Moon Mage Outfit with Moonlight Magic Staff. In-Game asset. 2d. High contrast. No shadows
Canadian Goose in Sun Warrior Outfit with Magic Sun Crossbow. In-Game asset. 2d. High contrast. No shadows
An Emden Goose in Blue Sun Treasure Hoarder Outfit with Blue Sun Long Sword. In-Game asset. 2d. High contrast. No shadows
A Emden Goose in Treasure Hoarder Red Moon Mage Outfit with Red Moon Magic Staff. In-Game asset. 2d. High contrast. No shadows
Purple Stun Aura, No text on image!. In-Game asset. 2d. High contrast. No shadows
A Canadian Goose in Green Glowing Anti Virus Outfit Armed with anti virus magic. In-Game asset. 2d
A Canadian Goose in maid chef outfit armed with spoon with tangerine pie on it. In-Game asset. 2d. High contrast. No shadows
Cherry pie with pink fire aura. In-Game asset. 2d. High contrast. No shadows
apple pie with green aura. In-Game asset. 2d. High contrast. No shadows
blueberry pie with frost aura. In-Game asset. 2d. High contrast. No shadows
A Canadian Goose in Pyro Mage outfit holding a pyro catalyst. In-Game asset. 2d. High contrast. No shadows
Canadian Goose in treasure hoarder outfit with claymore. In-Game asset. 2d. High contrast. No shadows