feedback5 WE2: 望's 棋子 may be placed on any tile, as PRTS records (#22)

tools/build-data.mjs TOKEN_POSITION_CORRECTIONS (PRTS 棋子 部署位置 "全部位", 备注
"游戏内召唤物信息与实际不符(显示为仅部署在近战位)") sets the 棋子 record's position to ALL;
validateAll checks every entry. Regenerated offline: one path changed,
backups.tokens.token_10064_wang_stone1.position MELEE -> ALL. Her stock / 阻回 unchanged
(an owner question). Golden: no scenario moved (none places 棋子).
This commit is contained in:
sganggs committed 2026-10-06 15:06:07 +08:00
1 parent 99d8807328
commit ad23320411
4 files changed
+94 -4

No files matched your search

+16 -2
View File
@@ -1483,6 +1483,15 @@ const TOKEN_ABNORMAL = Object.freeze({
enemy_9012_acloon: ['isolated'], // “炎佑”
});
/**
* Summon deployment positions the client's token row gets wrong, from the PRTS summon pages: 望's 棋子 — PRTS 棋子
* 部署位置 "全部位", 备注 "游戏内召唤物信息与实际不符(显示为仅部署在近战位)" (character_table: MELEE). The record's `position`
* (the prep's placement class, board.js positionClass) takes this value.
*/
const TOKEN_POSITION_CORRECTIONS = Object.freeze({
token_10064_wang_stone1: 'ALL', // 棋子
});
/**
* The tokens.json record of a summon (buildTokens; the 自选 picks' summons, buildDiyTokens) from its per-owner
* `variants` (key → variant; `owners` = the keys, in order; the defaults are the first owner's variant).
@@ -1502,7 +1511,7 @@ const TOKEN_ABNORMAL = Object.freeze({
* `ownerRange`: the token text "只能部署在召唤者攻击范围内" (the tacticians' 援军 — 伺夜's 狼群, 缪尔赛思's 流形; PRTS 狼群
* 特性): its hand piece may only be placed on a tile of its owner's attack range (server/match/board.js
* ownerRangeKeys, PlayerState._legal; player report #9 after 0.1.0: 伺夜's tactical point could go anywhere).
* `abnormal` = TOKEN_ABNORMAL (PRTS).
* `abnormal` = TOKEN_ABNORMAL (PRTS); `position` = TOKEN_POSITION_CORRECTIONS (PRTS) or the token row's.
*/
function summonRecord(ctx, tokenId, char, variants, produced) {
const displayType = ctx.ac.shopStateTokenDict?.[tokenId]?.tokenDisplayType || null;
@@ -1512,7 +1521,7 @@ function summonRecord(ctx, tokenId, char, variants, produced) {
return {
tokenId, kind: 'summon', name: char.name, appellation: char.appellation || null,
desc: stripRich(first.trait.desc), descRaw: first.trait.descRaw,
profession: char.profession, subProfessionId: char.subProfessionId, position: char.position,
profession: char.profession, subProfessionId: char.subProfessionId, position: TOKEN_POSITION_CORRECTIONS[tokenId] ?? char.position,
displayType, placeable: displayType !== 'HIDDEN' && produced, ownerRange,
owners,
// Defaults = first owner's variant; per-owner data in variants[owner].
@@ -3777,6 +3786,11 @@ function validateAll(f) {
if (!tokens[id]) err(`TOKEN_ABNORMAL: ${id} is not a token`);
for (const f of fl) if (f !== 'healFree' && f !== 'isolated') err(`TOKEN_ABNORMAL: ${id}: unknown effect ${f}`);
}
for (const [id, pos] of Object.entries(TOKEN_POSITION_CORRECTIONS)) {
const t = tokens[id] ?? backups?.tokens?.[id];
if (!t || t.kind !== 'summon') err(`TOKEN_POSITION_CORRECTIONS: ${id} is not a summon`);
else if (t.position !== pos || !['MELEE', 'RANGED', 'ALL'].includes(pos)) err(`TOKEN_POSITION_CORRECTIONS: ${id}: position ${t.position}`);
}
for (const t of Object.values(tokens)) {
if (!t.stats) err(`token ${t.tokenId}: no stats`);
for (const [o, v] of Object.entries(t.variants || {})) if (!Array.isArray(v.sources) || !v.sources.length) err(`token ${t.tokenId}@${o}: no sources`);