Small Modifications

This commit is contained in:
Brian Fertig 2026-07-11 19:33:37 -06:00
parent 2e8424a4af
commit 3dbfcd56de
3 changed files with 79 additions and 23 deletions

View File

@ -369,7 +369,10 @@ export default class BalatroGame extends Phaser.Scene {
const debuffed = opts.debuffed;
if (card.faceDown && !opts.reveal) {
if (this.textures.exists('cardbacks')) {
const af = this.run ? this.artFrame('deckBackSheet', 'deckBacks', this.run.deckId) : null;
if (af) {
this.addRoundedArt(cont, af.key, af.frame, w, h, 10);
} else if (this.textures.exists('cardbacks')) {
const img = this.add.image(0, 0, 'cardbacks', 0).setDisplaySize(w, h);
cont.add(img);
} else {
@ -714,15 +717,24 @@ export default class BalatroGame extends Phaser.Scene {
// Blind badge
const blind = BLINDS[run.blind];
const boss = run.blind === 'boss' ? bossFor(run) : null;
const bossIcon = boss ? this.artFrame('bossIconSheet', 'bosses', boss.id) : null;
const badgeColor = run.blind === 'boss' ? 0xc22f3a : run.blind === 'big' ? 0x8556d6 : 0x2f6fce;
this.panel(X + 16, 40, W - 32, boss ? 168 : 128, { fill: badgeColor, alpha: 0.35, strokeColor: badgeColor });
this.text(X + W / 2, 58, boss ? boss.name : blind.name, 30, C.ink, { ox: 0.5, bold: true });
this.text(X + W / 2, 100, `Score at least`, 17, C.muted, { ox: 0.5 });
this.text(X + W / 2, 124, fmtChips(run.blindChips), 32, '#ff8a6a', { ox: 0.5, bold: true });
if (boss) this.text(X + W / 2, 166, boss.desc, 16, '#ffb9a8', { ox: 0.5, align: 'center', wrap: W - 60 });
const badgeH = boss ? (bossIcon ? 268 : 168) : 128;
this.panel(X + 16, 40, W - 32, badgeH, { fill: badgeColor, alpha: 0.35, strokeColor: badgeColor });
let ny = 58;
if (bossIcon) {
const iconCont = this.add.container(X + W / 2, 40 + 16 + 28);
this.addRoundedArt(iconCont, bossIcon.key, bossIcon.frame, 56, 56, 8);
this.add2(iconCont);
ny = 134;
}
this.text(X + W / 2, ny, boss ? boss.name : blind.name, 30, C.ink, { ox: 0.5, bold: true });
this.text(X + W / 2, ny + 42, `Score at least`, 17, C.muted, { ox: 0.5 });
this.text(X + W / 2, ny + 66, fmtChips(run.blindChips), 32, '#ff8a6a', { ox: 0.5, bold: true });
if (boss) this.text(X + W / 2, ny + 108, boss.desc, 16, '#ffb9a8', { ox: 0.5, align: 'center', wrap: W - 60 });
// Round score
const sy = boss ? 226 : 190;
const sy = boss ? (bossIcon ? 326 : 226) : 190;
this.text(X + 24, sy, 'Round score', 18, C.muted);
this._roundScoreText = this.text(X + W - 24, sy - 6, fmtChips(this._roundScoreOverride ?? run.roundScore), 34, C.ink, { ox: 1, bold: true });
@ -935,10 +947,17 @@ export default class BalatroGame extends Phaser.Scene {
const run = this.run;
const x = 1840, y = 880, w = 110, h = 148;
const deck = DECK_BY_ID[run.deckId];
const g = this.add.graphics();
g.fillStyle(deck.color, 0.9); g.fillRoundedRect(x - w / 2, y - h / 2, w, h, 8);
g.lineStyle(2, 0xffffff, 0.4); g.strokeRoundedRect(x - w / 2, y - h / 2, w, h, 8);
this.add2(g);
const af = this.artFrame('deckBackSheet', 'deckBacks', deck.id);
if (af) {
const cont = this.add.container(x, y);
this.addRoundedArt(cont, af.key, af.frame, w, h, 8);
this.add2(cont);
} else {
const g = this.add.graphics();
g.fillStyle(deck.color, 0.9); g.fillRoundedRect(x - w / 2, y - h / 2, w, h, 8);
g.lineStyle(2, 0xffffff, 0.4); g.strokeRoundedRect(x - w / 2, y - h / 2, w, h, 8);
this.add2(g);
}
this.text(x, y + h / 2 + 14, `${run.drawPile.length}/${run.deck.length}`, 18, C.ink, { ox: 0.5 });
}

View File

@ -119,17 +119,26 @@ export function renderBlindSelect(scene) {
const isCur = i === curIdx;
const done = i < curIdx;
const boss = stage === 'boss' ? bossFor(run) : null;
const bossIcon = boss ? scene.artFrame('bossIconSheet', 'bosses', boss.id) : null;
const color = stage === 'boss' ? 0xc22f3a : stage === 'big' ? 0x8556d6 : 0x2f6fce;
scene.panel(x - w / 2, y - h / 2, w, h, { fill: isCur ? color : C.panel, alpha: isCur ? 0.4 : 0.75, strokeColor: color });
scene.text(x, y - h / 2 + 46, boss ? boss.name : BLINDS[stage].name, 32, C.ink, { ox: 0.5, bold: true });
const top = y - h / 2;
let ny = top + 46;
if (bossIcon) {
const iconCont = scene.add.container(x, top + 44);
scene.addRoundedArt(iconCont, bossIcon.key, bossIcon.frame, 56, 56, 8);
scene.add2(iconCont);
ny = top + 94;
}
scene.text(x, ny, boss ? boss.name : BLINDS[stage].name, 32, C.ink, { ox: 0.5, bold: true });
// Requirement uses the boss multiplier for the boss column.
const req = stage === 'boss'
? Math.floor(anteBase(run.ante) * ((boss && boss.reqMult) || 2))
: Math.floor(anteBase(run.ante) * BLINDS[stage].mult);
scene.text(x, y - h / 2 + 110, 'Score at least', 18, C.muted, { ox: 0.5 });
scene.text(x, y - h / 2 + 142, fmtChips(req), 36, '#ff8a6a', { ox: 0.5, bold: true });
scene.text(x, y - h / 2 + 200, `Reward: $${BLINDS[stage].reward}`, 22, C.money, { ox: 0.5 });
if (boss) scene.text(x, y - h / 2 + 260, boss.desc, 20, '#ffb9a8', { ox: 0.5, align: 'center', wrap: w - 60 });
scene.text(x, ny + 64, 'Score at least', 18, C.muted, { ox: 0.5 });
scene.text(x, ny + 96, fmtChips(req), 36, '#ff8a6a', { ox: 0.5, bold: true });
scene.text(x, ny + 154, `Reward: $${BLINDS[stage].reward}`, 22, C.money, { ox: 0.5 });
if (boss) scene.text(x, ny + 214, boss.desc, 20, '#ffb9a8', { ox: 0.5, align: 'center', wrap: w - 60 });
if (done) {
scene.text(x, y + h / 2 - 120, '✔ cleared', 26, '#7ce07c', { ox: 0.5 });

View File

@ -97,7 +97,7 @@ const CARD_DEEPDIVE_ZONES = [
},
{
id: 'bounty', side: 'right', title: 'Bounty',
text: 'Commit enough squad attack (matching this number) to defeat this row card instead of buying it, and claim the reward shown.',
text: (def) => `Commit ${def.target} or more squad attack to defeat this row card instead of buying it. Reward: ${bountyRewardSentence(def.reward)}.`,
condition: (def) => def.target != null,
rect: (w) => ({ x: -w / 2 + 10, y: 208, w: w - 20, h: 30 }),
anchorX: (w) => w / 2 + 130,
@ -105,6 +105,32 @@ const CARD_DEEPDIVE_ZONES = [
];
const DEEPDIVE_ZONES = { card: CARD_DEEPDIVE_ZONES };
// Bounty reward → short display bits, shared by the card footer and the
// bounty deep-dive tooltip so both stay in sync as reward shapes are added.
function bountyRewardBits(reward) {
const r = reward || {};
const bits = [];
if (r.resources) bits.push(`${r.resources}`);
if (r.force) bits.push(`${r.force}`);
if (r.draw) bits.push(`draw ${r.draw}`);
if (r.exile) bits.push(`exile ${r.exile}`);
if (r.freePurchase) bits.push('free buy');
return bits;
}
// Bounty reward → a plain-language sentence fragment for the deep-dive
// tooltip, spelling out exactly what this card's bounty grants.
function bountyRewardSentence(reward) {
const r = reward || {};
const bits = [];
if (r.resources) bits.push(`${r.resources} ▣ Resources`);
if (r.force) bits.push(`${r.force} ◈ Force`);
if (r.draw) bits.push(`draw ${r.draw} card${r.draw > 1 ? 's' : ''}`);
if (r.exile) bits.push(`exile ${r.exile} card${r.exile > 1 ? 's' : ''} from your hand or discard`);
if (r.freePurchase) bits.push('a free purchase from the galaxy row');
return bits.length ? bits.join(', ') : 'the reward shown';
}
// Mirrors makeCard's own stat() helper: slots are only consumed by truthy
// stats, in the fixed order attack -> resources -> force.
function statSlotY(def, key) {
@ -196,7 +222,9 @@ export default class SWDBGGame extends Phaser.Scene {
fontFamily: 'Righteous', fontSize: '23px', color: C.goldHex,
backgroundColor: '#05070fdd', padding: { x: 16, y: 6 },
}).setOrigin(0.5).setDepth(DEPTH.ui);
if (this.opponents[0]) createOpponentPortrait(this, this.opponents[0], 140, 128, 44, DEPTH.ui);
if (this.opponents[0]) {
this._portrait = createOpponentPortrait(this, this.opponents[0], 140, 128, 44, DEPTH.ui);
}
createPlayerPortrait(this, 140, 812, 44, DEPTH.ui, 'SWDBGGame');
}
@ -337,11 +365,7 @@ export default class SWDBGGame extends Phaser.Scene {
}
// bounty footer
if (def.target != null) {
const r = def.reward || {};
const bits = [];
if (r.resources) bits.push(`${r.resources}`);
if (r.force) bits.push(`${r.force}`);
if (r.draw) bits.push(`draw ${r.draw}`);
const bits = bountyRewardBits(def.reward);
cont.add(this.add.text(0, h / 2 - 12, `${def.target}${bits.join(' ')}`, {
fontFamily: '"Julius Sans One"', fontSize: `${Math.max(9, Math.round(w / 14.5))}px`, color: C.bountyHex,
}).setOrigin(0.5));
@ -2267,6 +2291,10 @@ export default class SWDBGGame extends Phaser.Scene {
? `💥 ${name} HAS FALLEN (${e.lost}/${this.gs.meta.basesToWin})`
: `💥 YOU DESTROYED ${name.toUpperCase()} (${e.lost}/${this.gs.meta.basesToWin})`);
this.cameras.main.shake(240, 0.006);
// Opponent reaction: happy when they destroy a base, upset when theirs falls
if (this._portrait) {
this._portrait.playEmotion(e.seat === this.humanSeat ? 'happy' : 'upset');
}
break;
}
case 'baseChosen':