/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Attack class (for both player and enemy)
var Attack = Container.expand(function () {
	var self = Container.call(this);
	// type: 'basic', 'special', 'enemy'
	self.type = 'basic';
	self.owner = null; // player or enemy
	self.dmg = 10;
	self.speed = 30;
	self.radius = 30;
	self.dirY = -1; // -1 up, 1 down
	// Attach asset
	self.setType = function (type) {
		self.type = type;
		if (type === 'basic') {
			self.removeChildren();
			self.attachAsset('attack_basic', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			self.dmg = 10;
			self.speed = 36;
			self.radius = 30;
			self.dirY = -1;
		} else if (type === 'special') {
			self.removeChildren();
			self.attachAsset('attack_special', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			self.dmg = 22;
			self.speed = 24;
			self.radius = 40;
			self.dirY = -1;
		} else if (type === 'enemy') {
			self.removeChildren();
			self.attachAsset('attack_enemy', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			self.dmg = 12;
			self.speed = 28;
			self.radius = 30;
			self.dirY = 1;
		}
	};
	// Update
	self.update = function () {
		self.y += self.speed * self.dirY;
	};
	return self;
});
// Enemy Pokemon class (AI)
var EnemyPokemon = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy asset
	var sprite = self.attachAsset('poke_enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Stats
	self.maxHP = 100;
	self.hp = 100;
	self.speed = 12; // px per move
	self.radius = sprite.width / 2;
	// For attack cooldowns
	self.basicCooldown = 0;
	self.specialCooldown = 0;
	// For invulnerability after hit
	self.invuln = 0;
	// Move to (x, y) with bounds
	self.moveTo = function (x, y) {
		// Clamp to arena bounds (leave 20px margin)
		var minX = 20 + self.radius;
		var maxX = 2048 - 20 - self.radius;
		var minY = 20 + self.radius;
		var maxY = 1366 - 20 - self.radius; // top half
		self.x = Math.max(minX, Math.min(maxX, x));
		self.y = Math.max(minY, Math.min(maxY, y));
	};
	// Take damage
	self.takeDamage = function (dmg) {
		if (self.invuln > 0) return;
		self.hp -= dmg;
		if (self.hp < 0) self.hp = 0;
		self.invuln = 30; // 0.5s invuln
		LK.effects.flashObject(self, 0xffffff, 200);
	};
	return self;
});
// Player Pokemon class
var PlayerPokemon = Container.expand(function () {
	var self = Container.call(this);
	// Attach player asset
	var sprite = self.attachAsset('poke_player', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Stats
	self.maxHP = 100;
	self.hp = 100;
	self.speed = 18; // px per move
	self.radius = sprite.width / 2;
	// For drag
	self.isDragging = false;
	// For attack cooldowns
	self.basicCooldown = 0;
	self.specialCooldown = 0;
	// For invulnerability after hit
	self.invuln = 0;
	// Move to (x, y) with bounds
	self.moveTo = function (x, y) {
		// Clamp to arena bounds (leave 20px margin)
		var minX = 20 + self.radius;
		var maxX = 2048 - 20 - self.radius;
		var minY = 1366 + 20 + self.radius; // bottom half
		var maxY = 2732 - 20 - self.radius;
		self.x = Math.max(minX, Math.min(maxX, x));
		self.y = Math.max(minY, Math.min(maxY, y));
	};
	// Take damage
	self.takeDamage = function (dmg) {
		if (self.invuln > 0) return;
		self.hp -= dmg;
		if (self.hp < 0) self.hp = 0;
		self.invuln = 30; // 0.5s invuln
		LK.effects.flashObject(self, 0xffffff, 200);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xf5f5f5
});
/**** 
* Game Code
****/ 
// Attack SFX
// Pokemon shapes (simple for MVP)
// Arena background
var arenaBg = LK.getAsset('arena_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
});
game.addChild(arenaBg);
// Player and enemy
var player = new PlayerPokemon();
var enemy = new EnemyPokemon();
game.addChild(player);
game.addChild(enemy);
// Initial positions
player.moveTo(2048 / 2, 2732 - 300);
enemy.moveTo(2048 / 2, 300);
// HP bars
var playerHpBg = LK.getAsset('hp_bar_bg', {
	anchorX: 0,
	anchorY: 0.5,
	x: 100,
	y: 2732 - 100
});
var playerHpFg = LK.getAsset('hp_bar_fg', {
	anchorX: 0,
	anchorY: 0.5,
	x: 100,
	y: 2732 - 100
});
game.addChild(playerHpBg);
game.addChild(playerHpFg);
var enemyHpBg = LK.getAsset('hp_bar_bg', {
	anchorX: 0,
	anchorY: 0.5,
	x: 100,
	y: 100
});
var enemyHpFg = LK.getAsset('hp_bar_fg_enemy', {
	anchorX: 0,
	anchorY: 0.5,
	x: 100,
	y: 100
});
game.addChild(enemyHpBg);
game.addChild(enemyHpFg);
// HP text
var playerHpTxt = new Text2('100/100', {
	size: 60,
	fill: "#222"
});
playerHpTxt.anchor.set(0, 0.5);
playerHpTxt.x = 520;
playerHpTxt.y = 2732 - 100;
game.addChild(playerHpTxt);
var enemyHpTxt = new Text2('100/100', {
	size: 60,
	fill: "#222"
});
enemyHpTxt.anchor.set(0, 0.5);
enemyHpTxt.x = 520;
enemyHpTxt.y = 100;
game.addChild(enemyHpTxt);
// Attack buttons (GUI)
var atkBtn = new Text2('Attack', {
	size: 90,
	fill: "#fff"
});
atkBtn.anchor.set(0.5, 0.5);
atkBtn.x = 2048 / 2 - 200;
atkBtn.y = 2732 - 220;
atkBtn.bg = LK.getAsset('hp_bar_bg', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: atkBtn.x,
	y: atkBtn.y,
	width: 260,
	height: 120
});
game.addChild(atkBtn.bg);
game.addChild(atkBtn);
var spcBtn = new Text2('Special', {
	size: 90,
	fill: "#fff"
});
spcBtn.anchor.set(0.5, 0.5);
spcBtn.x = 2048 / 2 + 200;
spcBtn.y = 2732 - 220;
spcBtn.bg = LK.getAsset('hp_bar_bg', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: spcBtn.x,
	y: spcBtn.y,
	width: 260,
	height: 120
});
game.addChild(spcBtn.bg);
game.addChild(spcBtn);
// Attack cooldown overlays
var atkBtnCd = LK.getAsset('hp_bar_fg', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: atkBtn.x,
	y: atkBtn.y,
	width: 260,
	height: 120
});
atkBtnCd.alpha = 0.5;
game.addChild(atkBtnCd);
atkBtnCd.visible = false;
var spcBtnCd = LK.getAsset('hp_bar_fg_enemy', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: spcBtn.x,
	y: spcBtn.y,
	width: 260,
	height: 120
});
spcBtnCd.alpha = 0.5;
game.addChild(spcBtnCd);
spcBtnCd.visible = false;
// Attacks array
var attacks = [];
var enemyAttacks = [];
// Dragging
var dragNode = null;
// Touch/move handlers
function handleMove(x, y, obj) {
	// Drag player
	if (dragNode === player) {
		player.moveTo(x, y);
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// If on attack button
	// Manual bounds check for attack button (fixes Script error)
	if (x >= atkBtn.bg.x - atkBtn.bg.width / 2 && x <= atkBtn.bg.x + atkBtn.bg.width / 2 && y >= atkBtn.bg.y - atkBtn.bg.height / 2 && y <= atkBtn.bg.y + atkBtn.bg.height / 2) {
		// Fire basic attack if not on cooldown
		if (player.basicCooldown <= 0) {
			var atk = new Attack();
			atk.setType('basic');
			atk.owner = 'player';
			atk.x = player.x;
			atk.y = player.y - player.radius - 40;
			attacks.push(atk);
			game.addChild(atk);
			player.basicCooldown = 30; // 0.5s
			LK.getSound('atk_basic').play();
		}
		return;
	}
	// Manual bounds check for special button (fixes Script error)
	if (x >= spcBtn.bg.x - spcBtn.bg.width / 2 && x <= spcBtn.bg.x + spcBtn.bg.width / 2 && y >= spcBtn.bg.y - spcBtn.bg.height / 2 && y <= spcBtn.bg.y + spcBtn.bg.height / 2) {
		// Fire special attack if not on cooldown
		if (player.specialCooldown <= 0) {
			var atk = new Attack();
			atk.setType('special');
			atk.owner = 'player';
			atk.x = player.x;
			atk.y = player.y - player.radius - 40;
			attacks.push(atk);
			game.addChild(atk);
			player.specialCooldown = 120; // 2s
			LK.getSound('atk_special').play();
		}
		return;
	}
	// If on player, start drag
	var local = player.toLocal({
		x: x,
		y: y
	});
	if (local.x * local.x + local.y * local.y <= player.radius * player.radius) {
		dragNode = player;
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// Helper: collision between two circles
function circlesCollide(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	return dist < a.radius + b.radius - 10;
}
// AI logic
function enemyAI() {
	// Move towards player x
	var dx = player.x - enemy.x;
	if (Math.abs(dx) > 10) {
		var dir = dx > 0 ? 1 : -1;
		enemy.moveTo(enemy.x + dir * enemy.speed, enemy.y);
	}
	// Randomly fire attack
	if (enemy.basicCooldown <= 0 && Math.random() < 0.04) {
		var atk = new Attack();
		atk.setType('enemy');
		atk.owner = 'enemy';
		atk.x = enemy.x;
		atk.y = enemy.y + enemy.radius + 40;
		enemyAttacks.push(atk);
		game.addChild(atk);
		enemy.basicCooldown = 36 + Math.floor(Math.random() * 24); // 0.6-1s
		LK.getSound('atk_enemy').play();
	}
	// Special attack less often
	if (enemy.specialCooldown <= 0 && Math.random() < 0.01) {
		var atk = new Attack();
		atk.setType('enemy');
		atk.owner = 'enemy';
		atk.dmg = 22;
		atk.speed = 20;
		atk.radius = 40;
		atk.x = enemy.x;
		atk.y = enemy.y + enemy.radius + 40;
		enemyAttacks.push(atk);
		game.addChild(atk);
		enemy.specialCooldown = 120 + Math.floor(Math.random() * 60);
		LK.getSound('atk_enemy').play();
	}
}
// Main update
game.update = function () {
	// Cooldowns
	if (player.basicCooldown > 0) player.basicCooldown--;
	if (player.specialCooldown > 0) player.specialCooldown--;
	if (player.invuln > 0) player.invuln--;
	if (enemy.basicCooldown > 0) enemy.basicCooldown--;
	if (enemy.specialCooldown > 0) enemy.specialCooldown--;
	if (enemy.invuln > 0) enemy.invuln--;
	// Update attack cooldown overlays
	atkBtnCd.visible = player.basicCooldown > 0;
	if (atkBtnCd.visible) {
		atkBtnCd.width = 260 * (player.basicCooldown / 30);
	}
	spcBtnCd.visible = player.specialCooldown > 0;
	if (spcBtnCd.visible) {
		spcBtnCd.width = 260 * (player.specialCooldown / 120);
	}
	// Update attacks
	for (var i = attacks.length - 1; i >= 0; i--) {
		var atk = attacks[i];
		atk.update();
		// Remove if off screen
		if (atk.y < -100) {
			atk.destroy();
			attacks.splice(i, 1);
			continue;
		}
		// Hit enemy
		if (circlesCollide(atk, enemy) && enemy.hp > 0) {
			enemy.takeDamage(atk.dmg);
			atk.destroy();
			attacks.splice(i, 1);
			continue;
		}
	}
	for (var i = enemyAttacks.length - 1; i >= 0; i--) {
		var atk = enemyAttacks[i];
		atk.update();
		// Remove if off screen
		if (atk.y > 2732 + 100) {
			atk.destroy();
			enemyAttacks.splice(i, 1);
			continue;
		}
		// Hit player
		if (circlesCollide(atk, player) && player.hp > 0) {
			player.takeDamage(atk.dmg);
			atk.destroy();
			enemyAttacks.splice(i, 1);
			continue;
		}
	}
	// Enemy AI
	if (enemy.hp > 0) {
		enemyAI();
	}
	// Update HP bars
	playerHpFg.width = 400 * (player.hp / player.maxHP);
	playerHpTxt.setText(player.hp + '/' + player.maxHP);
	enemyHpFg.width = 400 * (enemy.hp / enemy.maxHP);
	enemyHpTxt.setText(enemy.hp + '/' + enemy.maxHP);
	// Win/lose
	if (player.hp <= 0) {
		LK.effects.flashScreen(0xe53935, 800);
		LK.showGameOver();
		return;
	}
	if (enemy.hp <= 0) {
		LK.effects.flashScreen(0x4caf50, 800);
		LK.setScore(1);
		LK.showYouWin();
		return;
	}
};
// GUI: show player and enemy names
var playerName = new Text2('You', {
	size: 60,
	fill: 0x3B4CCA
});
playerName.anchor.set(0, 1);
playerName.x = 100;
playerName.y = 2732 - 160;
game.addChild(playerName);
var enemyName = new Text2('Enemy', {
	size: 60,
	fill: 0xE53935
});
enemyName.anchor.set(0, 0);
enemyName.x = 100;
enemyName.y = 160;
game.addChild(enemyName);
// Center arena (no scrolling, so nothing to do) ===================================================================
--- original.js
+++ change.js
@@ -282,12 +282,10 @@
 }
 game.move = handleMove;
 game.down = function (x, y, obj) {
 	// If on attack button
-	if (atkBtn.bg.containsPoint({
-		x: x,
-		y: y
-	})) {
+	// Manual bounds check for attack button (fixes Script error)
+	if (x >= atkBtn.bg.x - atkBtn.bg.width / 2 && x <= atkBtn.bg.x + atkBtn.bg.width / 2 && y >= atkBtn.bg.y - atkBtn.bg.height / 2 && y <= atkBtn.bg.y + atkBtn.bg.height / 2) {
 		// Fire basic attack if not on cooldown
 		if (player.basicCooldown <= 0) {
 			var atk = new Attack();
 			atk.setType('basic');
@@ -300,12 +298,10 @@
 			LK.getSound('atk_basic').play();
 		}
 		return;
 	}
-	if (spcBtn.bg.containsPoint({
-		x: x,
-		y: y
-	})) {
+	// Manual bounds check for special button (fixes Script error)
+	if (x >= spcBtn.bg.x - spcBtn.bg.width / 2 && x <= spcBtn.bg.x + spcBtn.bg.width / 2 && y >= spcBtn.bg.y - spcBtn.bg.height / 2 && y <= spcBtn.bg.y + spcBtn.bg.height / 2) {
 		// Fire special attack if not on cooldown
 		if (player.specialCooldown <= 0) {
 			var atk = new Attack();
 			atk.setType('special');
 Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Pokémon PvP: Battle Arena" and with the description "A real-time 2D Pokémon battle game where players control a Pokémon, use attacks, dodge, and outlast their opponent in quick PvP matches.". No text on banner!
 Darkrai. In-Game asset. 2d. High contrast. No shadows
 Lickilicky. In-Game asset. 2d. High contrast. No shadows
 Dark ball. In-Game asset. 2d. High contrast. No shadows