feedback5 WN: 补位 display follows the official game (the owner's recall of 2026-10-06) — a chess the player does not own is shown as its stand-in wherever the player's copy appears: shop and reward cards (the stand-in's portrait, name, class and backup skill; the chess's bonds, tier and price; a small 「替补」 mark), the hand and 临时整备区 pieces (the stand-in's model, a 「替补」 tag; the board already was), the detail card (the stand-in's portrait, name, skill, talents and module with the chess's bonds and 特质, 「银灰的替补」 under the name [ASSUMED]), bond popups (own and a teammate's by UnitInfo standInFor through ownerBoard / ownerOps), the result lineup (m.result standInFor), prep scouting of the bench, the equip-replace dialog, the elite and gift tickers; rules unchanged (bonds, price, tier, merges, pools and 特质 stay the chess's); new strings through t() with English; tests updated (standin-ui 15, standin-ownership 7, watch-bonds wiring) and the e2e now ends on the result screen (fastServer SP_FINISH_AFTER); golden unchanged
This commit is contained in:
1 parent
78251f499c
commit
0e8004a382
32 files changed
+518
-181
No files matched your search
@@ -75,12 +75,13 @@
|
||||
// * Operator ownership (0.2.0 补位, the approved plan — owner's decision 2026-10-05): the human's `seat.notOwned` (base
|
||||
// chess ids marked 未持有 on the 干员持有 screen) is re-checked against this match's data (shared/protocol.js
|
||||
// checkNotOwned + a stand-in record in data/backups.json) and fixed for the match (`standIns`; bots own every
|
||||
// operator). A piece of such a chess — normal or elite, wherever it is — keeps the chess's identity (name, bonds,
|
||||
// 特质, tier, price, sell price, merge: every rule that reads gd.chess) and fights as its official stand-in
|
||||
// operator). A piece of such a chess — normal or elite, wherever it is — keeps the chess's identity for the rules
|
||||
// (bonds, 特质, tier, price, sell price, merge: every rule that reads gd.chess) and is its official stand-in
|
||||
// (`fieldRecord` = gd.standIn: body, stats, range, position, skills / talents / module — the backup selection, the
|
||||
// loadout never applies to it, "对于补位干员其技能不可更改"): battleInput marks it `standIn: true`, placeClass /
|
||||
// summon range / the bots' range read the stand-in record, it makes no summons (none of the 17 stand-ins has one),
|
||||
// and the scouting views draw it with the stand-in's art on the board. m.private exposes `standIns`.
|
||||
// and what shows it shows the stand-in (the owner's recall of the official mode, 2026-10-06): the scouting views
|
||||
// (board and bench), the m.result lineup (`standInFor`), the elite / gift tickers' names. m.private exposes `standIns`.
|
||||
// * 自选编队 (0.2.0 DIY, the owner's decisions of 2026-10-05; player/diy.js): the human's `seat.diy` picks are re-checked
|
||||
// against this match's data and kits and fixed for the match (`diy`; bots none [ASSUMED]). With picks, `this.gd` is the
|
||||
// player's data view: the slotted slots' ids (normal and elite) are the composed 自选 records, so the player's piece
|
||||
|
||||
@@ -643,8 +643,15 @@ export function makeCtx(m, ps, source, hook, ev = null) {
|
||||
// a string or a shared/i18n.js msg(msgid, params)
|
||||
toast: (text, kind = 'info') => m.toast(ps, kind, text && typeof text === 'object' ? text : String(text)),
|
||||
ticker: (text) => m.tickerText(text && typeof text === 'object' ? text : String(text)),
|
||||
/** CHAR_GIFT broadcast to this player: "{0}博士给你赠送了{1}". */
|
||||
giftTicker: (fromName, chessId) => { const c = gd.chess(chessId); m.tickerFor('CHAR_GIFT', [String(fromName), c ? c.name : String(chessId)], { to: ps.playerId }); },
|
||||
/**
|
||||
* CHAR_GIFT broadcast to this player: "{0}博士给你赠送了{1}" — named as this player sees the gift (a chess it fields as
|
||||
* its 补位 stand-in by the stand-in's name: 0.2.0, the owner's recall of the official mode, 2026-10-06).
|
||||
*/
|
||||
giftTicker: (fromName, chessId) => {
|
||||
const c = gd.chess(chessId);
|
||||
const shown = c && typeof ps.fieldRecord === 'function' ? ps.fieldRecord(c) || c : c;
|
||||
m.tickerFor('CHAR_GIFT', [String(fromName), shown ? shown.name : String(chessId)], { to: ps.playerId });
|
||||
},
|
||||
|
||||
// ---- team
|
||||
teammates: () => m.alivePlayers().filter((p) => p !== ps).map((p) => makeCtx(m, p, source, hook, null)),
|
||||
|
||||
@@ -220,19 +220,20 @@ export class MatchViews {
|
||||
// items included (the client draws their floating plates). PRTS 帮助 counts the temp area with the hand (review of
|
||||
// PR #129). Part of the meta for every watcher alike — the spectator seat's copy equals a teammate's
|
||||
// (test/match/spectator.test.js). User playtest #2 item 1 (GitHub #44).
|
||||
// (a held chess the player fields as its stand-in keeps the chess's own art — the hand shows the original operator,
|
||||
// the approved 0.2.0 补位 plan — and carries `standInFor`: its card shows the stand-in it deploys as)
|
||||
// (a held chess the player fields as its stand-in is the stand-in there too — name, art, max HP — and carries
|
||||
// `standInFor`, like a board piece: the owner's recall of the official mode, 2026-10-06, the hand shows the stand-in)
|
||||
const benchUnit = (piece, i, y) => {
|
||||
const rec = piece.kind === 'item' ? gd.item(piece.id) : piece.kind === 'token' ? gd.token(piece.id) : gd.chess(piece.id);
|
||||
const assets = (rec && rec.assets) || {};
|
||||
const lo = piece.kind === 'chess' && rec ? ps.loadoutFor(rec) : null;
|
||||
const standIn = piece.kind === 'chess' && rec && ps.fieldsStandIn(rec) ? this.gd.standIn(rec.chessId) : null;
|
||||
const body = standIn || rec;
|
||||
const assets = (body && body.assets) || {};
|
||||
const lo = piece.kind === 'chess' && rec ? ps.loadoutFor(rec) : null;
|
||||
units.push({
|
||||
id: piece.uid, uid: piece.uid, kind: piece.kind === 'token' ? 'token' : piece.kind === 'item' ? 'item' : 'op',
|
||||
side: 'ally', ownerId: ps.playerId, defId: piece.id,
|
||||
name: rec ? rec.name : piece.id, tier: rec && Number.isInteger(rec.tier) ? rec.tier : 1, golden: !!(rec && rec.isGolden),
|
||||
spine: assets.spine || (rec && rec.charId) || piece.id, avatar: assets.avatar || (rec && rec.charId) || piece.id,
|
||||
x: i, y, maxHp: rec && rec.stats && Number.isFinite(rec.stats.maxHp) ? rec.stats.maxHp : 1,
|
||||
name: body ? body.name : piece.id, tier: rec && Number.isInteger(rec.tier) ? rec.tier : 1, golden: !!(rec && rec.isGolden),
|
||||
spine: assets.spine || (body && body.charId) || piece.id, avatar: assets.avatar || (body && body.charId) || piece.id,
|
||||
x: i, y, maxHp: body && body.stats && Number.isFinite(body.stats.maxHp) ? body.stats.maxHp : 1,
|
||||
skillIndex: lo && Number.isInteger(lo.skillIndex) ? lo.skillIndex : undefined,
|
||||
moduleId: lo && typeof lo.moduleId === 'string' ? lo.moduleId : undefined,
|
||||
items: piece.kind === 'chess' && Array.isArray(piece.items) && piece.items.length ? piece.items.map((it) => it.id) : undefined,
|
||||
|
||||
@@ -131,8 +131,11 @@ export class PlayerAcquire {
|
||||
}
|
||||
this.stats.merges++;
|
||||
this.pushRewardOffer('merge');
|
||||
// (named as everyone sees the elite: a chess this player fields as its stand-in by the stand-in's name — 0.2.0 补位,
|
||||
// the owner's recall of the official mode, 2026-10-06 [ASSUMED for the ticker])
|
||||
const rec = this.gd.chess(goldenId);
|
||||
this.m.tickerFor('GOLDEN_CHAR', [this.name, rec ? rec.name : goldenId], { playerId: this.playerId });
|
||||
const shown = rec ? this.fieldRecord(rec) || rec : null;
|
||||
this.m.tickerFor('GOLDEN_CHAR', [this.name, shown ? shown.name : goldenId], { playerId: this.playerId });
|
||||
this.m.dispatch(this, 'onMerge', { kind: 'chess', piece: elite, baseId, consumed: consumed.map((l) => l.piece.uid), area: where });
|
||||
return elite;
|
||||
}
|
||||
|
||||
@@ -124,8 +124,9 @@ export class PlayerBasics {
|
||||
* The record this player's piece of chess record `rec` fights with (0.2.0 补位): the stand-in record
|
||||
* (gd.standIn — the chess's identity, the stand-in's body) when the player fields its stand-in; for a DIY slot record
|
||||
* the player's 自选 record of that slot (this.gd — a caller holding the match's own record of the slot gets the
|
||||
* operator); else `rec` itself. Rules about the unit's body read it (placement class, summon / bot ranges, the
|
||||
* scouting art); rules about the chess (price, bonds, 特质, merges, pools) keep reading gd.chess.
|
||||
* operator); else `rec` itself. Rules about the unit's body read it (placement class, summon / bot ranges), and so
|
||||
* does what shows the piece (the scouting art, the elite / gift tickers' names — the owner's recall of 2026-10-06: the official
|
||||
* mode shows the stand-in everywhere); rules about the chess (price, bonds, 特质, merges, pools) keep reading gd.chess.
|
||||
* @param {object|null} rec
|
||||
*/
|
||||
fieldRecord(rec) {
|
||||
|
||||
@@ -89,7 +89,8 @@ export class PlayerViews {
|
||||
// DESIGN §16: the effective operator loadout ({ [baseChessId]: { skill, module } }; chess not listed use defaults)
|
||||
loadout: this.loadout,
|
||||
// 0.2.0 补位: the base chess ids this player fields as their stand-ins in this match (the not-owned list the seat had
|
||||
// at the match start; [] = every operator owned) — the client's 「替补:X」 badges, the stand-in's art and card
|
||||
// at the match start; [] = every operator owned) — the client shows these as their stand-ins (cards, pieces, the
|
||||
// detail card, with a small 「替补」 mark)
|
||||
standIns: this.standIns,
|
||||
// 0.2.0 自选编队: this player's 自选 picks in this match ({ [slotBaseId]: { charId, skillIndex, uniEquipId } } — the seat's
|
||||
// when the match started; {} = none) — the client composes the operator's record for its own cards and pieces
|
||||
|
||||
@@ -100,6 +100,10 @@ export function buildResult(m, outcome) {
|
||||
// 0.2.0 自选编队: a DIY slot's pick — the result screen names and draws the operator (shared/diy.js diyRecord)
|
||||
const pick = typeof ps.diyPickOf === 'function' ? ps.diyPickOf(piece.id) : null;
|
||||
if (pick) e.diy = { charId: pick.charId, skillIndex: pick.skillIndex, uniEquipId: pick.uniEquipId };
|
||||
// 0.2.0 补位: a chess this player fielded as its stand-in — the result screen draws the stand-in (the owner's recall
|
||||
// of the official mode, 2026-10-06); `standInFor` = the replaced operator's charId, like the sim's UnitInfo
|
||||
const si = typeof ps.fieldsStandIn === 'function' && ps.fieldsStandIn(piece.id) ? gd.standIn(piece.id) : null;
|
||||
if (si && si.standInFor) e.standInFor = si.standInFor;
|
||||
return e;
|
||||
});
|
||||
// the team's clear counts for the players still in; an eliminated / departed teammate did not pass the boss round
|
||||
|
||||
Reference in new issue
Block a user