/**** 
* Classes
****/ 
var BalrogEnemy = Container.expand(function () {
	var self = Container.call(this);
	var balrogGraphics = self.attachAsset('balrogSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	balrogGraphics.scale.set(2.5);
	self.hitpoints = balrogHitpoints;
	balrogHitpoints *= 2;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 4;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			if (this.zigzagCounter % 10 == 0) {
				this.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 500;
		playerScore += 10000;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 100; i++) {
			var t = new GoldCoin(self.x, self.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var Bullet = Container.expand(function (upgradeLevel) {
	var self = Container.call(this);
	self.game = null;
	self.upgradeLevel = upgradeLevel;
	self.damage = towerDamage[self.upgradeLevel];
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bulletGraphics.scale.set(0.2);
	var bulletGraphics1 = self.attachAsset('bulletSprite1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics2 = self.attachAsset('bulletSprite2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics3 = self.attachAsset('bulletSprite3', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics4 = self.attachAsset('bulletSprite4', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics5 = self.attachAsset('bulletSprite5', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics6 = self.attachAsset('bulletSprite6', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics7 = self.attachAsset('bulletSprite7', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics8 = self.attachAsset('bulletSprite8', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bulletGraphics1.scale.set(.2);
	bulletGraphics2.scale.set(.2);
	bulletGraphics3.scale.set(.2);
	bulletGraphics4.scale.set(.2);
	bulletGraphics5.scale.set(.2);
	bulletGraphics6.scale.set(.2);
	bulletGraphics7.scale.set(.2);
	bulletGraphics8.scale.set(.2);
	bulletGraphics1.alpha = 0;
	bulletGraphics2.alpha = 0;
	bulletGraphics3.alpha = 0;
	bulletGraphics4.alpha = 0;
	bulletGraphics5.alpha = 0;
	bulletGraphics6.alpha = 0;
	bulletGraphics7.alpha = 0;
	bulletGraphics8.alpha = 0;
	var a = [bulletGraphics1, bulletGraphics2, bulletGraphics3, bulletGraphics4, bulletGraphics5, bulletGraphics6, bulletGraphics7, bulletGraphics8];
	if (self.upgradeLevel > 0) {
		bulletGraphics.alpha = 0;
		for (var i = 0; i < 8; i++) {
			if (i + 1 == self.upgradeLevel) {
				a[i].alpha = 1;
			} else {
				a[i].setAlpha = 0;
			}
		}
	}
	self.vx = 0;
	self.vy = 0;
	self._move_migrated = function () {
		if (self.target) {
			var tx = self.target.x - self.x;
			var ty = self.target.y - self.y;
			var dist = Math.sqrt(tx * tx + ty * ty);
			if (dist > 0) {
				self.x += self.vx * 10;
				self.y += self.vy * 10;
			}
			if (dist < self.width / 2 + self.target.width / 2) {
				self.hit();
			} else if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
				self.destroy();
			}
		}
	};
	self.hit = function () {
		self.target.hitpoints -= self.damage;
		if (self.target.hitpoints <= 0 && !self.target.dead) {
			self.target.dead = true;
			self.target.die();
		}
		self.destroy();
	};
});
var CityWall = Container.expand(function () {
	var self = Container.call(this);
	var wallGraphics = self.attachAsset('cityWallSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(wallGraphics);
});
var DeathKnightEnemy = Container.expand(function () {
	var self = Container.call(this);
	var dKnightGraphics = self.attachAsset('deathKnightSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	dKnightGraphics.scale.set(2.5);
	self.hitpoints = 100;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 1;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(this.scale.x, 1);
			self.scale.y = Math.min(this.scale.y, 1);
			if (self.zigzagCounter % 10 == 0) {
				self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 50;
		playerScore += 2222;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 40; i++) {
			var t = new GoldCoin(this.x, this.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('enemySprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	enemyGraphics.scale.set(0.8);
	self.hitpoints = 3;
	self.zigzagTension = Math.floor(Math.random() * 40) + 10;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		//if (!towers) {
		//	towers = [];
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			//console.log('dist is:', dist);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		//console.log('minDist:', minDist);
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 0.5;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * this.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 50);
		}
	};
	self.die = function () {
		playerGold += 5;
		playerScore += 100;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 5; i++) {
			var t = new GoldCoin(this.x, this.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var GoldCoin = Container.expand(function (startX, startY, endX, endY, delay) {
	var self = Container.call(this);
	GoldCoin.delayIncrement = 0;
	//self.game = this;
	var coinTypes = ['bulletSprite1', 'bulletSprite2', 'bulletSprite3', 'bulletSprite4', 'bulletSprite5', 'bulletSprite6', 'bulletSprite7', 'bulletSprite8'];
	var sel = coinTypes[Math.floor(Math.random() * coinTypes.length)];
	if (false) {
		var coinGraphics = self.attachAsset('goldCoinSprite', {
			anchorX: 0.5,
			anchorY: 0.5
		});
	}
	var coinGraphics = self.createAsset(sel, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var tx = 80 / coinGraphics.width;
	coinGraphics.width = 80;
	coinGraphics.height = coinGraphics.height * tx;
	self.addChild(coinGraphics);
	self.x = startX;
	self.y = startY;
	var distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
	self.delayCounter = delay * 2;
	var duration = 60 + delay;
	var vx = (endX - startX) / duration;
	var vy = (endY - startY) / duration;
	self.alpha = 0;
	self.path = createQuadraticBezierArcPoints(startX, startY, endX, startY - 100, endX, endY, 60);
	self._move_migrated = function () {
		if (self.delayCounter > 0) {
			self.delayCounter--;
		} else {
			self.alpha = 1;
			if (self.path[duration]) {
				self.x = self.path[duration - self.delayCounter][0];
				self.y = self.path[duration - self.delayCounter][1];
			}
		}
		if (--duration <= 0) {
			self.destroy();
		}
	};
});
var OrcEnemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('orcEnemySprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	enemyGraphics.scale.set(0.8);
	self.hitpoints = 6;
	self.zigzagTension = Math.floor(Math.random() * 20) + 10;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 0.8;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			if (self.zigzagCounter % 5 == 0) {
				self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 10;
		playerScore += 150;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 8; i++) {
			var t = new GoldCoin(self.x, self.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var Tower = Container.expand(function (gameInstance) {
	var self = Container.call(this);
	self.game = gameInstance;
	self.upgradeLevel = upgradeLevel;
	//console.log('tower created,', self.upgradeLevel);
	var towerGraphics = self.attachAsset('towerSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics1 = self.attachAsset('towerSprite1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics2 = self.attachAsset('towerSprite2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics3 = self.attachAsset('towerSprite3', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics4 = self.attachAsset('towerSprite4', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics5 = self.attachAsset('towerSprite5', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics6 = self.attachAsset('towerSprite6', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics7 = self.attachAsset('towerSprite7', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics8 = self.attachAsset('towerSprite8', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	towerGraphics.scale.set(2);
	towerGraphics1.scale.set(2);
	towerGraphics2.scale.set(2);
	towerGraphics3.scale.set(2);
	towerGraphics4.scale.set(2);
	towerGraphics5.scale.set(2);
	towerGraphics6.scale.set(2);
	towerGraphics7.scale.set(2);
	towerGraphics8.scale.set(2);
	towerGraphics1.alpha = 0;
	towerGraphics2.alpha = 0;
	towerGraphics3.alpha = 0;
	towerGraphics4.alpha = 0;
	towerGraphics5.alpha = 0;
	towerGraphics6.alpha = 0;
	towerGraphics7.alpha = 0;
	towerGraphics8.alpha = 0;
	var a = [towerGraphics1, towerGraphics2, towerGraphics3, towerGraphics4, towerGraphics5, towerGraphics6, towerGraphics7, towerGraphics8];
	if (upgradeLevel > 0) {
		towerGraphics.alpha = 0;
		for (var i = 0; i < 8; i++) {
			if (i + 1 == upgradeLevel) {
				a[i].alpha = 1;
			} else {
				a[i].alpha = 0;
			}
		}
	}
	self.shoot = function () {
		if (self.shootCounter++ % towerShotDelay[self.upgradeLevel] === 0) {
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance <= 300) {
					//console.log('shot');
					var bullet = new Bullet(self.upgradeLevel);
					bullet.x = self.x;
					bullet.y = self.y;
					bullet.target = enemy;
					var tx = bullet.target.x - bullet.x;
					var ty = bullet.target.y - bullet.y;
					var rad = Math.atan2(ty, tx);
					bullet.rotation = rad + Math.PI / 2;
					bullet.vx = Math.cos(rad);
					bullet.vy = Math.sin(rad);
					addBullet(bullet);
					break;
				}
			}
		}
	};
	self.upgrade = function () {};
	self.shootCounter = 0;
	self.health = 200;
});
var TreasureChest = Container.expand(function () {
	var self = Container.call(this);
	var chestGraphics = self.attachAsset('treasureChestSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(chestGraphics);
});
var TrollEnemy = Container.expand(function () {
	var self = Container.call(this);
	var trollGraphics = self.attachAsset('trollSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	trollGraphics.scale.set(2);
	self.hitpoints = 30;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 0.5;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			if (self.zigzagCounter % 5 == 0) {
				self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 20;
		playerScore += 300;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 20; i++) {
			var t = new GoldCoin(self.x, self.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var UpgradeButton = Container.expand(function () {
	var self = Container.call(this);
	var upgradeButtonGraphics = self.attachAsset('buttonSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(upgradeButtonGraphics);
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
var enemySpawnCounter = 0;
var totalEnemiesSpawned = 0;
var playerGold = 30;
var playerScore = 0;
var enemySpawnDelay = 120;
var upgradeLevel = 0;
var upgradeCost = 100;
var towerDamage = [1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 8];
var towerShotDelay = [50, 45, 45, 40, 35, 30, 25, 20, 15];
var balrogHitpoints = 500;
var towers = []; // Initialize towers array to prevent undefined errors
var enemies = []; // Initialize enemies array to prevent undefined errors
var bullets = [];
var goldCoins = [];
var selectedTowerType = null;
var lerp = function lerp(start, end, t) {
	return start * (1 - t) + end * t;
};
var createQuadraticBezierArcPoints = function createQuadraticBezierArcPoints(p0x, p0y, p1x, p1y, p2x, p2y, numberOfSteps) {
	var points_along_axis = new Array(numberOfSteps).fill(null).map(function () {
		return [0, 0];
	});
	var stepping_constant = 1 / numberOfSteps;
	for (var i = 0; i < numberOfSteps; i++) {
		var i_p0_p1x = lerp(p0x, p1x, i * stepping_constant);
		var i_p0_p1y = lerp(p0y, p1y, i * stepping_constant);
		var i_p1_p2x = lerp(p1x, p2x, i * stepping_constant);
		var i_p1_p2y = lerp(p1y, p2y, i * stepping_constant);
		if (false) {
			points_along_axis.push(lerp(i_p0_p1x, i_p1_p2x, i * stepping_constant), lerp(i_p0_p1y, i_p1_p2y, i * stepping_constant));
		}
		points_along_axis[i][0] = lerp(i_p0_p1x, i_p1_p2x, i * stepping_constant);
		points_along_axis[i][1] = lerp(i_p0_p1y, i_p1_p2y, i * stepping_constant);
	}
	if (false) {
		console.log('path: ' + points_along_axis);
		console.log('path[2]: ' + points_along_axis[2]);
	}
	return points_along_axis.reverse();
};
var temp = createQuadraticBezierArcPoints(0, 0, 50, 50, 0, 50, 10);
var updateGoldLabel = function updateGoldLabel() {
	goldLabel.setText('Presents: ' + playerGold);
};
var updateScoreLabel = function updateScoreLabel() {
	scoreLabel.setText('Score: ' + playerScore);
};
var updateCostLabel = function updateCostLabel() {
	costLabel.setText('Cost: ' + upgradeCost);
};
//var playerGold = 0;
var addBullet = function addBullet(bullet) {
	bullets.push(bullet);
	game.addChild(bullet);
};
function sufficientDistanceToOtherTowers(position) {
	console.log('running function sufficientDistanceToOtherTowers');
	for (var i = 0; i < towers.length; i++) {
		var tower = towers[i];
		var dx = tower.x - position.x;
		var dy = tower.y - position.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < 120) {
			//console.log('too close to other tower');
			return false;
		}
	}
	//console.log('far enough from other towers');
	return true;
}
;
var background = game.attachAsset('background', {});
background.width = 2548;
background.height = 3732;
background.y = -400;
background.x = -300;
game.addChildAt(background, 0);
var initialEnemy = new Enemy();
initialEnemy.__game = game;
initialEnemy.x = 300 + Math.random() * (1848 - 300);
initialEnemy.y = 200;
initialEnemy.scale.set(0.1);
enemies.push(initialEnemy);
game.addChild(initialEnemy);
LK.on('tick', function () {
	enemySpawnCounter = enemySpawnCounter || 0;
	totalEnemiesSpawned = totalEnemiesSpawned || 0;
	if (++enemySpawnCounter >= enemySpawnDelay) {
		var newEnemy;
		if (totalEnemiesSpawned > 200 && totalEnemiesSpawned % 199 == 0) {
			newEnemy = new BalrogEnemy();
		} else if (totalEnemiesSpawned > 3 && totalEnemiesSpawned % 50 == 0) {
			newEnemy = new DeathKnightEnemy();
		} else if (totalEnemiesSpawned > 3 && totalEnemiesSpawned % 10 == 0) {
			newEnemy = new TrollEnemy();
		} else {
			if (Math.random() < 0.2 + upgradeLevel * 0.06) {
				newEnemy = new OrcEnemy();
			} else {
				newEnemy = new Enemy();
			}
		}
		if (newEnemy) {
			newEnemy.__game = game;
			newEnemy.x = 300 + Math.random() * (1848 - 300);
			newEnemy.y = 200;
			newEnemy.scale.set(0.1);
			enemies.push(newEnemy);
			game.addChild(newEnemy);
		}
		totalEnemiesSpawned++;
		if (totalEnemiesSpawned > 0 && totalEnemiesSpawned % 20 == 0) {
			enemySpawnDelay -= 4;
			if (enemySpawnDelay < 20) {
				enemySpawnDelay = 20;
			}
		}
		enemySpawnCounter = 0;
	}
	for (var i = 0; i < enemies.length; i++) {
		enemies[i]._move_migrated();
		if (enemies[i].y >= 2332 - enemies[i].height / 2) {
			LK.setScore(playerScore);
			LK.showGameOver();
		}
	}
	for (var j = 0; j < towers.length; j++) {
		towers[j].shoot();
	}
	for (var k = bullets.length - 1; k >= 0; k--) {
		bullets[k]._move_migrated();
		if (!bullets[k].parent) {
			bullets.splice(k, 1);
		}
	}
	for (var l = goldCoins.length - 1; l >= 0; l--) {
		goldCoins[l]._move_migrated();
		if (!goldCoins[l].parent) {
			goldCoins.splice(l, 1);
		}
	}
});
game.on('down', function (x, y, obj) {
	var position = game.toLocal(obj.global);
	//console.log('clicked on:', position.x, position.y);
	if (position.y >= 600 && position.y <= 2112) {
		//console.log('check1');
		if (playerGold >= 10) {
			//console.log('check2');
			if (sufficientDistanceToOtherTowers(position)) {
				//console.log('check3');
				playerGold -= 10;
				var newTower = game.addChild(new Tower(game));
				newTower.x = position.x;
				newTower.y = position.y;
				towers.push(newTower);
				towers.sort(function (a, b) {
					return a.y - b.y;
				});
				towers.forEach(function (tower, index) {
					game.addChildAt(tower, 6 + index);
				});
				updateGoldLabel();
			}
		}
	}
});
game.on('move', function (x, y, obj) {});
game.on('up', function (x, y, obj) {});
var cityWall2 = game.addChild(new CityWall());
cityWall2.y = 2432;
cityWall2.x = 365;
cityWall2.scale.y = 0.3;
cityWall2.scale.x = 0.4;
var cityWall3 = game.addChild(new CityWall());
cityWall3.y = 2432;
cityWall3.x = 1700;
cityWall3.scale.y = 0.3;
cityWall3.scale.x = 0.4;
var cityWall = game.addChild(new CityWall());
cityWall.y = 2432;
cityWall.x = 1035;
cityWall.scale.y = 0.3;
cityWall.scale.x = 0.5;
var bottomBlackBox = game.attachAsset('blackBox', {
	anchorY: 1
});
bottomBlackBox.width = 2720;
bottomBlackBox.height = 500;
bottomBlackBox.y = 2802;
bottomBlackBox.x = -630;
game.addChild(bottomBlackBox);
var goldLabel = new Text2('Presents: 30', {
	size: 100,
	fill: '#ffd700',
	align: 'left',
	//dropShadow: true
	stroke: '#000000',
	strokeThickness: 6
});
goldLabel.x = 120;
goldLabel.y = 2702 - bottomBlackBox.height + (bottomBlackBox.height - goldLabel.height) / 2;
game.addChild(goldLabel);
var scoreLabel = new Text2('Score: 0', {
	size: 100,
	fill: '#ccbbff',
	align: 'left',
	//dropShadow: true,
	stroke: '#000000',
	strokeThickness: 6
});
scoreLabel.x = 120;
scoreLabel.y = 2822 - bottomBlackBox.height + (bottomBlackBox.height - scoreLabel.height) / 2;
game.addChild(scoreLabel);
var instructionLabel = new Text2("Tap to build towers (cost 10 presents)\nDon't let enemies reach the wall!", {
	size: 58,
	fill: '#99bbff',
	align: 'left',
	stroke: '#000000',
	strokeThickness: 6
});
instructionLabel.x = 920;
instructionLabel.y = 2700 - bottomBlackBox.height + (bottomBlackBox.height - instructionLabel.height) / 2;
game.addChild(instructionLabel);
var treasureChest = game.addChild(new TreasureChest());
treasureChest.scale.x = 1.6;
treasureChest.scale.y = 1.6;
treasureChest.x = 820;
treasureChest.y = goldLabel.y + 65;
var upgradeButton = game.addChild(new UpgradeButton());
upgradeButton.x = 1500;
upgradeButton.y = 2590;
upgradeButton.scale.x = 1.2;
upgradeButton.scale.y = 1.2;
game.upgradeLabel = new Text2("Upgrade Towers:", {
	size: 58,
	fill: '#dddddd',
	align: 'left',
	//dropShadow: true
	stroke: '#000000',
	strokeThickness: 6
});
game.upgradeLabel.x = 920;
game.upgradeLabel.y = 2552;
game.addChild(game.upgradeLabel);
var costLabel = new Text2("Cost: 100", {
	size: 58,
	fill: '#dddd00',
	align: 'left',
	//dropShadow: true
	stroke: '#000000',
	strokeThickness: 6
});
costLabel.x = 1600;
costLabel.y = 2552;
game.addChild(costLabel);
var upgradeTowers = function upgradeTowers() {
	if (playerGold >= upgradeCost) {
		playerGold -= upgradeCost;
		upgradeLevel += 1;
		upgradeCost = Math.floor(upgradeCost * 1.5);
		updateGoldLabel();
		updateCostLabel();
		if (upgradeLevel == 8) {
			game.upgradeLabel.setText('All upgraded - Go for the High Score!');
			//if (upgradeButton) {
			upgradeButton.destroy();
			upgradeButton = null;
			//if (costLabel) {
			costLabel.destroy();
			costLabel = null;
		}
	}
};
upgradeButton.on('down', function (x, y, obj) {
	obj.event = obj;
	upgradeTowers(obj);
}); /**** 
* Classes
****/ 
var BalrogEnemy = Container.expand(function () {
	var self = Container.call(this);
	var balrogGraphics = self.attachAsset('balrogSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	balrogGraphics.scale.set(2.5);
	self.hitpoints = balrogHitpoints;
	balrogHitpoints *= 2;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 4;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			if (this.zigzagCounter % 10 == 0) {
				this.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 500;
		playerScore += 10000;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 100; i++) {
			var t = new GoldCoin(self.x, self.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var Bullet = Container.expand(function (upgradeLevel) {
	var self = Container.call(this);
	self.game = null;
	self.upgradeLevel = upgradeLevel;
	self.damage = towerDamage[self.upgradeLevel];
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bulletGraphics.scale.set(0.2);
	var bulletGraphics1 = self.attachAsset('bulletSprite1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics2 = self.attachAsset('bulletSprite2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics3 = self.attachAsset('bulletSprite3', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics4 = self.attachAsset('bulletSprite4', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics5 = self.attachAsset('bulletSprite5', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics6 = self.attachAsset('bulletSprite6', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics7 = self.attachAsset('bulletSprite7', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var bulletGraphics8 = self.attachAsset('bulletSprite8', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	bulletGraphics1.scale.set(.2);
	bulletGraphics2.scale.set(.2);
	bulletGraphics3.scale.set(.2);
	bulletGraphics4.scale.set(.2);
	bulletGraphics5.scale.set(.2);
	bulletGraphics6.scale.set(.2);
	bulletGraphics7.scale.set(.2);
	bulletGraphics8.scale.set(.2);
	bulletGraphics1.alpha = 0;
	bulletGraphics2.alpha = 0;
	bulletGraphics3.alpha = 0;
	bulletGraphics4.alpha = 0;
	bulletGraphics5.alpha = 0;
	bulletGraphics6.alpha = 0;
	bulletGraphics7.alpha = 0;
	bulletGraphics8.alpha = 0;
	var a = [bulletGraphics1, bulletGraphics2, bulletGraphics3, bulletGraphics4, bulletGraphics5, bulletGraphics6, bulletGraphics7, bulletGraphics8];
	if (self.upgradeLevel > 0) {
		bulletGraphics.alpha = 0;
		for (var i = 0; i < 8; i++) {
			if (i + 1 == self.upgradeLevel) {
				a[i].alpha = 1;
			} else {
				a[i].setAlpha = 0;
			}
		}
	}
	self.vx = 0;
	self.vy = 0;
	self._move_migrated = function () {
		if (self.target) {
			var tx = self.target.x - self.x;
			var ty = self.target.y - self.y;
			var dist = Math.sqrt(tx * tx + ty * ty);
			if (dist > 0) {
				self.x += self.vx * 10;
				self.y += self.vy * 10;
			}
			if (dist < self.width / 2 + self.target.width / 2) {
				self.hit();
			} else if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
				self.destroy();
			}
		}
	};
	self.hit = function () {
		self.target.hitpoints -= self.damage;
		if (self.target.hitpoints <= 0 && !self.target.dead) {
			self.target.dead = true;
			self.target.die();
		}
		self.destroy();
	};
});
var CityWall = Container.expand(function () {
	var self = Container.call(this);
	var wallGraphics = self.attachAsset('cityWallSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(wallGraphics);
});
var DeathKnightEnemy = Container.expand(function () {
	var self = Container.call(this);
	var dKnightGraphics = self.attachAsset('deathKnightSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	dKnightGraphics.scale.set(2.5);
	self.hitpoints = 100;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 1;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(this.scale.x, 1);
			self.scale.y = Math.min(this.scale.y, 1);
			if (self.zigzagCounter % 10 == 0) {
				self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 50;
		playerScore += 2222;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 40; i++) {
			var t = new GoldCoin(this.x, this.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('enemySprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	enemyGraphics.scale.set(0.8);
	self.hitpoints = 3;
	self.zigzagTension = Math.floor(Math.random() * 40) + 10;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		//if (!towers) {
		//	towers = [];
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			//console.log('dist is:', dist);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		//console.log('minDist:', minDist);
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 0.5;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * this.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 50);
		}
	};
	self.die = function () {
		playerGold += 5;
		playerScore += 100;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 5; i++) {
			var t = new GoldCoin(this.x, this.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var GoldCoin = Container.expand(function (startX, startY, endX, endY, delay) {
	var self = Container.call(this);
	GoldCoin.delayIncrement = 0;
	//self.game = this;
	var coinTypes = ['bulletSprite1', 'bulletSprite2', 'bulletSprite3', 'bulletSprite4', 'bulletSprite5', 'bulletSprite6', 'bulletSprite7', 'bulletSprite8'];
	var sel = coinTypes[Math.floor(Math.random() * coinTypes.length)];
	if (false) {
		var coinGraphics = self.attachAsset('goldCoinSprite', {
			anchorX: 0.5,
			anchorY: 0.5
		});
	}
	var coinGraphics = self.createAsset(sel, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var tx = 80 / coinGraphics.width;
	coinGraphics.width = 80;
	coinGraphics.height = coinGraphics.height * tx;
	self.addChild(coinGraphics);
	self.x = startX;
	self.y = startY;
	var distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
	self.delayCounter = delay * 2;
	var duration = 60 + delay;
	var vx = (endX - startX) / duration;
	var vy = (endY - startY) / duration;
	self.alpha = 0;
	self.path = createQuadraticBezierArcPoints(startX, startY, endX, startY - 100, endX, endY, 60);
	self._move_migrated = function () {
		if (self.delayCounter > 0) {
			self.delayCounter--;
		} else {
			self.alpha = 1;
			if (self.path[duration]) {
				self.x = self.path[duration - self.delayCounter][0];
				self.y = self.path[duration - self.delayCounter][1];
			}
		}
		if (--duration <= 0) {
			self.destroy();
		}
	};
});
var OrcEnemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('orcEnemySprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	enemyGraphics.scale.set(0.8);
	self.hitpoints = 6;
	self.zigzagTension = Math.floor(Math.random() * 20) + 10;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 0.8;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			if (self.zigzagCounter % 5 == 0) {
				self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 10;
		playerScore += 150;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 8; i++) {
			var t = new GoldCoin(self.x, self.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var Tower = Container.expand(function (gameInstance) {
	var self = Container.call(this);
	self.game = gameInstance;
	self.upgradeLevel = upgradeLevel;
	//console.log('tower created,', self.upgradeLevel);
	var towerGraphics = self.attachAsset('towerSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics1 = self.attachAsset('towerSprite1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics2 = self.attachAsset('towerSprite2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics3 = self.attachAsset('towerSprite3', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics4 = self.attachAsset('towerSprite4', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics5 = self.attachAsset('towerSprite5', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics6 = self.attachAsset('towerSprite6', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics7 = self.attachAsset('towerSprite7', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var towerGraphics8 = self.attachAsset('towerSprite8', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	towerGraphics.scale.set(2);
	towerGraphics1.scale.set(2);
	towerGraphics2.scale.set(2);
	towerGraphics3.scale.set(2);
	towerGraphics4.scale.set(2);
	towerGraphics5.scale.set(2);
	towerGraphics6.scale.set(2);
	towerGraphics7.scale.set(2);
	towerGraphics8.scale.set(2);
	towerGraphics1.alpha = 0;
	towerGraphics2.alpha = 0;
	towerGraphics3.alpha = 0;
	towerGraphics4.alpha = 0;
	towerGraphics5.alpha = 0;
	towerGraphics6.alpha = 0;
	towerGraphics7.alpha = 0;
	towerGraphics8.alpha = 0;
	var a = [towerGraphics1, towerGraphics2, towerGraphics3, towerGraphics4, towerGraphics5, towerGraphics6, towerGraphics7, towerGraphics8];
	if (upgradeLevel > 0) {
		towerGraphics.alpha = 0;
		for (var i = 0; i < 8; i++) {
			if (i + 1 == upgradeLevel) {
				a[i].alpha = 1;
			} else {
				a[i].alpha = 0;
			}
		}
	}
	self.shoot = function () {
		if (self.shootCounter++ % towerShotDelay[self.upgradeLevel] === 0) {
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance <= 300) {
					//console.log('shot');
					var bullet = new Bullet(self.upgradeLevel);
					bullet.x = self.x;
					bullet.y = self.y;
					bullet.target = enemy;
					var tx = bullet.target.x - bullet.x;
					var ty = bullet.target.y - bullet.y;
					var rad = Math.atan2(ty, tx);
					bullet.rotation = rad + Math.PI / 2;
					bullet.vx = Math.cos(rad);
					bullet.vy = Math.sin(rad);
					addBullet(bullet);
					break;
				}
			}
		}
	};
	self.upgrade = function () {};
	self.shootCounter = 0;
	self.health = 200;
});
var TreasureChest = Container.expand(function () {
	var self = Container.call(this);
	var chestGraphics = self.attachAsset('treasureChestSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(chestGraphics);
});
var TrollEnemy = Container.expand(function () {
	var self = Container.call(this);
	var trollGraphics = self.attachAsset('trollSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	trollGraphics.scale.set(2);
	self.hitpoints = 30;
	self._move_migrated = function () {
		var minDist = Infinity;
		var closestTower = null;
		for (var i = 0; i < towers.length; i++) {
			var dx = towers[i].x - self.x;
			var dy = towers[i].y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist) {
				minDist = dist;
				closestTower = towers[i];
			}
		}
		if (closestTower && minDist < closestTower.width / 2 + self.width / 2) {
			closestTower.health -= 0.5;
			if (closestTower.health <= 0) {
				var towerIndex = towers.indexOf(closestTower);
				if (towerIndex > -1) {
					towers.splice(towerIndex, 1);
				}
				closestTower.destroy();
			}
		} else if (closestTower && minDist < 100) {
			var avoidanceForce = 8;
			var ax = self.x - closestTower.x;
			var ay = self.y - closestTower.y;
			var len = Math.sqrt(ax * ax + ay * ay);
			ax = ax / len * avoidanceForce;
			ay = ay / len * avoidanceForce;
			self.x += ax;
			self.y += ay;
		} else {
			self.zigzagCounter = self.zigzagCounter || 0;
			self.zigzagDirection = self.zigzagDirection || 1;
			if (self.zigzagCounter++ % self.zigzagTension === 0) {
				self.zigzagDirection *= -1;
			}
			self.x += 4 * self.zigzagDirection;
			self.y += 2;
			if (Math.random() < 0.01) {
				self.zigzagTension = Math.floor(Math.random() * 40) + 10;
			}
			if (self.x > 2048) {
				self.zigzagDirection = -1;
			}
			if (self.x < 0) {
				self.zigzagDirection = 1;
			}
			var scaleIncrement = (1 - 0.1) / 200;
			self.scale.x += scaleIncrement;
			self.scale.y += scaleIncrement;
			self.scale.x = Math.min(self.scale.x, 1);
			self.scale.y = Math.min(self.scale.y, 1);
			if (self.zigzagCounter % 5 == 0) {
				self.rotation = (0.5 - Math.random()) * (Math.PI * 2 / 100);
			}
		}
	};
	self.die = function () {
		playerGold += 20;
		playerScore += 300;
		updateScoreLabel();
		updateGoldLabel();
		for (var i = 0; i < 20; i++) {
			var t = new GoldCoin(self.x, self.y, 820, 2500, i * 2);
			game.addChild(t);
			goldCoins.push(t);
		}
		var index = enemies.indexOf(self);
		if (index > -1) {
			enemies.splice(index, 1);
		}
		self.destroy();
	};
});
var UpgradeButton = Container.expand(function () {
	var self = Container.call(this);
	var upgradeButtonGraphics = self.attachAsset('buttonSprite', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(upgradeButtonGraphics);
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
var enemySpawnCounter = 0;
var totalEnemiesSpawned = 0;
var playerGold = 30;
var playerScore = 0;
var enemySpawnDelay = 120;
var upgradeLevel = 0;
var upgradeCost = 100;
var towerDamage = [1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 8];
var towerShotDelay = [50, 45, 45, 40, 35, 30, 25, 20, 15];
var balrogHitpoints = 500;
var towers = []; // Initialize towers array to prevent undefined errors
var enemies = []; // Initialize enemies array to prevent undefined errors
var bullets = [];
var goldCoins = [];
var selectedTowerType = null;
var lerp = function lerp(start, end, t) {
	return start * (1 - t) + end * t;
};
var createQuadraticBezierArcPoints = function createQuadraticBezierArcPoints(p0x, p0y, p1x, p1y, p2x, p2y, numberOfSteps) {
	var points_along_axis = new Array(numberOfSteps).fill(null).map(function () {
		return [0, 0];
	});
	var stepping_constant = 1 / numberOfSteps;
	for (var i = 0; i < numberOfSteps; i++) {
		var i_p0_p1x = lerp(p0x, p1x, i * stepping_constant);
		var i_p0_p1y = lerp(p0y, p1y, i * stepping_constant);
		var i_p1_p2x = lerp(p1x, p2x, i * stepping_constant);
		var i_p1_p2y = lerp(p1y, p2y, i * stepping_constant);
		if (false) {
			points_along_axis.push(lerp(i_p0_p1x, i_p1_p2x, i * stepping_constant), lerp(i_p0_p1y, i_p1_p2y, i * stepping_constant));
		}
		points_along_axis[i][0] = lerp(i_p0_p1x, i_p1_p2x, i * stepping_constant);
		points_along_axis[i][1] = lerp(i_p0_p1y, i_p1_p2y, i * stepping_constant);
	}
	if (false) {
		console.log('path: ' + points_along_axis);
		console.log('path[2]: ' + points_along_axis[2]);
	}
	return points_along_axis.reverse();
};
var temp = createQuadraticBezierArcPoints(0, 0, 50, 50, 0, 50, 10);
var updateGoldLabel = function updateGoldLabel() {
	goldLabel.setText('Presents: ' + playerGold);
};
var updateScoreLabel = function updateScoreLabel() {
	scoreLabel.setText('Score: ' + playerScore);
};
var updateCostLabel = function updateCostLabel() {
	costLabel.setText('Cost: ' + upgradeCost);
};
//var playerGold = 0;
var addBullet = function addBullet(bullet) {
	bullets.push(bullet);
	game.addChild(bullet);
};
function sufficientDistanceToOtherTowers(position) {
	console.log('running function sufficientDistanceToOtherTowers');
	for (var i = 0; i < towers.length; i++) {
		var tower = towers[i];
		var dx = tower.x - position.x;
		var dy = tower.y - position.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < 120) {
			//console.log('too close to other tower');
			return false;
		}
	}
	//console.log('far enough from other towers');
	return true;
}
;
var background = game.attachAsset('background', {});
background.width = 2548;
background.height = 3732;
background.y = -400;
background.x = -300;
game.addChildAt(background, 0);
var initialEnemy = new Enemy();
initialEnemy.__game = game;
initialEnemy.x = 300 + Math.random() * (1848 - 300);
initialEnemy.y = 200;
initialEnemy.scale.set(0.1);
enemies.push(initialEnemy);
game.addChild(initialEnemy);
LK.on('tick', function () {
	enemySpawnCounter = enemySpawnCounter || 0;
	totalEnemiesSpawned = totalEnemiesSpawned || 0;
	if (++enemySpawnCounter >= enemySpawnDelay) {
		var newEnemy;
		if (totalEnemiesSpawned > 200 && totalEnemiesSpawned % 199 == 0) {
			newEnemy = new BalrogEnemy();
		} else if (totalEnemiesSpawned > 3 && totalEnemiesSpawned % 50 == 0) {
			newEnemy = new DeathKnightEnemy();
		} else if (totalEnemiesSpawned > 3 && totalEnemiesSpawned % 10 == 0) {
			newEnemy = new TrollEnemy();
		} else {
			if (Math.random() < 0.2 + upgradeLevel * 0.06) {
				newEnemy = new OrcEnemy();
			} else {
				newEnemy = new Enemy();
			}
		}
		if (newEnemy) {
			newEnemy.__game = game;
			newEnemy.x = 300 + Math.random() * (1848 - 300);
			newEnemy.y = 200;
			newEnemy.scale.set(0.1);
			enemies.push(newEnemy);
			game.addChild(newEnemy);
		}
		totalEnemiesSpawned++;
		if (totalEnemiesSpawned > 0 && totalEnemiesSpawned % 20 == 0) {
			enemySpawnDelay -= 4;
			if (enemySpawnDelay < 20) {
				enemySpawnDelay = 20;
			}
		}
		enemySpawnCounter = 0;
	}
	for (var i = 0; i < enemies.length; i++) {
		enemies[i]._move_migrated();
		if (enemies[i].y >= 2332 - enemies[i].height / 2) {
			LK.setScore(playerScore);
			LK.showGameOver();
		}
	}
	for (var j = 0; j < towers.length; j++) {
		towers[j].shoot();
	}
	for (var k = bullets.length - 1; k >= 0; k--) {
		bullets[k]._move_migrated();
		if (!bullets[k].parent) {
			bullets.splice(k, 1);
		}
	}
	for (var l = goldCoins.length - 1; l >= 0; l--) {
		goldCoins[l]._move_migrated();
		if (!goldCoins[l].parent) {
			goldCoins.splice(l, 1);
		}
	}
});
game.on('down', function (x, y, obj) {
	var position = game.toLocal(obj.global);
	//console.log('clicked on:', position.x, position.y);
	if (position.y >= 600 && position.y <= 2112) {
		//console.log('check1');
		if (playerGold >= 10) {
			//console.log('check2');
			if (sufficientDistanceToOtherTowers(position)) {
				//console.log('check3');
				playerGold -= 10;
				var newTower = game.addChild(new Tower(game));
				newTower.x = position.x;
				newTower.y = position.y;
				towers.push(newTower);
				towers.sort(function (a, b) {
					return a.y - b.y;
				});
				towers.forEach(function (tower, index) {
					game.addChildAt(tower, 6 + index);
				});
				updateGoldLabel();
			}
		}
	}
});
game.on('move', function (x, y, obj) {});
game.on('up', function (x, y, obj) {});
var cityWall2 = game.addChild(new CityWall());
cityWall2.y = 2432;
cityWall2.x = 365;
cityWall2.scale.y = 0.3;
cityWall2.scale.x = 0.4;
var cityWall3 = game.addChild(new CityWall());
cityWall3.y = 2432;
cityWall3.x = 1700;
cityWall3.scale.y = 0.3;
cityWall3.scale.x = 0.4;
var cityWall = game.addChild(new CityWall());
cityWall.y = 2432;
cityWall.x = 1035;
cityWall.scale.y = 0.3;
cityWall.scale.x = 0.5;
var bottomBlackBox = game.attachAsset('blackBox', {
	anchorY: 1
});
bottomBlackBox.width = 2720;
bottomBlackBox.height = 500;
bottomBlackBox.y = 2802;
bottomBlackBox.x = -630;
game.addChild(bottomBlackBox);
var goldLabel = new Text2('Presents: 30', {
	size: 100,
	fill: '#ffd700',
	align: 'left',
	//dropShadow: true
	stroke: '#000000',
	strokeThickness: 6
});
goldLabel.x = 120;
goldLabel.y = 2702 - bottomBlackBox.height + (bottomBlackBox.height - goldLabel.height) / 2;
game.addChild(goldLabel);
var scoreLabel = new Text2('Score: 0', {
	size: 100,
	fill: '#ccbbff',
	align: 'left',
	//dropShadow: true,
	stroke: '#000000',
	strokeThickness: 6
});
scoreLabel.x = 120;
scoreLabel.y = 2822 - bottomBlackBox.height + (bottomBlackBox.height - scoreLabel.height) / 2;
game.addChild(scoreLabel);
var instructionLabel = new Text2("Tap to build towers (cost 10 presents)\nDon't let enemies reach the wall!", {
	size: 58,
	fill: '#99bbff',
	align: 'left',
	stroke: '#000000',
	strokeThickness: 6
});
instructionLabel.x = 920;
instructionLabel.y = 2700 - bottomBlackBox.height + (bottomBlackBox.height - instructionLabel.height) / 2;
game.addChild(instructionLabel);
var treasureChest = game.addChild(new TreasureChest());
treasureChest.scale.x = 1.6;
treasureChest.scale.y = 1.6;
treasureChest.x = 820;
treasureChest.y = goldLabel.y + 65;
var upgradeButton = game.addChild(new UpgradeButton());
upgradeButton.x = 1500;
upgradeButton.y = 2590;
upgradeButton.scale.x = 1.2;
upgradeButton.scale.y = 1.2;
game.upgradeLabel = new Text2("Upgrade Towers:", {
	size: 58,
	fill: '#dddddd',
	align: 'left',
	//dropShadow: true
	stroke: '#000000',
	strokeThickness: 6
});
game.upgradeLabel.x = 920;
game.upgradeLabel.y = 2552;
game.addChild(game.upgradeLabel);
var costLabel = new Text2("Cost: 100", {
	size: 58,
	fill: '#dddd00',
	align: 'left',
	//dropShadow: true
	stroke: '#000000',
	strokeThickness: 6
});
costLabel.x = 1600;
costLabel.y = 2552;
game.addChild(costLabel);
var upgradeTowers = function upgradeTowers() {
	if (playerGold >= upgradeCost) {
		playerGold -= upgradeCost;
		upgradeLevel += 1;
		upgradeCost = Math.floor(upgradeCost * 1.5);
		updateGoldLabel();
		updateCostLabel();
		if (upgradeLevel == 8) {
			game.upgradeLabel.setText('All upgraded - Go for the High Score!');
			//if (upgradeButton) {
			upgradeButton.destroy();
			upgradeButton = null;
			//if (costLabel) {
			costLabel.destroy();
			costLabel = null;
		}
	}
};
upgradeButton.on('down', function (x, y, obj) {
	obj.event = obj;
	upgradeTowers(obj);
});
:quality(85)/https://cdn.frvr.ai/657eb31779171befc64d75bc.png%3F3) 
 A medieval wall built of ice blocks, with stars and christmas hearts as ornaments. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eb60c79171befc64d7603.png%3F3) 
 A wooden plan with snow on top edge. In game gui element. Flat front view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eb90bd8748ef19dd5d788.png%3F3) 
 A square metal button with the image of a tower. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eb9e5d8748ef19dd5d798.png%3F3) 
 A turret tower built of iceblocks. Front view perspective. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eba76d8748ef19dd5d7a2.png%3F3) 
 A snowball. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ebbe9d8748ef19dd5d7af.png%3F3) 
 A turret tower built of ice blocks. Front view perspective. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ebd31d8748ef19dd5d7ba.png%3F3) 
 A turret tower built of ice blocks. Front view perspective. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ebda9d8748ef19dd5d7c5.png%3F3) 
 A turret tower built of ice blocks. Front view perspective. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ebf5b4616f9300021d7eb.png%3F3) 
 A super awesome turret tower built of ice blocks. Front view perspective. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ec2e7b50352442fdf2d8a.png%3F3) 
 A turret tower constructed out of square ice blocks. Front view perspective. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eceb1ec1d3dc8d766e32d.png%3F3) 
 A pine cone. Pixelart. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ed2effaf61f5756b91dd8.png%3F3) 
 A terrible frost giant enemy sprite. Pixelart. Front view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ed4a2a9d6db759901dc59.png%3F3) 
 A frost orc enemy sprite. pixelart. front view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ed747c4cd1f0aba030498.png%3F3) 
 A winter goblin enemy character. Pixelart. front view. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ed83f201ddef3b9a0f483.png%3F3) 
 A winter horned ogre enemy character. pixelart. front view.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ee1231239705d7803d4d5.png%3F3) 
 A straw goat christmas decoration. Pixelart. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ee38c1239705d7803d52a.png%3F3) 
 A christmas tree. Pixelart. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ee6351abb081f821e4a04.png%3F3) 
 A golden star. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ee7481abb081f821e4a1d.png%3F3) 
 A gingerbread man. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ee9891abb081f821e4a5c.png%3F3) 
 a heart christmas decoration. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eeb501abb081f821e4a90.png%3F3) 
 a white christmas present with red wrapper. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eec7b1abb081f821e4aa5.png%3F3) 
 A candy cane. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657eecdd1abb081f821e4aaf.png%3F3) 
 A blue christmas present. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657ef1031abb081f821e4af2.png%3F3) 
 An open sack. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/657f014f1abc2fe20c1af975.png%3F3) 
 A snow covered plains stretching to horizon. Top down perspective view from afar. Rich winter colors. Illustration. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.