diff --git a/gameplay.js b/gameplay.js index 9362334..c1ce0b5 100644 --- a/gameplay.js +++ b/gameplay.js @@ -594,24 +594,28 @@ export function deliverTin() { aside('ump_new_balls_dark', 2.0); // "...and a new opponent, apparently." // THE PRIZE GETS ITS OWN CARD, with the tin's own icon on it. It used to borrow G.flash — the // same channel as PERFECT and DOUBLE KILL — so the one thing you played the duel FOR arrived as a - // word in the praise slot and read as another compliment. weaponModal still fires the first time - // a tin is seen (it has rules to teach); every time after, this card is the announcement, and it + // word in the praise slot and read as another compliment. The first time a tin is seen the modal + // announces it (and teaches its rules), so the card would be the SAME news twice, back to back — + // it only speaks when the modal doesn't. Every time after, the card is the announcement, and it // does not want a tap: you have just won a point, not been asked a question. - G.card = { title: WEAPONS[id].label, sub1: 'DELIVERED TO THE RACK', - sub2: (WEAPONS[id].desc && WEAPONS[id].desc[0]) || '', - icon: WEAPONS[id].icon, color: UI.warm, t: TUNE.tinCardT }; - weaponModal(id); + if (!weaponModal(id)) + G.card = { title: WEAPONS[id].label, sub1: 'DELIVERED TO THE RACK', + sub2: (WEAPONS[id].desc && WEAPONS[id].desc[0]) || '', + icon: WEAPONS[id].icon, color: UI.warm, t: TUNE.tinCardT }; } // The one-per-run "what this thing does" popup, shared by the duel ladder and the barrels. // THE GATE LIVES HERE, not at the call sites. The barrels gated themselves and the tin ladder did // not, so the four delivered weapons re-explained themselves every three games for a whole run // while a barrel weapon explained itself once — the same popup behaving two different ways. +// Returns whether it actually announced, so a caller with its own announcement (the tin card, the +// barrel's flash) can stay quiet rather than say the same thing twice. export function weaponModal(id) { - if (G.seen['w' + id]) return; + if (G.seen['w' + id]) return false; G.seen['w' + id] = true; const w = WEAPONS[id]; showModal({ title: w.label, body: w.desc, icon: w.icon, iconH: 40, color: UI.warm }); + return true; } // ---- TEST MODE. Triple-tap the scoreboard. A sandbox for trying the new content without playing diff --git a/zombies.js b/zombies.js index 6cef2fc..a0894cf 100644 --- a/zombies.js +++ b/zombies.js @@ -359,9 +359,9 @@ function popBarrel(zb) { vx: (Math.random() * 2 - 1) * 4, vy: 1.2 + Math.random() * 3.5, vz: (Math.random() * 2 - 1) * 4, t: 0.35 + Math.random() * 0.5, pink: true }); grantWeapon(zb.wid); - const w = WEAPONS[zb.wid]; - G.flash = { text: w.label, t: 1.1 }; - weaponModal(zb.wid); // first sight only — the gate lives in weaponModal, for both callers + // first sight only — the gate lives in weaponModal, for both callers — and the flash keeps quiet + // when the modal spoke, so the same weapon isn't named twice in the same beat + if (!weaponModal(zb.wid)) G.flash = { text: WEAPONS[zb.wid].label, t: 1.1 }; } // dark smoke: one puff, drifting up and spreading. Not gravity-bound like gore (see the parts loop).