feedback7: merge fb7-g-ui — PRs #306 #309 #341 #349 #356 #358 #361 applied as-is (Grok coding run; static review p3: MERGE)
- Golden unchanged (union OK); broad node --test 5257 (5256 pass, 0 fail, 1 skipped); lint 0 errors.
This commit is contained in:
commit
f9969aeeef
15 files changed
+842
-55
No files matched your search
@@ -8,7 +8,6 @@
|
||||
// Installed on Match.prototype by server/match/Match.js (a method container: never instantiated; `this` is the match).
|
||||
|
||||
import { PHASE, ERR } from '../../../shared/constants.js';
|
||||
import { boardOrder, pieceDir } from '../board.js';
|
||||
import { snapFrame } from '../fields.js';
|
||||
import { OK, fail } from './common.js';
|
||||
|
||||
@@ -238,38 +237,9 @@ export class MatchWatch {
|
||||
}
|
||||
}
|
||||
|
||||
/** Board signature of a prep scout view (board, hand and temp rows: a shop or funds change is not a board change).
|
||||
* Hand / temp entries carry their slot — `prepFieldMeta` draws x from it, so a piece moved to another slot is a
|
||||
* change (review of PR #129). In a boss round's prep the pair partner's board is part of the view (item 51). */
|
||||
_prepScoutSig(ps) {
|
||||
const parts = [];
|
||||
const boardSig = (q) => {
|
||||
for (const { r, c, piece } of boardOrder(q.board)) {
|
||||
const items = piece.kind === 'chess' && Array.isArray(piece.items) ? piece.items.map((it) => `${it.uid}:${it.id}`).join(',') : '';
|
||||
parts.push(`${piece.uid}:${piece.id}@${r},${c}:${pieceDir(piece)}:${items}`);
|
||||
}
|
||||
};
|
||||
boardSig(ps);
|
||||
const m = this._bossMateOf(ps);
|
||||
if (m) { parts.push(`|mate:${m.mate.playerId}:${m.side}`); boardSig(m.mate); }
|
||||
for (let i = 0; i < ps.hand.length; i++) {
|
||||
const piece = ps.hand[i];
|
||||
if (!piece) continue;
|
||||
const items = piece.kind === 'chess' && Array.isArray(piece.items) ? piece.items.map((it) => `${it.uid}:${it.id}`).join(',') : '';
|
||||
parts.push(`h${i}:${piece.uid}:${piece.id}:${items}`);
|
||||
}
|
||||
for (let i = 0; i < ps.temp.length; i++) {
|
||||
const piece = ps.temp[i];
|
||||
if (!piece) continue;
|
||||
const items = piece.kind === 'chess' && Array.isArray(piece.items) ? piece.items.map((it) => `${it.uid}:${it.id}`).join(',') : '';
|
||||
parts.push(`t${i}:${piece.uid}:${piece.id}:${items}`);
|
||||
}
|
||||
return parts.join(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* Push prepFieldMeta to whoever is scouting `ps` during prep (GitHub #87). `to` always receives the current board
|
||||
* (the player who just asked to watch); everyone scouting it receives a new `m.field` only when the board changed.
|
||||
* Push prepFieldMeta to whoever is scouting `ps` during prep (GitHub #87). `to` always receives the current view
|
||||
* (the player who just asked to watch); everyone scouting it receives a new `m.field` only when that view changed.
|
||||
* A live battle field owns the `n:<pid>` id, so this stays quiet once fields exist.
|
||||
*/
|
||||
_notifyPrepScouts(ps, { to = null } = {}) {
|
||||
@@ -277,12 +247,13 @@ export class MatchWatch {
|
||||
const fid = `n:${ps.playerId}`;
|
||||
const watchers = this.watchersOf(fid);
|
||||
if (!watchers.length) return;
|
||||
const sig = this._prepScoutSig(ps);
|
||||
const meta = this.prepFieldMeta(ps);
|
||||
// Deduplicate the public payload itself: effects and enemy previews can change without any piece moving (#346).
|
||||
const sig = JSON.stringify(meta);
|
||||
const changed = sig !== ps._prepScoutSig;
|
||||
ps._prepScoutSig = sig;
|
||||
const dest = changed ? watchers : (to ? [to] : []);
|
||||
if (!dest.length) return;
|
||||
const meta = this.prepFieldMeta(ps);
|
||||
for (const pid of dest) this.sendTo(pid, meta);
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,9 @@ export class PlayerEconomy {
|
||||
if (loc.piece.kind !== 'chess') return fail(ERR.BAD_TARGET, loc.piece.kind === 'item' ? 'items cannot be sold' : 'tokens cannot be sold');
|
||||
const piece = loc.piece;
|
||||
// its equipment returns to the hand (overflow temp): refuse rather than destroy it when there is no room
|
||||
const room = this.hand.filter((x) => x == null).length + this.temp.filter((x) => x == null).length + (loc.area === 'hand' || loc.area === 'temp' ? 1 : 0);
|
||||
// Removing the owner's summon stacks frees one slot per stack, regardless of its summon count.
|
||||
const freed = (x) => x == null || (x.kind === 'token' && x.ownerUid === piece.uid);
|
||||
const room = this.hand.filter(freed).length + this.temp.filter(freed).length + (loc.area === 'hand' || loc.area === 'temp' ? 1 : 0);
|
||||
if ((piece.items || []).length > room) return fail(ERR.HAND_FULL, 'no room for the equipment');
|
||||
this._detach(loc);
|
||||
this.removeTokensOf(piece.uid);
|
||||
|
||||
Reference in new issue
Block a user