Watching a teammate shows their hand, 临时整备区, equipment, strategy and effects (#129)
The prep scout of another player's board carries their 整备区 hand and 临时整备区 as units on the bench rows (like the own prep bench), the equipped items of their operators, their strategy in the drawer and their effects column (the official mode shows a teammate's hand too). The scout signature includes the hand / temp slots, so a moved card refreshes the watcher. Closes #128. Contributed by @2321Robin.
This commit is contained in:
1 parent
bd892a4dd6
commit
bce182703b
15 files changed
+521
-20
No files matched your search
@@ -96,7 +96,7 @@ import {
|
||||
snapHud, activeBubbles, shortcutFor, shortcutBlocked, closesOnFieldPress, phaseTotalSeconds, homeFieldId, ownFieldId, normalizeSp, sortedPlayers,
|
||||
countdownState, shopBlockReason, stageOverrides, effectiveStage, watchTarget, dropFailureReason,
|
||||
previewEnemyKey, prepCamera, prepCameraFor, foldCamera, deployFieldOf, panelSide, panelSlots, bondPopupPlace, chessLoadout, unitLoadout,
|
||||
mergeTarget, modeOffBonds, readyFundsPrompt,
|
||||
mergeTarget, modeOffBonds, readyFundsPrompt, ownerBandId,
|
||||
} from '../ui/gameLogic.js';
|
||||
import { toast } from '../ui/toasts.js';
|
||||
import { BriefingScreen } from './briefing.js';
|
||||
@@ -234,6 +234,10 @@ function MatchScreen() {
|
||||
const alive = spectator ? false : priv ? priv.alive !== false : meP?.alive !== false;
|
||||
const home = homeFieldId(pub, myId);
|
||||
const watchingOther = !!watching && watching !== home && watching !== ownFieldId(myId);
|
||||
// watching a teammate's prep board: the 本局信息 drawer shows THEIR 策略 in place of one's own (user playtest #2 item 2)
|
||||
const scoutPid = watchingOther && field?.prep && typeof field.fieldId === 'string' && field.fieldId.startsWith('n:') ? field.fieldId.slice(2) : null;
|
||||
const scoutBandId = scoutPid ? ownerBandId(pub, scoutPid) : null;
|
||||
const scoutBandOwner = scoutPid ? (players.find((p) => p.playerId === scoutPid)?.name || null) : null;
|
||||
const editable = phase === PHASE.PREP && !!priv && alive && !priv.ready && !watchingOther;
|
||||
const showShop = !!priv && alive && (phase === PHASE.PREP || phase === PHASE.SP_DRAFT || phase === PHASE.ROUND_START) && !watchingOther;
|
||||
const layersDisabled = phase === PHASE.UNITE || isBossPhase(phase);
|
||||
@@ -404,7 +408,9 @@ function MatchScreen() {
|
||||
evBufRef.current.delete(field.fieldId);
|
||||
const earlySnap = snapBufRef.current.get(field.fieldId);
|
||||
snapBufRef.current.delete(field.fieldId);
|
||||
const kind = field.kind === 'hidden' ? 'boss' : field.kind || 'normal';
|
||||
// a scouted prep board frames like the own prep with the shop folded (the bench row included, app.js camRect);
|
||||
// 'prep' expands the rect's top to the hand row
|
||||
const kind = field.prep ? 'prep' : (field.kind === 'hidden' ? 'boss' : field.kind || 'normal');
|
||||
const pf = (Array.isArray(pub?.fields) ? pub.fields : []).find((f) => f && f.fieldId === field.fieldId);
|
||||
const members = Array.isArray(pf?.players) ? pf.players : Array.isArray(field.players) ? field.players : [];
|
||||
const sides = field.sides && typeof field.sides === 'object' ? field.sides : null;
|
||||
@@ -415,7 +421,7 @@ function MatchScreen() {
|
||||
// a lone player's boss field (solo modes, the odd player of a co-op Final Assault: the `_s` templates route every
|
||||
// enemy to the left objective) is framed on its own half like the ‹ › half view; pairs start on 全景
|
||||
const lone = kind === 'boss' && members.length === 1;
|
||||
setCam(kind, lone ? { rect: field.rect, side, half: true } : { rect: field.rect, side });
|
||||
setCam(kind, lone ? { rect: field.rect, side, half: true } : { rect: field.rect, side, ...(field.prep ? { shop: false } : {}) });
|
||||
audio.setFieldUnits(field.units);
|
||||
if (early && early.length) {
|
||||
// replay state-bearing events only (a burst of stale hit sparks / damage numbers would look wrong)
|
||||
@@ -1246,7 +1252,7 @@ function MatchScreen() {
|
||||
self=${Number.isFinite(priv?.lp) ? { lp: priv.lp, pending: liveLpNow.pending, unite: liveLpNow.unite, left: liveLpNow.left } : null}
|
||||
observe=${cc ? { canObserve: (p) => observeTarget(p, pub, myId, { observing: watchingOther, ownDone: localDone }), observing: watchingOther, onBack: backHome } : null} />
|
||||
|
||||
<div class="gm__effects"><${EffectsList} effects=${priv?.effects} /></div>
|
||||
<div class="gm__effects"><${EffectsList} effects=${watchingOther && field ? (field.effects ?? null) : priv?.effects} /></div>
|
||||
|
||||
${watchingOther && !combat ? html`<div class="gm__watching" role="status">
|
||||
<${GIcon} name="eye" /><span>正在查看 <b>${watchedName}</b> 的阵地(只读)</span>
|
||||
@@ -1283,6 +1289,7 @@ function MatchScreen() {
|
||||
</div>
|
||||
|
||||
${drawer ? html`<${EnemyDrawer} tab=${drawer} onTab=${setDrawer} pub=${pub} priv=${priv} onClose=${() => setDrawer(null)}
|
||||
bandId=${scoutBandId} bandOwner=${scoutBandOwner}
|
||||
onEnemy=${(k, n) => setDetail({ kind: 'enemy', id: k, count: n })} onChess=${(id) => setDetail({ kind: 'chess', id })} />` : null}
|
||||
|
||||
${bondPop ? html`<${BondPopup} bondId=${bondPop.bondId} entry=${bondPop.entry} priv=${bondPop.priv} banned=${pub?.bannedChess || []} owner=${bondPop.name}
|
||||
|
||||
Reference in new issue
Block a user