Compare commits
No commits in common. "33bbeff79b5dfcd53651080402d2b1a4e1e878a2" and "41466e14f31171c3708309a98df02398838f6cf3" have entirely different histories.
33bbeff79b
...
41466e14f3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 MiB After Width: | Height: | Size: 4.7 MiB |
|
|
@ -100,26 +100,10 @@ export default class DominionGame extends Phaser.Scene {
|
|||
this._suppressTurnUi = false;
|
||||
this._handFxGraphics = [];
|
||||
this._handFxTweens = [];
|
||||
this._supplyFxEmitters = [];
|
||||
this._deckAnimDisplay = null;
|
||||
this._discardAnimDisplay = null;
|
||||
this._liveDeckPile = null;
|
||||
this._liveDeckBadge = null;
|
||||
this._liveDeckCountText = null;
|
||||
this._liveDiscardPile = null;
|
||||
this._liveDiscardBadge = null;
|
||||
this._liveDiscardCountText = null;
|
||||
}
|
||||
|
||||
create() {
|
||||
new MusicPlayer(this, this.cache.json.get('music').tracks);
|
||||
if (!this.textures.exists('dominion-sparkle')) {
|
||||
const g = this.add.graphics();
|
||||
g.fillStyle(0xffffff, 1);
|
||||
g.fillCircle(3, 3, 3);
|
||||
g.generateTexture('dominion-sparkle', 6, 6);
|
||||
g.destroy();
|
||||
}
|
||||
this.buildBackground();
|
||||
this.buildPortraits();
|
||||
this.buildTurnArrow();
|
||||
|
|
@ -161,8 +145,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
};
|
||||
this.gs = preDeal;
|
||||
this.render();
|
||||
this._deckAnimDisplay = preDeal.players[0].deck.length; // 10 before deal
|
||||
this._discardAnimDisplay = 0;
|
||||
this._animDrawCards(p0.hand, initialState);
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +421,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
|
||||
render() {
|
||||
this._clearHandFx();
|
||||
this._clearSupplyFx();
|
||||
if (this.hoverTimer) { this.hoverTimer.remove(); this.hoverTimer = null; }
|
||||
this.hideHover();
|
||||
this.dynamicLayer?.destroy(true);
|
||||
|
|
@ -519,7 +500,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
hit.setInteractive({ useHandCursor: true });
|
||||
hit.on('pointerup', () => this.humanBuy(id));
|
||||
this.markBuyable(face);
|
||||
this._buildSupplyFxItem(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -530,27 +510,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
face.addAt(glow, 0);
|
||||
}
|
||||
|
||||
_clearSupplyFx() {
|
||||
this._supplyFxEmitters.forEach(e => e.destroy());
|
||||
this._supplyFxEmitters = [];
|
||||
}
|
||||
|
||||
_buildSupplyFxItem(x, y) {
|
||||
const emitter = this.add.particles(x, y, 'dominion-sparkle', {
|
||||
x: { min: -SUPPLY_W / 2 + 4, max: SUPPLY_W / 2 - 4 },
|
||||
y: -SUPPLY_H / 2,
|
||||
speedX: { min: -18, max: 18 },
|
||||
speedY: { min: -70, max: -30 },
|
||||
alpha: { start: 0.9, end: 0 },
|
||||
scale: { start: 0.8, end: 0.15 },
|
||||
lifespan: 900,
|
||||
frequency: 100,
|
||||
tint: [0xffffff, 0xffeebb, 0xd4a017, 0xc8a84b],
|
||||
depth: D.supply + 8,
|
||||
});
|
||||
this._supplyFxEmitters.push(emitter);
|
||||
}
|
||||
|
||||
renderInPlay() {
|
||||
const gs = this.gs;
|
||||
const p = gs.players[gs.turn];
|
||||
|
|
@ -693,52 +652,39 @@ export default class DominionGame extends Phaser.Scene {
|
|||
|
||||
renderCounts() {
|
||||
const gs = this.gs;
|
||||
const displayDeck = this._deckAnimDisplay ?? gs.players[0].deck.length;
|
||||
const displayDiscard = this._discardAnimDisplay ?? gs.players[0].discard.length;
|
||||
|
||||
// Human deck — face-down card pile with count badge
|
||||
const deckPile = this.buildCardFace(HAND_W, HAND_H, null, { faceDown: true });
|
||||
deckPile.setPosition(DECK_PILE_X, DECK_PILE_Y).setDepth(D.hand);
|
||||
deckPile.setVisible(displayDeck > 0);
|
||||
this.dynamicLayer.add(deckPile);
|
||||
const deckCount = gs.players[0].deck.length;
|
||||
const dcBg = this.add.graphics();
|
||||
dcBg.fillStyle(0x000000, 0.72);
|
||||
dcBg.fillCircle(DECK_PILE_X, DECK_PILE_Y, 22);
|
||||
dcBg.lineStyle(2, COLORS.accent, 1);
|
||||
dcBg.strokeCircle(DECK_PILE_X, DECK_PILE_Y, 22);
|
||||
dcBg.setDepth(D.hand + 1);
|
||||
dcBg.setVisible(displayDeck > 0);
|
||||
const dcText = this.add.text(DECK_PILE_X, DECK_PILE_Y, `${displayDeck}`, {
|
||||
const dcText = this.add.text(DECK_PILE_X, DECK_PILE_Y, `${deckCount}`, {
|
||||
fontFamily: 'Righteous', fontSize: '22px', color: COLORS.textHex,
|
||||
}).setOrigin(0.5).setDepth(D.hand + 1);
|
||||
dcText.setVisible(displayDeck > 0);
|
||||
this.dynamicLayer.add(dcBg);
|
||||
this.dynamicLayer.add(dcText);
|
||||
this._liveDeckPile = deckPile;
|
||||
this._liveDeckBadge = dcBg;
|
||||
this._liveDeckCountText = dcText;
|
||||
|
||||
// Human discard pile — face-down card with count badge
|
||||
const discardPile = this.buildCardFace(HAND_W, HAND_H, null, { faceDown: true });
|
||||
discardPile.setPosition(DISCARD_PILE_X, DISCARD_PILE_Y).setDepth(D.hand);
|
||||
discardPile.setVisible(displayDiscard > 0);
|
||||
this.dynamicLayer.add(discardPile);
|
||||
const discardCount = gs.players[0].discard.length;
|
||||
const dpBg = this.add.graphics();
|
||||
dpBg.fillStyle(0x000000, 0.72);
|
||||
dpBg.fillCircle(DISCARD_PILE_X, DISCARD_PILE_Y, 22);
|
||||
dpBg.lineStyle(2, COLORS.accent, 1);
|
||||
dpBg.strokeCircle(DISCARD_PILE_X, DISCARD_PILE_Y, 22);
|
||||
dpBg.setDepth(D.hand + 1);
|
||||
dpBg.setVisible(displayDiscard > 0);
|
||||
const dpText = this.add.text(DISCARD_PILE_X, DISCARD_PILE_Y, `${displayDiscard}`, {
|
||||
const dpText = this.add.text(DISCARD_PILE_X, DISCARD_PILE_Y, `${discardCount}`, {
|
||||
fontFamily: 'Righteous', fontSize: '22px', color: COLORS.textHex,
|
||||
}).setOrigin(0.5).setDepth(D.hand + 1);
|
||||
dpText.setVisible(displayDiscard > 0);
|
||||
this.dynamicLayer.add(dpBg);
|
||||
this.dynamicLayer.add(dpText);
|
||||
this._liveDiscardPile = discardPile;
|
||||
this._liveDiscardBadge = dpBg;
|
||||
this._liveDiscardCountText = dpText;
|
||||
|
||||
this.opponents.forEach((opp, i) => {
|
||||
const seat = i + 1;
|
||||
|
|
@ -857,7 +803,7 @@ export default class DominionGame extends Phaser.Scene {
|
|||
}).setOrigin(0.5));
|
||||
|
||||
// Icon row (between title and type line)
|
||||
this.addIconRow(c, def, 0, bandTop + (h / 2 - bandTop) * 0.55, h, w);
|
||||
this.addIconRow(c, def, 0, bandTop + (h / 2 - bandTop) * 0.55, h);
|
||||
|
||||
// Cost coin (top-left)
|
||||
this.addCoinBadge(c, -w / 2 + 14, -h / 2 + 14, def.cost, Math.round(h * 0.075));
|
||||
|
|
@ -872,7 +818,7 @@ export default class DominionGame extends Phaser.Scene {
|
|||
return c;
|
||||
}
|
||||
|
||||
addIconRow(container, def, cx, cy, h, w = Infinity) {
|
||||
addIconRow(container, def, cx, cy, h) {
|
||||
const tokens = [];
|
||||
if (def.plus.cards) tokens.push(['cards', def.plus.cards, 0x2f6fb0]);
|
||||
if (def.plus.actions) tokens.push(['action', def.plus.actions, 0x3f9b54]);
|
||||
|
|
@ -881,31 +827,9 @@ export default class DominionGame extends Phaser.Scene {
|
|||
if (def.coin !== undefined) tokens.push(['$', def.coin, 0xd4a017]); // treasure value
|
||||
if (tokens.length === 0) return;
|
||||
|
||||
const fs0 = Phaser.Math.Clamp(Math.round(h * 0.06), 8, 13);
|
||||
let tw = fs0 * 4.2;
|
||||
let fs = fs0;
|
||||
const gap = 4;
|
||||
const maxW = w - 8;
|
||||
|
||||
const nominalTotalW = tokens.length * tw + (tokens.length - 1) * gap;
|
||||
if (nominalTotalW > maxW) {
|
||||
tw = (maxW - (tokens.length - 1) * gap) / tokens.length;
|
||||
fs = Math.floor(tw / 4.2);
|
||||
if (fs < 7) {
|
||||
const barGap = 2;
|
||||
const barW = (maxW - (tokens.length - 1) * barGap) / tokens.length;
|
||||
const barH = Math.max(3, Math.round(h * 0.025));
|
||||
let bx = cx - maxW / 2 + barW / 2;
|
||||
for (const [, , color] of tokens) {
|
||||
const bar = this.add.rectangle(bx, cy, barW, barH, color, 0.9);
|
||||
bar.setStrokeStyle(0.5, 0x000000, 0.3);
|
||||
container.add(bar);
|
||||
bx += barW + barGap;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const fs = Phaser.Math.Clamp(Math.round(h * 0.06), 8, 13);
|
||||
const tw = fs * 4.2;
|
||||
const gap = 4;
|
||||
const totalW = tokens.length * tw + (tokens.length - 1) * gap;
|
||||
let x = cx - totalW / 2 + tw / 2;
|
||||
for (const [kind, val, color] of tokens) {
|
||||
|
|
@ -1062,13 +986,7 @@ export default class DominionGame extends Phaser.Scene {
|
|||
this._suppressTurnUi = true;
|
||||
}
|
||||
const draws = (drawnCards.length > 0 && deckChanged) ? drawnCards : [];
|
||||
const prevMe = prev.players[0];
|
||||
const hadShuffle = newLog.some(e => e.kind === 'shuffle' && e.seat === 0);
|
||||
this._deckAnimDisplay = prevMe.deck.length;
|
||||
this._discardAnimDisplay = prevMe.discard.length;
|
||||
this._animDiscardThenDraw(allDiscarded, draws, s, {
|
||||
hadShuffle, oldDeckCount: prevMe.deck.length, oldDiscardCount: prevMe.discard.length,
|
||||
});
|
||||
this._animDiscardThenDraw(allDiscarded, draws, s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1085,13 +1003,7 @@ export default class DominionGame extends Phaser.Scene {
|
|||
}
|
||||
|
||||
if (drawnCards.length > 0 && deckChanged) {
|
||||
const prevMe2 = prev.players[0];
|
||||
const hadShuffle2 = newLog.some(e => e.kind === 'shuffle' && e.seat === 0);
|
||||
this._deckAnimDisplay = prevMe2.deck.length;
|
||||
this._discardAnimDisplay = prevMe2.discard.length;
|
||||
this._animDrawCards(drawnCards, s, {
|
||||
hadShuffle: hadShuffle2, oldDeckCount: prevMe2.deck.length, oldDiscardCount: prevMe2.discard.length,
|
||||
});
|
||||
this._animDrawCards(drawnCards, s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1191,13 +1103,12 @@ export default class DominionGame extends Phaser.Scene {
|
|||
|
||||
if (gs.phase === 'buy') {
|
||||
if (gs.players[seat].hand.some((c) => isType(c.id, 'treasure'))) {
|
||||
playSound(this, SFX.COINS);
|
||||
this.setState(playAllTreasures(gs));
|
||||
return;
|
||||
}
|
||||
const buy = AI.chooseBuy(gs, seat, skill);
|
||||
if (buy) {
|
||||
playSound(this, SFX.PURCHASE);
|
||||
playSound(this, SFX.CARD_SHOW);
|
||||
if (buy === 'province') this.portraits[seat]?.playEmotion?.('happy');
|
||||
this.setState(buyCard(gs, buy));
|
||||
} else {
|
||||
|
|
@ -1217,20 +1128,19 @@ export default class DominionGame extends Phaser.Scene {
|
|||
|
||||
humanPlayTreasure(iid) {
|
||||
if (this.gs.pending || this.gs.turn !== 0 || this._animating) return;
|
||||
playSound(this, SFX.COINS);
|
||||
this.setState(playTreasure(this.gs, iid));
|
||||
}
|
||||
|
||||
humanPlayTreasures() {
|
||||
if (this.gs.pending || this.gs.turn !== 0 || this._animating) return;
|
||||
playSound(this, SFX.COINS);
|
||||
playSound(this, SFX.CARD_PLACE);
|
||||
this.setState(playAllTreasures(this.gs));
|
||||
}
|
||||
|
||||
humanBuy(id) {
|
||||
if (this.gs.pending || this.gs.turn !== 0 || this._animating) return;
|
||||
this._boughtThisTurn = true;
|
||||
playSound(this, SFX.PURCHASE);
|
||||
playSound(this, SFX.CARD_SHOW);
|
||||
this.setState(buyCard(this.gs, id));
|
||||
}
|
||||
|
||||
|
|
@ -1636,7 +1546,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
const fu = this.buildCardFace(PLAY_W, PLAY_H, def);
|
||||
fu.setPosition(src.x, src.y).setScale(OPP_W / PLAY_W, OPP_H / PLAY_H);
|
||||
this.animLayer.add(fu);
|
||||
playSound(this, SFX.CARD_SHOW);
|
||||
this.tweens.add({
|
||||
targets: fu, x: tx, y: ty, scaleX: 1, scaleY: 1,
|
||||
duration: 350, ease: 'Cubic.easeOut',
|
||||
|
|
@ -1679,7 +1588,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
targets: mini, x: tx, y: ty, duration: 320, ease: 'Cubic.easeOut',
|
||||
onComplete: () => {
|
||||
mini.destroy();
|
||||
playSound(this, SFX.CARD_DEAL);
|
||||
if (tgt?.face) tgt.face.setAlpha(1);
|
||||
next();
|
||||
},
|
||||
|
|
@ -1738,24 +1646,22 @@ export default class DominionGame extends Phaser.Scene {
|
|||
this.render();
|
||||
const slot = this.oppSlot(seat - 1);
|
||||
|
||||
this._animPurchaseShowcase(cardId, srcX, srcY, slot.x, slot.y, () => {
|
||||
const cardName = getCard(cardId).name;
|
||||
const label = this.add.text(slot.x - slot.r - 74, slot.y, `Purchased:\n${cardName}`, {
|
||||
fontFamily: 'Righteous', fontSize: '32px', color: '#FFD700',
|
||||
align: 'right', stroke: '#000000', strokeThickness: 4,
|
||||
}).setOrigin(1, 0.5).setDepth(D.hud + 5).setAlpha(1);
|
||||
const cardName = getCard(cardId).name;
|
||||
const label = this.add.text(slot.x - slot.r - 74, slot.y, `Purchased:\n${cardName}`, {
|
||||
fontFamily: 'Righteous', fontSize: '32px', color: '#FFD700',
|
||||
align: 'right', stroke: '#000000', strokeThickness: 4,
|
||||
}).setOrigin(1, 0.5).setDepth(D.hud + 5).setAlpha(1);
|
||||
|
||||
const src = { iid: -1, id: cardId, x: slot.x, y: slot.y };
|
||||
this._animDiscardCard(src, slot.x, slot.y, () => {
|
||||
this.tweens.add({
|
||||
targets: label, alpha: 0, duration: 600, delay: 400, ease: 'Sine.easeIn',
|
||||
onComplete: () => label.destroy(),
|
||||
});
|
||||
this._animating = false;
|
||||
if (this._pendingAnimState) { const s = this._pendingAnimState; this._pendingAnimState = null; this.setState(s); }
|
||||
else this.scheduleAdvance(10);
|
||||
}, { flyDuration: 1, foldDuration: 500 });
|
||||
});
|
||||
const src = { iid: -1, id: cardId, x: srcX, y: srcY };
|
||||
this._animDiscardCard(src, slot.x, slot.y, () => {
|
||||
this.tweens.add({
|
||||
targets: label, alpha: 0, duration: 600, delay: 400, ease: 'Sine.easeIn',
|
||||
onComplete: () => label.destroy(),
|
||||
});
|
||||
this._animating = false;
|
||||
if (this._pendingAnimState) { const s = this._pendingAnimState; this._pendingAnimState = null; this.setState(s); }
|
||||
else this.scheduleAdvance(10);
|
||||
}, { flyDuration: 1000, foldDuration: 500 });
|
||||
}
|
||||
|
||||
_chainHumanGain(gainEvt, newState) {
|
||||
|
|
@ -1776,7 +1682,7 @@ export default class DominionGame extends Phaser.Scene {
|
|||
|
||||
// ── Draw animations ───────────────────────────────────────────────────────────
|
||||
|
||||
_animDiscardThenDraw(discardedCards, drawnCards, newState, shuffleInfo = {}) {
|
||||
_animDiscardThenDraw(discardedCards, drawnCards, newState) {
|
||||
this._animating = true;
|
||||
|
||||
// Capture positions + face sprite refs BEFORE any render wipes the arrays.
|
||||
|
|
@ -1794,14 +1700,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
|
||||
let idx = 0;
|
||||
const animateNext = () => {
|
||||
// Each call after the first means the previous card just landed in the discard pile.
|
||||
if (idx > 0) {
|
||||
this._discardAnimDisplay = (this._discardAnimDisplay ?? 0) + 1;
|
||||
if (this._liveDiscardCountText?.active)
|
||||
this._liveDiscardCountText.setText(`${this._discardAnimDisplay}`);
|
||||
if (this._liveDiscardPile?.active) this._liveDiscardPile.setVisible(true);
|
||||
if (this._liveDiscardBadge?.active) this._liveDiscardBadge.setVisible(true);
|
||||
}
|
||||
if (idx >= sources.length) {
|
||||
// All cards have landed. Now render the intermediate/final state.
|
||||
const p0 = newState.players[0];
|
||||
|
|
@ -1818,13 +1716,8 @@ export default class DominionGame extends Phaser.Scene {
|
|||
this.render();
|
||||
|
||||
if (drawnCards.length > 0) {
|
||||
this._animDrawCards(drawnCards, newState, {
|
||||
...shuffleInfo,
|
||||
oldDiscardCount: this._discardAnimDisplay ?? 0,
|
||||
});
|
||||
this._animDrawCards(drawnCards, newState);
|
||||
} else {
|
||||
this._deckAnimDisplay = null;
|
||||
this._discardAnimDisplay = null;
|
||||
this._suppressTurnUi = false;
|
||||
this.updateTurnUi();
|
||||
this._animating = false;
|
||||
|
|
@ -1860,7 +1753,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
const fdCard = this.buildCardFace(HAND_W, HAND_H, null, { faceDown: true });
|
||||
fdCard.setPosition(tx, ty).setScale(0, 1);
|
||||
this.animLayer.add(fdCard);
|
||||
playSound(this, SFX.CARD_SHOW);
|
||||
this.tweens.add({
|
||||
targets: fdCard, scaleX: 1, duration: foldDuration, ease: 'Sine.easeOut',
|
||||
onComplete: () => { fdCard.destroy(); onComplete(); },
|
||||
|
|
@ -1871,92 +1763,23 @@ export default class DominionGame extends Phaser.Scene {
|
|||
});
|
||||
}
|
||||
|
||||
_animPurchaseShowcase(cardId, srcX, srcY, tx, ty, onComplete) {
|
||||
const cy = GAME_HEIGHT / 2;
|
||||
const SHOW_W = 270, SHOW_H = 390;
|
||||
const def = getCard(cardId);
|
||||
|
||||
const overlay = this.add.rectangle(CX, cy, GAME_WIDTH, GAME_HEIGHT, 0x000000, 0)
|
||||
.setDepth(D.modal);
|
||||
this.tweens.add({ targets: overlay, alpha: 0.65, duration: 250 });
|
||||
|
||||
const card = this.buildCardFace(SHOW_W, SHOW_H, def);
|
||||
card.setPosition(srcX, srcY).setScale(SUPPLY_W / SHOW_W).setDepth(D.modal + 1);
|
||||
|
||||
this.tweens.add({
|
||||
targets: card, x: CX, y: cy, scaleX: 1, scaleY: 1,
|
||||
duration: 350, ease: 'Back.easeOut',
|
||||
onComplete: () => {
|
||||
// Comet border effect around the full-size card
|
||||
const gfx = this.add.graphics().setDepth(D.modal + 2);
|
||||
const perim = 2 * (SHOW_W + SHOW_H);
|
||||
const TAIL_PX = 130;
|
||||
const SEGMENTS = 24;
|
||||
const COMETS = 3;
|
||||
const COMET_COLORS = [0xffd700, 0xffffff, 0xff9900];
|
||||
const left = CX - SHOW_W / 2, top = cy - SHOW_H / 2;
|
||||
const tracker = { t: 0 };
|
||||
const borderTween = this.tweens.add({
|
||||
targets: tracker, t: { from: 0, to: 1 },
|
||||
duration: 1400, repeat: -1, ease: 'Linear',
|
||||
onUpdate: () => {
|
||||
gfx.clear();
|
||||
for (let c = 0; c < COMETS; c++) {
|
||||
const headDist = ((tracker.t + c / COMETS) % 1) * perim;
|
||||
const cometColor = COMET_COLORS[c];
|
||||
for (let seg = 0; seg < SEGMENTS; seg++) {
|
||||
const frac = seg / SEGMENTS;
|
||||
const d1 = ((headDist - (1 - frac) * TAIL_PX + perim * 100) % perim);
|
||||
const d2 = ((headDist - (1 - (seg + 1) / SEGMENTS) * TAIL_PX + perim * 100) % perim);
|
||||
const [x1, y1] = perimPoint(d1, SHOW_W, SHOW_H, left, top);
|
||||
const [x2, y2] = perimPoint(d2, SHOW_W, SHOW_H, left, top);
|
||||
const alpha = 0.1 + frac * 0.9;
|
||||
const lineColor = frac > 0.85 ? 0xffffff : cometColor;
|
||||
const lineWidth = frac > 0.85 ? 5 : 2.5;
|
||||
gfx.lineStyle(lineWidth, lineColor, alpha);
|
||||
gfx.beginPath();
|
||||
gfx.moveTo(x1, y1);
|
||||
gfx.lineTo(x2, y2);
|
||||
gfx.strokePath();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.time.delayedCall(1500, () => {
|
||||
borderTween.stop();
|
||||
gfx.destroy();
|
||||
this.tweens.add({ targets: overlay, alpha: 0, duration: 300 });
|
||||
this.tweens.add({
|
||||
targets: card,
|
||||
x: tx, y: ty, scaleX: HAND_W / SHOW_W, scaleY: HAND_H / SHOW_H,
|
||||
duration: 400, ease: 'Cubic.easeIn',
|
||||
onComplete: () => { card.destroy(); overlay.destroy(); onComplete(); },
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_animGainCard(gainedCard, srcX, srcY, dest, newState) {
|
||||
this._animating = true;
|
||||
this.gs = newState;
|
||||
this.clearPrompt();
|
||||
this.render();
|
||||
|
||||
const tx = dest === 'deck' ? DECK_PILE_X : DISCARD_PILE_X;
|
||||
const ty = dest === 'deck' ? DECK_PILE_Y : DISCARD_PILE_Y;
|
||||
const tx = dest === 'deck' ? DECK_PILE_X : DISCARD_PILE_X;
|
||||
const ty = dest === 'deck' ? DECK_PILE_Y : DISCARD_PILE_Y;
|
||||
const src = { iid: gainedCard.iid, id: gainedCard.id, x: srcX, y: srcY };
|
||||
|
||||
this._animPurchaseShowcase(gainedCard.id, srcX, srcY, tx, ty, () => {
|
||||
const src = { iid: gainedCard.iid, id: gainedCard.id, x: tx, y: ty };
|
||||
this._animDiscardCard(src, tx, ty, () => {
|
||||
this._animating = false;
|
||||
if (this._pendingAnimState) {
|
||||
const s = this._pendingAnimState; this._pendingAnimState = null; this.setState(s);
|
||||
} else {
|
||||
this.scheduleAdvance(10);
|
||||
}
|
||||
}, { flyDuration: 1, foldDuration: 250 });
|
||||
this._animDiscardCard(src, tx, ty, () => {
|
||||
this._animating = false;
|
||||
if (this._pendingAnimState) {
|
||||
const s = this._pendingAnimState; this._pendingAnimState = null; this.setState(s);
|
||||
} else {
|
||||
this.scheduleAdvance(10);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -2085,69 +1908,23 @@ export default class DominionGame extends Phaser.Scene {
|
|||
this._dragDropLabel = null;
|
||||
}
|
||||
|
||||
_animDrawCards(drawnCards, newState, shuffleInfo = {}) {
|
||||
const { hadShuffle = false, oldDeckCount = 0 } = shuffleInfo;
|
||||
|
||||
_animDrawCards(drawnCards, newState) {
|
||||
this._animating = true;
|
||||
this._animatingIids = new Set(drawnCards.map(c => c.iid));
|
||||
this.gs = newState;
|
||||
this.clearPrompt();
|
||||
this.render(); // uses _deckAnimDisplay / _discardAnimDisplay overrides
|
||||
|
||||
const updateDeckDisplay = () => {
|
||||
if (this._liveDeckCountText?.active)
|
||||
this._liveDeckCountText.setText(`${this._deckAnimDisplay}`);
|
||||
const empty = this._deckAnimDisplay <= 0;
|
||||
if (this._liveDeckPile?.active) this._liveDeckPile.setVisible(!empty);
|
||||
if (this._liveDeckBadge?.active) this._liveDeckBadge.setVisible(!empty);
|
||||
};
|
||||
|
||||
const doShuffle = (callback) => {
|
||||
this.time.delayedCall(400, () => {
|
||||
playSound(this, SFX.CARD_SHUFFLE);
|
||||
const startVal = this._discardAnimDisplay ?? 0;
|
||||
const counter = { v: startVal };
|
||||
this.tweens.add({
|
||||
targets: counter, v: 0, duration: 600, ease: 'Cubic.Out',
|
||||
onUpdate: () => {
|
||||
this._discardAnimDisplay = Math.round(counter.v);
|
||||
if (this._liveDiscardCountText?.active)
|
||||
this._liveDiscardCountText.setText(`${this._discardAnimDisplay}`);
|
||||
},
|
||||
onComplete: () => {
|
||||
const postDeck = (drawnCards.length - drawnSoFar) + newState.players[0].deck.length;
|
||||
this._deckAnimDisplay = postDeck;
|
||||
updateDeckDisplay();
|
||||
callback();
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
this.render();
|
||||
|
||||
let idx = 0;
|
||||
let drawnSoFar = 0;
|
||||
let shuffleDone = false;
|
||||
|
||||
const animateNext = () => {
|
||||
if (hadShuffle && !shuffleDone && drawnSoFar === oldDeckCount) {
|
||||
shuffleDone = true;
|
||||
doShuffle(animateNext);
|
||||
return;
|
||||
}
|
||||
if (idx >= drawnCards.length) { this._finishDrawAnim(); return; }
|
||||
const card = drawnCards[idx++];
|
||||
const card = drawnCards[idx++];
|
||||
const sprite = this.handSprites.find(s => s.iid === card.iid);
|
||||
const tx = sprite?.x ?? CX;
|
||||
const tx = sprite?.x ?? CX;
|
||||
this._animateOneCard(card, tx, 968, () => {
|
||||
drawnSoFar++;
|
||||
playSound(this, SFX.CARD_DEAL);
|
||||
const s2 = this.handSprites.find(s => s.iid === card.iid);
|
||||
if (s2) s2.face.setAlpha(1);
|
||||
this._animatingIids.delete(card.iid);
|
||||
|
||||
this._deckAnimDisplay = (this._deckAnimDisplay ?? 1) - 1;
|
||||
updateDeckDisplay();
|
||||
|
||||
animateNext();
|
||||
});
|
||||
};
|
||||
|
|
@ -2168,7 +1945,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
const fuCard = this.buildCardFace(HAND_W, HAND_H, def);
|
||||
fuCard.setPosition(DECK_PILE_X, DECK_PILE_Y).setScale(0, 1);
|
||||
this.animLayer.add(fuCard);
|
||||
playSound(this, SFX.CARD_SHOW);
|
||||
|
||||
this.tweens.add({
|
||||
targets: fuCard, scaleX: 1, duration: 250, ease: 'Sine.easeOut',
|
||||
|
|
@ -2184,8 +1960,6 @@ export default class DominionGame extends Phaser.Scene {
|
|||
}
|
||||
|
||||
_finishDrawAnim() {
|
||||
this._deckAnimDisplay = null;
|
||||
this._discardAnimDisplay = null;
|
||||
this.handSprites.forEach(s => s.face.setAlpha(1));
|
||||
this._animatingIids.clear();
|
||||
this._animating = false;
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@ export default class PreloadScene extends Phaser.Scene {
|
|||
this.load.audio('sfx-card-place', '/assets/fx/card-place.mp3');
|
||||
this.load.audio('sfx-card-show', '/assets/fx/card-show.mp3');
|
||||
this.load.audio('sfx-card-shuffle', '/assets/fx/card-shuffle.mp3');
|
||||
this.load.audio('sfx-coins', '/assets/fx/coins.mp3');
|
||||
this.load.audio('sfx-purchase', '/assets/fx/purchase.mp3');
|
||||
this.load.audio('sfx-casino-blackjack', '/assets/fx/casino-blackjack.mp3');
|
||||
this.load.audio('sfx-casino-lose', '/assets/fx/casino-lose.mp3');
|
||||
this.load.audio('sfx-casino-win', '/assets/fx/casino-win.mp3');
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ export const SFX = {
|
|||
CARD_PLACE: 'sfx-card-place',
|
||||
CARD_SHOW: 'sfx-card-show',
|
||||
CARD_SHUFFLE: 'sfx-card-shuffle',
|
||||
COINS: 'sfx-coins',
|
||||
PURCHASE: 'sfx-purchase',
|
||||
CASINO_BLACKJACK: 'sfx-casino-blackjack',
|
||||
CASINO_LOSE: 'sfx-casino-lose',
|
||||
CASINO_WIN: 'sfx-casino-win',
|
||||
|
|
|
|||
Loading…
Reference in New Issue