feat(combat): add 'overwhelm' win condition with visual effects and result display
- Introduces `winType` field to track victory conditions (commander/depletion/overwhelm) - Implements `_overwhelmCheck()` logic to detect when one side exhausts all resources while the other retains combat capability - Adds `_animateOverwhelm()` sequence: banner, rally, strikes, HP drain, and commander defeat with shake/flash/particle effects - Updates `BattleResultScene` to show "VICTORY BY OVERWHELM!" / "OVERWHELMED" titles and annotate report accordingly
This commit is contained in:
parent
d1a5deb7ed
commit
3e8c4ab7b8
|
|
@ -219,21 +219,21 @@ export class BattleScene extends Phaser.Scene {
|
|||
this.playerGoesFirst = true;
|
||||
this.initiativeIndicator = null;
|
||||
|
||||
const autoBtn = this.add.rectangle(1680, 35, 180, 44, 0x224422)
|
||||
this.autoBtn = this.add.rectangle(1680, 35, 180, 44, 0x224422)
|
||||
.setInteractive({ useHandCursor: true })
|
||||
.setStrokeStyle(1, 0x44aa44);
|
||||
this.autoBtnText = this.add.text(1680, 35, 'Auto: OFF', {
|
||||
fontSize: '18px', color: '#ffffff', fontFamily: 'Audiowide'
|
||||
}).setOrigin(0.5);
|
||||
autoBtn.on('pointerdown', () => this._toggleAuto());
|
||||
this.autoBtn.on('pointerdown', () => this._toggleAuto());
|
||||
|
||||
const nextBtn = this.add.rectangle(1840, 35, 180, 44, 0x1a3a5c)
|
||||
this.nextBtn = this.add.rectangle(1840, 35, 180, 44, 0x1a3a5c)
|
||||
.setInteractive({ useHandCursor: true })
|
||||
.setStrokeStyle(1, 0x4488ff);
|
||||
this.add.text(1840, 35, 'Next Turn', {
|
||||
this.nextBtnText = this.add.text(1840, 35, 'Next Turn', {
|
||||
fontSize: '18px', color: '#ffffff', fontFamily: 'Audiowide'
|
||||
}).setOrigin(0.5);
|
||||
nextBtn.on('pointerdown', () => this._beginTurn());
|
||||
this.nextBtn.on('pointerdown', () => this._beginTurn());
|
||||
|
||||
// Keyboard
|
||||
this.input.keyboard.on('keydown-SPACE', () => this._beginTurn());
|
||||
|
|
@ -761,6 +761,7 @@ export class BattleScene extends Phaser.Scene {
|
|||
}
|
||||
|
||||
_beginTurn() {
|
||||
this._clearNextTurnHint();
|
||||
if (this._tutorialActive) return;
|
||||
if (this.waitingForPick || this.isAnimating) return;
|
||||
if (this.engine.winner) { this._showResult(); return; }
|
||||
|
|
@ -924,6 +925,7 @@ export class BattleScene extends Phaser.Scene {
|
|||
this._animateInitiativeHandoff();
|
||||
this.isAnimating = false;
|
||||
this.statusText.setText('Press SPACE or click Next Turn to advance');
|
||||
if (!this.autoPlay) this._startNextTurnHint();
|
||||
}
|
||||
});
|
||||
return;
|
||||
|
|
@ -4738,10 +4740,76 @@ export class BattleScene extends Phaser.Scene {
|
|||
});
|
||||
}
|
||||
|
||||
_startNextTurnHint() {
|
||||
this._clearNextTurnHint();
|
||||
const btnX = 1840, btnY = 35;
|
||||
|
||||
// After 2s: yellow arrow that bobs up and down below the Next Turn button
|
||||
this._nextTurnHintTimer1 = this.time.delayedCall(2000, () => {
|
||||
if (this.autoPlay || this.isAnimating || this.waitingForPick) return;
|
||||
this._nextTurnArrow = this.add.text(btnX, btnY + 50, '▲', {
|
||||
fontSize: '32px', color: '#ffdd00', fontFamily: 'Audiowide'
|
||||
}).setOrigin(0.5).setDepth(101);
|
||||
|
||||
this.tweens.add({
|
||||
targets: this._nextTurnArrow,
|
||||
y: { from: btnY + 44, to: btnY + 58 },
|
||||
duration: 450,
|
||||
yoyo: true,
|
||||
repeat: -1,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
});
|
||||
|
||||
// After 5s: dim the screen, lift the buttons above the overlay, show hint text
|
||||
this._nextTurnHintTimer2 = this.time.delayedCall(5000, () => {
|
||||
if (this.autoPlay || this.isAnimating || this.waitingForPick) return;
|
||||
|
||||
// Full-screen dim overlay
|
||||
const { width, height } = this.scale;
|
||||
this._nextTurnDim = this.add.rectangle(width / 2, height / 2, width, height, 0x000000, 0.55)
|
||||
.setDepth(98);
|
||||
|
||||
// Lift buttons above the dim
|
||||
this.autoBtn.setDepth(99);
|
||||
this.autoBtnText.setDepth(99);
|
||||
this.nextBtn.setDepth(99);
|
||||
this.nextBtnText.setDepth(99);
|
||||
|
||||
// Bring arrow above the dim too
|
||||
if (this._nextTurnArrow) this._nextTurnArrow.setDepth(101);
|
||||
|
||||
// Hint text — right-aligned so it stays within the screen
|
||||
this._nextTurnHintLabel = this.add.text(1910, btnY + 95, "Click 'Next' to begin the next turn", {
|
||||
fontSize: '16px', color: '#ffffff', fontFamily: 'Audiowide'
|
||||
}).setOrigin(1, 0.5).setDepth(101);
|
||||
|
||||
this.tweens.add({
|
||||
targets: this._nextTurnHintLabel,
|
||||
alpha: { from: 1, to: 0.3 },
|
||||
duration: 800,
|
||||
yoyo: true,
|
||||
repeat: -1
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_clearNextTurnHint() {
|
||||
if (this._nextTurnHintTimer1) { this._nextTurnHintTimer1.remove(); this._nextTurnHintTimer1 = null; }
|
||||
if (this._nextTurnHintTimer2) { this._nextTurnHintTimer2.remove(); this._nextTurnHintTimer2 = null; }
|
||||
if (this._nextTurnArrow) { this.tweens.killTweensOf(this._nextTurnArrow); this._nextTurnArrow.destroy(); this._nextTurnArrow = null; }
|
||||
if (this._nextTurnHintLabel) { this.tweens.killTweensOf(this._nextTurnHintLabel); this._nextTurnHintLabel.destroy(); this._nextTurnHintLabel = null; }
|
||||
if (this._nextTurnDim) { this._nextTurnDim.destroy(); this._nextTurnDim = null; }
|
||||
// Reset button depths
|
||||
if (this.autoBtn) { this.autoBtn.setDepth(0); this.autoBtnText.setDepth(0); }
|
||||
if (this.nextBtn) { this.nextBtn.setDepth(0); this.nextBtnText.setDepth(0); }
|
||||
}
|
||||
|
||||
_toggleAuto() {
|
||||
this.autoPlay = !this.autoPlay;
|
||||
this.autoBtnText.setText(`Auto: ${this.autoPlay ? 'ON' : 'OFF'}`);
|
||||
if (this.autoPlay) {
|
||||
this._clearNextTurnHint();
|
||||
this.autoTimer = this.time.addEvent({
|
||||
delay: 300,
|
||||
callback: () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue