0.2.4-dev: round-29 community fixes and the official shared card pool
- Shared card pool and item stock as in the official mode (the owner's request, from the 路标档案馆 video and public notes): solo low-tier exceptions, co-op operators x2, shared item stock with special-item exceptions, normal / advanced occupancy 1 / 2, re-check on buy, 机变 exhaustion, release on consume / destroy / elimination; 整备 never exceeds stock; invariant held <= cap. - 突袭: one taunt-first reselect right after a revive (the owner's rule); ordinary polls and redeploys keep the 0.2.3 rule; a revive on an enemy's tile stays. #475: online boss / hidden-boss Raid may land on the empty half (owner-limited scope). - 浊心斯卡蒂 S1 x 坚守 no longer bounce redirected damage, and the two shares conserve the hit (idea of PR #464 by @HappyTanuki). - Operator fixes adapted from PRs by @Xinglan233 (#459 哈洛德 S2 elemental trigger, #460 涤火杰西卡 shield on the four adjacent tiles, #461 家族徽章 first hit after stealth, #462 松果 S2 regrow per deploy); 克莱门莎 S2 splash 1.1 / 100% ATK and air auto-trigger (#467); 白面 copying 歌蕾蒂娅 / 余 skips the three-member condition (#473, the owner's video). - 香槟炸弹 is not chosen by friendly auras / heals (PR #468 / #476 by @Siornya); 琳琅诗怀雅 coin balance (PR #450 by @IceCodeNew); Touch prep display (PR #451 by @YinqiMargatroid); lobby header (PR #471 by @YuriRestia); Japanese UI terms (PR #448 by @scutkane). - AI-only boss countdown grace, render-failure cache / recovery without restarting a battle, device units kept on a same-field re-entry, DIY detail / skill previews, large-text result buttons. - golden: battle families equal 0.2.3 except diy-135 / diy-136 (克莱门莎); all 18 release matches move through the shared pool, every flip named in docs/history/0.2.4.md §29.12; two coverage scenarios added.
This commit is contained in:
1 parent
1db8e51023
commit
6bfc08270c
129 files changed
+3477
-1011
No files matched your search
@@ -3,6 +3,7 @@
|
||||
import { GEO } from '../../../../shared/constants.js';
|
||||
import { attackRangeGrid } from '../../../../shared/loadoutRecord.js';
|
||||
import { meleeOnHighGround } from '../../../../shared/highGround.js';
|
||||
import { summonPlacementGrid } from '../../../../shared/summonPlacement.js';
|
||||
import { pieceDir, rangeTiles } from '../facing.js';
|
||||
import { isObj, tileKey } from './shared.js';
|
||||
import { boardTileOf, fieldTile } from './camera.js';
|
||||
@@ -250,15 +251,18 @@ export function tileAllows(ctx, piece, row, col) {
|
||||
/**
|
||||
* Board tiles ('r,c') where a summon whose text reads "只能部署在召唤者攻击范围内" may stand (tokens.json `ownerRange`:
|
||||
* 伺夜's 狼群, 缪尔赛思's 流形 — the tactical point; player report #9 after 0.1.0): its owner's attack range (the
|
||||
* loadout's grid, shared/loadoutRecord.js attackRangeGrid, rotated by the owner's facing around its tile). Null when
|
||||
* loadout's grid, shared/loadoutRecord.js attackRangeGrid, rotated by the owner's facing around its tile).
|
||||
* Jessica's shield uses the four-adjacent-tile grid instead, independent of facing/skill/module. Null when
|
||||
* the piece is not range-bound or its owner is not on the board. `owner` ({ row, col, piece }) replaces the owner's
|
||||
* current position (a summon swapped with its own owner). Mirror of server/match/PlayerState.js summonRange.
|
||||
* @param {ReturnType<typeof placementContext>} ctx
|
||||
* @returns {Set<string> | null}
|
||||
*/
|
||||
export function summonRange(ctx, piece, owner = null) {
|
||||
if (!isObj(piece) || piece.kind !== 'token' || ctx?.getToken?.(piece.id)?.ownerRange !== true) return null;
|
||||
return ownerRangeOf(ctx, piece, owner);
|
||||
if (!isObj(piece) || piece.kind !== 'token') return null;
|
||||
const grid = summonPlacementGrid(piece.id);
|
||||
if (!grid && ctx?.getToken?.(piece.id)?.ownerRange !== true) return null;
|
||||
return ownerRangeOf(ctx, piece, owner, grid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,14 +277,14 @@ export function summonExcluded(ctx, piece, owner = null) {
|
||||
return ownerRangeOf(ctx, piece, owner);
|
||||
}
|
||||
|
||||
/** The attack-range tiles of a summon piece's owner on the board (summonRange / summonExcluded), or null. */
|
||||
function ownerRangeOf(ctx, piece, owner = null) {
|
||||
/** The attack or fixed placement range of a summon piece's owner on the board, or null. */
|
||||
function ownerRangeOf(ctx, piece, owner = null, placementGrid = null) {
|
||||
let at = owner;
|
||||
if (!at) for (const e of ctx.boardAt.values()) if (e.piece.uid === piece.ownerUid && e.piece.kind === 'chess') { at = e; break; }
|
||||
const rec = at && ctx.getChess(at.piece.id);
|
||||
if (!rec) return null;
|
||||
let grid = null;
|
||||
try { grid = attackRangeGrid(deployedRecord(rec, ctx.priv, ctx.getChess, ctx.backups) || rec); } catch { /* the data grid */ }
|
||||
try { grid = placementGrid || attackRangeGrid(deployedRecord(rec, ctx.priv, ctx.getChess, ctx.backups) || rec); } catch { /* the data grid */ }
|
||||
return new Set(rangeTiles(grid || rec.rangeGrid, at.row, at.col, pieceDir(at.piece)).map(([r, c]) => tileKey(r, c)));
|
||||
}
|
||||
|
||||
@@ -367,7 +371,7 @@ export function canPlace(ctx, uid, target) {
|
||||
// dropped onto its own owner (the two swap); an outside-bound one (战术锚点) outside it
|
||||
const ownerSwap = src.area === 'board' && occ && occ.piece.uid === piece.ownerUid ? { row: src.row, col: src.col, piece: occ.piece } : null;
|
||||
const range = summonRange(ctx, piece, ownerSwap);
|
||||
if (range && !range.has(tileKey(row, col))) return no('BAD_TILE', t('只能部署在召唤者攻击范围内'));
|
||||
if (range && !range.has(tileKey(row, col))) return no('BAD_TILE', summonPlacementGrid(piece.id) ? t('只能部署在召唤者相邻四格') : t('只能部署在召唤者攻击范围内'));
|
||||
const out = summonExcluded(ctx, piece, ownerSwap);
|
||||
if (out && out.has(tileKey(row, col))) return no('BAD_TILE', t('只能部署在召唤者攻击范围外'));
|
||||
if (src.area === 'board') {
|
||||
|
||||
Reference in new issue
Block a user