feedback1 WC: no deployment in the water, tactical points inside the tactician's range

Player reports #3 and #9 after the 0.1.0 release.

#3 On 战场#08(下半) 涨潮控制 (act2autochess_m04) operators could be placed in the
pool and 突袭 members jumped into it. The 深水区 (tile_deepsea) has buildableType
ALL in the level file, but it refuses deployment (PRTS 地形 深水区 "地形机制:拒绝
部署"; the season-1 战场#05 puts a 特制水上平台 - "在水上建立可以部署任意单位的
平台" - on every one of its water tiles).
- grid.js DEPLOY_REFUSED_TILES: the legend's effective build is NONE, so
  canStand (突袭 landing tile, tactical points, summon tiles) never picks the
  water; a hard-blocked 射击台 / mound tile takes no melee unit either.
- build-data: stages.json legend `buildable` is the effective type (the level's
  value kept in `buildableType`), deployTiles exclude the water, a 特制水上平台
  makes its tile deployable (act1 m05, inactive). board.js / gameLogic.js
  deploy maps follow (water platforms included); bots plan on the same map.
- Gate routes are unchanged; the water now counts as non-blockable ground in
  the path tie-break (audit lists updated).

#9 伺夜's 狼群 and 缪尔赛思's 流形 ("只能部署在召唤者攻击范围内", tokens.json
`ownerRange`) could be placed anywhere.
- PlayerState._legal / summonRange: a range-bound summon only on a tile of its
  owner's attack range (loadout grid rotated by the owner's facing); swaps with
  the owner are checked from the owner's new tile; re-orienting (or promoting)
  the owner sends a summon left outside back onto its stack with a toast.
- The client lights and accepts the same tiles (gameLogic.summonRange), the bot
  plans inside them, the invariants check it, the 伺夜 kit re-uses the piece's
  tile only inside her range.

Tests: test/match/feedback1-placement, test/sim/feedback1-water, the opt-in
headless-Chrome test/ui/feedback1-placement.e2e (fastServer hook SP_STAGE);
existing summon / deploy / pathing tests moved off the water tiles.
This commit is contained in:
sganggs committed 2026-10-03 02:01:34 +08:00
1 parent 7f134737ce
commit c92867656d
26 files changed
+789 -73

No files matched your search

+3 -1
View File
@@ -46,9 +46,11 @@ function official(sid, { crates: extraCrates = [], blocks: extraBlocks = [], rec
for (const [r, c] of extraBlocks) blocked.add(`${r},${c}`);
const inside = (r, c) => (rect ? r >= rect.r0 && r <= rect.r1 && c >= rect.c0 && c <= rect.c1 : r >= 0 && r < H && c >= 0 && c < W);
const passable = (r, c) => inside(r, c) && ['ALL', 'WALK_ONLY'].includes(tile(r, c).passableMask) && !blocked.has(`${r},${c}`);
// non-blockable walkable terrain: not LOWLAND buildable for melee (floor, gates, goal, teleports)
// non-blockable walkable terrain: not LOWLAND buildable for melee (floor, gates, goal, teleports) — and the 深水区,
// which refuses deployment whatever its buildableType (PRTS 地形 深水区 "拒绝部署"; player report #3 after 0.1.0)
const nb = (r, c) => {
const t = tile(r, c);
if (t.tileKey === 'tile_deepsea') return true;
return !(t.heightType === 'LOWLAND' && (t.buildableType === 'ALL' || t.buildableType === 'MELEE'));
};
const bres = ([r0, c0], [r1, c1], clear) => {