User prompt
que el boss cat tenga su propio sprite
User prompt
qutar casa
User prompt
que esten en una casa
User prompt
poner un gato summoner que cada 15 segundos ponga 5 gatos rapidos zombies i que tengan su propio sprite ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
quitar eso
User prompt
al summonear una nueva que se te quede permanente mente pero que cueste queso
User prompt
que los zombies al chocarse que le quita vida a los gatos y a ellos
User prompt
que los zombies vayan por el camino de ños gatos
User prompt
que sea posible obtener el summoner rat
User prompt
que las ratas zombies vayan al reves que los gatos
User prompt
que sea posible obtener el summoner rat
User prompt
que el summoner sea rara
User prompt
pon un summoner rat que hacer que invoca ratas zombies que defienden el queso y que tengan su propio sprite
User prompt
que el bomberRat tenga su propio sprite
User prompt
pon una nueva rata
User prompt
put a rat bomber
User prompt
poner una tercera torre
User prompt
hazer el camino de los gatos mas visible
User prompt
Rareza epica
User prompt
Nueva torre rata grande
User prompt
Pon una rata grande que se desbloquea en el summon
User prompt
Pon una rata grande
User prompt
Poner más tipos de ratas
User prompt
Poner menos ratas
User prompt
Poner más ratas
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 25;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distanceSquared = dx * dx + dy * dy;
var speedSquared = self.speed * self.speed;
if (distanceSquared < speedSquared) {
self.x = self.targetX;
self.y = self.targetY;
self.reachedTarget = true;
} else {
var distance = Math.sqrt(distanceSquared);
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var Cat = Container.expand(function () {
var self = Container.call(this);
self.catType = 'basic';
self.health = 50;
self.maxHealth = 50;
self.speed = 1;
self.pathIndex = 0;
self.cheeseValue = 10;
var graphics = self.attachAsset('catBasic', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
self.healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50
});
// Health bar foreground
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50
});
self.update = function () {
if (self.pathIndex < gamePath.length) {
var targetTile = gamePath[self.pathIndex];
var dx = targetTile.x - self.x;
var dy = targetTile.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < 25) {
// 5 * 5 = 25
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
self.reachedCheese = true;
}
} else {
var distance = Math.sqrt(distanceSquared);
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.isDead = true;
LK.effects.flashObject(self, 0xFF0000, 200);
} else {
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent;
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00; // Yellow
} else {
self.healthBar.tint = 0xFF0000; // Red
}
}
};
return self;
});
var FastCat = Cat.expand(function () {
var self = Cat.call(this);
self.catType = 'fast';
self.health = 30;
self.maxHealth = 30;
self.speed = 2;
self.cheeseValue = 15;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('catFast', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var FastCatBoss = FastCat.expand(function () {
var self = FastCat.call(this);
self.catType = 'fastboss';
self.health = 120;
self.maxHealth = 120;
self.speed = 1.5;
self.cheeseValue = 75;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('catFast', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8
});
graphics.tint = 0x4B0082; // Indigo tint for fast boss
return self;
});
var CatBoss = Cat.expand(function () {
var self = Cat.call(this);
self.catType = 'boss';
self.health = 200;
self.maxHealth = 200;
self.speed = 0.5;
self.cheeseValue = 50;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('catBasic', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
graphics.tint = 0x8B0000; // Dark red tint for boss
return self;
});
var CollectedUnitSlot = Container.expand(function (collectedUnit, index) {
var self = Container.call(this);
self.collectedUnit = collectedUnit;
self.isSelected = false;
var slotGraphics = self.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5
});
slotGraphics.tint = collectedUnit.color;
slotGraphics.scaleX = 0.8;
slotGraphics.scaleY = 0.8;
// Add unit preview
var ratAsset = collectedUnit.type === 'archer' || collectedUnit.type === 'sniper' ? 'ratArcher' : collectedUnit.type === 'bomber' ? 'ratBomber' : collectedUnit.type === 'summoner' ? 'ratSummoner' : 'ratWarrior';
var ratPreview = self.attachAsset(ratAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: collectedUnit.type === 'tower' ? 1.2 : collectedUnit.type === 'mega' ? 1.0 : collectedUnit.type === 'giant' ? 0.8 : collectedUnit.type === 'electric' ? 0.6 : collectedUnit.type === 'shadow' ? 0.55 : collectedUnit.type === 'summoner' ? 0.65 : 0.5,
scaleY: collectedUnit.type === 'tower' ? 1.2 : collectedUnit.type === 'mega' ? 1.0 : collectedUnit.type === 'giant' ? 0.8 : collectedUnit.type === 'electric' ? 0.6 : collectedUnit.type === 'shadow' ? 0.55 : collectedUnit.type === 'summoner' ? 0.65 : 0.5,
y: -10
});
// Apply type-specific tints
if (collectedUnit.type === 'magic') {
ratPreview.tint = 0x9932CC; // Purple
} else if (collectedUnit.type === 'sniper') {
ratPreview.tint = 0x8B4513; // Brown
} else if (collectedUnit.type === 'bomber') {
ratPreview.tint = 0xFF6347; // Red-orange
} else if (collectedUnit.type === 'healer') {
ratPreview.tint = 0x00FF7F; // Spring green
} else if (collectedUnit.type === 'giant') {
ratPreview.tint = 0x8B0000; // Dark red
} else if (collectedUnit.type === 'mega') {
ratPreview.tint = 0x4B0082; // Indigo
} else if (collectedUnit.type === 'tower') {
ratPreview.tint = 0x2F4F4F; // Dark slate gray
} else if (collectedUnit.type === 'electric') {
ratPreview.tint = 0x00FFFF; // Cyan
} else if (collectedUnit.type === 'shadow') {
ratPreview.tint = 0x4B0082; // Dark purple
ratPreview.alpha = 0.7; // Semi-transparent
} else if (collectedUnit.type === 'summoner') {
ratPreview.tint = 0x4B0082; // Dark purple
}
// Add rarity text
var rarityText = new Text2(collectedUnit.rarity.charAt(0).toUpperCase(), {
size: 20,
fill: '#FFFFFF'
});
rarityText.anchor.set(0.5, 0.5);
rarityText.y = 25;
self.addChild(rarityText);
self.setSelected = function (selected) {
self.isSelected = selected;
slotGraphics.alpha = selected ? 0.8 : 1.0;
if (selected) {
slotGraphics.scaleX = 0.9;
slotGraphics.scaleY = 0.9;
} else {
slotGraphics.scaleX = 0.8;
slotGraphics.scaleY = 0.8;
}
};
self.down = function (x, y, obj) {
if (gameStarted && !upgradeMode) {
selectedCollectedUnit = self.collectedUnit;
selectedRatType = null; // Deselect basic rat types
// Update all inventory slots selection
for (var i = 0; i < inventorySlots.length; i++) {
inventorySlots[i].setSelected(false);
}
// Update all collected unit slots selection
updateCollectedUnitsDisplay();
}
};
return self;
});
var InventorySlot = Container.expand(function (ratType, cost) {
var self = Container.call(this);
self.ratType = ratType;
self.cost = cost;
self.isSelected = false;
var slotGraphics = self.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5
});
// Add rat preview
var ratAsset = ratType === 'warrior' ? 'ratWarrior' : 'ratArcher';
var ratPreview = self.attachAsset(ratAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
y: -15
});
// Add cost text
var costText = new Text2(cost.toString(), {
size: 25,
fill: '#FFD700'
});
costText.anchor.set(0.5, 0.5);
costText.y = 35;
self.addChild(costText);
// Add type label
var typeText = new Text2(ratType.toUpperCase(), {
size: 20,
fill: '#FFFFFF'
});
typeText.anchor.set(0.5, 0.5);
typeText.y = -45;
self.addChild(typeText);
self.setSelected = function (selected) {
self.isSelected = selected;
slotGraphics.tint = selected ? 0x00FF00 : 0xFFFFFF;
slotGraphics.alpha = selected ? 0.8 : 1.0;
};
self.canAfford = function () {
return cheesePoints >= self.cost;
};
self.updateDisplay = function () {
var affordable = self.canAfford();
ratPreview.alpha = affordable ? 1.0 : 0.5;
costText.tint = affordable ? 0xFFD700 : 0xFF0000;
};
self.down = function (x, y, obj) {
if (gameStarted && !upgradeMode) {
selectedRatType = self.ratType;
selectedCollectedUnit = null; // Deselect collected units
// Update all inventory slots selection
for (var i = 0; i < inventorySlots.length; i++) {
inventorySlots[i].setSelected(inventorySlots[i].ratType === selectedRatType);
}
// Update collected unit slots to deselect them
updateCollectedUnitsDisplay();
updateUI();
}
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Menu background
var menuBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0,
scaleX: 34,
scaleY: 91,
x: 0,
y: 0
});
menuBg.alpha = 0.8;
self.addChild(menuBg);
// Game title
var titleText = new Text2('RAT DEFENSE', {
size: 120,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
self.addChild(titleText);
// Subtitle
var subtitleText = new Text2('Defend Your Cheese!', {
size: 60,
fill: '#FFFFFF'
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 950;
self.addChild(subtitleText);
// Start button
var startButton = new Text2('START GAME', {
size: 80,
fill: '#00FF00'
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 1024;
startButton.y = 1400;
self.addChild(startButton);
// Instructions
var instructionsText = new Text2('Place rats to defend against cats\nUpgrade your rats for better defense', {
size: 45,
fill: '#CCCCCC'
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1600;
self.addChild(instructionsText);
startButton.down = function () {
self.destroy();
gameStarted = true;
initializeGame();
};
return self;
});
var Rat = Container.expand(function () {
var self = Container.call(this);
self.ratType = 'warrior';
self.range = 150;
self.damage = 25;
self.fireRate = 60;
self.lastShot = 0;
self.cost = 50;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (LK.ticks - self.lastShot > self.fireRate) {
var target = self.findTarget();
if (target) {
self.shoot(target);
self.lastShot = LK.ticks;
}
}
};
self.findTarget = function () {
var closestCat = null;
var closestDistanceSquared = Infinity;
var rangeSquared = self.range * self.range;
for (var i = 0; i < cats.length; i++) {
var cat = cats[i];
var dx = cat.x - self.x;
var dy = cat.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared <= rangeSquared && distanceSquared < closestDistanceSquared) {
closestDistanceSquared = distanceSquared;
closestCat = cat;
}
}
return closestCat;
};
self.shoot = function (target) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.upgrade = function () {
if (self.upgradeLevel < self.maxUpgrades) {
self.upgradeLevel++;
// Increase damage by 50% per upgrade
self.damage = Math.floor(self.damage * 1.5);
// Increase range by 25% per upgrade
self.range = Math.floor(self.range * 1.25);
// Visual indicator of upgrade
self.children[0].tint = self.upgradeLevel === 1 ? 0x00FF00 : self.upgradeLevel === 2 ? 0x0000FF : 0xFF00FF;
self.children[0].scaleX = 1 + self.upgradeLevel * 0.2;
self.children[0].scaleY = 1 + self.upgradeLevel * 0.2;
// Update range indicator if visible
self.updateRangeIndicator();
// Add upgrade level stars
self.showUpgradeStars();
return true;
}
return false;
};
self.getUpgradeCost = function () {
return (self.upgradeLevel + 1) * self.cost;
};
self.canUpgrade = function () {
return self.upgradeLevel < self.maxUpgrades;
};
self.showRangeIndicator = function () {
if (!self.rangeIndicator) {
self.rangeIndicator = LK.getAsset('rangeIndicator', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.range / 2,
scaleY: self.range / 2,
x: self.x,
y: self.y
});
self.rangeIndicator.alpha = 0.3;
game.addChild(self.rangeIndicator);
}
};
self.hideRangeIndicator = function () {
if (self.rangeIndicator) {
self.rangeIndicator.destroy();
self.rangeIndicator = null;
}
};
self.updateRangeIndicator = function () {
if (self.rangeIndicator) {
self.rangeIndicator.scaleX = self.range / 2;
self.rangeIndicator.scaleY = self.range / 2;
self.rangeIndicator.x = self.x;
self.rangeIndicator.y = self.y;
}
};
self.showUpgradeStars = function () {
// Remove existing stars
if (self.upgradeStars) {
for (var i = 0; i < self.upgradeStars.length; i++) {
self.upgradeStars[i].destroy();
}
}
self.upgradeStars = [];
// Add stars based on upgrade level
for (var i = 0; i < self.upgradeLevel; i++) {
var star = new Text2('★', {
size: 25,
fill: '#FFD700'
});
star.anchor.set(0.5, 0.5);
star.x = self.x - 30 + i * 20;
star.y = self.y - 60;
self.upgradeStars.push(star);
game.addChild(star);
}
};
return self;
});
var ZombieRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'zombie';
self.range = 100;
self.damage = 15;
self.fireRate = 50;
self.cost = 0; // Summoned, not bought
self.upgradeLevel = 0;
self.maxUpgrades = 0; // Cannot be upgraded
self.health = 75;
self.maxHealth = 75;
self.lifespan = 1800; // 30 seconds at 60fps
self.timeAlive = 0;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratZombie', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x8B4513; // Brown tint for zombie
graphics.alpha = 0.8; // Slightly transparent
// Add health bar for zombie rat
self.healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50,
scaleX: 1.0,
scaleY: 0.8
});
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50,
scaleX: 1.0,
scaleY: 0.8
});
// Override update to handle lifespan and movement
var originalUpdate = self.update;
self.pathIndex = gamePath.length - 1; // Start from the end of the path
self.lastX = self.x;
self.lastY = self.y;
self.update = function () {
// Move along the path in reverse direction (towards cats)
if (self.pathIndex >= 0) {
var targetTile = gamePath[self.pathIndex];
var dx = targetTile.x - self.x;
var dy = targetTile.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < 25) {
// Reached current path point, move to previous one
self.pathIndex--;
if (self.pathIndex < 0) {
// Reached start of path, stay there
self.pathIndex = 0;
}
} else {
var distance = Math.sqrt(distanceSquared);
var moveSpeed = 1.5;
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
}
originalUpdate.call(self);
self.timeAlive++;
if (self.timeAlive >= self.lifespan) {
self.isDead = true;
LK.effects.flashObject(self, 0x654321, 300);
}
};
// Zombie rat can take damage from cats
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.isDead = true;
LK.effects.flashObject(self, 0xFF0000, 300);
} else {
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent * 1.0;
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00; // Yellow
} else {
self.healthBar.tint = 0xFF0000; // Red
}
}
};
return self;
});
var TowerRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'tower';
self.range = 500;
self.damage = 300;
self.fireRate = 180;
self.cost = 750;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.health = 500;
self.maxHealth = 500;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.5,
scaleY: 4.5
});
graphics.tint = 0x2F4F4F; // Dark slate gray tint for tower rat
// Add health bar for tower rat
self.healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -150,
scaleX: 3.0,
scaleY: 2.5
});
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -150,
scaleX: 3.0,
scaleY: 2.5
});
// Tower rat can take damage from cats
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.isDead = true;
LK.effects.flashObject(self, 0xFF0000, 750);
} else {
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent * 3.0;
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00; // Yellow
} else {
self.healthBar.tint = 0xFF0000; // Red
}
}
};
return self;
});
var SummonerRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'summoner';
self.range = 200;
self.damage = 20;
self.fireRate = 120;
self.cost = 300;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.summonCooldown = 600; // 10 seconds
self.lastSummon = 0;
self.maxZombies = 2;
self.zombiesCount = 0;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratSummoner', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x4B0082; // Dark purple tint for summoner
// Override update to handle summoning
var originalUpdate = self.update;
self.update = function () {
originalUpdate.call(self);
// Count current zombies
self.zombiesCount = 0;
for (var i = 0; i < rats.length; i++) {
if (rats[i].ratType === 'zombie') {
self.zombiesCount++;
}
}
// Summon zombie if cooldown is ready and we need more
if (LK.ticks - self.lastSummon > self.summonCooldown && self.zombiesCount < self.maxZombies) {
// Find empty placement tile near cheese
var cheeseX = gamePath[gamePath.length - 1].x;
var cheeseY = gamePath[gamePath.length - 1].y;
var bestTile = null;
var bestDistance = Infinity;
for (var j = 0; j < placementTiles.length; j++) {
var tile = placementTiles[j];
var dx = cheeseX - tile.x;
var dy = cheeseY - tile.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Check if tile is free
var tileOccupied = false;
for (var k = 0; k < rats.length; k++) {
var ratDx = rats[k].x - tile.x;
var ratDy = rats[k].y - tile.y;
if (ratDx * ratDx + ratDy * ratDy < 50 * 50) {
tileOccupied = true;
break;
}
}
if (!tileOccupied && distance < bestDistance) {
bestDistance = distance;
bestTile = tile;
}
}
if (bestTile) {
// Summon zombie rat
var zombie = new ZombieRat();
zombie.x = bestTile.x;
zombie.y = bestTile.y;
rats.push(zombie);
game.addChild(zombie);
// Update placement indicator for this tile
for (var k = 0; k < placementTiles.length; k++) {
if (placementTiles[k].x === bestTile.x && placementTiles[k].y === bestTile.y) {
placementIndicators[k].tint = 0xFF6347; // Red tint to show occupied
placementIndicators[k].alpha = 0.2; // Make it more transparent
break;
}
}
// Visual summoning effect
LK.effects.flashObject(self, 0x9932CC, 500);
LK.effects.flashObject(zombie, 0x00FF00, 700);
self.lastSummon = LK.ticks;
}
}
};
return self;
});
var ShadowRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'shadow';
self.range = 180;
self.damage = 60;
self.fireRate = 75;
self.cost = 175;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.teleportCooldown = 300; // 5 seconds
self.lastTeleport = 0;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
graphics.tint = 0x4B0082; // Dark purple tint for shadow
graphics.alpha = 0.7; // Semi-transparent for stealth effect
// Override findTarget to prioritize high-value targets
self.findTarget = function () {
var bestTarget = null;
var bestScore = 0;
var rangeSquared = self.range * self.range;
for (var i = 0; i < cats.length; i++) {
var cat = cats[i];
var dx = cat.x - self.x;
var dy = cat.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared <= rangeSquared) {
// Score based on health and cheese value
var score = cat.health + cat.cheeseValue * 2;
if (score > bestScore) {
bestScore = score;
bestTarget = cat;
}
}
}
return bestTarget;
};
// Override shoot to include teleportation ability
self.shoot = function (target) {
// Normal attack
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Teleport ability on cooldown
if (LK.ticks - self.lastTeleport > self.teleportCooldown) {
var teleportTargets = [];
for (var i = 0; i < cats.length; i++) {
var cat = cats[i];
var dx = cat.x - self.x;
var dy = cat.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.range && distance < self.range * 2) {
teleportTargets.push(cat);
}
}
if (teleportTargets.length > 0) {
// Teleport to attack distant target
var teleportTarget = teleportTargets[Math.floor(Math.random() * teleportTargets.length)];
// Find nearest placement tile to target
var nearestTile = null;
var nearestDistance = Infinity;
for (var j = 0; j < placementTiles.length; j++) {
var tile = placementTiles[j];
var tileDx = teleportTarget.x - tile.x;
var tileDy = teleportTarget.y - tile.y;
var tileDistance = Math.sqrt(tileDx * tileDx + tileDy * tileDy);
// Check if tile is free
var tileOccupied = false;
for (var k = 0; k < rats.length; k++) {
if (rats[k] !== self) {
var ratDx = rats[k].x - tile.x;
var ratDy = rats[k].y - tile.y;
if (ratDx * ratDx + ratDy * ratDy < 50 * 50) {
tileOccupied = true;
break;
}
}
}
if (!tileOccupied && tileDistance < nearestDistance) {
nearestDistance = tileDistance;
nearestTile = tile;
}
}
if (nearestTile) {
// Teleportation effect
LK.effects.flashObject(self, 0x9932CC, 300);
// Update old tile indicator
for (var k = 0; k < placementTiles.length; k++) {
var tile = placementTiles[k];
var dx = self.x - tile.x;
var dy = self.y - tile.y;
if (dx * dx + dy * dy < 50 * 50) {
placementIndicators[k].tint = 0x90EE90;
placementIndicators[k].alpha = 0.6;
break;
}
}
// Teleport to new position
self.x = nearestTile.x;
self.y = nearestTile.y;
// Update new tile indicator
for (var k = 0; k < placementTiles.length; k++) {
var tile = placementTiles[k];
if (tile.x === nearestTile.x && tile.y === nearestTile.y) {
placementIndicators[k].tint = 0xFF6347;
placementIndicators[k].alpha = 0.2;
break;
}
}
self.lastTeleport = LK.ticks;
LK.effects.flashObject(self, 0x4B0082, 500);
}
}
}
};
return self;
});
var MegaRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'mega';
self.range = 400;
self.damage = 200;
self.fireRate = 120;
self.cost = 500;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.health = 300;
self.maxHealth = 300;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 3.5
});
graphics.tint = 0x4B0082; // Indigo tint for mega rat
// Add health bar for mega rat
self.healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -120,
scaleX: 2.0,
scaleY: 2.0
});
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -120,
scaleX: 2.0,
scaleY: 2.0
});
// Mega rat can take damage from cats
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.isDead = true;
LK.effects.flashObject(self, 0xFF0000, 500);
} else {
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent * 2.0;
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00; // Yellow
} else {
self.healthBar.tint = 0xFF0000; // Red
}
}
};
return self;
});
var MagicRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'magic';
self.range = 180;
self.damage = 35;
self.fireRate = 75;
self.cost = 100;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x9932CC; // Purple tint for magic
return self;
});
var HealerRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'healer';
self.range = 200;
self.damage = 0;
self.fireRate = 180;
self.cost = 80;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.healAmount = 25;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x00FF7F; // Spring green tint for healer
// Override findTarget to find damaged rats instead of cats
self.findTarget = function () {
var mostDamagedRat = null;
var lowestHealthPercent = 1.0;
var rangeSquared = self.range * self.range;
for (var i = 0; i < rats.length; i++) {
var rat = rats[i];
if (rat === self) continue; // Don't heal self
var dx = rat.x - self.x;
var dy = rat.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared <= rangeSquared && rat.health && rat.maxHealth) {
var healthPercent = rat.health / rat.maxHealth;
if (healthPercent < lowestHealthPercent && healthPercent < 1.0) {
lowestHealthPercent = healthPercent;
mostDamagedRat = rat;
}
}
}
return mostDamagedRat;
};
// Override shoot to heal instead of damage
self.shoot = function (target) {
if (target.health && target.maxHealth) {
target.health = Math.min(target.maxHealth, target.health + self.healAmount);
// Visual healing effect
LK.effects.flashObject(target, 0x00FF00, 300);
}
};
return self;
});
var GiantRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'giant';
self.range = 300;
self.damage = 100;
self.fireRate = 150;
self.cost = 250;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.health = 150;
self.maxHealth = 150;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
graphics.tint = 0x8B0000; // Dark red tint for giant
// Add health bar for giant rat
self.healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80,
scaleX: 1.5,
scaleY: 1.5
});
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80,
scaleX: 1.5,
scaleY: 1.5
});
// Giant rat can take damage from cats
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.isDead = true;
LK.effects.flashObject(self, 0xFF0000, 500);
} else {
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent * 1.5;
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00; // Yellow
} else {
self.healthBar.tint = 0xFF0000; // Red
}
}
};
return self;
});
var ElectricRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'electric';
self.range = 250;
self.damage = 40;
self.fireRate = 90;
self.cost = 200;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratWarrior', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
graphics.tint = 0x00FFFF; // Cyan tint for electric
// Override shoot to create chain lightning
self.shoot = function (target) {
var chainTargets = [target];
var chainRange = 100;
var maxChains = 3;
// Find additional targets for chain lightning
for (var chain = 0; chain < maxChains; chain++) {
var lastTarget = chainTargets[chainTargets.length - 1];
var closestCat = null;
var closestDistanceSquared = Infinity;
var chainRangeSquared = chainRange * chainRange;
for (var i = 0; i < cats.length; i++) {
var cat = cats[i];
if (chainTargets.indexOf(cat) === -1) {
// Not already targeted
var dx = cat.x - lastTarget.x;
var dy = cat.y - lastTarget.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared <= chainRangeSquared && distanceSquared < closestDistanceSquared) {
closestDistanceSquared = distanceSquared;
closestCat = cat;
}
}
}
if (closestCat) {
chainTargets.push(closestCat);
} else {
break;
}
}
// Damage all targets in chain
for (var i = 0; i < chainTargets.length; i++) {
var damage = Math.floor(self.damage * (0.8 + 0.2 * (4 - i) / 4)); // Damage decreases per chain
chainTargets[i].takeDamage(damage);
LK.effects.flashObject(chainTargets[i], 0x00FFFF, 200);
}
// Visual lightning effect
LK.effects.flashScreen(0x00FFFF, 150);
LK.getSound('shoot').play();
};
return self;
});
var BomberRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'bomber';
self.range = 120;
self.damage = 15;
self.fireRate = 90;
self.cost = 125;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratBomber', {
anchorX: 0.5,
anchorY: 0.5
});
// Override shoot to create splash damage
self.shoot = function (target) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
bullet.isSplash = true; // Mark as splash damage bullet
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
return self;
});
var ArcherRat = Rat.expand(function () {
var self = Rat.call(this);
self.ratType = 'archer';
self.range = 220;
self.damage = 20;
self.fireRate = 45;
self.cost = 75;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratArcher', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var SniperRat = ArcherRat.expand(function () {
var self = ArcherRat.call(this);
self.ratType = 'sniper';
self.range = 350;
self.damage = 50;
self.fireRate = 120;
self.cost = 150;
self.upgradeLevel = 0;
self.maxUpgrades = 3;
self.removeChild(self.children[0]);
var graphics = self.attachAsset('ratArcher', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x8B4513; // Brown tint for sniper
return self;
});
var RollScreen = Container.expand(function () {
var self = Container.call(this);
// Background overlay
var overlay = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0,
scaleX: 34,
scaleY: 91,
x: 0,
y: 0
});
overlay.alpha = 0.9;
overlay.tint = 0x000033;
self.addChild(overlay);
// Title
var titleText = new Text2('SUMMON UNITS', {
size: 100,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
self.addChild(titleText);
// Roll result area
var resultContainer = new Container();
resultContainer.x = 1024;
resultContainer.y = 1000;
self.addChild(resultContainer);
// Single roll button
var singleRollButton = new Text2('SINGLE ROLL (25 Cheese)', {
size: 60,
fill: '#00FF00'
});
singleRollButton.anchor.set(0.5, 0.5);
singleRollButton.x = 512;
singleRollButton.y = 1600;
self.addChild(singleRollButton);
// Multi roll button
var multiRollButton = new Text2('MULTI ROLL x5 (100 Cheese)', {
size: 60,
fill: '#0080FF'
});
multiRollButton.anchor.set(0.5, 0.5);
multiRollButton.x = 1536;
multiRollButton.y = 1600;
self.addChild(multiRollButton);
// Close button
var closeButton = new Text2('CLOSE', {
size: 50,
fill: '#FF4444'
});
closeButton.anchor.set(0.5, 0.5);
closeButton.x = 1024;
closeButton.y = 2200;
self.addChild(closeButton);
// Roll rarities and chances
var rollTable = [{
type: 'warrior',
rarity: 'common',
chance: 0.3,
color: 0xCCCCCC
}, {
type: 'archer',
rarity: 'common',
chance: 0.17,
color: 0xCCCCCC
}, {
type: 'magic',
rarity: 'common',
chance: 0.10,
color: 0xCCCCCC
}, {
type: 'summoner',
rarity: 'common',
chance: 0.12,
color: 0xCCCCCC
}, {
type: 'bomber',
rarity: 'common',
chance: 0.11,
color: 0xCCCCCC
}, {
type: 'warrior',
rarity: 'rare',
chance: 0.08,
color: 0x0080FF
}, {
type: 'archer',
rarity: 'rare',
chance: 0.06,
color: 0x0080FF
}, {
type: 'magic',
rarity: 'rare',
chance: 0.05,
color: 0x0080FF
}, {
type: 'bomber',
rarity: 'rare',
chance: 0.04,
color: 0x0080FF
}, {
type: 'healer',
rarity: 'rare',
chance: 0.03,
color: 0x0080FF
}, {
type: 'warrior',
rarity: 'epic',
chance: 0.025,
color: 0x9C27B0
}, {
type: 'archer',
rarity: 'epic',
chance: 0.02,
color: 0x9C27B0
}, {
type: 'magic',
rarity: 'epic',
chance: 0.015,
color: 0x9C27B0
}, {
type: 'bomber',
rarity: 'epic',
chance: 0.012,
color: 0x9C27B0
}, {
type: 'healer',
rarity: 'epic',
chance: 0.01,
color: 0x9C27B0
}, {
type: 'sniper',
rarity: 'epic',
chance: 0.008,
color: 0x9C27B0
}, {
type: 'electric',
rarity: 'epic',
chance: 0.006,
color: 0x9C27B0
}, {
type: 'shadow',
rarity: 'epic',
chance: 0.004,
color: 0x9C27B0
}, {
type: 'summoner',
rarity: 'rare',
chance: 0.055,
color: 0x0080FF
}, {
type: 'warrior',
rarity: 'legendary',
chance: 0.015,
color: 0xFF8000
}, {
type: 'archer',
rarity: 'legendary',
chance: 0.01,
color: 0xFF8000
}, {
type: 'sniper',
rarity: 'legendary',
chance: 0.008,
color: 0xFF8000
}, {
type: 'magic',
rarity: 'legendary',
chance: 0.005,
color: 0xFF8000
}, {
type: 'bomber',
rarity: 'legendary',
chance: 0.003,
color: 0xFF8000
}, {
type: 'healer',
rarity: 'legendary',
chance: 0.002,
color: 0xFF8000
}, {
type: 'giant',
rarity: 'legendary',
chance: 0.001,
color: 0xFF8000
}, {
type: 'mega',
rarity: 'legendary',
chance: 0.0005,
color: 0xFF8000
}, {
type: 'tower',
rarity: 'legendary',
chance: 0.0002,
color: 0xFF8000
}];
self.performRoll = function () {
var random = Math.random();
var cumulative = 0;
for (var i = 0; i < rollTable.length; i++) {
cumulative += rollTable[i].chance;
if (random <= cumulative) {
return rollTable[i];
}
}
return rollTable[0]; // Fallback to common warrior
};
self.showRollResult = function (results) {
// Clear previous results
while (resultContainer.children.length > 0) {
resultContainer.removeChild(resultContainer.children[0]);
}
for (var i = 0; i < results.length; i++) {
var result = results[i];
var resultCard = new Container();
// Card background
var cardBg = LK.getAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5
});
cardBg.tint = result.color;
cardBg.scaleX = 1.5;
cardBg.scaleY = 1.5;
resultCard.addChild(cardBg);
// Unit preview
var unitAsset = result.type === 'archer' || result.type === 'sniper' ? 'ratArcher' : result.type === 'bomber' ? 'ratBomber' : result.type === 'summoner' ? 'ratSummoner' : 'ratWarrior';
var unitPreview = LK.getAsset(unitAsset, {
anchorX: 0.5,
anchorY: 0.5,
y: -20,
scaleX: result.type === 'tower' ? 2.5 : result.type === 'mega' ? 2.0 : result.type === 'giant' ? 1.5 : result.type === 'electric' ? 1.2 : result.type === 'shadow' ? 1.1 : result.type === 'summoner' ? 1.3 : 1.0,
scaleY: result.type === 'tower' ? 2.5 : result.type === 'mega' ? 2.0 : result.type === 'giant' ? 1.5 : result.type === 'electric' ? 1.2 : result.type === 'shadow' ? 1.1 : result.type === 'summoner' ? 1.3 : 1.0
});
// Apply type-specific tints
if (result.type === 'magic') {
unitPreview.tint = 0x9932CC; // Purple
} else if (result.type === 'sniper') {
unitPreview.tint = 0x8B4513; // Brown
} else if (result.type === 'bomber') {
unitPreview.tint = 0xFF6347; // Red-orange
} else if (result.type === 'healer') {
unitPreview.tint = 0x00FF7F; // Spring green
} else if (result.type === 'giant') {
unitPreview.tint = 0x8B0000; // Dark red
} else if (result.type === 'mega') {
unitPreview.tint = 0x4B0082; // Indigo
} else if (result.type === 'tower') {
unitPreview.tint = 0x2F4F4F; // Dark slate gray
} else if (result.type === 'electric') {
unitPreview.tint = 0x00FFFF; // Cyan
} else if (result.type === 'shadow') {
unitPreview.tint = 0x4B0082; // Dark purple
unitPreview.alpha = 0.7; // Semi-transparent
} else if (result.type === 'summoner') {
unitPreview.tint = 0x4B0082; // Dark purple
}
resultCard.addChild(unitPreview);
// Rarity text
var rarityText = new Text2(result.rarity.toUpperCase(), {
size: 25,
fill: '#FFFFFF'
});
rarityText.anchor.set(0.5, 0.5);
rarityText.y = 60;
resultCard.addChild(rarityText);
// Type text
var typeText = new Text2(result.type.toUpperCase(), {
size: 20,
fill: '#FFFFFF'
});
typeText.anchor.set(0.5, 0.5);
typeText.y = 85;
resultCard.addChild(typeText);
// Position cards
if (results.length === 1) {
resultCard.x = 0;
} else {
resultCard.x = (i - 2) * 200;
}
resultCard.y = 0;
// Scale animation
resultCard.scaleX = 0;
resultCard.scaleY = 0;
tween(resultCard, {
scaleX: 1,
scaleY: 1
}, {
duration: 500
});
resultContainer.addChild(resultCard);
// Add to player inventory based on rarity
var ratCost = result.type === 'warrior' ? 50 : 75;
if (result.rarity === 'rare') {
ratCost = Math.floor(ratCost * 0.8); // 20% discount for rare
} else if (result.rarity === 'epic') {
ratCost = Math.floor(ratCost * 0.7); // 30% discount for epic
} else if (result.rarity === 'legendary') {
ratCost = Math.floor(ratCost * 0.6); // 40% discount for legendary
}
// Add unit to collected units
var collectedUnit = {
type: result.type,
rarity: result.rarity,
color: result.color,
cost: ratCost
};
collectedUnits.push(collectedUnit);
// Give bonus cheese for higher rarities
if (result.rarity === 'rare') {
cheesePoints += 15;
} else if (result.rarity === 'epic') {
cheesePoints += 35;
} else if (result.rarity === 'legendary') {
cheesePoints += 50;
}
}
updateUI();
};
singleRollButton.down = function () {
if (cheesePoints >= 25) {
cheesePoints -= 25;
var result = self.performRoll();
self.showRollResult([result]);
LK.effects.flashScreen(0x00FF00, 200);
}
};
multiRollButton.down = function () {
if (cheesePoints >= 100) {
cheesePoints -= 100;
var results = [];
for (var i = 0; i < 5; i++) {
results.push(self.performRoll());
}
self.showRollResult(results);
LK.effects.flashScreen(0x0080FF, 300);
}
};
closeButton.down = function () {
self.destroy();
rollScreen = null;
};
return self;
});
var SummoningZone = Container.expand(function () {
var self = Container.call(this);
var zoneGraphics = self.attachAsset('summonZone', {
anchorX: 0.5,
anchorY: 0.5
});
zoneGraphics.alpha = 0.3;
var zoneText = new Text2('GACHA ROLLS', {
size: 40,
fill: '#FFFFFF'
});
zoneText.anchor.set(0.5, 0.5);
zoneText.y = -30;
self.addChild(zoneText);
var instructionText = new Text2('Tap to open roll screen', {
size: 25,
fill: '#CCCCCC'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.y = 0;
self.addChild(instructionText);
var instructionText2 = new Text2('Place rats on green tiles anywhere', {
size: 25,
fill: '#90EE90'
});
instructionText2.anchor.set(0.5, 0.5);
instructionText2.y = 30;
self.addChild(instructionText2);
// Summon button for gacha rolls
var summonButton = new Text2('OPEN ROLLS', {
size: 35,
fill: '#FFD700'
});
summonButton.anchor.set(0.5, 0.5);
summonButton.y = 60;
self.addChild(summonButton);
self.down = function (x, y, obj) {
if (gameStarted && !upgradeMode) {
// Open roll screen for gacha summons
if (!rollScreen) {
rollScreen = new RollScreen();
game.addChild(rollScreen);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
// Game state
var gameStarted = false;
var mainMenu = null;
// Center map offset for mobile display
var mapOffsetX = (2048 - 1200) / 2;
var mapOffsetY = 200;
var gamePath = [{
x: 40 + mapOffsetX,
y: 400 + mapOffsetY
}, {
x: 200 + mapOffsetX,
y: 400 + mapOffsetY
}, {
x: 200 + mapOffsetX,
y: 200 + mapOffsetY
}, {
x: 400 + mapOffsetX,
y: 200 + mapOffsetY
}, {
x: 400 + mapOffsetX,
y: 500 + mapOffsetY
}, {
x: 600 + mapOffsetX,
y: 500 + mapOffsetY
}, {
x: 600 + mapOffsetX,
y: 300 + mapOffsetY
}, {
x: 800 + mapOffsetX,
y: 300 + mapOffsetY
}, {
x: 800 + mapOffsetX,
y: 600 + mapOffsetY
}, {
x: 1000 + mapOffsetX,
y: 600 + mapOffsetY
}, {
x: 1000 + mapOffsetX,
y: 400 + mapOffsetY
}, {
x: 1200 + mapOffsetX,
y: 400 + mapOffsetY
}];
var placementTiles = [{
x: 280 + mapOffsetX,
y: 280 + mapOffsetY
}, {
x: 520 + mapOffsetX,
y: 380 + mapOffsetY
}, {
x: 680 + mapOffsetX,
y: 380 + mapOffsetY
}, {
x: 720 + mapOffsetX,
y: 200 + mapOffsetY
}, {
x: 880 + mapOffsetX,
y: 200 + mapOffsetY
}, {
x: 880 + mapOffsetX,
y: 500 + mapOffsetY
}, {
x: 1080 + mapOffsetX,
y: 500 + mapOffsetY
}, {
x: 280 + mapOffsetX,
y: 120 + mapOffsetY
}, {
x: 680 + mapOffsetX,
y: 580 + mapOffsetY
}, {
x: 360 + mapOffsetX,
y: 160 + mapOffsetY
}, {
x: 760 + mapOffsetX,
y: 160 + mapOffsetY
}, {
x: 1160 + mapOffsetX,
y: 160 + mapOffsetY
}];
var cats = [];
var rats = [];
var bullets = [];
var cheesePoints = 150;
var lives = 5;
var currentWave = 1;
var waveInProgress = false;
var catsToSpawn = 0;
var spawnTimer = 0;
var selectedRatType = 'warrior';
var selectedRat = null;
var upgradeMode = false;
// Initialize game variables
var pathIndicators = [];
var placementIndicators = [];
var cheese = null;
var cheeseText = null;
var livesText = null;
var waveText = null;
var startWaveButton = null;
var ratTypeButton = null;
var upgradeButton = null;
var upgradeInfoText = null;
var summoningZone = null;
var inventorySlots = [];
var rollScreen = null;
// Collected units from rolls
var collectedUnits = [];
var selectedCollectedUnit = null;
function startWave() {
if (!waveInProgress) {
waveInProgress = true;
catsToSpawn = 3 + currentWave * 2;
spawnTimer = 0;
startWaveButton.setText('WAVE IN PROGRESS');
startWaveButton.tint = 0xFF0000;
}
}
function spawnCat() {
var cat;
var random = Math.random();
// Spawn boss cats in later waves
if (currentWave >= 8 && random < 0.15) {
cat = new FastCatBoss();
} else if (currentWave >= 5 && random < 0.2) {
cat = new CatBoss();
} else if (random < 0.3 && currentWave > 2) {
cat = new FastCat();
} else {
cat = new Cat();
}
cat.x = gamePath[0].x;
cat.y = gamePath[0].y;
cat.health += currentWave * 10;
cat.maxHealth = cat.health;
cats.push(cat);
game.addChild(cat);
catsToSpawn--;
}
var collectedUnitSlots = [];
function updateCollectedUnitsDisplay() {
// Remove existing collected unit slots
for (var i = 0; i < collectedUnitSlots.length; i++) {
collectedUnitSlots[i].destroy();
}
collectedUnitSlots = [];
// Create new slots for collected units
for (var i = 0; i < collectedUnits.length && i < 8; i++) {
var slot = new CollectedUnitSlot(collectedUnits[i], i);
slot.x = 500 + i % 4 * 100;
slot.y = 2400 + Math.floor(i / 4) * 100;
collectedUnitSlots.push(slot);
game.addChild(slot);
// Select if this is the selected unit
if (selectedCollectedUnit === collectedUnits[i]) {
slot.setSelected(true);
}
}
}
function updateUI() {
if (!cheeseText) return; // Don't update UI if elements aren't initialized yet
cheeseText.setText('Cheese: ' + cheesePoints);
livesText.setText('Lives: ' + lives);
waveText.setText('Wave: ' + currentWave);
if (selectedCollectedUnit) {
ratTypeButton.setText('COLLECTED: ' + selectedCollectedUnit.type.toUpperCase() + ' (' + selectedCollectedUnit.rarity + ')');
} else if (selectedRatType) {
var ratCost = selectedRatType === 'warrior' ? 50 : 75;
ratTypeButton.setText('RAT: ' + selectedRatType.toUpperCase() + ' (' + ratCost + ')');
} else {
ratTypeButton.setText('SELECT A UNIT');
}
upgradeButton.setText('UPGRADE MODE: ' + (upgradeMode ? 'ON' : 'OFF'));
upgradeButton.tint = upgradeMode ? 0x00FF00 : 0x9932CC;
if (selectedRat && upgradeMode) {
var upgradeCost = selectedRat.getUpgradeCost();
var canAfford = cheesePoints >= upgradeCost;
var canUpgrade = selectedRat.canUpgrade();
if (canUpgrade) {
upgradeInfoText.setText('UPGRADE (' + upgradeCost + ') - DMG:' + Math.floor(selectedRat.damage * 1.5) + ' RNG:' + Math.floor(selectedRat.range * 1.25));
upgradeInfoText.tint = canAfford ? 0x00FF00 : 0xFF0000;
} else {
upgradeInfoText.setText('MAX LEVEL REACHED');
upgradeInfoText.tint = 0xFFFF00;
}
} else {
upgradeInfoText.setText(upgradeMode ? 'SELECT A RAT TO UPGRADE' : '');
upgradeInfoText.tint = 0xFFFFFF;
}
// Update inventory slots
if (inventorySlots && inventorySlots.length > 0) {
for (var i = 0; i < inventorySlots.length; i++) {
inventorySlots[i].updateDisplay();
}
}
// Update collected units display
updateCollectedUnitsDisplay();
}
function canPlaceRat(x, y) {
var placementDistanceSquared = 120 * 120; // 14400 - even more forgiving radius for easier targeting
for (var i = 0; i < placementTiles.length; i++) {
var tile = placementTiles[i];
var dx = x - tile.x;
var dy = y - tile.y;
if (dx * dx + dy * dy < placementDistanceSquared) {
// Check if tile is already occupied
for (var j = 0; j < rats.length; j++) {
var ratDx = rats[j].x - tile.x;
var ratDy = rats[j].y - tile.y;
if (ratDx * ratDx + ratDy * ratDy < 50 * 50) {
// Slightly reduced occupied check radius for tighter packing
return false;
}
}
return true;
}
}
return false;
}
function initializeGame() {
// Create visual path indicators to show where cats walk
pathIndicators = [];
for (var i = 0; i < gamePath.length; i++) {
var pathPoint = gamePath[i];
var indicator = LK.getAsset('pathIndicator', {
anchorX: 0.5,
anchorY: 0.5,
x: pathPoint.x,
y: pathPoint.y
});
indicator.alpha = 0.8;
pathIndicators.push(indicator);
game.addChild(indicator);
// Add directional arrows between path points
if (i < gamePath.length - 1) {
var nextPoint = gamePath[i + 1];
var arrow = LK.getAsset('pathArrow', {
anchorX: 0.5,
anchorY: 0.5,
x: (pathPoint.x + nextPoint.x) / 2,
y: (pathPoint.y + nextPoint.y) / 2
});
// Rotate arrow to point in direction of movement
var dx = nextPoint.x - pathPoint.x;
var dy = nextPoint.y - pathPoint.y;
arrow.rotation = Math.atan2(dy, dx);
arrow.alpha = 0.7;
pathIndicators.push(arrow);
game.addChild(arrow);
}
}
// Create visual indicators for placement tiles
placementIndicators = [];
for (var i = 0; i < placementTiles.length; i++) {
var tile = placementTiles[i];
var indicator = LK.getAsset('summonZone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
x: tile.x,
y: tile.y
});
indicator.alpha = 0.6;
indicator.tint = 0x90EE90;
placementIndicators.push(indicator);
game.addChild(indicator);
}
// Create cheese at the end
cheese = LK.getAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
x: gamePath[gamePath.length - 1].x,
y: gamePath[gamePath.length - 1].y
});
game.addChild(cheese);
// UI Elements
cheeseText = new Text2('Cheese: ' + cheesePoints, {
size: 60,
fill: '#FFD700'
});
cheeseText.anchor.set(0, 0);
cheeseText.x = 120;
LK.gui.topLeft.addChild(cheeseText);
livesText = new Text2('Lives: ' + lives, {
size: 60,
fill: '#FF6347'
});
livesText.anchor.set(0, 0);
livesText.x = 120;
livesText.y = 80;
LK.gui.topLeft.addChild(livesText);
waveText = new Text2('Wave: ' + currentWave, {
size: 60,
fill: '#87CEEB'
});
waveText.anchor.set(0, 0);
waveText.x = 120;
waveText.y = 160;
LK.gui.topLeft.addChild(waveText);
startWaveButton = new Text2('START WAVE', {
size: 70,
fill: '#00FF00'
});
startWaveButton.anchor.set(0.5, 0.5);
startWaveButton.down = function () {
startWave();
};
LK.gui.bottom.addChild(startWaveButton);
ratTypeButton = new Text2('RAT: WARRIOR (50)', {
size: 55,
fill: '#8B4513'
});
ratTypeButton.anchor.set(0.5, 0.5);
ratTypeButton.y = -120;
ratTypeButton.down = function () {
// Cycle through rat types and update selection
if (selectedRatType === 'warrior') {
selectedRatType = 'archer';
selectedCollectedUnit = null;
// Update inventory slots
for (var i = 0; i < inventorySlots.length; i++) {
inventorySlots[i].setSelected(inventorySlots[i].ratType === 'archer');
}
} else {
selectedRatType = 'warrior';
selectedCollectedUnit = null;
// Update inventory slots
for (var i = 0; i < inventorySlots.length; i++) {
inventorySlots[i].setSelected(inventorySlots[i].ratType === 'warrior');
}
}
updateCollectedUnitsDisplay();
updateUI();
};
LK.gui.bottom.addChild(ratTypeButton);
upgradeButton = new Text2('UPGRADE MODE: OFF', {
size: 50,
fill: '#9932CC'
});
upgradeButton.anchor.set(0.5, 0.5);
upgradeButton.y = -200;
upgradeButton.down = function () {
upgradeMode = !upgradeMode;
selectedRat = null;
updateUI();
};
LK.gui.bottom.addChild(upgradeButton);
upgradeInfoText = new Text2('', {
size: 45,
fill: '#FFFFFF'
});
upgradeInfoText.anchor.set(0.5, 0.5);
upgradeInfoText.y = -280;
LK.gui.bottom.addChild(upgradeInfoText);
// Create summoning zone
summoningZone = new SummoningZone();
summoningZone.x = 1024;
summoningZone.y = 1800;
game.addChild(summoningZone);
// Create inventory slots
inventorySlots = [];
var warriorSlot = new InventorySlot('warrior', 50);
warriorSlot.x = 200;
warriorSlot.y = 2400;
inventorySlots.push(warriorSlot);
game.addChild(warriorSlot);
var archerSlot = new InventorySlot('archer', 75);
archerSlot.x = 350;
archerSlot.y = 2400;
inventorySlots.push(archerSlot);
game.addChild(archerSlot);
// Set initial selection - auto-select warrior for immediate placement
selectedRatType = 'warrior';
selectedCollectedUnit = null;
warriorSlot.setSelected(true);
// Show helpful message
var helpText = new Text2('Tap anywhere on green tiles to place rats!', {
size: 40,
fill: '#90EE90'
});
helpText.anchor.set(0.5, 0.5);
helpText.x = 1024;
helpText.y = 1000;
game.addChild(helpText);
// Fade out help text after 5 seconds
LK.setTimeout(function () {
if (helpText && helpText.parent) {
tween(helpText, {
alpha: 0
}, {
duration: 1000
});
}
}, 5000);
updateUI();
}
function placeRat(x, y) {
var ratCost = selectedRatType === 'warrior' ? 50 : 75;
if (cheesePoints >= ratCost && canPlaceRat(x, y)) {
var rat;
if (selectedRatType === 'warrior') {
rat = new Rat();
} else {
rat = new ArcherRat();
}
// Snap to nearest placement tile
var nearestTile = null;
var nearestDistanceSquared = Infinity;
for (var i = 0; i < placementTiles.length; i++) {
var tile = placementTiles[i];
var dx = x - tile.x;
var dy = y - tile.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < nearestDistanceSquared) {
nearestDistanceSquared = distanceSquared;
nearestTile = tile;
}
}
rat.x = nearestTile.x;
rat.y = nearestTile.y;
rats.push(rat);
game.addChild(rat);
cheesePoints -= ratCost;
// Update placement indicator for this tile
for (var k = 0; k < placementTiles.length; k++) {
if (placementTiles[k].x === nearestTile.x && placementTiles[k].y === nearestTile.y) {
placementIndicators[k].tint = 0xFF6347; // Red tint to show occupied
placementIndicators[k].alpha = 0.2; // Make it more transparent
break;
}
}
LK.getSound('ratPlace').play();
updateUI();
}
}
// Show main menu initially
mainMenu = new MainMenu();
game.addChild(mainMenu);
game.down = function (x, y, obj) {
if (!gameStarted) return;
if (upgradeMode) {
// Check if clicking on a rat for upgrade
var clickedRat = null;
var clickDistanceSquared = 60 * 60; // 3600
for (var i = 0; i < rats.length; i++) {
var rat = rats[i];
var dx = x - rat.x;
var dy = y - rat.y;
if (dx * dx + dy * dy < clickDistanceSquared) {
clickedRat = rat;
break;
}
}
if (clickedRat) {
if (selectedRat === clickedRat) {
// Clicking same rat again - perform upgrade
if (clickedRat.canUpgrade() && cheesePoints >= clickedRat.getUpgradeCost()) {
cheesePoints -= clickedRat.getUpgradeCost();
clickedRat.upgrade();
LK.effects.flashObject(clickedRat, 0x00FF00, 500);
updateUI();
}
} else {
// Select this rat
// Hide range indicator for previously selected rat
if (selectedRat) {
selectedRat.hideRangeIndicator();
}
selectedRat = clickedRat;
// Remove selection indicator from all rats
for (var j = 0; j < rats.length; j++) {
rats[j].children[0].alpha = 1.0;
rats[j].hideRangeIndicator();
}
// Add selection indicator and show range
selectedRat.children[0].alpha = 0.7;
selectedRat.showRangeIndicator();
updateUI();
}
} else {
// Clicked empty space - deselect
if (selectedRat) {
selectedRat.hideRangeIndicator();
}
selectedRat = null;
for (var j = 0; j < rats.length; j++) {
rats[j].children[0].alpha = 1.0;
rats[j].hideRangeIndicator();
}
updateUI();
}
} else {
// Try to place a rat if we have one selected and can place it
if (selectedCollectedUnit && canPlaceRat(x, y)) {
// Place collected unit
var rat;
if (selectedCollectedUnit.type === 'warrior') {
rat = new Rat();
} else if (selectedCollectedUnit.type === 'archer') {
rat = new ArcherRat();
} else if (selectedCollectedUnit.type === 'magic') {
rat = new MagicRat();
} else if (selectedCollectedUnit.type === 'sniper') {
rat = new SniperRat();
} else if (selectedCollectedUnit.type === 'bomber') {
rat = new BomberRat();
} else if (selectedCollectedUnit.type === 'healer') {
rat = new HealerRat();
} else if (selectedCollectedUnit.type === 'giant') {
rat = new GiantRat();
} else if (selectedCollectedUnit.type === 'mega') {
rat = new MegaRat();
} else if (selectedCollectedUnit.type === 'tower') {
rat = new TowerRat();
} else if (selectedCollectedUnit.type === 'electric') {
rat = new ElectricRat();
} else if (selectedCollectedUnit.type === 'shadow') {
rat = new ShadowRat();
} else if (selectedCollectedUnit.type === 'summoner') {
rat = new SummonerRat();
} else {
// Default fallback for any unhandled types
rat = new Rat();
}
// Apply rarity bonuses
if (selectedCollectedUnit.rarity === 'rare') {
rat.damage = Math.floor(rat.damage * 1.3);
rat.range = Math.floor(rat.range * 1.2);
rat.children[0].tint = 0x0080FF;
} else if (selectedCollectedUnit.rarity === 'epic') {
rat.damage = Math.floor(rat.damage * 1.5);
rat.range = Math.floor(rat.range * 1.35);
rat.children[0].tint = 0x9C27B0;
} else if (selectedCollectedUnit.rarity === 'legendary') {
rat.damage = Math.floor(rat.damage * 1.8);
rat.range = Math.floor(rat.range * 1.5);
rat.children[0].tint = 0xFF8000;
}
// Snap to nearest placement tile
var nearestTile = null;
var nearestDistanceSquared = Infinity;
for (var k = 0; k < placementTiles.length; k++) {
var tile = placementTiles[k];
var dx = x - tile.x;
var dy = y - tile.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < nearestDistanceSquared) {
nearestDistanceSquared = distanceSquared;
nearestTile = tile;
}
}
rat.x = nearestTile.x;
rat.y = nearestTile.y;
rats.push(rat);
game.addChild(rat);
// Remove unit from collected units
for (var i = 0; i < collectedUnits.length; i++) {
if (collectedUnits[i] === selectedCollectedUnit) {
collectedUnits.splice(i, 1);
break;
}
}
selectedCollectedUnit = null;
LK.getSound('ratPlace').play();
updateUI();
} else if (selectedRatType && canPlaceRat(x, y)) {
// Place basic rat
var ratCost = selectedRatType === 'warrior' ? 50 : 75;
if (cheesePoints >= ratCost) {
var rat;
if (selectedRatType === 'warrior') {
rat = new Rat();
} else {
rat = new ArcherRat();
}
// Snap to nearest placement tile
var nearestTile = null;
var nearestDistanceSquared = Infinity;
for (var k = 0; k < placementTiles.length; k++) {
var tile = placementTiles[k];
var dx = x - tile.x;
var dy = y - tile.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < nearestDistanceSquared) {
nearestDistanceSquared = distanceSquared;
nearestTile = tile;
}
}
rat.x = nearestTile.x;
rat.y = nearestTile.y;
rats.push(rat);
game.addChild(rat);
cheesePoints -= ratCost;
// Update placement indicator for this tile
for (var k = 0; k < placementTiles.length; k++) {
if (placementTiles[k].x === nearestTile.x && placementTiles[k].y === nearestTile.y) {
placementIndicators[k].tint = 0xFF6347; // Red tint to show occupied
placementIndicators[k].alpha = 0.2; // Make it more transparent
break;
}
}
LK.getSound('ratPlace').play();
// Show cost feedback
var costText = new Text2('-' + ratCost, {
size: 50,
fill: '#FFD700'
});
costText.anchor.set(0.5, 0.5);
costText.x = nearestTile.x;
costText.y = nearestTile.y - 80;
game.addChild(costText);
// Animate cost text
tween(costText, {
y: nearestTile.y - 120,
alpha: 0
}, {
duration: 1000
});
// Remove cost text after animation
LK.setTimeout(function () {
if (costText && costText.parent) {
costText.destroy();
}
}, 1000);
updateUI();
}
}
}
};
game.update = function () {
if (!gameStarted) return;
// Spawn cats during wave
if (waveInProgress && catsToSpawn > 0) {
spawnTimer++;
if (spawnTimer >= 90) {
spawnCat();
spawnTimer = 0;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.reachedTarget) {
// Check collision with cats using squared distance (avoid sqrt)
var collisionDistanceSquared = 45 * 45; // 2025
if (bullet.isSplash) {
// Splash damage affects all cats in area
var splashDistanceSquared = 80 * 80; // 6400
for (var j = cats.length - 1; j >= 0; j--) {
var cat = cats[j];
var dx = bullet.x - cat.x;
var dy = bullet.y - cat.y;
if (dx * dx + dy * dy < splashDistanceSquared) {
cat.takeDamage(bullet.damage);
}
}
// Visual splash effect
LK.effects.flashScreen(0xFFA500, 200);
} else {
// Normal single target damage
for (var j = cats.length - 1; j >= 0; j--) {
var cat = cats[j];
var dx = bullet.x - cat.x;
var dy = bullet.y - cat.y;
if (dx * dx + dy * dy < collisionDistanceSquared) {
cat.takeDamage(bullet.damage);
break;
}
}
}
bullet.destroy();
bullets.splice(i, 1);
}
}
// Update cats and let them attack giant rats
for (var i = cats.length - 1; i >= 0; i--) {
var cat = cats[i];
if (cat.isDead) {
cheesePoints += cat.cheeseValue;
cat.destroy();
cats.splice(i, 1);
LK.getSound('catDefeat').play();
updateUI();
} else if (cat.reachedCheese) {
lives--;
cat.destroy();
cats.splice(i, 1);
updateUI();
if (lives <= 0) {
LK.showGameOver();
}
} else {
// Let cats attack giant, mega, tower and zombie rats that are close
for (var j = 0; j < rats.length; j++) {
var rat = rats[j];
if ((rat.ratType === 'giant' || rat.ratType === 'mega' || rat.ratType === 'tower' || rat.ratType === 'zombie') && rat.health && rat.health > 0) {
var dx = cat.x - rat.x;
var dy = cat.y - rat.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < 80 * 80 && LK.ticks % 60 === 0) {
rat.takeDamage(rat.ratType === 'zombie' ? 15 : 10);
LK.effects.flashObject(rat, 0xFF0000, 200);
}
}
}
// Check collision between zombie rats and cats
for (var j = 0; j < rats.length; j++) {
var rat = rats[j];
if (rat.ratType === 'zombie' && rat.health && rat.health > 0) {
var dx = cat.x - rat.x;
var dy = cat.y - rat.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < 60 * 60 && LK.ticks % 30 === 0) {
// Zombie rat damages cat
cat.takeDamage(15);
// Cat damages zombie rat
rat.takeDamage(10);
LK.effects.flashObject(cat, 0xFF0000, 200);
LK.effects.flashObject(rat, 0xFF0000, 200);
}
}
}
}
}
// Update rats and remove dead giant/mega/tower/zombie rats
for (var i = rats.length - 1; i >= 0; i--) {
var rat = rats[i];
if ((rat.ratType === 'giant' || rat.ratType === 'mega' || rat.ratType === 'tower' || rat.ratType === 'zombie') && rat.isDead) {
rat.destroy();
rats.splice(i, 1);
// Update placement indicator for this tile
for (var k = 0; k < placementTiles.length; k++) {
var tile = placementTiles[k];
var dx = rat.x - tile.x;
var dy = rat.y - tile.y;
if (dx * dx + dy * dy < 50 * 50) {
placementIndicators[k].tint = 0x90EE90;
placementIndicators[k].alpha = 0.6;
break;
}
}
}
}
// Check if wave is complete
if (waveInProgress && catsToSpawn === 0 && cats.length === 0) {
waveInProgress = false;
currentWave++;
if (currentWave > 10) {
LK.showYouWin();
} else {
cheesePoints += 25;
startWaveButton.setText('START WAVE');
startWaveButton.tint = 0x00FF00;
updateUI();
}
}
};
updateUI(); ===================================================================
--- original.js
+++ change.js
@@ -2228,8 +2228,25 @@
LK.effects.flashObject(rat, 0xFF0000, 200);
}
}
}
+ // Check collision between zombie rats and cats
+ for (var j = 0; j < rats.length; j++) {
+ var rat = rats[j];
+ if (rat.ratType === 'zombie' && rat.health && rat.health > 0) {
+ var dx = cat.x - rat.x;
+ var dy = cat.y - rat.y;
+ var distanceSquared = dx * dx + dy * dy;
+ if (distanceSquared < 60 * 60 && LK.ticks % 30 === 0) {
+ // Zombie rat damages cat
+ cat.takeDamage(15);
+ // Cat damages zombie rat
+ rat.takeDamage(10);
+ LK.effects.flashObject(cat, 0xFF0000, 200);
+ LK.effects.flashObject(rat, 0xFF0000, 200);
+ }
+ }
+ }
}
}
// Update rats and remove dead giant/mega/tower/zombie rats
for (var i = rats.length - 1; i >= 0; i--) {
Cat. In-Game asset. 2d. High contrast. No shadows
Chese. In-Game asset. 2d. High contrast. No shadows
Rat with a arco. In-Game asset. 2d. High contrast. No shadows
Rata con pistola. In-Game asset. 2d. High contrast. No shadows
bomberRat. In-Game asset. 2d. High contrast. No shadows
zombie rat. In-Game asset. 2d. High contrast. No shadows
wizard rat. In-Game asset. 2d. High contrast. No shadows
wizard cat. In-Game asset. 2d. High contrast. No shadows
zombie ca. In-Game asset. 2d. High contrast. No shadows
strong cat. In-Game asset. 2d. High contrast. No shadows