diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 593fed5e..0252423d 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -312,7 +312,7 @@ Duration end cleans the window and emits `skillEnd`; it leaves zero charges and Redeployment opens a new full window. Permanent passives retain `passive`; first-kill recasts of 缄默德克萨斯 explicitly restart a full window. Special timed kits and their effect rules are described in SIM §7.2. -Auto-trigger rules (`skillTrigger.rule` in data — the official 技能策略, PRTS 卫戍协议/帮助 §作战阶段 技能操作; §20.2): `DEFAULT` (SP ready AND about to attack/heal AND an enemy/injured ally inside the **initial** range, or an enemy the unit blocks; with `trigger.allies` + `hpAtMost` an ally of the skill grid at or below that HP ratio — 塞雷娅 S1 急救, whose cast replaces that attack and is withdrawn with its charge if the ally recovers first), `SKILL_RANGE` (a MANUAL skill with a 技能范围 of its own, not an attack-range change: any living enemy, stealthed ones included, on the skill range, checked every tick — "仅在技能范围内存在敌人(无视其不可选中)时释放技能"; 13 skills / 26 records by the official rule, 14 / 28 in the data with 余 S2's deviation, §22.10), `ACTIVE_RANGE` (the owner's deliberate deviation of 2026-10-05, 0.2.0: a MANUAL skill on the basic strategy — or, by the owner's further decisions of the same day, on the `SEARCH` row, and 深巡 S2 on top of its §21.29 DEFAULT — whose attack range while it runs strictly contains the operator's own range — its rangeId grid, or the own range grown by `ability_range_forward_extend` — checks the DEFAULT condition on that running range every tick, no attack needed; `customRangeGrid` = the running range, `rawRule` the official row (DEFAULT, SEARCH, 深巡's TAKE_DAMAGE); 39 skills / 78 records, of them 薄绿 S1, 蜜蜡 S1, 卡涅利安 S3, 玛恩纳 S2 and 安洁莉娜 S3 from SEARCH; 烛煌 S2 / S3, whose ranges do not contain her 3-1, keep DEFAULT), `TAKE_DAMAGE` (on taking damage — any damage, 无来源 included, never a 流失; every MANUAL 重装 skill, §21.12 — but the six of the deliberate deviation, §21.29: 深巡 / 雷蛇 S2, 号角 S2 / S3 and 灰毫 S1 / S2 are `DEFAULT`, `rawRule` keeping the official TAKE_DAMAGE — 深巡 S2 then `ACTIVE_RANGE` on its 3-2; and 余 S2, `SKILL_RANGE` on its x-1 (§22.10); the 重装 of data/backups.json — the 补位 stand-ins 预备干员-重装 / Mechanist and every 自选 重装 — cast with an enemy in range, `DEFAULT` (or `ACTIVE_RANGE` when the skill's running range is larger), by the owner's decisions of 2026-10-05), `SP_FULL` (immediately — 执旗手 / 战术家 / 吟游者 MANUAL skills, AUTO DP skills such as 焰尾 S1, 凛御银灰 S1 (伺夜 S1 / S2 too, but only while his pack is on the field — PRTS 备注 「仅场上存在狼群时可触发技能」, the kit's own cast; the owner's decision of 2026-10-05 for S1; S1 also while the pack sits in its 战术点形态, which the cast ends — S2 waits for it to come back [ASSUMED]), and, by their kits, AUTO skills whose effects act on allies only: 引星棘刺 S1, 浊心斯卡蒂 S2, 纯烬艾雅法拉 S1 — the owner's decision of 2026-10-05 for the last), `CUSTOM_RANGE` (enemy inside the custom grid), `SEARCH` (an enemy inside the initial range, checked every tick — no attack needed; 解放者 / 阵法术师 MANUAL skills and 安洁莉娜 S2, those without a larger running range), `GDGLOW_SKILL_2` (a valid target anywhere on the field: 荒芜拉普兰德, 纯烬艾雅法拉 S3), special ids. The class rows cover **every MANUAL skill** of the class and never an AUTO skill (AUTO skills keep their own rule — an inference: PRTS names whole classes; the data's `skillIndex 0` / `-1` sentinel argues the other way, §20.2). **Operation cooldown**: the engine auto-casts a MANUAL skill no sooner than `AUTO_OP_COOLDOWN` (3 s) after its previous cast and after the unit's battle-start deployment ("自动操作具有3s冷却,在完成一次操作或作战开始时部署的单位将进入冷却"; `Battle._deploy` initial, `battle.flags.startOpCooldown`); kits with an automatic cast of their own check `skill.opCooling`; a pending "next attack" never takes a second charge. Permanent passive skills are always on; finite deployment effects use the duration lifecycle above. +Auto-trigger rules (`skillTrigger.rule` in data — the official 技能策略, PRTS 卫戍协议/帮助 §作战阶段 技能操作; §20.2): `DEFAULT` (SP ready AND about to attack/heal AND an enemy/injured ally inside the **initial** range, or an enemy the unit blocks; with `trigger.allies` + `hpAtMost` an ally of the skill grid at or below that HP ratio — 塞雷娅 S1 急救, whose cast replaces that attack and is withdrawn with its charge if the ally recovers first), `SKILL_RANGE` (a MANUAL skill with a 技能范围 of its own, not an attack-range change: any living enemy, stealthed ones included, on the skill range, checked every tick — "仅在技能范围内存在敌人(无视其不可选中)时释放技能"; 13 skills / 26 records by the official rule, 14 / 28 in the data with 余 S2's deviation, §22.10), `ACTIVE_RANGE` (the owner's deliberate deviation of 2026-10-05, 0.2.0: a MANUAL skill on the basic strategy — or, by the owner's further decisions of the same day, on the `SEARCH` row, and 深巡 S2 on top of its §21.29 DEFAULT — whose attack range while it runs strictly contains the operator's own range — its rangeId grid, or the own range grown by `ability_range_forward_extend` — checks the DEFAULT condition on that running range every tick, no attack needed; `customRangeGrid` = the running range, `rawRule` the official row (DEFAULT, SEARCH, 深巡's TAKE_DAMAGE); 39 skills / 78 records, of them 薄绿 S1, 蜜蜡 S1, 卡涅利安 S3, 玛恩纳 S2 and 安洁莉娜 S3 from SEARCH; 烛煌 S2 / S3, whose ranges do not contain her 3-1, keep DEFAULT), `TAKE_DAMAGE` (on taking damage — any damage, 无来源 included, never a 流失; every MANUAL 重装 skill, §21.12 — but the six of the deliberate deviation, §21.29: 深巡 / 雷蛇 S2, 号角 S2 / S3 and 灰毫 S1 / S2 are `DEFAULT`, `rawRule` keeping the official TAKE_DAMAGE — 深巡 S2 then `ACTIVE_RANGE` on its 3-2; and 余 S2, `SKILL_RANGE` on its x-1 (§22.10); the 重装 of data/backups.json — the 补位 stand-ins 预备干员-重装 / Mechanist and every 自选 重装 — cast with an enemy in range, `DEFAULT` (or `ACTIVE_RANGE` when the skill's running range is larger), by the owner's decisions of 2026-10-05), `SP_FULL` (immediately — 执旗手 / 战术家 / 吟游者 MANUAL skills, AUTO DP skills such as 焰尾 S1, 凛御银灰 S1 (伺夜 S1 / S2 too, but only while his pack is on the field — PRTS 备注 「仅场上存在狼群时可触发技能」, the kit's own cast; the owner's decision of 2026-10-05 for S1; S1 also while the pack sits in its 战术点形态, which the cast ends — S2 waits for it to come back [ASSUMED]; 黑键 S2 荒芜回响 likewise only while one placeable tile of his range is free, no enemy needed — PRTS 备注 「攻击范围内不存在可部署位时,技能不会被触发」, its kit's cast, 0.2.0), and, by their kits, AUTO skills whose effects act on allies only: 引星棘刺 S1, 浊心斯卡蒂 S2, 纯烬艾雅法拉 S1 — the owner's decision of 2026-10-05 for the last), `CUSTOM_RANGE` (enemy inside the custom grid), `SEARCH` (an enemy inside the initial range, checked every tick — no attack needed; 解放者 / 阵法术师 MANUAL skills and 安洁莉娜 S2, those without a larger running range), `GDGLOW_SKILL_2` (a valid target anywhere on the field: 荒芜拉普兰德, 纯烬艾雅法拉 S3), special ids. The class rows cover **every MANUAL skill** of the class and never an AUTO skill (AUTO skills keep their own rule — an inference: PRTS names whole classes; the data's `skillIndex 0` / `-1` sentinel argues the other way, §20.2). **Operation cooldown**: the engine auto-casts a MANUAL skill no sooner than `AUTO_OP_COOLDOWN` (3 s) after its previous cast and after the unit's battle-start deployment ("自动操作具有3s冷却,在完成一次操作或作战开始时部署的单位将进入冷却"; `Battle._deploy` initial, `battle.flags.startOpCooldown`); kits with an automatic cast of their own check `skill.opCooling`; a pending "next attack" never takes a second charge. Permanent passive skills are always on; finite deployment effects use the duration lifecycle above. **SkillSpec** (authored per chess in `sim/content/kits/tierN.js`; values come from the chess's skill blackboard at its level — normal Lv4, elite Lv7 — so a spec is a *function of the blackboard*): ```js diff --git a/server/sim/content/kits/ops/op-ebnhlz.js b/server/sim/content/kits/ops/op-ebnhlz.js index 5bc3ef9f..3f467373 100644 --- a/server/sim/content/kits/ops/op-ebnhlz.js +++ b/server/sim/content/kits/ops/op-ebnhlz.js @@ -39,7 +39,10 @@ // (PRTS "大幅度缩短(*0.2)": batMod's ratio reading), every attack attack@atk_scale × ATK; the energies released meanwhile // use that scale too (备注 "该技能的“每次攻击的攻击倍率”会实时应用在特性积攒的“攻击能量”抛射物上") × the energy scale. // `attack@cnt` (1) has no text [unused]. -// - S2 荒芜回响 (AUTO, instant, data DEFAULT — an AUTO skill whose effect acts on enemies keeps the data rule): spends every +// - S2 荒芜回响 (AUTO, instant): cast at full SP as soon as one placeable tile of his attack range is free — no enemy needed +// (PRTS 备注 "攻击范围内不存在可部署位时,技能不会被触发"; the skill prefab's `_trigger._minTileNum` 1 — O20's report; 0.2.0 WE2: +// until then the data's DEFAULT waited for an enemy in his range; `trigger: 'NEVER'` + this kit's cast, the pattern of +// 伺夜's conditional casts): spends every // stored energy (elite ones first: 备注 "可以消耗并优先消耗第一天赋储存的额外能量") and places energies + 1 旧日残影 on free // placeable tiles of his attack range (部署位置 全部位), in the 备注's order: tiles holding a selectable ground enemy (the // best of them first by his target order — 仇恨值 [ASSUMED: the engine's default operator order]), then the tiles nearest @@ -88,6 +91,15 @@ export const eliteOrLeader = (e) => !!e && (!!e.isBoss || e.def?.rank === 'ELITE /** His stored energies (per deployment): `n` normal, `e` elite, `q` the volleys in flight per target id. */ const stateOf = (unit) => unit.trait.ebn ?? (unit.trait.ebn = { n: 0, e: 0, q: new Map() }); +/** A tile 荒芜回响 may place a 旧日残影 on: inside the field, deployable (全部位) and free (Battle.isReservedTile). */ +const remnantTileOk = (battle, r, c) => battle.grid.inRect(r, c) && battle.grid.canStand(r, c, { ranged: true }) && !battle.isReservedTile(r, c); + +/** Whether `unit`'s attack range holds one tile 荒芜回响 may use (its cast condition; no rng, unlike remnantTiles). */ +function hasRemnantTile(battle, unit) { + for (const k of unit.rangeKeys || []) if (remnantTileOk(battle, Math.floor(k / COLS), k % COLS)) return true; + return false; +} + /** * The tiles 荒芜回响 may place 旧日残影 on (PRTS 备注 order): free deployable tiles of `unit`'s attack range — first those * holding a selectable ground enemy, by the best of them in his target order; then by the distance to the nearest @@ -97,8 +109,7 @@ function remnantTiles(battle, unit) { const tiles = []; for (const k of unit.rangeKeys || []) { const r = Math.floor(k / COLS), c = k % COLS; - if (!battle.grid.inRect(r, c) || !battle.grid.canStand(r, c, { ranged: true }) || battle.isReservedTile(r, c)) continue; - tiles.push([r, c]); + if (remnantTileOk(battle, r, c)) tiles.push([r, c]); } if (!tiles.length) return tiles; const foes = battle.enemies.filter((e) => canTargetEnemy(unit, e, GROUND)); @@ -231,6 +242,7 @@ export default { }, [S2]: { kind: 'instant', + trigger: 'NEVER', // the kit's cast (install): full SP and one free placeable tile in his range onStart({ battle, unit, skill }) { const tiles = remnantTiles(battle, unit); if (!tiles.length) { skill.addCharge(1); return; } // "攻击范围内不存在可部署位时,技能不会被触发" @@ -260,6 +272,14 @@ export default { }, }, install(battle, unit) { + // S2 荒芜回响: cast at full SP with one free placeable tile in his range, no enemy needed (see the header) + if (unit.skill?.id === S2) { + battle.on('tick', () => { + const sk = unit.skill; + if (!sk || !sk.ready || sk.active || !up(unit) || !unit.canAct || unit.s.flags.silence) return; + if (hasRemnantTile(battle, unit)) sk.activate('SP_FULL'); + }, { owner: unit }); + } // MSC-Y: ASPD while any energy is stored const aspd = num(hidden.attack_speed); if (aspd) toggleBuff(battle, unit, 'trait:ebnhlz:stored', () => { const v = stateOf(unit); return v.n + v.e > 0; }, { aspd }); diff --git a/test/content/op_ebnhlz.test.js b/test/content/op_ebnhlz.test.js index 2f4cd611..55f93320 100644 --- a/test/content/op_ebnhlz.test.js +++ b/test/content/op_ebnhlz.test.js @@ -76,7 +76,7 @@ function storeUp(h, u, n, e, max = 60) { return log; } -test('黑键 in every 自选 form: his operator kit (all three skills authored), the form\'s stats + module attributes, 3-14, ranged arts every 3 s that hits air units, blocks 1, ground-targetable, the data\'s DEFAULT triggers, 空 bond, no 特质', () => { +test('黑键 in every 自选 form: his operator kit (all three skills authored), the form\'s stats + module attributes, 3-14, ranged arts every 3 s that hits air units, blocks 1, ground-targetable, the data\'s DEFAULT triggers (S2: the kit casts it), 空 bond, no 特质', () => { assert.equal(OPERATOR_KITS[EBN], KITS[EBN]); for (const f of FORMS_ALL) { const [tier, elite, mod] = f; @@ -88,7 +88,7 @@ test('黑键 in every 自选 form: his operator kit (all three skills authored), [form.stats.maxHp + (m?.attr.maxHp ?? 0), form.stats.atk + (m?.attr.atk ?? 0), form.stats.def + (m?.attr.def ?? 0), form.stats.res + (m?.attr.res ?? 0), 100 + (m?.attr.aspd ?? 0)], `${label(f)}: stats`); assert.deepEqual([u.s.blockCnt, u.profile.attack, u.profile.dmgType, u.profile.canHitFly, u.base.bat], [1, 'ranged', 'arts', true, 3], `${label(f)}: 秘术师`); assert.deepEqual(u.liveRangeGrid, form.rangeGrid, `${label(f)}: 3-14`); - assert.equal(u.skill.rule, 'DEFAULT', `${label(f)}: the data's trigger`); + assert.equal(u.skill.rule, skill === 1 ? 'NEVER' : 'DEFAULT', `${label(f)}: the data's trigger (S2: the kit's own cast)`); assert.deepEqual([u.def.bonds, u.def.raw.garrisonIds], [['emptyShip'], []], `${label(f)}: bonds / 特质`); assert.ok(!u.s.flags.liftoff && !u.s.flags.camou && !u.s.flags.stealth, `${label(f)}: ground enemies target him`); done(h); @@ -292,16 +292,29 @@ test('S1 渐快急板 (MANUAL, data DEFAULT): 5 s, range 4-1, attack interval × } }); -test('S2 荒芜回响 (AUTO, data DEFAULT): spends every energy (elite first) on energies + 1 旧日残影 on free tiles of his range — the enemy\'s tile first, then the nearest; fewer tiles ⇒ fewer spent; no free tile ⇒ no cast (the charge back)', () => { +test('S2 荒芜回响 (AUTO: full SP and one free placeable tile in his range, no enemy needed — PRTS 备注, prefab _minTileNum 1): spends every energy (elite first) on energies + 1 旧日残影 on free tiles of his range — the enemy\'s tile first, then the nearest; fewer tiles ⇒ fewer spent; no free tile ⇒ no cast', () => { for (const [tier, elite, mod] of [[5, false, null], [6, true, MX]]) { const sk = skillOf(tier, elite, S2); assert.deepEqual([sk.skillType, sk.bb.atk_scale, sk.bb.force, sk.spCost, sk.initSp], ['AUTO', elite ? 2 : 1.7, 1, elite ? 14 : 15, 0]); + // no enemy on the field: it casts as soon as its SP is full + { + const { h, u } = field({ tier, elite, mod, skill: 1 }); + assert.equal(u.skill.rule, 'NEVER', 'the kit casts it'); + let before = stored(u); + for (let i = 0; i < (sk.spCost + 1) * 30 && u.skill.activations === 0; i++) { before = stored(u); h.step(); } + assert.equal(u.skill.activations, 1, 'cast at full SP with no enemy anywhere'); + approx(h.b.time, sk.spCost, `T${tier}: at ${sk.spCost} s`, 0.2); + assert.equal(h.b.allyUnits.filter((t) => t.kind === 'token' && t.defId === REMNANT && t.alive).length, before.n + before.e + 1, 'the energies stored meanwhile + 1 remnants'); + assert.deepEqual(stored(u), { n: 0, e: 0 }, 'every energy spent'); + done(h); + } const { h, u } = field({ tier, elite, mod, skill: 1 }); const N = traitOf(tier, elite, mod).times; + holdSkill(u); storeUp(h, u, N, 1); - u.skill.gainSp(999); const e = h.spawn('enemy_dummy', { pos: [10, 7] }); - assert.ok(h.runUntil(() => u.skill.activations === 1, 5), 'cast with an enemy in range'); + u.skill.gainSp(999); + assert.ok(h.runUntil(() => u.skill.activations === 1, 5), 'cast'); const rem = h.b.allyUnits.filter((t) => t.kind === 'token' && t.defId === REMNANT); assert.equal(rem.length, N + 2, `${N} + 1 energies + 1 remnants`); assert.deepEqual([rem[0].tileR, rem[0].tileC], [10, 7], 'the enemy\'s tile first'); @@ -315,27 +328,30 @@ test('S2 荒芜回响 (AUTO, data DEFAULT): spends every energy (elite first) on // the flat stage's edge (col 2: RANGED tiles; cols 0–1 none): facing LEFT from (10, 2) no tile of his range is free { const { h, u } = field({ tier: 5, skill: 1, row: 10, col: 2, dir: 'LEFT' }); + holdSkill(u); storeUp(h, u, 3, 1); - u.skill.gainSp(999); h.spawn('enemy_dummy', { pos: [10, 1] }); - assert.ok(h.runUntil(() => u.skill.activations >= 1, 5), 'the DEFAULT condition holds (an enemy in range)'); - assert.equal(h.b.allyUnits.filter((t) => t.kind === 'token').length, 0, 'no placeable tile: no remnant'); - assert.ok(u.skill.ready, 'the charge is back'); + u.skill.gainSp(999); + h.run(5); + assert.equal(u.skill.activations, 0, 'no placeable tile: no cast, an enemy in range notwithstanding'); + assert.equal(h.b.allyUnits.filter((t) => t.kind === 'token').length, 0, 'no remnant'); + assert.ok(u.skill.ready, 'the charge waits'); done(h); } // fewer free tiles than energies + 1: facing LEFT from (10, 3) only (10, 2) and (11, 2) are placeable { const { h, u } = field({ tier: 5, skill: 1, row: 10, col: 3, dir: 'LEFT' }); + holdSkill(u); storeUp(h, u, 3, 1); - u.skill.gainSp(999); let atEnd = null; h.b.on('skillEnd', (c) => { if (c.unit === u) atEnd = stored(u); }); h.spawn('enemy_dummy', { pos: [10, 2] }); + u.skill.gainSp(999); assert.ok(h.runUntil(() => u.skill.activations === 1, 5)); const rem = h.b.allyUnits.filter((t) => t.kind === 'token' && t.defId === REMNANT); assert.deepEqual(rem.map((t) => [t.tileR, t.tileC]), [[10, 2], [11, 2]], 'the enemy\'s tile, then the other free one'); assert.deepEqual(atEnd, { n: 3, e: 0 }, 'one energy spent — the elite one first'); - assert.ok(h.runUntil(() => energyHits(h, u).length === 3, 2), 'the attack that follows releases the three left'); + assert.ok(h.runUntil(() => energyHits(h, u).length === 3, 4), 'his next attack (3 s interval) releases the three left'); done(h); } }); diff --git a/test/golden/diy.json b/test/golden/diy.json index 0e37fa91..7e38056a 100644 --- a/test/golden/diy.json +++ b/test/golden/diy.json @@ -4867,45 +4867,45 @@ "time": 205.67, "ticks": 6170, "reason": "cleared", - "killed": 124, - "total": 189, + "killed": 121, + "total": 183, "unspawned": 0, "bossHpLeft": null, "rngDraws": 8, "errors": {"count":0,"kinds":[]}, - "players": {"p1":{"killed":124,"total":189,"perfect":false,"leaks":65,"leaksUncounted":0,"coins":0,"dmg":549243,"bossDmg":0,"heal":0,"deaths":16,"layerGains":{}}}, + "players": {"p1":{"killed":121,"total":183,"perfect":false,"leaks":62,"leaksUncounted":0,"coins":0,"dmg":524053,"bossDmg":0,"heal":0,"deaths":17,"layerGains":{}}}, "units": [ - ["p1",1,"op","chess_char_6_diy1_a",0,null,1884,1,191,8,54401,1884,0,59,2], - ["p1",2,"op","chess_char_6_diy2_a",1,null,0,0,210,41,38926,3768,0,48,2], - ["p1",3,"op","chess_char_6_diy1_a",2,null,1884,1,218,11,57866,1884,0,43,1], - ["p1",4,"op","chess_char_6_diy2_b",0,"none",2216,1,196,14,85238,2216,0,68,2], - ["p1",5,"op","chess_char_6_diy1_b",1,"none",0,0,153,18,110415,4432,0,41,1], - ["p1",6,"op","chess_char_6_diy2_b",2,"none",0,0,182,13,101208,4432,0,48,1], + ["p1",1,"op","chess_char_6_diy1_a",0,null,1884,1,190,7,74139,1884,0,56,2], + ["p1",2,"op","chess_char_6_diy2_a",1,null,0,0,204,35,51212,3768,0,38,2], + ["p1",3,"op","chess_char_6_diy1_a",2,null,0,0,193,8,36822,3768,0,38,1], + ["p1",4,"op","chess_char_6_diy2_b",0,"none",2216,1,212,5,23864,2216,0,45,2], + ["p1",5,"op","chess_char_6_diy1_b",1,"none",0,0,153,18,103390,4432,0,41,1], + ["p1",6,"op","chess_char_6_diy2_b",2,"none",0,0,182,14,109015,4432,0,46,1], ["p1",7,"op","chess_char_5_diy1_a",0,null,1359,1,4,0,0,0,0,0,0], - ["p1",8,"op","chess_char_5_diy2_a",1,null,1359,1,5,2,31646,0,0,53,53], - ["p1",9,"op","chess_char_5_diy1_a",2,null,1359,1,154,0,39160,1359,0,42,3], - ["p1",10,"op","chess_char_5_diy2_b",0,"none",0,0,180,2,9770,3140,0,25,2], - ["p1",11,"op","chess_char_5_diy1_b",1,"none",0,0,175,0,6679,3140,0,21,4], - ["p1",12,"op","chess_char_5_diy2_b",2,"none",0,0,141,4,9738,3140,0,12,1], + ["p1",8,"op","chess_char_5_diy2_a",1,null,1359,1,5,3,28459,0,0,52,0], + ["p1",9,"op","chess_char_5_diy1_a",2,null,1359,1,176,0,49348,1359,0,39,2], + ["p1",10,"op","chess_char_5_diy2_b",0,"none",0,0,181,4,14787,3140,0,38,3], + ["p1",11,"op","chess_char_5_diy1_b",1,"none",0,0,174,1,9156,3140,0,21,4], + ["p1",12,"op","chess_char_5_diy2_b",2,"none",0,0,141,4,11236,3140,0,12,1], ["-","~1","device","trap_1105_accrate",null,null,100,1,1,0,0,0,0,0,null], ["-","~2","device","trap_1105_accrate",null,null,100,1,2,0,0,0,0,0,null], ["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null], - ["p1","~1","token","token_10024_ebnhlz_rcube",null,null,1000,0,37,0,2623,0,0,0,null], - ["p1","~2","token","token_10024_ebnhlz_rcube",null,null,1000,0,53,0,1,0,0,0,null], - ["p1","~3","token","token_10024_ebnhlz_rcube",null,null,1000,0,71,0,1572,0,0,0,null], - ["p1","~4","token","token_10024_ebnhlz_rcube",null,null,1000,0,83,0,0,0,0,0,null] + ["p1","~1","token","token_10024_ebnhlz_rcube",null,null,1000,0,37,0,1572,0,0,0,null], + ["p1","~2","token","token_10024_ebnhlz_rcube",null,null,1000,0,52,0,0,0,0,0,null], + ["p1","~3","token","token_10024_ebnhlz_rcube",null,null,1000,0,67,0,6859,0,0,0,null], + ["p1","~4","token","token_10024_ebnhlz_rcube",null,null,1000,0,81,0,4195,0,0,0,null] ], "enemies": { - "enemy_1197_sfshu": [15,11,4,2272,51823], - "enemy_1197_sfshu_2": [39,21,18,6413,151033], - "enemy_1198_msfshu": [33,26,7,0,81], - "enemy_1198_msfshu_2": [63,54,9,0,225], - "enemy_9010_acpupp": [39,12,27,16255,412992] + "enemy_1197_sfshu": [15,10,5,1799,50834], + "enemy_1197_sfshu_2": [39,20,19,6094,139516], + "enemy_1198_msfshu": [30,26,4,0,79], + "enemy_1198_msfshu_2": [60,54,6,0,217], + "enemy_9010_acpupp": [39,11,28,18930,401042] }, - "hooks": [1,218,6170,550,550,2484,2286,0,140,209,72,69,61,11555,18,37,189,65,1,153,0,0,0], - "events": {"atk":913,"deploy":26,"die":144,"dmg":2286,"engage":11,"fx":143,"leak":65,"skill":141,"spawn":208,"status":408}, - "fx": {"aoe":4,"dash":3,"displace":8,"ember":13,"pull":8,"shieldBreak":37,"summon":36,"takeoff":9,"telegraph":13,"volley":12}, - "snaps": "97d774f4 d56f2c40 38cfa54f 7e2be674 45424794 b549bc6d d02f3886 8eef35d8 186b734d ef22c4fe 6eed958f 1c82384a 2d257b7e e4c0bf84 b322c2f5 561c30ac c139ed4b 0f61007b e04f8bf8 c8e87b59 3c8fbdd4" + "hooks": [1,212,6170,507,507,2408,2252,0,138,204,19,17,61,12292,18,39,183,62,1,150,0,0,0], + "events": {"atk":827,"deploy":26,"die":142,"dmg":2252,"engage":11,"fx":136,"leak":62,"skill":36,"spawn":202,"status":382}, + "fx": {"aoe":4,"dash":3,"displace":8,"ember":12,"pull":8,"revive":1,"shieldBreak":28,"summon":34,"takeoff":9,"telegraph":12,"volley":17}, + "snaps": "97d774f4 3a87e9c0 6315b127 d1ff957b 8b0cf599 ffcafc10 f97c63e0 b090bfcf 503cb562 30e78f94 453e3e4b 5c62e222 794d1210 f8da69f3 40109745 bfd2d8ad 9529555d def80e98 4395baef ad6ed566 87adb778" }, "diy-115": { "about": "5_diy1_b=ebnhlz/S1/002_ebnhlz 5_diy2_b=ebnhlz/S2/002_ebnhlz 5_diy1_b=ebnhlz/S3/002_ebnhlz 5_diy2_b=ebnhlz/S1/003_ebnhlz 5_diy1_b=ebnhlz/S2/003_ebnhlz 5_diy2_b=ebnhlz/S3/003_ebnhlz 5_diy1_b=ebnhlz/S1/004_ebnhlz 5_diy2_b=ebnhlz/S2/004_ebnhlz 5_diy1_b=ebnhlz/S3/004_ebnhlz 6_diy1_a=ebnhlz/S1 6_diy2_a=ebnhlz/S2 6_diy1_a=ebnhlz/S3", @@ -4916,59 +4916,61 @@ "round": 12, "seed": 2479968306, "waveId": "act1autochess_h05", - "time": 193.8, - "ticks": 5814, + "time": 193.6, + "ticks": 5808, "reason": "cleared", - "killed": 195, - "total": 246, + "killed": 197, + "total": 243, "unspawned": 0, "bossHpLeft": null, "rngDraws": 0, "errors": {"count":0,"kinds":[]}, - "players": {"p1":{"killed":195,"total":246,"perfect":false,"leaks":51,"leaksUncounted":0,"coins":0,"dmg":515319,"bossDmg":0,"heal":0,"deaths":9,"layerGains":{}}}, + "players": {"p1":{"killed":197,"total":243,"perfect":false,"leaks":46,"leaksUncounted":0,"coins":0,"dmg":532641,"bossDmg":0,"heal":0,"deaths":8,"layerGains":{}}}, "units": [ ["p1",1,"op","chess_char_5_diy1_b",0,"uniequip_002_ebnhlz",1570,1,10,7,61901,0,0,45,5], - ["p1",2,"op","chess_char_5_diy2_b",1,"uniequip_002_ebnhlz",1570,1,11,9,35088,0,0,28,25], - ["p1",3,"op","chess_char_5_diy1_b",2,"uniequip_002_ebnhlz",1570,1,1,9,12719,0,0,24,4], - ["p1",4,"op","chess_char_5_diy2_b",0,"uniequip_003_ebnhlz",1650,1,3,21,55599,0,0,72,7], - ["p1",5,"op","chess_char_5_diy1_b",1,"uniequip_003_ebnhlz",1650,1,5,7,56916,0,0,60,33], - ["p1",6,"op","chess_char_5_diy2_b",2,"uniequip_003_ebnhlz",1650,1,7,12,124221,0,0,54,4], + ["p1",2,"op","chess_char_5_diy2_b",1,"uniequip_002_ebnhlz",1570,1,11,9,33720,0,0,27,0], + ["p1",3,"op","chess_char_5_diy1_b",2,"uniequip_002_ebnhlz",1570,1,1,11,16041,0,0,24,4], + ["p1",4,"op","chess_char_5_diy2_b",0,"uniequip_003_ebnhlz",1650,1,3,15,56353,0,0,77,7], + ["p1",5,"op","chess_char_5_diy1_b",1,"uniequip_003_ebnhlz",1650,1,5,10,52596,0,0,60,6], + ["p1",6,"op","chess_char_5_diy2_b",2,"uniequip_003_ebnhlz",1650,1,7,13,127550,0,0,51,4], ["p1",7,"op","chess_char_5_diy1_b",0,"uniequip_004_ebnhlz",1570,1,9,0,0,0,0,0,3], - ["p1",8,"op","chess_char_5_diy2_b",1,"uniequip_004_ebnhlz",1570,1,12,6,63692,0,0,49,11], - ["p1",9,"op","chess_char_5_diy1_b",2,"uniequip_004_ebnhlz",0,0,194,2,8623,3140,0,8,2], - ["p1",10,"op","chess_char_6_diy1_a",0,null,0,0,172,10,12844,2718,0,33,2], - ["p1",11,"op","chess_char_6_diy2_a",1,null,1025.48,1,275,3,14668,3052,0,17,7], - ["p1",12,"op","chess_char_6_diy1_a",2,null,0,0,269,0,16023,4077,0,12,1], - ["p1","~1","token","token_10024_ebnhlz_rcube",null,null,1000,0,29,0,10534,0,0,0,null], - ["p1","~2","token","token_10024_ebnhlz_rcube",null,null,1000,0,32,0,0,0,0,0,null], - ["p1","~3","token","token_10024_ebnhlz_rcube",null,null,1000,0,56,0,7762,0,0,0,null], - ["p1","~4","token","token_10024_ebnhlz_rcube",null,null,1000,0,78,1,4611,0,0,0,null], - ["p1","~5","token","token_10024_ebnhlz_rcube",null,null,1000,0,87,0,0,0,0,0,null], - ["p1","~6","token","token_10024_ebnhlz_rcube",null,null,1000,0,106,0,7762,0,0,0,null], - ["p1","~7","token","token_10024_ebnhlz_rcube",null,null,1000,0,128,0,0,0,0,0,null], - ["p1","~8","token","token_10024_ebnhlz_rcube",null,null,1000,0,133,0,2772,0,0,0,null], - ["p1","~9","token","token_10024_ebnhlz_rcube",null,null,1000,0,150,0,2219,0,0,0,null], - ["p1","~10","token","token_10024_ebnhlz_rcube",null,null,1000,0,162,0,0,0,0,0,null], - ["p1","~11","token","token_10024_ebnhlz_rcube",null,null,1000,0,169,1,4611,0,0,0,null], - ["p1","~12","token","token_10024_ebnhlz_rcube",null,null,1000,0,197,0,2218,0,0,0,null], - ["p1","~13","token","token_10024_ebnhlz_rcube",null,null,1000,0,219,0,0,0,0,0,null], - ["p1","~14","token","token_10024_ebnhlz_rcube",null,null,1000,0,220,0,2772,0,0,0,null], - ["p1","~15","token","token_10024_ebnhlz_rcube",null,null,1000,0,240,0,2776,0,0,0,null], - ["p1","~16","token","token_10024_ebnhlz_rcube",null,null,1000,1,254,0,0,0,0,0,null], - ["p1","~17","token","token_10024_ebnhlz_rcube",null,null,1000,0,256,0,4990,0,0,0,null] + ["p1",8,"op","chess_char_5_diy2_b",1,"uniequip_004_ebnhlz",1570,1,12,8,66486,0,0,49,13], + ["p1",9,"op","chess_char_5_diy1_b",2,"uniequip_004_ebnhlz",0,0,225,5,6116,3140,0,10,2], + ["p1",10,"op","chess_char_6_diy1_a",0,null,0,0,164,8,12174,2718,0,31,2], + ["p1",11,"op","chess_char_6_diy2_a",1,null,1025.48,1,275,5,13604,3052,0,16,0], + ["p1",12,"op","chess_char_6_diy1_a",2,null,81.61,1,270,2,15684,3995,0,14,1], + ["p1","~1","token","token_10024_ebnhlz_rcube",null,null,1000,0,29,0,0,0,0,0,null], + ["p1","~2","token","token_10024_ebnhlz_rcube",null,null,1000,0,30,1,12752,0,0,0,null], + ["p1","~3","token","token_10024_ebnhlz_rcube",null,null,1000,0,55,0,5544,0,0,0,null], + ["p1","~4","token","token_10024_ebnhlz_rcube",null,null,1000,0,70,0,4990,0,0,0,null], + ["p1","~5","token","token_10024_ebnhlz_rcube",null,null,1000,0,72,0,0,0,0,0,null], + ["p1","~6","token","token_10024_ebnhlz_rcube",null,null,1000,0,92,0,4990,0,0,0,null], + ["p1","~7","token","token_10024_ebnhlz_rcube",null,null,1000,0,122,0,12197,0,0,0,null], + ["p1","~8","token","token_10024_ebnhlz_rcube",null,null,1000,0,125,0,0,0,0,0,null], + ["p1","~9","token","token_10024_ebnhlz_rcube",null,null,1000,0,138,0,2772,0,0,0,null], + ["p1","~10","token","token_10024_ebnhlz_rcube",null,null,1000,0,155,0,2221,0,0,0,null], + ["p1","~11","token","token_10024_ebnhlz_rcube",null,null,1000,0,160,0,0,0,0,0,null], + ["p1","~12","token","token_10024_ebnhlz_rcube",null,null,1000,0,171,0,4990,0,0,0,null], + ["p1","~13","token","token_10024_ebnhlz_rcube",null,null,1000,0,204,0,9425,0,0,0,null], + ["p1","~14","token","token_10024_ebnhlz_rcube",null,null,1000,0,216,0,0,0,0,0,null], + ["p1","~15","token","token_10024_ebnhlz_rcube",null,null,1000,0,223,0,2772,0,0,0,null], + ["p1","~16","token","token_10024_ebnhlz_rcube",null,null,1000,0,243,0,2776,0,0,0,null], + ["p1","~17","token","token_10024_ebnhlz_rcube",null,null,1000,1,254,0,0,0,0,0,null], + ["p1","~18","token","token_10024_ebnhlz_rcube",null,null,1000,0,257,0,4990,0,0,0,null], + ["p1","~19","token","token_10024_ebnhlz_rcube",null,null,1000,0,272,0,0,0,0,0,null] ], "enemies": { - "enemy_1195_sfyin": [45,24,21,8753,152906], - "enemy_1196_msfyin": [48,44,4,0,90], - "enemy_1197_sfshu": [39,30,9,4234,206523], - "enemy_1198_msfshu": [90,76,14,0,242], + "enemy_1195_sfyin": [45,30,15,8741,173581], + "enemy_1196_msfyin": [60,51,9,0,105], + "enemy_1197_sfshu": [39,25,14,4164,201605], + "enemy_1198_msfshu": [75,70,5,0,216], "enemy_1199_sfjin": [12,12,0,0,186325], - "enemy_1200_msfjin": [12,9,3,0,348] + "enemy_1200_msfjin": [12,9,3,0,346] }, - "hooks": [1,281,5814,450,450,1977,2088,0,204,271,104,102,0,27867,0,31,246,51,1,204,0,0,0], - "events": {"atk":450,"deploy":35,"die":220,"dmg":2088,"engage":11,"fx":189,"leak":51,"skill":206,"spawn":275}, - "fx": {"aoe":11,"displace":13,"pull":13,"summon":83,"volley":69}, - "snaps": "b588f908 018cc7d1 02df24b0 d7fb7008 01901fca 88a112ed f0544f8d 91caefd2 24dd8e93 26798334 2b5c19c3 091cb2b8 45da698c 1d8e5f22 91d224aa a413c6ff af6b4e5f d69eff16 da950540 179fa098" + "hooks": [1,280,5808,450,450,1944,2063,0,205,269,47,45,0,28772,0,29,243,46,1,205,0,0,0], + "events": {"atk":450,"deploy":37,"die":223,"dmg":2063,"engage":11,"fx":197,"leak":46,"skill":92,"spawn":274}, + "fx": {"aoe":13,"displace":15,"pull":15,"summon":86,"volley":68}, + "snaps": "b588f908 30b58fc4 0067aae8 073e6898 0cbd5145 a0736062 6e599248 f14345d4 7c4901d1 2f52111e a8cc7280 ac1fd796 f60de3a9 9b4b7177 cc02ceba e6974a52 cf27fc35 a4a00c5a a7501807 6a48f2bc" }, "diy-116": { "about": "6_diy1_b=ebnhlz/S1 6_diy2_b=ebnhlz/S2 6_diy1_b=ebnhlz/S3 6_diy2_b=ebnhlz/S1/002_ebnhlz 6_diy1_b=ebnhlz/S2/002_ebnhlz 6_diy2_b=ebnhlz/S3/002_ebnhlz 6_diy1_b=ebnhlz/S1/003_ebnhlz 6_diy2_b=ebnhlz/S2/003_ebnhlz 6_diy1_b=ebnhlz/S3/003_ebnhlz 6_diy2_b=ebnhlz/S1/004_ebnhlz 6_diy1_b=ebnhlz/S2/004_ebnhlz 6_diy2_b=ebnhlz/S3/004_ebnhlz", @@ -4986,31 +4988,32 @@ "total": 123, "unspawned": 0, "bossHpLeft": null, - "rngDraws": 5, + "rngDraws": 6, "errors": {"count":0,"kinds":[]}, - "players": {"p1":{"killed":1,"total":123,"perfect":false,"leaks":122,"leaksUncounted":0,"coins":0,"dmg":271272,"bossDmg":0,"heal":0,"deaths":19,"layerGains":{}}}, + "players": {"p1":{"killed":1,"total":123,"perfect":false,"leaks":122,"leaksUncounted":0,"coins":0,"dmg":286822,"bossDmg":0,"heal":0,"deaths":19,"layerGains":{}}}, "units": [ - ["p1",1,"op","chess_char_6_diy1_b",0,"none",1570,1,147,0,23015,3140,0,31,2], - ["p1",2,"op","chess_char_6_diy2_b",1,"none",0,0,123,0,19192,3140,0,10,1], - ["p1",3,"op","chess_char_6_diy1_b",2,"none",1570,1,134,0,52931,1570,0,26,2], - ["p1",4,"op","chess_char_6_diy2_b",0,"uniequip_002_ebnhlz",0,0,146,0,15092,3140,0,15,1], - ["p1",5,"op","chess_char_6_diy1_b",1,"uniequip_002_ebnhlz",0,0,82,0,13594,3140,0,7,1], - ["p1",6,"op","chess_char_6_diy2_b",2,"uniequip_002_ebnhlz",0,0,78,0,9982,3140,0,6,0], - ["p1",7,"op","chess_char_6_diy1_b",0,"uniequip_003_ebnhlz",0,0,74,0,14427,3490,0,4,0], - ["p1",8,"op","chess_char_6_diy2_b",1,"uniequip_003_ebnhlz",0,0,7,0,14109,1745,0,5,1], - ["p1",9,"op","chess_char_6_diy1_b",2,"uniequip_003_ebnhlz",0,0,9,0,19195,1745,0,7,1], - ["p1",10,"op","chess_char_6_diy2_b",0,"uniequip_004_ebnhlz",0,0,79,0,8532,3140,0,4,0], - ["p1",11,"op","chess_char_6_diy1_b",1,"uniequip_004_ebnhlz",0,0,4,1,20024,1570,0,6,1], - ["p1",12,"op","chess_char_6_diy2_b",2,"uniequip_004_ebnhlz",0,0,6,0,34442,1570,0,6,1], - ["p1","~1","token","token_10024_ebnhlz_rcube",null,null,1000,0,27,0,15400,0,0,0,null], - ["p1","~2","token","token_10024_ebnhlz_rcube",null,null,1000,0,28,0,4454,0,0,0,null], - ["p1","~3","token","token_10024_ebnhlz_rcube",null,null,1000,0,29,0,6883,0,0,0,null] + ["p1",1,"op","chess_char_6_diy1_b",0,"none",1570,1,148,1,25031,3140,0,31,2], + ["p1",2,"op","chess_char_6_diy2_b",1,"none",0,0,124,0,18799,3140,0,10,2], + ["p1",3,"op","chess_char_6_diy1_b",2,"none",1570,1,135,0,49295,1570,0,24,2], + ["p1",4,"op","chess_char_6_diy2_b",0,"uniequip_002_ebnhlz",0,0,147,0,16828,3140,0,16,1], + ["p1",5,"op","chess_char_6_diy1_b",1,"uniequip_002_ebnhlz",0,0,83,0,13594,3140,0,7,1], + ["p1",6,"op","chess_char_6_diy2_b",2,"uniequip_002_ebnhlz",0,0,79,0,9982,3140,0,6,0], + ["p1",7,"op","chess_char_6_diy1_b",0,"uniequip_003_ebnhlz",0,0,75,0,14427,3490,0,4,0], + ["p1",8,"op","chess_char_6_diy2_b",1,"uniequip_003_ebnhlz",0,0,7,0,16808,1745,0,7,0], + ["p1",9,"op","chess_char_6_diy1_b",2,"uniequip_003_ebnhlz",0,0,9,0,22161,1745,0,7,1], + ["p1",10,"op","chess_char_6_diy2_b",0,"uniequip_004_ebnhlz",0,0,80,0,8532,3140,0,4,0], + ["p1",11,"op","chess_char_6_diy1_b",1,"uniequip_004_ebnhlz",0,0,4,0,18212,1570,0,4,1], + ["p1",12,"op","chess_char_6_diy2_b",2,"uniequip_004_ebnhlz",0,0,6,0,39389,1570,0,8,1], + ["p1","~1","token","token_10024_ebnhlz_rcube",null,null,1000,0,26,0,4454,0,0,0,null], + ["p1","~2","token","token_10024_ebnhlz_rcube",null,null,1000,0,27,0,17360,0,0,0,null], + ["p1","~3","token","token_10024_ebnhlz_rcube",null,null,1000,0,28,0,4876,0,0,0,null], + ["p1","~4","token","token_10024_ebnhlz_rcube",null,null,1000,0,37,0,7074,0,0,0,null] ], - "enemies": {"enemy_1006_shield_3":[21,0,21,8166,127088],"enemy_1043_zomsbr":[66,1,65,14521,60428],"enemy_1402_tgshd_2":[36,0,36,7843,83756]}, - "hooks": [1,147,6528,189,189,333,355,10424,20,145,11,11,0,8727,0,21,123,122,1,20,0,1,0], - "events": {"atk":189,"deploy":24,"die":23,"dmg":355,"engage":12,"fx":96,"leak":122,"skill":22,"spawn":138,"status":36}, - "fx": {"aoe":3,"burst":1,"displace":5,"expose":67,"pull":5,"summon":3,"volley":12}, - "snaps": "389ca6e3 c8f155a4 e2e7a3b2 2f4c8838 6a9c72f0 8c585b7e a26f5d0c 80f56fed a04d35ab 88374c55 043f03c3 acc9e8b4 6dc5a029 a28ee86b d72cad57 77ed9536 4cd333ad 94a7e729 29475fd8 b7079863 f08523df a6844f3a" + "enemies": {"enemy_1006_shield_3":[21,0,21,8025,133387],"enemy_1043_zomsbr":[66,1,65,13522,62006],"enemy_1402_tgshd_2":[36,0,36,8983,91429]}, + "hooks": [1,148,6528,187,187,341,362,10129,20,146,11,11,0,8777,0,22,123,122,1,20,0,1,0], + "events": {"atk":187,"deploy":25,"die":24,"dmg":362,"engage":12,"fx":108,"leak":122,"skill":22,"spawn":139,"status":38}, + "fx": {"aoe":4,"burst":1,"displace":6,"expose":74,"pull":6,"summon":4,"volley":13}, + "snaps": "389ca6e3 d4a0046f e8e318e4 2dfb6564 d6b9ac5b 05f87e6d 4fddc6c0 abdaf56e 564d85ec f523de7f 8fc91296 e8062bef a97ba650 2328edb5 b076db9a 504c2000 80dda69d 2e369d1e 56349199 70fdf2ec 97f6afb9 059a1cef" }, "diy-117": { "about": "5_diy1_a=mgllan/S1 5_diy2_a=mgllan/S2 5_diy1_a=mgllan/S3 5_diy2_b=mgllan/S1 5_diy1_b=mgllan/S2 5_diy2_b=mgllan/S3 5_diy1_b=mgllan/S1/002_mgllan 5_diy2_b=mgllan/S2/002_mgllan 5_diy1_b=mgllan/S3/002_mgllan 5_diy2_b=mgllan/S1/003_mgllan 5_diy1_b=mgllan/S2/003_mgllan 5_diy2_b=mgllan/S3/003_mgllan",