128 lines
4.4 KiB
JavaScript
128 lines
4.4 KiB
JavaScript
class Boss extends NPC {
|
|
constructor(scene, gridX, gridY) {
|
|
super(scene, gridX, gridY, scene.terrainOffsetX, scene.terrainOffsetY, 'boss');
|
|
this.maxHp = 500;
|
|
this.hp = this.maxHp;
|
|
this.moveSpeed = 70; // Slower than normal zombies
|
|
|
|
// Cooldowns
|
|
this.summonCooldown = 12000;
|
|
this.smashCooldown = 6000;
|
|
this.currentSkillTimer = 0;
|
|
}
|
|
|
|
createSprite() {
|
|
super.createSprite();
|
|
// Customize appearance
|
|
this.sprite.setScale(2.0); // Big Boss
|
|
this.sprite.setTint(0x6600cc); // Dark Purple
|
|
|
|
// Add a crown or something? (Text)
|
|
this.crown = this.scene.add.text(this.sprite.x, this.sprite.y - 80, '👑', { fontSize: '30px' });
|
|
this.crown.setOrigin(0.5);
|
|
this.crown.setDepth(this.sprite.depth + 100);
|
|
}
|
|
|
|
update(delta) {
|
|
super.update(delta);
|
|
|
|
// Update Crown position
|
|
if (this.crown && this.sprite) {
|
|
this.crown.setPosition(this.sprite.x, this.sprite.y - 80);
|
|
this.crown.setDepth(this.sprite.depth + 100);
|
|
}
|
|
|
|
if (this.state === 'CHASE' || this.state === 'WANDER') {
|
|
this.handleBossSkills(delta);
|
|
}
|
|
}
|
|
|
|
handleBossSkills(delta) {
|
|
if (!this.scene.player) return;
|
|
|
|
this.currentSkillTimer += delta;
|
|
|
|
const dist = Phaser.Math.Distance.Between(this.gridX, this.gridY, this.scene.player.gridX, this.scene.player.gridY);
|
|
|
|
// Smash Attack (AoE close range)
|
|
if (this.currentSkillTimer > this.smashCooldown && dist < 4) {
|
|
this.smashAttack();
|
|
this.currentSkillTimer = 0; // Reset timer partially? No, full reset for simpler logic
|
|
}
|
|
// Summon Minions (Long range or cooldown)
|
|
else if (this.currentSkillTimer > this.summonCooldown) {
|
|
this.summonMinions();
|
|
this.currentSkillTimer = 5000; // Give back some time so he doesn't wait full CD for smash
|
|
}
|
|
}
|
|
|
|
smashAttack() {
|
|
console.log('💥 BOSS SMASH!');
|
|
this.scene.cameras.main.shake(300, 0.01);
|
|
|
|
// Visual Warning
|
|
const warning = this.scene.add.circle(this.sprite.x, this.sprite.y, 150, 0xff0000, 0.4);
|
|
warning.setScale(0);
|
|
this.scene.tweens.add({
|
|
targets: warning,
|
|
scale: 1,
|
|
alpha: 0,
|
|
duration: 500,
|
|
onComplete: () => {
|
|
warning.destroy();
|
|
// Damage Logic
|
|
const playerPos = this.scene.player.getPosition();
|
|
const d = Phaser.Math.Distance.Between(this.sprite.x, this.sprite.y, playerPos.x, playerPos.y); // Pixel distance
|
|
if (d < 150) {
|
|
this.scene.player.takeDamage(30);
|
|
// Knockback
|
|
// todo
|
|
}
|
|
|
|
// Sound
|
|
if (this.scene.soundManager) this.scene.soundManager.playDeath(); // Placeholder for big boom
|
|
}
|
|
});
|
|
}
|
|
|
|
summonMinions() {
|
|
console.log('🧟🧟🧟 BOSS SUMMONS MINIONS!');
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
const angle = (Math.PI * 2 / 3) * i;
|
|
const dist = 3;
|
|
const sx = Math.floor(this.gridX + Math.cos(angle) * dist);
|
|
const sy = Math.floor(this.gridY + Math.sin(angle) * dist);
|
|
|
|
if (this.scene.terrainSystem.getTile(sx, sy)) {
|
|
// Spawn normal zombie
|
|
// We access GameScene's spawn method or create NPC directly
|
|
const zombie = new NPC(this.scene, sx, sy, this.scene.terrainOffsetX, this.scene.terrainOffsetY, 'zombie');
|
|
zombie.state = 'CHASE';
|
|
this.scene.npcs.push(zombie);
|
|
|
|
// Spawn Effect
|
|
if (this.scene.particleEffects) {
|
|
const iso = new IsometricUtils(48, 24);
|
|
const pos = iso.toScreen(sx, sy);
|
|
this.scene.particleEffects.bloodSplash(pos.x + 300, pos.y + 100); // hardcoded offset fix maybe needed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
if (this.crown) this.crown.destroy();
|
|
super.destroy();
|
|
|
|
// Boss Drops
|
|
if (this.scene.lootSystem) {
|
|
this.scene.lootSystem.spawnLoot(this.gridX, this.gridY, 'item_gold', 50);
|
|
this.scene.lootSystem.spawnLoot(this.gridX, this.gridY, 'item_sword', 1); // Rare drop
|
|
}
|
|
|
|
// Boss Death Event?
|
|
this.scene.events.emit('boss_killed');
|
|
}
|
|
}
|