feedback1 WB: bounty-half evidence stated as a trend with its counter-evidence; queued free offers counted on the pill and header
- tools/build-data.mjs bountyDraftHalf: exact faction-series counts (12 of 18 two-battle cards bring first-half enemies, 5 outside the wave tables, enemyeffect_12_4 a second-half attachment), base-HP gradient, the user's two-battle recall; counter-evidence (假想敌 named enemyInitial_*, the unread NGA R3 guide); the split marked [ASSUMED] with its flip; data unchanged - server/match/choices.js, docs/META.md, docs/DATA.md: the split marked [ASSUMED] - m.private shop.rewardOffer.queued: offers waiting behind the shown one; the header says 之后还有 N 项 and the reminder pill +N (a 定向投放 behind a promotion reward put off) - tests: corrected headers, the stale bountyTiers fixture dropped, queued checks (unit + opt-in e2e on desktop and 756x366)
This commit is contained in:
1 parent
49c0ebcf4d
commit
6e0c26af9e
14 files changed
+158
-37
No files matched your search
@@ -187,6 +187,7 @@
|
||||
.rwtag__title { writing-mode: vertical-rl; font-size: .22rem; font-weight: 900; letter-spacing: .2em; line-height: 1; }
|
||||
.rwtag__micro { font-family: var(--font-display); font-size: .09rem; letter-spacing: .14em; opacity: .75; }
|
||||
.rwtag__sub { font-size: .12rem; color: var(--text-md); line-height: 1.3; }
|
||||
.rwtag__more { color: var(--gold); }
|
||||
.rwtag__later { display: flex; align-items: center; gap: .02rem; margin-top: .04rem; padding: .02rem .08rem; font-size: .13rem; color: var(--text-lo);
|
||||
background: rgba(0, 0, 0, .35); border: 1px solid var(--line-2); }
|
||||
.rwtag__later .icon { width: .12rem; height: .12rem; }
|
||||
@@ -200,6 +201,7 @@
|
||||
animation: pulse-gold 1.6s ease-in-out infinite;
|
||||
}
|
||||
.rewardpill .icon { width: .2rem; height: .2rem; }
|
||||
.rewardpill__more { padding: 0 .06rem; border: 1px solid var(--gold); font-size: .13rem; line-height: 1.4; }
|
||||
@keyframes pulse-gold { 50% { box-shadow: 0 0 .24rem rgba(255, 198, 0, .5); } }
|
||||
|
||||
/* ---- two-tap buy / upgrade (research 09 §5): the first tap lifts + enlarges the card and shows 确认购买 ---- */
|
||||
|
||||
@@ -543,18 +543,22 @@ export function completesMerge(priv, slot, { getChess = () => null, getItem = ()
|
||||
* reads 晋升奖励 / PROMOTION; any other offer — a strategy's special refresh (凯瑟琳 定向投放, 娜仁图亚 见者有份), an item
|
||||
* (寻呼模块, 信标) or a 特质 (松果) — reads its `label` with the refresh icon (player report #6 after 0.1.0: 凯瑟琳's three
|
||||
* items showed up as nameless operator cards under 晋升奖励). `items` = the offer holds items (cards drawn as item cards).
|
||||
* `queued` = offers waiting behind this one (shop.rewardOffer.queued, e.g. a 定向投放 behind a promotion reward put
|
||||
* off): `more` (header) and the pill's "+N" say so, null / no suffix when none.
|
||||
* @param {any} offer
|
||||
* @returns {{ title: string, micro: string, sub: string, icon: string, items: boolean, pill: string }}
|
||||
* @returns {{ title: string, micro: string, sub: string, icon: string, items: boolean, pill: string, queued: number, more: string|null }}
|
||||
*/
|
||||
export function offerHeader(offer) {
|
||||
const slots = isObj(offer) && Array.isArray(offer.slots) ? offer.slots : [];
|
||||
const items = slots.some((s) => isObj(s) && s.kind === 'item');
|
||||
const label = isObj(offer) && typeof offer.label === 'string' && offer.label ? offer.label : null;
|
||||
const queued = isObj(offer) && Number.isInteger(offer.queued) && offer.queued > 0 ? offer.queued : 0;
|
||||
const tail = { queued, more: queued ? `之后还有 ${queued} 项` : null };
|
||||
if (!items && (!isObj(offer) || offer.source === 'merge' || offer.source == null) && !label) {
|
||||
return { title: '晋升奖励', micro: 'PROMOTION', sub: '免费选择 1 名', icon: 'crown', items: false, pill: '晋升奖励待选择' };
|
||||
return { title: '晋升奖励', micro: 'PROMOTION', sub: '免费选择 1 名', icon: 'crown', items: false, pill: '晋升奖励待选择', ...tail };
|
||||
}
|
||||
const title = label || (items ? '装备补给' : '特殊招募');
|
||||
return { title, micro: 'SPECIAL', sub: items ? '免费选择 1 件' : '免费选择 1 名', icon: 'refresh', items, pill: `${title}待选择` };
|
||||
return { title, micro: 'SPECIAL', sub: items ? '免费选择 1 件' : '免费选择 1 名', icon: 'refresh', items, pill: `${title}待选择`, ...tail };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Pick-one offer reminder (research 00 §3): the offer's cards themselves live in the shop bar (shopBar.js RewardCards —
|
||||
// after a promotion, or a special refresh such as 凯瑟琳's 定向投放, they replace the bar's operator cards, like the
|
||||
// original). When the player puts the pick off (稍后选择) this pill above the bar brings the cards back; it names the
|
||||
// offer like the bar's header (gameLogic.offerHeader: 晋升奖励待选择 / 定向投放待选择 …, player report #6 after 0.1.0) and
|
||||
// disappears once the server clears `shop.rewardOffer` (picked, or the round ended).
|
||||
// offer like the bar's header (gameLogic.offerHeader: 晋升奖励待选择 / 定向投放待选择 …, player report #6 after 0.1.0), with
|
||||
// "+N" while N more offers wait behind it, and disappears once the server clears `shop.rewardOffer` (picked, or the
|
||||
// round ended).
|
||||
|
||||
import { html, Icon, TierChip } from './components.js';
|
||||
import { offerHeader } from './gameLogic.js';
|
||||
@@ -15,6 +16,6 @@ export function RewardOverlay({ priv, minimized, onMinimize }) {
|
||||
if (!offer || !Array.isArray(offer.slots) || !offer.slots.length || !minimized) return null;
|
||||
const head = offerHeader(offer);
|
||||
return html`<button type="button" class="rewardpill" onClick=${() => onMinimize(false)}>
|
||||
<${Icon} name=${head.icon} /><span>${head.pill}</span>${Number.isInteger(offer.tier) ? html`<${TierChip} tier=${offer.tier} size="sm" />` : null}
|
||||
<${Icon} name=${head.icon} /><span>${head.pill}</span>${Number.isInteger(offer.tier) ? html`<${TierChip} tier=${offer.tier} size="sm" />` : null}${head.queued ? html`<span class="rewardpill__more" title=${head.more}>+${head.queued}</span>` : null}
|
||||
</button>`;
|
||||
}
|
||||
@@ -217,7 +217,7 @@ export function useTwoTap({ editable, keys }) {
|
||||
* the special refreshes of strategies, items and 特质 — e.g. 凯瑟琳 【定向投放】 "在调度中心刷新随机3件装备,可以选择并获得
|
||||
* 其中1件". Each slot is drawn by its kind: an item slot is an item card (icon, name, tier, description, FREE) — player
|
||||
* report #6 after 0.1.0, the items used to be drawn as nameless operator cards — and the header names the offer
|
||||
* (gameLogic.offerHeader: 晋升奖励 / the strategy's effect name …).
|
||||
* (gameLogic.offerHeader: 晋升奖励 / the strategy's effect name …; "之后还有 N 项" while more offers wait behind it).
|
||||
*/
|
||||
export function RewardCards({ offer, priv, editable, onPick, onDetail, onLater, armed, onTap }) {
|
||||
const head = offerHeader(offer);
|
||||
@@ -227,6 +227,7 @@ export function RewardCards({ offer, priv, editable, onPick, onDetail, onLater,
|
||||
<b class="rwtag__title">${head.title}</b>
|
||||
<span class="rwtag__micro">${head.micro}</span>
|
||||
<span class="rwtag__sub">${head.sub}</span>
|
||||
${head.more ? html`<span class="rwtag__sub rwtag__more">${head.more}</span>` : null}
|
||||
<button type="button" class="rwtag__later" onClick=${onLater} title="稍后选择(回合结束后消失)"><${Icon} name="minus" />稍后</button>
|
||||
</div>
|
||||
<div class="shopbar__rwcards">
|
||||
|
||||
Reference in new issue
Block a user