feat(catan): add visual and audio feedback for card theft by robber
- Detect when the robber steals a resource from player 0 by comparing resource counts before and after the move. - Display a temporary "CARD STOLEN" banner with the stolen resource name and robber's name. - Play a lose sound effect to provide immediate audio feedback. - Apply this notification logic consistently across all three locations where the robber is moved (AI turn, player turn, and initial setup).
This commit is contained in:
parent
67500636cb
commit
58c4edf8fd
|
|
@ -1389,7 +1389,12 @@ export default class CatanGame extends Phaser.Scene {
|
||||||
this.renderAll(); await this.delay(400);
|
this.renderAll(); await this.delay(400);
|
||||||
const m = AI.chooseRobberMove(this.gs, seat);
|
const m = AI.chooseRobberMove(this.gs, seat);
|
||||||
const preRobberHex = this.gs.robberHex;
|
const preRobberHex = this.gs.robberHex;
|
||||||
|
const preRes0roll = { ...this.gs.players[0].resources };
|
||||||
this.gs = L.moveRobber(this.gs, m.hexId, m.targetSeat);
|
this.gs = L.moveRobber(this.gs, m.hexId, m.targetSeat);
|
||||||
|
if (m.targetSeat === 0) {
|
||||||
|
const stolen = RESOURCE_TYPES.find(r => this.gs.players[0].resources[r] < preRes0roll[r]);
|
||||||
|
if (stolen) this._notifyStolenCard(stolen, this.pname(seat));
|
||||||
|
}
|
||||||
await this.animateRobber(preRobberHex, m.hexId);
|
await this.animateRobber(preRobberHex, m.hexId);
|
||||||
this.renderAll(); await this.delay(400);
|
this.renderAll(); await this.delay(400);
|
||||||
}
|
}
|
||||||
|
|
@ -1412,9 +1417,14 @@ export default class CatanGame extends Phaser.Scene {
|
||||||
await this.delay(450);
|
await this.delay(450);
|
||||||
const m = AI.chooseRobberMove(this.gs, seat);
|
const m = AI.chooseRobberMove(this.gs, seat);
|
||||||
const preRobberHex = this.gs.robberHex;
|
const preRobberHex = this.gs.robberHex;
|
||||||
|
const preRes0 = { ...this.gs.players[0].resources };
|
||||||
this.gs = L.moveRobber(this.gs, m.hexId, m.targetSeat);
|
this.gs = L.moveRobber(this.gs, m.hexId, m.targetSeat);
|
||||||
const animPromise = this.animateRobber(preRobberHex, m.hexId);
|
const animPromise = this.animateRobber(preRobberHex, m.hexId);
|
||||||
if (m.targetSeat != null) this.opponentPortraits[seat]?.playEmotion?.('happy');
|
if (m.targetSeat != null) this.opponentPortraits[seat]?.playEmotion?.('happy');
|
||||||
|
if (m.targetSeat === 0) {
|
||||||
|
const stolen = RESOURCE_TYPES.find(r => this.gs.players[0].resources[r] < preRes0[r]);
|
||||||
|
if (stolen) this._notifyStolenCard(stolen, this.pname(seat));
|
||||||
|
}
|
||||||
await animPromise;
|
await animPromise;
|
||||||
this.renderAll();
|
this.renderAll();
|
||||||
await this.delay(450);
|
await this.delay(450);
|
||||||
|
|
@ -1444,7 +1454,12 @@ export default class CatanGame extends Phaser.Scene {
|
||||||
if (this.gs.phase === 'moveRobber') {
|
if (this.gs.phase === 'moveRobber') {
|
||||||
const m = AI.chooseRobberMove(this.gs, seat);
|
const m = AI.chooseRobberMove(this.gs, seat);
|
||||||
const preRobberHex = this.gs.robberHex;
|
const preRobberHex = this.gs.robberHex;
|
||||||
|
const preRes0action = { ...this.gs.players[0].resources };
|
||||||
this.gs = L.moveRobber(this.gs, m.hexId, m.targetSeat);
|
this.gs = L.moveRobber(this.gs, m.hexId, m.targetSeat);
|
||||||
|
if (m.targetSeat === 0) {
|
||||||
|
const stolen = RESOURCE_TYPES.find(r => this.gs.players[0].resources[r] < preRes0action[r]);
|
||||||
|
if (stolen) this._notifyStolenCard(stolen, this.pname(seat));
|
||||||
|
}
|
||||||
await this.animateRobber(preRobberHex, m.hexId);
|
await this.animateRobber(preRobberHex, m.hexId);
|
||||||
}
|
}
|
||||||
this.renderAll();
|
this.renderAll();
|
||||||
|
|
@ -1779,6 +1794,21 @@ export default class CatanGame extends Phaser.Scene {
|
||||||
this.statusText.setText(msg);
|
this.statusText.setText(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_notifyStolenCard(resource, robberName) {
|
||||||
|
playSound(this, SFX.CASINO_LOSE);
|
||||||
|
const label = (RESOURCE_INFO[resource]?.label ?? resource).toUpperCase();
|
||||||
|
const txt = this.add.text(GAME_WIDTH / 2, 855,
|
||||||
|
`CARD STOLEN: ${label} BY ${robberName.toUpperCase()}`, {
|
||||||
|
fontFamily: 'Righteous', fontSize: '38px', color: '#ffd700',
|
||||||
|
stroke: '#000000', strokeThickness: 5,
|
||||||
|
}
|
||||||
|
).setOrigin(0.5).setDepth(D.banner + 2);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: txt, alpha: 0, delay: 3000, duration: 500,
|
||||||
|
onComplete: () => txt.destroy(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
showTurnBanner(text) {
|
showTurnBanner(text) {
|
||||||
const banner = this.add.text(1000, 120, text, {
|
const banner = this.add.text(1000, 120, text, {
|
||||||
fontFamily: 'Righteous', fontSize: '34px', color: COLORS.textHex,
|
fontFamily: 'Righteous', fontSize: '34px', color: COLORS.textHex,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue