feedback5: merge CB1 — community reports (bonds / strategies / items): a pair of colds on an enemy becomes the freeze and leaves no cold (the 谢拉格 wind no longer freezes for good), a 复活 (埃芒加德's 命结之秘, M3茧甲) is a knock-out and an immediate free redeploy where the operator lies (砾's and 瑕光's 被击倒时 / 部署时 layers fire), 佩佩's special refresh is paid, the result card hides the layers of 调和 / 协防干员 / 独行 / 绝技, the 炎佑 keeps off 外勤医疗's slot, 凯瑟琳's 定向投放 offers every shop item; 烛煌's 绝处重燃 before the hammer's lock and the 寻呼模块 / 简易通讯机 tier cap kept as they are (the owner's decisions of 2026-10-07); §25.15 → §25.21 (§25.15 is the shortcuts'); golden: vs feedback5 CB1's own rules — roster-005/009/010/012/014/015/016/018/026/029/031/033/036/040/042/046/047/049, bond-egirShip-high, bond-indomShip-low, bond-kjeragShip-high, bond-maniShip-high, bond-raidShip-low, bond-steadShip-high, bond-suntShip-low, boss-boss_2/3/4/6-pair, hidden-boss_8/9/10-pair, standin-07, matches solo-FUNNY-1, solo-NORMAL-1, solo-HARD-1, solo-ABYSS-1, coop3-ABYSS-5, coop4-FUNNY-6, coop4-ABYSS-7; vs CB1 what feedback5 changed since its base (CB2, CB3, CB4, CB5) plus roster-014
Conflicts resolved by hand: - server/sim/content/items/battle.js: CB3 had extended `revivedInPlace` (an in-place 复活 restarts a deploy-timed skill, item 44); CB1 replaced the in-place revive by PRTS's form — `reviveNow`, a `death` hook that redeploys the operator at once, free, where it lies — and removed `revivedInPlace`. CB1's side is kept: its redeploy resets the skill, so an `activateOnDeploy` skill starts anew by itself; CB3's tests (test/sim/feedback5-raid-revive.test.js: the jump at once after M3茧甲 / 埃芒加德, the window back to full, 砾's fresh barrier) pass on it unchanged. Their header, bonds_core's comment, DESIGN §25.17.5 say so. - docs/SIM.md, docs/design/engine.md: CB1's `fatal` rows (the 复活 are `death` hooks now); the `death` rows also say a deploy-timed skill starts anew (§25.17.5). - data/choices.json: no conflict; `node tools/build-data.mjs --offline` on the merged tree rewrites all 15 data files byte-identically, and the JSON compare with feedback5 shows only pools.pool_equip_kathe.maxTier removed (CB1). - docs/history/0.2.0.md: CB1's section renumbered §25.21 (its §25.15.1–10 and two self-citations; no citation of it elsewhere), placed last; the owner's decisions of 2026-10-07 on items 5 and 45 recorded there, in the intro and in the two pin tests' headers (feedback5-blaze-hammer, feedback5-cb1-pins). Golden: solo-FUNNY-1 (outside CB1's list) has 6 埃芒加德 revives and 85 freezes on feedback5's path (instrumented). roster-014 differs from CB1's own digest by 玛恩纳's 无动于衷: CB3's rule (every enemy damage instance) answers the 萨卡兹枯朽战车's pollution that hits a 卡西米尔 operator in CB1's timeline — with that counter limited to attacks the merged roster-014 equals CB1's digest exactly (checked). Gate: non-browser suites 5021 / 5021, npm run golden ok, test/golden.test.js 9 / 9, lint 0 errors, check:imports ok, typecheck ok.
This commit is contained in:
commit
9ca52ba798
39 files changed
+1433
-861
No files matched your search
@@ -7,8 +7,12 @@
|
||||
// act1autochess_band2_buff 阿米娅 众志合一 ≥ value_i active bonds (highest i) ⇒ every operator ATK +atk_i,
|
||||
// HP +max_hp_i (直接乘算 — support directMods —, bonds snapshot at combat start)
|
||||
// act1autochess_band28_buff 埃芒加德 命结之秘 the first max_respawn_cnt operator knock-downs of the battle revive at
|
||||
// once at full HP (runs after every other death saver, items included;
|
||||
// a new deployment for 坚固维式重锤's lock — items revivedInPlace)
|
||||
// once — PRTS 备注 "“复活”的实现方式为:受益者因移动之外的原因退场时下次部署
|
||||
// 的再部署时间和费用归零": the knock-out stands (被击倒时 effects run) and the
|
||||
// operator redeploys at once, free, where it lies (部署时 effects run, SP
|
||||
// reset): items reviveNow, a `death` hook after M3茧甲's and before 阿戈尔
|
||||
// 5 / 不屈 (in place until 0.2.0, community report 「…砾和瑕光这种死亡和部
|
||||
// 署的叠层效果,如果有艾芒加德的3次复活似乎是无法触发」)
|
||||
// act1autochess_band13_buff 克莱门莎 崇高牺牲 a <bond_id> operator knocked down ⇒ +its tier (等阶) <bond_id> layers
|
||||
// (bond_add_type by_charlevel; no "已激活" in the text ⇒ requireActive false)
|
||||
// act1autochess_band16_buff 大帝 加急调派 "每次部署后再部署时间减少50%": every deployment of an operator stacks one
|
||||
@@ -37,12 +41,15 @@ import {
|
||||
num, buffsOf, bandRecord, isOp, onField, isElite, tierOf, unitBonds, activeBondIds, playerOps, passiveBuff, fxOn,
|
||||
matchBands, gainLayers, alliesAround, N4, baseChessId, isGroundOp, directMods,
|
||||
} from '../support/index.js';
|
||||
import { weaknessRetype, addShieldLayer, PRIO_REVIVE, revivedInPlace } from '../items/battle.js';
|
||||
import { weaknessRetype, addShieldLayer, PRIO_RESPAWN, reviveNow } from '../items/battle.js';
|
||||
import { spawnMapChar } from '../tokens.js';
|
||||
|
||||
export const AMEDIC_BAND = 'band_amedic';
|
||||
/** 'fatal' priority of 埃芒加德: after the operators' own items (PRIO_REVIVE / PRIO_RESPAWN) and every talent / skill saver. */
|
||||
export const PRIO_BAND_REVIVE = PRIO_REVIVE - 10;
|
||||
/**
|
||||
* 'death' priority of 埃芒加德's revive: a knock-out (so after every `fatal` saver — kits', 坚固维式重锤's 不死), after the
|
||||
* operator's own M3茧甲 (PRIO_RESPAWN 13), before 阿戈尔 5's first-knock-out revive (11) and 不屈 (10).
|
||||
*/
|
||||
export const PRIO_BAND_REVIVE = PRIO_RESPAWN - 1;
|
||||
|
||||
const keyOf = (bandId, part = '') => `band:${bandId}${part ? `:${part}` : ''}`;
|
||||
const deployedOps = (battle, pid) => playerOps(battle, pid, { fieldOnly: true });
|
||||
@@ -68,13 +75,10 @@ const BY_KEY = {
|
||||
const max = Math.floor(num(p.max_respawn_cnt, 3));
|
||||
if (!(max > 0)) return;
|
||||
let used = 0;
|
||||
battle.on('fatal', (c) => {
|
||||
battle.on('death', (c) => {
|
||||
const u = c.unit;
|
||||
if (c.prevented || used >= max || !isOp(u) || u.ownerId !== ps.playerId || !u.alive) return;
|
||||
if (used >= max || !isOp(u) || u.ownerId !== ps.playerId || !reviveNow(battle, c, 'band')) return;
|
||||
used++;
|
||||
c.prevented = true;
|
||||
u.hp = u.s.maxHp;
|
||||
revivedInPlace(u); // in place for PRTS's 0-time / 0-cost redeploy: a new deployment for 坚固维式重锤's lock (items)
|
||||
fxOn(battle, 'revive', u, keyOf(bandId), bandId, { left: max - used });
|
||||
}, { priority: PRIO_BAND_REVIVE });
|
||||
},
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
// give_coin_in_round {round,coin} 老鲤 income of round `round` = coin (R1/R2 0, R3 15)
|
||||
// prep_start_gain_chess_from_pool_in_round {round} 老鲤 round start of `round`: 1 chess of pool
|
||||
// band_coin_cost_gain_random_char_by_shop_level 绮良 every coin_cnt funds spent → count random chess ≤ shop level
|
||||
// up_shop_next_refresh_must_present_bond_char 佩佩 level-up to a level of lvlist → +1 free refresh (price 0) that prefers <bond>
|
||||
// up_shop_next_refresh_must_present_bond_char 佩佩 level-up to a level of lvlist → the next manual refresh (its usual
|
||||
// price) prefers <bond>
|
||||
// gain_bond_char_per_round {round,preround,bond} 哈洛德 rounds round, round+preround, …: a <bond> chess (≤ shop level, else any tier)
|
||||
// first_buy_in_round_char_price_change {price,bond} 休露丝 first <bond> chess of the round costs `price` (bought in the
|
||||
// shop: onBuy — a free pick / grant never uses it up)
|
||||
@@ -184,12 +185,15 @@ K.band_coin_cost_gain_random_char_by_shop_level = (ps) => ({
|
||||
},
|
||||
});
|
||||
|
||||
// 佩佩 博学多通 "升级调度中心至2、4和6级后,获得1次特殊刷新:此次刷新出现的干员优先为<萨尔贡>干员": the special refresh is the
|
||||
// player's next manual refresh, paid as usual — the text gives no 免费 (德克萨斯's trait says 「获得1次免费刷新」 for a free
|
||||
// one), and the community report of 2026-10-06 「佩佩策略的特殊刷新也是要花钱的,不是免费」. Until 0.2.0 a free refresh came
|
||||
// with it (blackboard `price` 0 read as its price) [ASSUMED: `cnt` / `price` 0 change nothing].
|
||||
K.up_shop_next_refresh_must_present_bond_char = (ps) => ({
|
||||
onLevelUp(ctx, ev) {
|
||||
const p = ps[0];
|
||||
if (!list(p.lvlist).map(Number).includes(ev.level)) return;
|
||||
ctx.incCounter('band:pepe:special', 1);
|
||||
if (int(p.price, 0) === 0) ctx.grantFreeRefresh(1);
|
||||
},
|
||||
onRefresh(ctx) {
|
||||
if (ctx.counter('band:pepe:special') <= 0) return;
|
||||
|
||||
@@ -424,7 +424,7 @@ function devour(battle, pid, bb, members) {
|
||||
const amount = num(bb.damage_value, 0);
|
||||
const layered = new Set();
|
||||
// a target knocked out during the pass = off the field, or in another deployment than when the marks were placed (items
|
||||
// deploymentOf: the 5-tier revive and 不屈 redeploy it, 埃芒加德 / M3茧甲 revive it in place) — a revived member was
|
||||
// deploymentOf: the 5-tier revive, 不屈 and the 复活 of 埃芒加德 / M3茧甲 redeploy it) — a revived member was
|
||||
// standing again when its pending marks used to knock it out a second time and spend every revive at t = 0 (GitHub #33)
|
||||
const dep = new Map();
|
||||
for (const [, t] of marks) if (!dep.has(t)) dep.set(t, items.deploymentOf(t));
|
||||
@@ -457,10 +457,12 @@ function installEgir(battle, pid, bb, members) {
|
||||
// other, so the eaten food usually takes them at t = 0 and survivors = uneaten members + 3. A member takes at most one
|
||||
// slot, on its first knock-out ('killed') in the battle: its later knock-outs never take one, and a first knock-out
|
||||
// after the 3 are gone stays down. However many members mark it, its pending marks are cancelled once it is knocked
|
||||
// out (devour), so a multi-devoured member spends one slot at most. Its own saver acts first: every kit, item or band
|
||||
// revive that prevents or replaces the knock-out is a `fatal` hook (斯卡蒂's DRE-Y −50, kit savers 10 … −60, 坚固维式
|
||||
// 重锤 PRIO_REVIVE −100, M3茧甲 PRIO_RESPAWN −101, 埃芒加德 −110), so the unit is never knocked out and no slot is used —
|
||||
// the slot waits for its first real knock-out [ASSUMED for 埃芒加德, a band: as M3茧甲, the item revive the owner named].
|
||||
// out (devour), so a multi-devoured member spends one slot at most. Its own saver acts first: a kit or item saver that
|
||||
// prevents the knock-out is a `fatal` hook (斯卡蒂's DRE-Y −50, kit savers 10 … −60, 坚固维式重锤 PRIO_REVIVE −100), so the
|
||||
// unit is never knocked out and no slot is used; a 复活 (M3茧甲 13, 埃芒加德 12 — items reviveNow, a knock-out and a free
|
||||
// redeploy since 0.2.0) answers the knock-out before this hook and marks it `revivedBy`: that knock-out is not the
|
||||
// member's first either — the slot waits for its first unanswered knock-out (the owner's decision of 2026-10-05: an
|
||||
// operator's own revive uses no slot; [ASSUMED] for 埃芒加德, a band, as for M3茧甲, the item revive the owner named).
|
||||
// An operator entering 联防 down (FORCED_EXIT) is not knocked out either; a 调和 member counts like any other. Each
|
||||
// battle (normal, 联防, boss) counts its own. PRTS: the knocked-out unit's next deployment has 0 redeploy time and 0
|
||||
// cost, i.e. it IS knocked out (被击倒 triggers, 克莱门莎, 幽灵鲨 … fire) and redeploys at once where it lies (the
|
||||
@@ -478,7 +480,7 @@ function installEgir(battle, pid, bb, members) {
|
||||
let revives = 0;
|
||||
battle.on('death', (c) => {
|
||||
const u = c.unit;
|
||||
if (c.reason !== 'killed' || !memberOps.has(u) || knockedOut.has(u)) return;
|
||||
if (c.reason !== 'killed' || c.revivedBy || !memberOps.has(u) || knockedOut.has(u)) return;
|
||||
knockedOut.add(u);
|
||||
if (revives >= max || u.alive || u.removed) return;
|
||||
if (!battle.redeploy(u, { free: true })) return;
|
||||
|
||||
@@ -23,12 +23,15 @@
|
||||
// use 10 … −60) never wastes a charge: 坚固维式重锤's lock (异常效果 不死, once per deployment — deploymentOf) at
|
||||
// PRIO_REVIVE −100 and its running windows, held by one battle-level hook, at PRIO_UNDYING_HELD −99 — before a 傀儡师's
|
||||
// switch to its 替身 (professions.js, −100: PRTS 分支特性信息 傀儡师 "受到足以致命的伤害且未持有不死的情况下"), while the
|
||||
// lock itself still comes after that switch (as in 0.1.1); then the M3茧甲 revive at PRIO_RESPAWN −101 — PRTS
|
||||
// 卫戍协议:盟约 下半/PRTS盟约记录 备注 "“复活”的实现方式为:受益者因移动之外的原因退场时下次部署的再部署时间和费用归零": a
|
||||
// revive acts on a knock-out, which a 不死 prevents, so the lock always comes first whatever the equip order (player
|
||||
// report F1 after 0.1.0: with the 茧甲 equipped first the revive ran first and the first lethal hit showed no lock);
|
||||
// 埃芒加德's band revive follows (bands/battle.js PRIO_BAND_REVIVE −110). Both revives stand in place for that redeploy,
|
||||
// so each opens a new deployment for the lock (revivedInPlace).
|
||||
// lock itself still comes after that switch (as in 0.1.1). The 复活 — M3茧甲 here, 埃芒加德's band (bands/battle.js) —
|
||||
// act on the knock-out itself: PRTS 卫戍协议:盟约 下半/PRTS盟约记录 备注 "“复活”的实现方式为:受益者因移动之外的原因退场时下
|
||||
// 次部署的再部署时间和费用归零" — the unit IS knocked out (its `death` hooks, every 被击倒时 effect, run) and its next
|
||||
// deployment, at once, free, where it lies, is a deployment like any other (部署时 effects, SP reset, a new lock): a
|
||||
// `death` hook at PRIO_RESPAWN 13, then 埃芒加德 12 (PRIO_BAND_REVIVE), ahead of 阿戈尔 5's first-knock-out revive (11)
|
||||
// and 不屈 (10) — reviveNow. A 不死 prevents the knock-out, so the lock always comes first whatever the equip order (player
|
||||
// report F1 after 0.1.0: with the 茧甲 equipped first the revive ran first and the first lethal hit showed no lock). Until
|
||||
// 0.2.0 both revived in place (`fatal` savers at −101 / −110): no 被击倒时 / 部署时 effect fired (community report
|
||||
// 「像砾和瑕光这种死亡和部署的叠层效果,如果有艾芒加德的3次复活似乎是无法触发」).
|
||||
// 骑士戒律's free in-skill undying runs early (20). Flat damage reduction 'hit' −10 (after the other damage modifiers).
|
||||
// Proc damage dealt by items carries the tag 'item' and never re-triggers item procs.
|
||||
//
|
||||
@@ -69,8 +72,11 @@ const ENEMY_RECORD = /^enemy_/;
|
||||
export const PRIO_REVIVE = -100;
|
||||
/** A running 坚固 window (不死 held): before a 傀儡师's switch to its 替身 at −100 — see header. */
|
||||
export const PRIO_UNDYING_HELD = PRIO_REVIVE + 1;
|
||||
/** The items' 复活 (M3茧甲): acts on a knock-out, so after every 不死 (PRIO_REVIVE) — see header. */
|
||||
export const PRIO_RESPAWN = PRIO_REVIVE - 1;
|
||||
/**
|
||||
* 'death' priority of the items' 复活 (M3茧甲): it acts on the knock-out, so after every `fatal` saver (不死 included) —
|
||||
* before 埃芒加德 (12), 阿戈尔 5's revive (11) and 不屈 (10). See header and reviveNow.
|
||||
*/
|
||||
export const PRIO_RESPAWN = 13;
|
||||
const PRIO_FREE_UNDYING = 20;
|
||||
|
||||
/** Stat keys of a stat buff → mods (直接乘算, see header). */
|
||||
@@ -238,33 +244,29 @@ function hammerState(battle, rt, u) {
|
||||
// 娜仁图亚's 60 s lend) follows the same rule as an owner.
|
||||
|
||||
/**
|
||||
* The deployment `u` is in: every deploy bumps `deploySeq` (the redeploy after a knock-out, a 突袭 retreat + redeploy
|
||||
* [ASSUMED a deployment], 阿戈尔's 立刻复活), and an in-place 复活 (M3茧甲, 埃芒加德: revivedInPlace) opens a new one too
|
||||
* [ASSUMED] — PRTS (M3茧甲 / 埃芒加德 / 阿戈尔 备注) "“复活”的实现方式为:受益者因移动之外的原因退场时下次部署的再部署时间和
|
||||
* 费用归零": officially a revive is a 0-time / 0-cost redeploy; the remake keeps the unit standing instead.
|
||||
* Also read by 阿戈尔's devour (bonds/core.js): a unit whose deployment changed during the pass was knocked out.
|
||||
* The deployment `u` is in: every deploy bumps `deploySeq` — the redeploy after a knock-out, a 突袭 retreat + redeploy
|
||||
* [ASSUMED a deployment], 阿戈尔's 立刻复活 and every 复活 (M3茧甲, 埃芒加德: reviveNow — PRTS "“复活”的实现方式为:受益者因移动
|
||||
* 之外的原因退场时下次部署的再部署时间和费用归零", a 0-time / 0-cost redeploy; in place until 0.2.0, when an extra counter
|
||||
* opened the new deployment). Also read by 阿戈尔's devour (bonds/core.js): a unit whose deployment changed during the
|
||||
* pass was knocked out.
|
||||
*/
|
||||
export function deploymentOf(u) { return `${u.deploySeq}:${u.mem.revives | 0}`; }
|
||||
export function deploymentOf(u) { return `${u.deploySeq}`; }
|
||||
|
||||
/**
|
||||
* An in-place 复活 (M3茧甲, 埃芒加德) happened. PRTS's 复活 is 退场 + a 0-time / 0-cost redeploy (PRTS 盟约记录 备注) — a new
|
||||
* deployment, of which the remake carries: the once-per-deployment lock (deploymentOf) and a deploy-timed skill ("部署后…秒内",
|
||||
* SkillSpec `activateOnDeploy`: 缄默德克萨斯 S1–S3, 宴 S2, 斯卡蒂 S2, 砾's barrier …) running again — started anew when its window
|
||||
* had ended, its window back to the full duration when it still ran (the next tick, out of the damage pipeline that set the
|
||||
* revive off). Community report of 2026-10-06 (item 44): a 突袭 member counts such a running window as 技能就绪
|
||||
* (bonds/addon/battle.js raidPoll), and after an in-place revive it waited out the 10 s idle time instead of jumping at once
|
||||
* as after a redeploy. The SP reset and the other 部署时 effects of PRTS's form stay unmodelled (DESIGN §21.21).
|
||||
* A 复活 answering a knock-out — call from a `death` hook (M3茧甲 PRIO_RESPAWN, 埃芒加德 PRIO_BAND_REVIVE). PRTS 备注
|
||||
* "“复活”的实现方式为:受益者因移动之外的原因退场时下次部署的再部署时间和费用归零": the operator was knocked out (this death;
|
||||
* its 被击倒时 effects run) and redeploys at once, free, where it lies (Battle.redeploy: full HP, SP reset, `deploy` —
|
||||
* its 部署时 effects run). True when it stands again; the ctx then carries `revivedBy`, so 阿戈尔 5 does not count the
|
||||
* knock-out as the member's first (the owner's decision of 2026-10-05: an operator's own revive uses no slot; 埃芒加德
|
||||
* [ASSUMED] alike, DESIGN §24.3). A redeploy that cannot happen (its tile taken) spends nothing [ASSUMED].
|
||||
* @param {object} battle @param {{ unit: object, reason: string, revivedBy?: string }} c the `death` ctx @param {string} by
|
||||
*/
|
||||
export function revivedInPlace(u) {
|
||||
if (!u || !u.mem) return;
|
||||
u.mem.revives = (u.mem.revives | 0) + 1;
|
||||
const sk = u.skill;
|
||||
if (!sk || sk.noSkill || !sk.spec || !sk.spec.activateOnDeploy || !sk.battle) return;
|
||||
const seq = u.deploySeq, n = u.mem.revives;
|
||||
sk.battle.after(0, () => {
|
||||
if (!u.alive || !u.deployed || u.deploySeq !== seq || u.mem.revives !== n || u.skill !== sk) return;
|
||||
if (sk.active) { if (sk.duration > 0) sk.timeLeft = sk.duration; } else sk.activate('deploy', { free: true });
|
||||
}, { owner: u });
|
||||
export function reviveNow(battle, c, by) {
|
||||
const u = c && c.unit;
|
||||
if (!u || c.reason !== 'killed' || c.revivedBy || !isOp(u) || u.alive || u.removed) return false;
|
||||
if (!battle.redeploy(u, { free: true })) return false;
|
||||
c.revivedBy = by;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -620,21 +622,18 @@ const BY_ITEM = {
|
||||
if (addShieldLayer(battle, c.target, SHIELD_KEY, cap)) fxOn(battle, 'shield', c.target, 'item:chess_item_4_11_e', rec.id);
|
||||
});
|
||||
},
|
||||
// M3茧甲: knocked down in battle ⇒ revive at full HP (max_respawn_cnt per battle), in place — PRTS's form (退场, then a
|
||||
// 0-time / 0-cost redeploy) is not modelled, but it counts as a new deployment for 坚固维式重锤's lock (revivedInPlace)
|
||||
// M3茧甲: knocked down in battle ⇒ 立刻复活 (max_respawn_cnt per battle) — PRTS's form: the knock-out stands (its
|
||||
// 被击倒时 effects run) and the carrier redeploys at once, free, where it lies (reviveNow; in place until 0.2.0)
|
||||
chess_item_4_12_e(battle, u, rec, S) {
|
||||
const p = bp(rec, 'act1autochess_equip_acarm068_global_buff');
|
||||
const max = p ? Math.floor(num(p.max_respawn_cnt, 1)) : 0;
|
||||
if (!(max > 0)) return;
|
||||
let used = 0;
|
||||
S.on('fatal', (c) => {
|
||||
if (c.unit !== u || c.prevented || used >= max) return;
|
||||
S.on('death', (c) => {
|
||||
if (c.unit !== u || used >= max || !reviveNow(battle, c, 'item')) return;
|
||||
used++;
|
||||
c.prevented = true;
|
||||
u.hp = u.s.maxHp;
|
||||
revivedInPlace(u);
|
||||
fxOn(battle, 'revive', u, 'item:chess_item_4_12_e', rec.id, { left: max - used });
|
||||
}, PRIO_RESPAWN); // after the hammer's 不死 lock, whatever the equip order (header)
|
||||
}, PRIO_RESPAWN); // a knock-out: after every 不死 (the hammer's lock), whatever the equip order (header)
|
||||
},
|
||||
// 催泪瓦斯: on attack prob ⇒ 1 麻痹 stack
|
||||
chess_item_5_01_e(battle, u, rec, S) {
|
||||
|
||||
@@ -55,13 +55,13 @@
|
||||
// once per cast the first operator of her range taking lethal damage (not its own — CheckEntitySuicide; not while it already
|
||||
// holds 不死 — "_dontConsumeWhenUndeadable") keeps ≥ 1 HP and holds 不死 for grave_duration s (slent2_shallow_grave, buff
|
||||
// flag `undying`; it outlasts her leaving). Order of the `fatal` step (items/battle.js): after the kits' own savers, a
|
||||
// 傀儡师's switch and 坚固维式重锤's lock (PRIO_REVIVE −100), before the 复活 (PRIO_RESPAWN −101); the window it opens is
|
||||
// held like the hammer's (PRIO_UNDYING_HELD −99).
|
||||
// 傀儡师's switch and 坚固维式重锤's lock (PRIO_REVIVE −100) — the 复活 (M3茧甲, 埃芒加德) act on the knock-out after the
|
||||
// whole `fatal` step; the window it opens is held like the hammer's (PRIO_UNDYING_HELD −99).
|
||||
// Statuses: none applied to enemies. Damage: arts normal attacks only.
|
||||
|
||||
import { num, up, traitBb, moduleBb, talentBb, skillRec, once, holdProtect } from '../shared/tier1.js';
|
||||
import { releaseSkillSummon } from '../../tokens.js';
|
||||
import { holdsUndying, PRIO_UNDYING_HELD, PRIO_REVIVE, PRIO_RESPAWN } from '../../items/battle.js';
|
||||
import { holdsUndying, PRIO_UNDYING_HELD, PRIO_REVIVE } from '../../items/battle.js';
|
||||
import { absoluteRangeKeys } from '../../../targeting.js';
|
||||
import { COLS } from '../../../constants.js';
|
||||
|
||||
@@ -79,8 +79,8 @@ const REGEN_IV = 1;
|
||||
export const MAXHP_KEY = 'slent2:maxhp';
|
||||
/** S3's 不死 (slent2_shallow_grave). */
|
||||
export const GRAVE_KEY = 'slent2:grave';
|
||||
/** S3's place in the `fatal` step: after the items' 不死 lock (−100), before their 复活 (−101) — see the header. */
|
||||
const PRIO_GRAVE = (PRIO_REVIVE + PRIO_RESPAWN) / 2;
|
||||
/** S3's place in the `fatal` step: right after the items' 不死 lock (−100) — see the header. */
|
||||
const PRIO_GRAVE = PRIO_REVIVE - 0.5;
|
||||
/** 夜灯's area when its record carries no grid: its tile and the 8 around (x-4). */
|
||||
const X4 = Object.freeze([[1, -1], [1, 0], [1, 1], [0, -1], [0, 0], [0, 1], [-1, -1], [-1, 0], [-1, 1]]);
|
||||
/** 【莱茵生命】 (character_table groupId "rhine": every member, so a 自选 pick counts too). */
|
||||
|
||||
@@ -1321,17 +1321,34 @@ function yanyouKit(bb, raw) {
|
||||
};
|
||||
}
|
||||
|
||||
/** Free field tile for a flyer: the player's half, void/non-deployable tiles first, nearest to the half's centre. */
|
||||
/**
|
||||
* Stage positions held for the band map characters (data/stages.json `mapChars`: the levels' predefined 预备干员-医疗 /
|
||||
* Touch of 外勤医疗, hidden until a player holds the strategy), as tile keys.
|
||||
*/
|
||||
function mapCharKeys(battle) {
|
||||
const list = battle.stage?.raw?.mapChars ?? battle.stage?.mapChars ?? [];
|
||||
const out = new Set();
|
||||
for (const m of Array.isArray(list) ? list : []) if (m && Array.isArray(m.pos)) out.add(m.pos[0] * COLS + m.pos[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free field tile for a flyer: the player's half, void/non-deployable tiles first, nearest to the half's centre — never a
|
||||
* map character's position: the 炎佑 spawns at the same battle start as 外勤医疗's medic and took its tile on the maps
|
||||
* whose free void tiles nearest the centre include it (战场#08 涨潮控制 always, 战场#07 排气格栅 with 9 炎), so the medic
|
||||
* never stood (community report of 2026-10-06 「Touch策略给的医疗干员会跟炎盟约的炎祐冲突,无法同时出场」).
|
||||
*/
|
||||
function airTile(battle, playerId, taken) {
|
||||
const R = battle.rect;
|
||||
const ps = battle.getPlayer(playerId);
|
||||
let c0 = R.c0, c1 = R.c1;
|
||||
if (battle.players.length > 1 && ps) { if (ps.half === 'R') c0 = Math.max(c0, 11); else c1 = Math.min(c1, 10); }
|
||||
const cr = (R.r0 + R.r1) / 2, cc = (c0 + c1) / 2;
|
||||
const held = mapCharKeys(battle);
|
||||
let best = null, bs = null;
|
||||
for (let r = R.r0; r <= R.r1; r++) {
|
||||
for (let c = c0; c <= c1; c++) {
|
||||
if (taken.has(r * COLS + c) || !tileFree(battle, r, c)) continue;
|
||||
if (taken.has(r * COLS + c) || held.has(r * COLS + c) || !tileFree(battle, r, c)) continue;
|
||||
const t = battle.grid.tile(r, c);
|
||||
const cls = t.build === 'NONE' && t.pass !== 'ALL' ? 0 : t.build === 'NONE' ? 1 : 2;
|
||||
const s = [cls, Math.hypot(r - cr, c - cc), r * COLS + c];
|
||||
|
||||
Reference in new issue
Block a user