Skip to content

Instantly share code, notes, and snippets.

@StringManolo
Created November 12, 2025 00:02
Show Gist options
  • Select an option

  • Save StringManolo/f420dc7a67edd55e6003d801af3173ed to your computer and use it in GitHub Desktop.

Select an option

Save StringManolo/f420dc7a67edd55e6003d801af3173ed to your computer and use it in GitHub Desktop.
Claude Sonnet 4.5
export class BattleScene extends Phaser.Scene {
constructor() {
super({ key: 'BattleScene' });
}
init(data) {
this.playerData = data.playerData || this.getDefaultPlayerStats();
this.onBattleEnd = data.onBattleEnd;
this.terrain = data.terrain;
}
preload() {
// Load battle backgrounds
this.load.image('battle_grass', 'assets/images/battles/battle_grass.png');
this.load.image('battle_forest', 'assets/images/battles/battle_forest.png');
this.load.image('battle_mountain', 'assets/images/battles/battle_mountain.png');
this.load.image('battle_dirt', 'assets/images/battles/battle_dirt.png');
// Load basic enemies
this.load.image('goat', 'assets/images/enemies/goat.png');
this.load.image('war_dwarf', 'assets/images/enemies/war_dwarf.png');
this.load.image('snake', 'assets/images/enemies/snake.png');
this.load.image('wolf', 'assets/images/enemies/wolf.png');
this.load.image('fly', 'assets/images/enemies/fly.png');
this.load.image('war_blob', 'assets/images/enemies/war_blob.png');
this.load.image('war_orc', 'assets/images/enemies/war_orc.png');
this.load.image('magic_demon', 'assets/images/enemies/magic_demon.png');
// High quality assets for warrior attack animation
this.load.image("warrior_basic_attack", "assets/images/battleAnimations/warrior_basic_1.png");
this.load.image("warrior_basic_attack_2", "assets/images/battleAnimations/warrior_basic_2.png");
this.load.image("warrior_basic_attack_3", "assets/images/battleAnimations/warrior_basic_3.png");
this.load.image("warrior_basic_attack_4", "assets/images/battleAnimations/warrior_basic_4.png");
// Sound effect for attack
this.load.audio("warrior_slash", "assets/audio/warrior_slash.wav");
// Battle music
this.load.audio("battle_music", "assets/audio/battle.mp3");
}
create() {
let backgroundKey = "battle_grass";
const terrainMap = {
'grass': 'battle_grass',
'forest': 'battle_forest',
'mountain': 'battle_mountain',
'path': 'battle_dirt',
'water': 'battle_grass'
};
if (this.terrain && terrainMap[this.terrain]) {
backgroundKey = terrainMap[this.terrain];
}
const background = this.add.image(400, 300, backgroundKey);
background.setDisplaySize(800, 600);
// Initialize combat system
this.initializeCombatants();
this.createUI();
this.createATBSystem();
// Play the battle music
this.sound.play('battle_music', { loop: true });
// Start ATB system
this.startATBSystem();
}
getDefaultPlayerStats() {
return {
name: 'Warrior',
level: 1,
maxHP: 100,
currentHP: 100,
maxMP: 50,
currentMP: 50,
attack: 15,
defense: 10,
magic: 8,
speed: 10,
items: [
{ name: 'Potion', effect: 'heal', value: 30, count: 3 },
{ name: 'Ether', effect: 'restore_mp', value: 20, count: 2 }
]
};
}
initializeCombatants() {
// Load enemy configuration
this.enemyConfig = this.getEnemyForTerrain(this.terrain);
// Create enemy stats
this.enemyStats = {
name: this.enemyConfig.name,
level: this.enemyConfig.level,
maxHP: this.enemyConfig.maxHP,
currentHP: this.enemyConfig.maxHP,
attack: this.enemyConfig.attack,
defense: this.enemyConfig.defense,
magic: this.enemyConfig.magic,
speed: this.enemyConfig.speed,
exp: this.enemyConfig.exp,
gold: this.enemyConfig.gold
};
// Create enemy sprite
this.enemy = this.add.image(550, 250, this.enemyConfig.key);
this.enemy.setDisplaySize(175, 175);
// Create warrior sprite
this.warrior = this.add.sprite(250, 400, 'warrior_basic_attack');
this.warrior.setOrigin(0.5, 1);
this.warrior.setDisplaySize(175, 175);
this.warrior.setDepth(2);
// ATB gauges
this.playerATB = 0;
this.enemyATB = 0;
this.atbMax = 100;
this.atbSpeed = 1;
// Combat state
this.isPlayerTurn = false;
this.isEnemyTurn = false;
this.battleActive = true;
this.isAnimating = false;
this.menuOpen = false;
}
createUI() {
// Player HP/MP display
this.playerUIBg = this.add.rectangle(150, 520, 280, 100, 0x000000, 0.7);
this.playerUIBg.setOrigin(0, 0);
this.playerNameText = this.add.text(160, 530, this.playerData.name, {
fontSize: '18px',
fill: '#fff',
fontStyle: 'bold'
});
this.playerHPText = this.add.text(160, 555,
`HP: ${this.playerData.currentHP}/${this.playerData.maxHP}`, {
fontSize: '16px',
fill: '#fff'
});
this.playerMPText = this.add.text(160, 580,
`MP: ${this.playerData.currentMP}/${this.playerData.maxMP}`, {
fontSize: '16px',
fill: '#fff'
});
// Player HP bar
this.playerHPBarBg = this.add.rectangle(280, 558, 130, 12, 0x333333);
this.playerHPBar = this.add.rectangle(280, 558, 130, 12, 0x00ff00);
this.playerHPBar.setOrigin(0, 0.5);
this.playerHPBarBg.setOrigin(0, 0.5);
// Player MP bar
this.playerMPBarBg = this.add.rectangle(280, 583, 130, 12, 0x333333);
this.playerMPBar = this.add.rectangle(280, 583, 130, 12, 0x0088ff);
this.playerMPBar.setOrigin(0, 0.5);
this.playerMPBarBg.setOrigin(0, 0.5);
// Enemy HP display
this.enemyUIBg = this.add.rectangle(470, 140, 280, 80, 0x000000, 0.7);
this.enemyUIBg.setOrigin(0, 0);
this.enemyNameText = this.add.text(480, 150, this.enemyStats.name, {
fontSize: '18px',
fill: '#fff',
fontStyle: 'bold'
});
this.enemyHPText = this.add.text(480, 175,
`HP: ${this.enemyStats.currentHP}/${this.enemyStats.maxHP}`, {
fontSize: '16px',
fill: '#fff'
});
// Enemy HP bar
this.enemyHPBarBg = this.add.rectangle(600, 178, 130, 12, 0x333333);
this.enemyHPBar = this.add.rectangle(600, 178, 130, 12, 0xff0000);
this.enemyHPBar.setOrigin(0, 0.5);
this.enemyHPBarBg.setOrigin(0, 0.5);
// Player ATB gauge
this.playerATBText = this.add.text(160, 600, 'ATB', {
fontSize: '14px',
fill: '#ffff00'
});
this.playerATBBarBg = this.add.rectangle(200, 605, 210, 10, 0x333333);
this.playerATBBar = this.add.rectangle(200, 605, 0, 10, 0xffff00);
this.playerATBBar.setOrigin(0, 0.5);
this.playerATBBarBg.setOrigin(0, 0.5);
// Enemy ATB gauge
this.enemyATBText = this.add.text(480, 200, 'ATB', {
fontSize: '14px',
fill: '#ff8800'
});
this.enemyATBBarBg = this.add.rectangle(520, 205, 210, 10, 0x333333);
this.enemyATBBar = this.add.rectangle(520, 205, 0, 10, 0xff8800);
this.enemyATBBar.setOrigin(0, 0.5);
this.enemyATBBarBg.setOrigin(0, 0.5);
// Battle menu (initially hidden)
this.createBattleMenu();
}
createBattleMenu() {
// Main menu background
this.menuBg = this.add.rectangle(400, 480, 760, 200, 0x000033, 0.9);
this.menuBg.setOrigin(0.5, 0);
this.menuBg.setVisible(false);
// Main menu options
this.mainMenuOptions = ['Attack', 'Magic', 'Ability', 'Defend', 'Item', 'Flee'];
this.mainMenuButtons = [];
const startX = 60;
const startY = 500;
const spacing = 120;
this.mainMenuOptions.forEach((option, index) => {
const x = startX + (index % 3) * spacing + (Math.floor(index / 3) * 360);
const y = startY + Math.floor(index / 3) * 60;
const bg = this.add.rectangle(x, y, 110, 45, 0x0066cc, 0.8);
bg.setOrigin(0, 0);
bg.setInteractive();
const text = this.add.text(x + 55, y + 22, option, {
fontSize: '18px',
fill: '#fff',
fontStyle: 'bold'
}).setOrigin(0.5);
bg.on('pointerover', () => {
bg.setFillStyle(0x0088ff);
});
bg.on('pointerout', () => {
bg.setFillStyle(0x0066cc);
});
bg.on('pointerdown', () => {
this.handleMenuOption(option);
});
bg.setVisible(false);
text.setVisible(false);
this.mainMenuButtons.push({ bg, text, option });
});
// Submenu (for magic, abilities, items)
this.submenuBg = this.add.rectangle(400, 480, 760, 200, 0x001133, 0.95);
this.submenuBg.setOrigin(0.5, 0);
this.submenuBg.setVisible(false);
this.submenuTitle = this.add.text(400, 495, '', {
fontSize: '20px',
fill: '#ffff00',
fontStyle: 'bold'
}).setOrigin(0.5);
this.submenuTitle.setVisible(false);
this.submenuButtons = [];
this.createSubmenuButtons();
// Back button for submenu
this.backButton = this.add.rectangle(700, 640, 80, 35, 0xcc0000, 0.8);
this.backButton.setOrigin(0.5);
this.backButton.setInteractive();
this.backButtonText = this.add.text(700, 640, 'Back', {
fontSize: '16px',
fill: '#fff'
}).setOrigin(0.5);
this.backButton.on('pointerover', () => {
this.backButton.setFillStyle(0xff0000);
});
this.backButton.on('pointerout', () => {
this.backButton.setFillStyle(0xcc0000);
});
this.backButton.on('pointerdown', () => {
this.closeSubmenu();
});
this.backButton.setVisible(false);
this.backButtonText.setVisible(false);
}
createSubmenuButtons() {
const startX = 60;
const startY = 535;
const spacing = 180;
for (let i = 0; i < 12; i++) {
const x = startX + (i % 4) * spacing;
const y = startY + Math.floor(i / 4) * 45;
const bg = this.add.rectangle(x, y, 170, 40, 0x0066cc, 0.8);
bg.setOrigin(0, 0);
bg.setInteractive();
const text = this.add.text(x + 85, y + 20, '', {
fontSize: '16px',
fill: '#fff'
}).setOrigin(0.5);
bg.on('pointerover', () => {
bg.setFillStyle(0x0088ff);
});
bg.on('pointerout', () => {
bg.setFillStyle(0x0066cc);
});
bg.setVisible(false);
text.setVisible(false);
this.submenuButtons.push({ bg, text, data: null });
}
}
createATBSystem() {
this.atbTimer = this.time.addEvent({
delay: 50,
callback: this.updateATB,
callbackScope: this,
loop: true
});
}
startATBSystem() {
this.battleActive = true;
}
updateATB() {
if (!this.battleActive || this.isAnimating) return;
// Update player ATB
if (!this.isPlayerTurn && this.playerATB < this.atbMax) {
this.playerATB += this.atbSpeed * (this.playerData.speed / 10);
if (this.playerATB >= this.atbMax) {
this.playerATB = this.atbMax;
this.onPlayerTurnReady();
}
}
// Update enemy ATB
if (!this.isEnemyTurn && this.enemyATB < this.atbMax) {
this.enemyATB += this.atbSpeed * (this.enemyStats.speed / 10);
if (this.enemyATB >= this.atbMax) {
this.enemyATB = this.atbMax;
this.onEnemyTurnReady();
}
}
// Update ATB bars
this.updateATBBars();
}
updateATBBars() {
const playerWidth = (this.playerATB / this.atbMax) * 210;
const enemyWidth = (this.enemyATB / this.atbMax) * 210;
this.playerATBBar.setSize(playerWidth, 10);
this.enemyATBBar.setSize(enemyWidth, 10);
}
onPlayerTurnReady() {
this.isPlayerTurn = true;
this.battleActive = false; // Pause ATB
this.showBattleMenu();
}
onEnemyTurnReady() {
this.isEnemyTurn = true;
this.battleActive = false; // Pause ATB
this.time.delayedCall(500, () => {
this.executeEnemyAction();
});
}
showBattleMenu() {
this.menuOpen = true;
this.menuBg.setVisible(true);
this.mainMenuButtons.forEach(btn => {
btn.bg.setVisible(true);
btn.text.setVisible(true);
});
}
hideBattleMenu() {
this.menuOpen = false;
this.menuBg.setVisible(false);
this.mainMenuButtons.forEach(btn => {
btn.bg.setVisible(false);
btn.text.setVisible(false);
});
}
handleMenuOption(option) {
switch(option) {
case 'Attack':
this.hideBattleMenu();
this.executePlayerAttack();
break;
case 'Magic':
this.showMagicMenu();
break;
case 'Ability':
this.showAbilityMenu();
break;
case 'Defend':
this.hideBattleMenu();
this.executeDefend();
break;
case 'Item':
this.showItemMenu();
break;
case 'Flee':
this.hideBattleMenu();
this.attemptFlee();
break;
}
}
showMagicMenu() {
this.hideBattleMenu();
this.submenuBg.setVisible(true);
this.submenuTitle.setText('Magic');
this.submenuTitle.setVisible(true);
this.backButton.setVisible(true);
this.backButtonText.setVisible(true);
const magicSpells = [
{ name: 'Fire', cost: 8, damage: 25, type: 'damage' },
{ name: 'Ice', cost: 8, damage: 25, type: 'damage' },
{ name: 'Thunder', cost: 10, damage: 30, type: 'damage' },
{ name: 'Cure', cost: 12, heal: 40, type: 'heal' }
];
magicSpells.forEach((spell, index) => {
if (index < this.submenuButtons.length) {
const btn = this.submenuButtons[index];
const canUse = this.playerData.currentMP >= spell.cost;
btn.text.setText(`${spell.name} (${spell.cost} MP)`);
btn.text.setColor(canUse ? '#fff' : '#666');
btn.bg.setVisible(true);
btn.text.setVisible(true);
btn.data = spell;
btn.bg.removeAllListeners('pointerdown');
btn.bg.on('pointerdown', () => {
if (canUse) {
this.closeSubmenu();
this.executeMagic(spell);
}
});
}
});
// Hide unused buttons
for (let i = magicSpells.length; i < this.submenuButtons.length; i++) {
this.submenuButtons[i].bg.setVisible(false);
this.submenuButtons[i].text.setVisible(false);
}
}
showAbilityMenu() {
this.hideBattleMenu();
this.submenuBg.setVisible(true);
this.submenuTitle.setText('Abilities');
this.submenuTitle.setVisible(true);
this.backButton.setVisible(true);
this.backButtonText.setVisible(true);
const abilities = [
{ name: 'Power Strike', cost: 0, damageMultiplier: 1.5 },
{ name: 'Double Attack', cost: 0, hits: 2 }
];
abilities.forEach((ability, index) => {
if (index < this.submenuButtons.length) {
const btn = this.submenuButtons[index];
btn.text.setText(ability.name);
btn.text.setColor('#fff');
btn.bg.setVisible(true);
btn.text.setVisible(true);
btn.data = ability;
btn.bg.removeAllListeners('pointerdown');
btn.bg.on('pointerdown', () => {
this.closeSubmenu();
this.executeAbility(ability);
});
}
});
for (let i = abilities.length; i < this.submenuButtons.length; i++) {
this.submenuButtons[i].bg.setVisible(false);
this.submenuButtons[i].text.setVisible(false);
}
}
showItemMenu() {
this.hideBattleMenu();
this.submenuBg.setVisible(true);
this.submenuTitle.setText('Items');
this.submenuTitle.setVisible(true);
this.backButton.setVisible(true);
this.backButtonText.setVisible(true);
const items = this.playerData.items || [];
items.forEach((item, index) => {
if (index < this.submenuButtons.length && item.count > 0) {
const btn = this.submenuButtons[index];
btn.text.setText(`${item.name} (${item.count})`);
btn.text.setColor('#fff');
btn.bg.setVisible(true);
btn.text.setVisible(true);
btn.data = item;
btn.bg.removeAllListeners('pointerdown');
btn.bg.on('pointerdown', () => {
this.closeSubmenu();
this.useItem(item);
});
}
});
for (let i = items.length; i < this.submenuButtons.length; i++) {
this.submenuButtons[i].bg.setVisible(false);
this.submenuButtons[i].text.setVisible(false);
}
}
closeSubmenu() {
this.submenuBg.setVisible(false);
this.submenuTitle.setVisible(false);
this.backButton.setVisible(false);
this.backButtonText.setVisible(false);
this.submenuButtons.forEach(btn => {
btn.bg.setVisible(false);
btn.text.setVisible(false);
btn.bg.removeAllListeners('pointerdown');
});
this.showBattleMenu();
}
executePlayerAttack() {
this.isAnimating = true;
this.startAttack(() => {
const damage = this.calculateDamage(this.playerData.attack, this.enemyStats.defense);
this.damageEnemy(damage);
this.endPlayerTurn();
});
}
executeMagic(spell) {
this.isAnimating = true;
this.playerData.currentMP -= spell.cost;
this.updatePlayerUI();
if (spell.type === 'damage') {
const damage = spell.damage + Math.floor(this.playerData.magic * 1.5);
this.showFloatingText(this.enemy.x, this.enemy.y - 100, spell.name, '#00ffff');
this.time.delayedCall(500, () => {
this.damageEnemy(damage);
this.endPlayerTurn();
});
} else if (spell.type === 'heal') {
this.playerData.currentHP = Math.min(
this.playerData.currentHP + spell.heal,
this.playerData.maxHP
);
this.updatePlayerUI();
this.showFloatingText(this.warrior.x, this.warrior.y - 100, `+${spell.heal}`, '#00ff00');
this.time.delayedCall(1000, () => {
this.endPlayerTurn();
});
}
}
executeAbility(ability) {
this.isAnimating = true;
if (ability.damageMultiplier) {
this.startAttack(() => {
const damage = Math.floor(
this.calculateDamage(this.playerData.attack, this.enemyStats.defense) * ability.damageMultiplier
);
this.damageEnemy(damage);
this.endPlayerTurn();
});
} else if (ability.hits) {
let hitCount = 0;
const executeHit = () => {
this.startAttack(() => {
const damage = this.calculateDamage(this.playerData.attack, this.enemyStats.defense);
this.damageEnemy(damage);
hitCount++;
if (hitCount < ability.hits && this.enemyStats.currentHP > 0) {
this.time.delayedCall(300, executeHit);
} else {
this.endPlayerTurn();
}
});
};
executeHit();
}
}
executeDefend() {
this.isAnimating = true;
this.playerDefending = true;
this.showFloatingText(this.warrior.x, this.warrior.y - 100, 'Defend', '#ffff00');
this.time.delayedCall(1000, () => {
this.endPlayerTurn();
});
}
useItem(item) {
this.isAnimating = true;
item.count--;
if (item.effect === 'heal') {
this.playerData.currentHP = Math.min(
this.playerData.currentHP + item.value,
this.playerData.maxHP
);
this.updatePlayerUI();
this.showFloatingText(this.warrior.x, this.warrior.y - 100, `+${item.value} HP`, '#00ff00');
} else if (item.effect === 'restore_mp') {
this.playerData.currentMP = Math.min(
this.playerData.currentMP + item.value,
this.playerData.maxMP
);
this.updatePlayerUI();
this.showFloatingText(this.warrior.x, this.warrior.y - 100, `+${item.value} MP`, '#0088ff');
}
this.time.delayedCall(1000, () => {
this.endPlayerTurn();
});
}
attemptFlee() {
this.isAnimating = true;
const fleeChance = 0.5;
if (Math.random() < fleeChance) {
this.showFloatingText(400, 300, 'Escaped!', '#ffff00');
this.time.delayedCall(1500, () => {
this.endBattle(false, true);
});
} else {
this.showFloatingText(400, 300, 'Could not escape!', '#ff0000');
this.time.delayedCall(1500, () => {
this.endPlayerTurn();
});
}
}
startAttack(onComplete) {
const originalX = this.warrior.x;
const originalY = this.warrior.y;
this.tweens.add({
targets: this.warrior,
x: this.enemy.x - 80,
y: this.enemy.y + 50,
displayWidth: 175 * 0.7,
displayHeight: 175 * 0.7,
duration: 200,
onComplete: () => {
this.warrior.setTexture('warrior_basic_attack_2');
this.time.delayedCall(25, () => {
this.warrior.setTexture('warrior_basic_attack_3');
this.sound.play('warrior_slash', { volume: 0.8 });
this.time.delayedCall(20, () => {
this.warrior.setTexture('warrior_basic_attack_4');
this.time.delayedCall(60, () => {
this.warrior.setTexture('warrior_basic_attack');
this.tweens.add({
targets: this.warrior,
x: originalX,
y: originalY,
displayWidth: 175,
displayHeight: 175,
duration: 200,
onComplete: () => {
if (onComplete) onComplete();
}
});
});
});
});
}
});
}
executeEnemyAction() {
this.isAnimating = true;
const action = Math.random();
if (action < 0.7) {
// Normal attack
const damage = this.calculateDamage(this.enemyStats.attack, this.playerData.defense);
const finalDamage = this.playerDefending ? Math.floor(damage * 0.5) : damage;
this.playerDefending = false;
this.damagePlayer(finalDamage);
this.time.delayedCall(1500, () => {
this.endEnemyTurn();
});
} else {
// Special attack
const damage = Math.floor(this.calculateDamage(this.enemyStats.attack, this.playerData.defense) * 1.5);
this.showFloatingText(this.warrior.x, this.warrior.y - 100, 'Special!', '#ff00ff');
this.time.delayedCall(500, () => {
this.damagePlayer(damage);
this.time.delayedCall(1500, () => {
this.endEnemyTurn();
});
});
}
}
calculateDamage(attack, defense) {
const baseDamage = attack - Math.floor(defense / 2);
const variance = Math.floor(baseDamage * 0.2);
return Math.max(1, baseDamage + Math.floor(Math.random() * variance * 2) - variance);
}
damageEnemy(damage) {
this.enemyStats.currentHP = Math.max(0, this.enemyStats.currentHP - damage);
this.updateEnemyUI();
this.showFloatingText(this.enemy.x, this.enemy.y - 50, `-${damage}`, '#ff0000');
// Flash enemy
this.tweens.add({
targets: this.enemy,
alpha: 0.3,
duration: 100,
yoyo: true,
repeat: 2
});
if (this.enemyStats.currentHP <= 0) {
this.time.delayedCall(1000, () => {
this.endBattle(true);
});
}
}
damagePlayer(damage) {
this.playerData.currentHP = Math.max(0, this.playerData.currentHP - damage);
this.updatePlayerUI();
this.showFloatingText(this.warrior.x, this.warrior.y - 50, `-${damage}`, '#ff0000');
// Flash warrior
this.tweens.add({
targets: this.warrior,
alpha: 0.3,
duration: 100,
yoyo: true,
repeat: 2
});
if (this.playerData.currentHP <= 0) {
this.time.delayedCall(1000, () => {
this.endBattle(false);
});
}
}
showFloatingText(x, y, text, color) {
const floatingText = this.add.text(x, y, text, {
fontSize: '32px',
fill: color,
fontStyle: 'bold',
stroke: '#000',
strokeThickness: 4
}).setOrigin(0.5);
this.tweens.add({
targets: floatingText,
y: y - 80,
alpha: 0,
duration: 1500,
ease: 'Power2',
onComplete: () => {
floatingText.destroy();
}
});
}
updatePlayerUI() {
this.playerHPText.setText(`HP: ${this.playerData.currentHP}/${this.playerData.maxHP}`);
this.playerMPText.setText(`MP: ${this.playerData.currentMP}/${this.playerData.maxMP}`);
const hpPercent = this.playerData.currentHP / this.playerData.maxHP;
this.playerHPBar.setSize(130 * hpPercent, 12);
if (hpPercent > 0.5) {
this.playerHPBar.setFillStyle(0x00ff00);
} else if (hpPercent > 0.25) {
this.playerHPBar.setFillStyle(0xffff00);
} else {
this.playerHPBar.setFillStyle(0xff0000);
}
const mpPercent = this.playerData.currentMP / this.playerData.maxMP;
this.playerMPBar.setSize(130 * mpPercent, 12);
}
updateEnemyUI() {
this.enemyHPText.setText(`HP: ${this.enemyStats.currentHP}/${this.enemyStats.maxHP}`);
const hpPercent = this.enemyStats.currentHP / this.enemyStats.maxHP;
this.enemyHPBar.setSize(130 * hpPercent, 12);
if (hpPercent > 0.5) {
this.enemyHPBar.setFillStyle(0xff0000);
} else if (hpPercent > 0.25) {
this.enemyHPBar.setFillStyle(0xff8800);
} else {
this.enemyHPBar.setFillStyle(0xffff00);
}
}
endPlayerTurn() {
this.isPlayerTurn = false;
this.playerATB = 0;
this.isAnimating = false;
this.battleActive = true;
}
endEnemyTurn() {
this.isEnemyTurn = false;
this.enemyATB = 0;
this.isAnimating = false;
this.battleActive = true;
}
endBattle(victory, fled = false) {
this.battleActive = false;
this.sound.stopAll();
if (this.atbTimer) {
this.atbTimer.destroy();
}
let resultText = '';
let resultColor = '';
if (fled) {
resultText = 'Fled from battle!';
resultColor = '#ffff00';
} else if (victory) {
resultText = 'Victory!';
resultColor = '#00ff00';
} else {
resultText = 'Defeat...';
resultColor = '#ff0000';
}
const resultDisplay = this.add.text(400, 300, resultText, {
fontSize: '48px',
fill: resultColor,
fontStyle: 'bold',
stroke: '#000',
strokeThickness: 6
}).setOrigin(0.5);
resultDisplay.setAlpha(0);
this.tweens.add({
targets: resultDisplay,
alpha: 1,
duration: 500
});
this.time.delayedCall(2000, () => {
this.scene.stop();
if (this.onBattleEnd) {
this.onBattleEnd({
victory: victory,
fled: fled,
experience: victory ? this.enemyStats.exp : 0,
gold: victory ? this.enemyStats.gold : 0,
enemy: this.enemyStats.name,
playerData: this.playerData
});
}
});
}
getEnemyForTerrain(terrain) {
const enemyPools = {
'mountain': [
{
key: 'goat',
name: 'Mountain Goat',
weight: 35,
level: 3,
maxHP: 60,
attack: 12,
defense: 8,
magic: 3,
speed: 12,
exp: 45,
gold: 30
},
{
key: 'war_dwarf',
name: 'War Dwarf',
weight: 30,
level: 5,
maxHP: 90,
attack: 18,
defense: 15,
magic: 5,
speed: 8,
exp: 80,
gold: 60
},
{
key: 'war_blob',
name: 'War Blob',
weight: 20,
level: 6,
maxHP: 100,
attack: 15,
defense: 12,
magic: 8,
speed: 6,
exp: 90,
gold: 70
},
{
key: 'magic_demon',
name: 'Magic Demon',
weight: 5,
level: 10,
maxHP: 150,
attack: 25,
defense: 18,
magic: 20,
speed: 15,
exp: 200,
gold: 150
},
{
key: 'wolf',
name: 'Wolf',
weight: 10,
level: 4,
maxHP: 70,
attack: 16,
defense: 9,
magic: 2,
speed: 14,
exp: 55,
gold: 40
}
],
'forest': [
{
key: 'snake',
name: 'Forest Snake',
weight: 40,
level: 2,
maxHP: 50,
attack: 10,
defense: 6,
magic: 4,
speed: 13,
exp: 35,
gold: 25
},
{
key: 'wolf',
name: 'Wolf',
weight: 35,
level: 4,
maxHP: 70,
attack: 16,
defense: 9,
magic: 2,
speed: 14,
exp: 55,
gold: 40
},
{
key: 'fly',
name: 'Giant Fly',
weight: 15,
level: 3,
maxHP: 55,
attack: 11,
defense: 7,
magic: 3,
speed: 16,
exp: 40,
gold: 30
},
{
key: 'magic_demon',
name: 'Magic Demon',
weight: 5,
level: 10,
maxHP: 150,
attack: 25,
defense: 18,
magic: 20,
speed: 15,
exp: 200,
gold: 150
},
{
key: 'war_orc',
name: 'Forest Orc',
weight: 5,
level: 7,
maxHP: 110,
attack: 20,
defense: 14,
magic: 6,
speed: 9,
exp: 100,
gold: 80
}
],
'grass': [
{
key: 'fly',
name: 'Giant Fly',
weight: 40,
level: 3,
maxHP: 55,
attack: 11,
defense: 7,
magic: 3,
speed: 16,
exp: 40,
gold: 30
},
{
key: 'wolf',
name: 'Wolf',
weight: 30,
level: 4,
maxHP: 70,
attack: 16,
defense: 9,
magic: 2,
speed: 14,
exp: 55,
gold: 40
},
{
key: 'snake',
name: 'Snake',
weight: 15,
level: 2,
maxHP: 50,
attack: 10,
defense: 6,
magic: 4,
speed: 13,
exp: 35,
gold: 25
},
{
key: 'magic_demon',
name: 'Magic Demon',
weight: 5,
level: 10,
maxHP: 150,
attack: 25,
defense: 18,
magic: 20,
speed: 15,
exp: 200,
gold: 150
},
{
key: 'goat',
name: 'Goat',
weight: 10,
level: 3,
maxHP: 60,
attack: 12,
defense: 8,
magic: 3,
speed: 12,
exp: 45,
gold: 30
}
],
'path': [
{
key: 'war_orc',
name: 'Orc Warrior',
weight: 40,
level: 7,
maxHP: 110,
attack: 20,
defense: 14,
magic: 6,
speed: 9,
exp: 100,
gold: 80
},
{
key: 'fly',
name: 'Giant Fly',
weight: 25,
level: 3,
maxHP: 55,
attack: 11,
defense: 7,
magic: 3,
speed: 16,
exp: 40,
gold: 30
},
{
key: 'wolf',
name: 'Wolf',
weight: 20,
level: 4,
maxHP: 70,
attack: 16,
defense: 9,
magic: 2,
speed: 14,
exp: 55,
gold: 40
},
{
key: 'magic_demon',
name: 'Magic Demon',
weight: 5,
level: 10,
maxHP: 150,
attack: 25,
defense: 18,
magic: 20,
speed: 15,
exp: 200,
gold: 150
},
{
key: 'snake',
name: 'Snake',
weight: 10,
level: 2,
maxHP: 50,
attack: 10,
defense: 6,
magic: 4,
speed: 13,
exp: 35,
gold: 25
}
],
'water': [
{
key: 'fly',
name: 'Giant Fly',
weight: 40,
level: 3,
maxHP: 55,
attack: 11,
defense: 7,
magic: 3,
speed: 16,
exp: 40,
gold: 30
},
{
key: 'snake',
name: 'Water Snake',
weight: 30,
level: 2,
maxHP: 50,
attack: 10,
defense: 6,
magic: 4,
speed: 13,
exp: 35,
gold: 25
},
{
key: 'magic_demon',
name: 'Magic Demon',
weight: 10,
level: 10,
maxHP: 150,
attack: 25,
defense: 18,
magic: 20,
speed: 15,
exp: 200,
gold: 150
},
{
key: 'wolf',
name: 'Wolf',
weight: 20,
level: 4,
maxHP: 70,
attack: 16,
defense: 9,
magic: 2,
speed: 14,
exp: 55,
gold: 40
}
]
};
const pool = enemyPools[terrain] || enemyPools['grass'];
return this.selectRandomEnemy(pool);
}
selectRandomEnemy(enemyPool) {
const totalWeight = enemyPool.reduce((sum, enemy) => sum + enemy.weight, 0);
let random = Math.random() * totalWeight;
let weightSum = 0;
for (const enemy of enemyPool) {
weightSum += enemy.weight;
if (random <= weightSum) {
return enemy;
}
}
return enemyPool[0];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment