feedback7: merge fb7-tick — whole-frame attack intervals and time-SP costs take exactly that many frames, 1 s = 30 not 31 (PR #402 by @Cloudnyco, ported onto 0.2.2: 1e-9 on the ally / enemy attack countdown, the 双眼皮 turret and 寒檀's icicles, gainSp / _normalize; PRTS 作战机制 帧对齐); golden: every family moves (281 of 283, end-result flips in §27.61); union OK
This commit is contained in:
commit
e1b75e1308
21 files changed
+5008
-4776
No files matched your search
+13
-1
@@ -565,6 +565,16 @@ Aggregation: `ATK/DEF/maxHp = (base + Σflat) × (1 + Σpct) × Πmul`, for ATK
|
||||
percentages: `ATK = ((base + ΣatkFlat) × (1 + ΣatkPct) + ΣatkFinal) × ΠatkMul`; `res = clamp((base + ΣresFlat) × ΠresMul, 0, 100)`;
|
||||
`aspd = clamp(base + Σaspd, 20, 600)` (floor 20: PRTS 数值范围 ATTACK_SPEED 默认下限; user playtest #6); `interval = bat × (1 + ΣbatPct) × 100 / aspd`; `moveSpeed = (base + ΣmoveFlat) × ΠmoveMul`;
|
||||
tiles/s = `moveSpeed × MOVE_SCALE (0.5)`. A maxHp change keeps the HP ratio. Elite stats (module included) come from data.
|
||||
The attack cooldown `atkCd` starts at `interval` and counts down by `TICK`; what is left within 1e-9 of 0 is 0
|
||||
(`ai.js attackCountdown`, the tolerance of skill `timeLeft`, buff intervals and `every()`; PR #402 by @Cloudnyco, 0.2.2),
|
||||
so an interval of a whole number of ticks takes exactly that many: 1 s = 30 ticks, 3 s = 90 (floating point alone left
|
||||
2.1e-16 after thirty steps of 1/30, and every such attack came a tick late — 31, 91). The same countdown runs the 双眼皮
|
||||
turrets (`content/devices.js`) and 寒檀's S2 icicles; the drones of 澄闪 / 荒芜拉普兰德 and 电弧's 赛柯 volleys compared
|
||||
with 1e-9 already. Content clocks that count up and restart from 0 (the boss self-timers of `content/bosses.js`, kit auras)
|
||||
are not covered. Official (PRTS 作战机制/sandbox 「帧对齐机制对攻速的影响」): the time unit is one frame, 1/30 s, and since
|
||||
the 2019-12-24 update a non-integer frame count is rounded (四舍五入; before, 进一取整); an exact one stays. Here a
|
||||
non-integer count still ends on the tick that crosses 0 — ⌈30 × interval⌉ ticks (1.2 s = 36, 1.25 s = 38; 能天使's
|
||||
0.678 s is 21 here, 20 frames officially): an older difference from the official rounding, not changed by this rule.
|
||||
|
||||
**Which bucket (PRTS 游戏数据基础 属性基本公式 / 作战机制, DESIGN §20.10).** `Σpct` is the official **直接乘算** class — its
|
||||
values are summed (`A = (A₀ + D_p)(1 + D_t)`, D_t = t₁ + … + tₙ): a skill's or talent's "攻击力+X%" **and** every "+X%"
|
||||
@@ -918,7 +928,9 @@ instance) and skip `'counter'` / `'reflect'` damage. When the guard trips, the l
|
||||
PRTS 异常效果 晕眩 names no SP effect — community report #18). Attack-type SP: attacks made
|
||||
by the skill (the pending "next attack" of an instant/charge skill, every shot of a timed skill including the one that
|
||||
ends it) recover nothing, so a cost-N skill fires every **N+1** attacks (AK). Charges (`maxChargeTime > 1`):
|
||||
SP fills to cost → +1 charge (SP restarts) until charges are full (then SP stays full).
|
||||
SP fills to cost → +1 charge (SP restarts) until charges are full (then SP stays full). SP within 1e-9 of the cost is
|
||||
the cost (`gainSp`, `_normalize`; a tiny negative remainder is 0): the float sum of the 1/30-SP time gains can stop
|
||||
2.5e-14 short of it — a 10-SP skill at 1 SP/s took 301 ticks, now 300 (PR #402, 0.2.2).
|
||||
- Triggers (`skill.trigger.rule` in data — the official 技能策略, PRTS 卫戍协议/帮助 §作战阶段 技能操作, resolved by
|
||||
`tools/build-data.mjs resolveTrigger`: charId rows by skill index; the class rows (重装 / 执旗手 / 战术家 / 吟游者 / 解放者 /
|
||||
阵法术师) for **every MANUAL skill** of the class; SKILL_RANGE for a MANUAL skill with a 技能范围 of its own; ACTIVE_RANGE
|
||||
|
||||
@@ -22,6 +22,13 @@ Part of [DESIGN.md](../DESIGN.md) (the index; section numbers are global).
|
||||
## 4. Time model
|
||||
|
||||
- Simulation time is **game seconds**. Fixed step `TICK = 1/30 s`.
|
||||
- Timers count in ticks and take what is within 1e-9 as reached — attack cooldowns and enemy wind-ups (`ai.js
|
||||
attackCountdown`), time SP against its cost (`skills.js gainSp`), skill durations, buff intervals, `every()` /
|
||||
`after()`, enemy abilities, the 失衡 end —, so a whole number of ticks takes exactly that many: 1 s = 30 ticks (PRTS
|
||||
作战机制/sandbox 「帧对齐机制对攻速的影响」: one frame = 1/30 s). Floating point alone held 1 s attacks and 10-SP charges a
|
||||
tick longer until 0.2.2 (PR #402, §27.61). A non-integer count ends on the tick that crosses the line, ⌈30 × t⌉ (1.25 s
|
||||
= 38); the official game rounds it (四舍五入 since 2019-12-24: 能天使's 0.678 s is 20 frames there, 21 here) — an older
|
||||
difference, not changed.
|
||||
- Combat runs at **2× real time** (forced, like the original): 60 ticks per real second — in the browser's runner (§14) or, for server-run fields, the server's accumulator (2 ticks every real 1/30 s, never more than 8 ticks per interval to avoid spirals).
|
||||
- Combat time limits come from `data/config.json → modes[m].rounds[r].combatTimeLimit` (= the level's `maxPlayTime`; also `modes[m].combatTimeLimit[r]`) and are **real seconds of the forced-2× battle** (verified by the balance pass: spawn schedules exceed the limit when read as game seconds). The server passes `2 × value` game seconds to the Battle (`server/match/gamedata.js → combatTimeLimit`; `config.combatTimeScale`, default 2); the countdown players see equals the data value. When time runs out, living non-boss enemies count as leaked. 联防 uses the round's limit.
|
||||
- Final Assault / Hidden Core have **no hard stop** and their clocks are real seconds too: the boss level's `levelMaxPlayTime` (120 real s) is only the HUD countdown (`m.public.deadline`; the battle goes on past it), and the overtime drain (`bossOvertimeAfter` 150 / `bossOvertimeDrainPerSec` 1 = official `bossTurnHpReduceTime`) takes 1 team LP per whole **real** second from 150 real s (= 300 game s on the 2× field clock; first point at 151 s — `gamedata.js bossOvertimeDue`). `m.public.overtimeAt` = the ms epoch when the drain starts; both are placed on the field clock.
|
||||
|
||||
+64
-1
@@ -18,7 +18,8 @@ the boss bounty payout and the bots' guards → §27.33–§27.35; the battle vi
|
||||
pull slides, the champagne's bar, closed eyes, late attack clips, the HP-bar readouts, the renderer abort, held skill
|
||||
cues, atlas refreshes, 梓兰's frost) → §27.36–§27.46; the interface (device tips, the settings button, the shop fold,
|
||||
spectators, the top-bar capsule, the empty new shop slot) → §27.47–§27.52; voices → §27.53–§27.54; the statistics page
|
||||
→ §27.55; potential and training (潜能 / 练度) and the 干员调配 list → §27.56–§27.59; the 自选 picker's Esc → §27.60.
|
||||
→ §27.55; potential and training (潜能 / 练度) and the 干员调配 list → §27.56–§27.59; the 自选 picker's Esc → §27.60;
|
||||
whole-frame attack intervals and SP costs (PR #402) → §27.61.
|
||||
|
||||
Decisions of the owner, 2026-10-08 (round 22, from community reports, GitHub and research into the official rules):
|
||||
潜能 and the 自持有 练度 bonus are set per operator in 干员调配, defaults 潜能 6 and 精英2 Lv.60 (official: the account's
|
||||
@@ -1456,3 +1457,65 @@ Notes for the integrator
|
||||
- **Tests**: test/ui/diy.e2e.test.js adds the immediate Esc (it fails without the fix). The loadout-battle /
|
||||
teammate-loadout / loadout browser tests follow §27.57's 干员调配: the row's quick skill / module choices, the default
|
||||
练度 in the detail card's base ATK (×1.1), the detail back at the top before a click.
|
||||
|
||||
### 27.61 An attack interval or a time-SP cost of a whole number of frames takes exactly that many — 1 s is 30 frames, not 31 (PR #402 by @Cloudnyco; the owner's approval of 2026-10-09) — `sim/ai.js attackCountdown / updateAlly / updateEnemy`, `sim/skills.js SkillRuntime.gainSp / _normalize`, `sim/content/devices.js tickTurret`, `sim/content/kits/ops/chess_char_5_21-sntlla.js`
|
||||
- **Seen**: PR #402: an attack cooldown counted down by TICK = 1/30 s (not a binary fraction) stops at 2.1e-16 after
|
||||
thirty steps from 1 s, and the fire check `atkCd > 0` waited a 31st frame; 300 time gains of 1/30 SP add up to
|
||||
9.999999999999975, so `sp >= cost` charged a 10-SP skill a frame late. Measured on 0.2.2 before the fix, over the 265
|
||||
golden battles: 30.85 % of the consecutive attacks on a whole-frame interval came a frame late (the other intervals,
|
||||
the control: 0.09 %) — 1 s gaps were 31 frames in 3 545 of 3 801, 3 s 91 in all 6 677, 4 s 121 in all 2 223 —, and
|
||||
4 157 end-of-tick states sat within 1e-9 under a skill's cost (229 battles). The engine already took a timer within
|
||||
1e-9 as done (skill `timeLeft`, buff intervals, `every()` / `after()`, enemy abilities, nextCastAt, the 失衡 end);
|
||||
these two did not.
|
||||
- **Official**: PRTS 作战机制/sandbox 「帧对齐机制对攻速的影响」: the time unit is one frame, 1/30 s; since the 2019-12-24
|
||||
update a non-integer frame count is rounded (四舍五入; before, 进一取整) — 能天使's 0.696 s is 21 frames, 0.678 s 20.
|
||||
An exact 1 s is 30 frames under either rule; PRTS 游戏数据基础 攻速公式 (T = T₀ / (clamp(S, 10, 600) / 100)) adds no frame.
|
||||
- **Now**: `ai.js attackCountdown(cd, dt)` — what is left within 1e-9 of 0 is 0 — counts down the operators' cooldown
|
||||
(still only while `canAct`) and the enemies' (not while stunned or hidden; the 失衡 swing cut as it was). An enemy's
|
||||
strike frame is that countdown's 0, so a whole-frame wind-up is exact too (a 0.4 s clip hit: 12 frames, 13 before). The
|
||||
“双眼皮” turrets (`content/devices.js`) and 寒檀's S2 icicles (0.5 s: 15 frames, 16 before) use it — the same `cd -= dt;
|
||||
if (cd > 0)` shape; the drones of 澄闪 / 荒芜拉普兰德 and 电弧's 赛柯 volleys compared with 1e-9 already. `gainSp` takes SP
|
||||
within 1e-9 of the cost as full, every charge of a multi-charge skill included (a tiny negative remainder is 0), and
|
||||
`_normalize` (an SP cost changed mid-battle) compares the same way. Attack / hurt SP (+1 on an integer cost) compare as
|
||||
before: a cost-N attack-SP skill still fires every N + 1 attacks, its attacks now on time. 1e-9 is far above any float
|
||||
residue and far below a frame (PR #402's bounds: ≤ 7.5e-13 on the ASPD 20–600 grid; an interval off the frame grid is
|
||||
≥ 1 / (30 × 600) ≈ 5.6e-5 s from a boundary). Unchanged on purpose: a non-integer count still ends on the frame that crosses 0, ⌈30 × interval⌉ (1.25 s =
|
||||
38; 0.678 s = 21, officially 20) — the official 四舍五入 is an older, separate difference; content clocks that count up
|
||||
and restart from 0 (the boss self-timers of `content/bosses.js`: 管 / 弦's strikes and summons, “萨米的意志”'s 冰凌,
|
||||
阿利斯泰尔's 王权号令 SP; kit auras and pulses — PR #402 lists them) are not touched and may still take a frame more.
|
||||
- **Golden**: 281 of 283 scenarios move — roster 49 / 49, bonds 46 / 46, fields 22 / 22, matches 18 / 18, standins
|
||||
10 / 10, diy 136 / 138: both sides attack on time (more enemy kinds than operator forms sit on whole-frame intervals —
|
||||
3 s, 4 s, 1 s …) and time SP charges a frame sooner. After it: 0.04 % of the whole-frame consecutive attacks a frame
|
||||
late (control 0.13 %), no SP state short of its cost. The moved battles' totals: kills 10 647 → 10 625, leaks 12 398 →
|
||||
12 445, deaths 2 913 → 2 944. End results that flip (one frame cascades; the causes as measured):
|
||||
- solo-NORMAL-1: won → lost in round 14 (team LP 8 → 0) — the Final Assault on 卢西恩 (pool 390 000) runs as before for
|
||||
two minutes (his 0.4 s wind-up a frame shorter), then the team's damage on the pool trails: 884 are left when the
|
||||
overtime drain (from 300 game s) takes the last of the 17 LP at 334 s; before, the pool emptied at 318 s with 8 left.
|
||||
- solo-HARD-1: LP 10 → 12 — round 8 lets one more through (26 → 25; rounds 11–12 even it out) and the Final Assault ends
|
||||
at 300.6 s, before the overtime drain (304.8 s and 2 LP before).
|
||||
- solo-NORMAL-2: LP 9 → 25 — round 5 lets one more through (26 → 25, a coin less), the bot's shop path parts from round
|
||||
6, and its later board (突袭, 232 layers at round 13 against 94) clears rounds 12–13 with no leak (7 + 18 before).
|
||||
- coop2-NORMAL-3: team LP 63 → 68 — ai_1's round-13 battle leaks 1 instead of 6 (its round-12 leaker now goes to 联防).
|
||||
- coop2-ABYSS-10-boosted: team LP 583 → 630 — the Final Assault ends at 606.6 s (639.6) and the Hidden Core at 335.9 s
|
||||
(397.8): 47 LP less of overtime drain.
|
||||
- coop2-NORMAL-14-standins: team LP 41 → 40 — ai_0's round-13 battle lets one 潜伏者 through (23 → 22).
|
||||
- Battles: roster-016 cleared at 220.3 s → a time-out at 230 s (主角阵营角色 leaks instead of falling; kills 101 → 105,
|
||||
leaks 26 → 22); roster-041 a time-out → cleared at 189.0 s, perfect (the last 粉碎攻坚组长 falls inside the 190 s);
|
||||
bond-suntShip-high cleared at 164.2 s → a time-out at 190 s (kills 11 → 13, deaths 4 → 2); standin-04 perfect → 10
|
||||
leaks (deaths 8 → 10); diy-005 / diy-008 cleared at 225.3 s → a time-out at 230 s (a last 宿主重装士兵 / 深池方阵指挥官
|
||||
still walking); diy-127 (白铁 / 酒神) a time-out → cleared at 225.8 s (deaths 7 → 13, leaks 57 → 72); diy-131 (死芒)
|
||||
perfect → 1 leak (a 掠海漂移体).
|
||||
- **Tests**: `test/sim/tick-tolerance.test.js` (new, 7 — the PR's four adapted, plus three): the residue itself;
|
||||
attackCountdown over bat 0.1–10 s × 14 ASPD values = ⌈30 × interval⌉; a 1 s operator every 30 frames and a 3 s ranged
|
||||
enemy every 90; the control 1.2 s = 36, 1.25 s = 38; time-SP costs 4 / 10 / 16 / 20 / 30 / 50 after exactly 30 × N
|
||||
gains, one and two charges; the “双眼皮” turret at 0 layers (BAT 4 s) every 120; 寒檀's icicles every 15 — the four
|
||||
engine ones fail on the parent (31 / 91, cost 4 at 121 gains, 121, 16). The PR's seven test edits, re-run here: the same
|
||||
8 assertions failed on the new timing, and each edit passes on the parent and on the fix — feedback2-surtr-stealth
|
||||
(counts from when no arrow is in flight: a shot keeps its target), kits_alt_t2 拉普兰德 S1 (the dummy's ATK 300 → 250:
|
||||
at 15 frames a hit, 120 × 15 = her 1 791 HP by 59.5 s), kits_alt_t6 (the medic smoke starts the team at half HP; 余 S1
|
||||
compares up to the attacker's first 燃烧 burst, which refuses the next fill), op_jesca2 (the T6 shield, 60 + 30 = the
|
||||
90 s cost, returns a tick after the cast), op_lmlee (his hits before the burst), op_logos (counts after the clear),
|
||||
op_narant (the first attack thrown after the new enemies came). node --test: 5 703 tests, 5 701 pass, 0 fail, 2
|
||||
skipped (the browser suites off); GOLDEN_FULL golden.test 9 / 9; eslint 0 errors (135 warnings, as on the parent).
|
||||
- **Docs**: docs/SIM.md §2 (the countdown, the turrets / icicles, the official 帧对齐 note) and §7.1 (SP);
|
||||
docs/design/geometry-time.md §4.
|
||||
+13
-2
@@ -75,8 +75,19 @@ export function effectiveProfile(u) {
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// ally attack loop
|
||||
|
||||
/**
|
||||
* One tick off an attack cooldown. What is left within 1e-9 of 0 is 0 (the engine's timer tolerance, as skills.js
|
||||
* `timeLeft`, buff intervals and `every()`): 1 s counted down in thirty steps of 1/30 leaves 2.1e-16 in floating point,
|
||||
* which held every attack whose interval is a whole number of ticks — 1 s, 3 s, 4 s … — one tick longer (PR #402; PRTS
|
||||
* 作战机制 帧对齐: 1 s is 30 frames). A non-integer count still ends on the tick that crosses 0 (docs/SIM.md §2).
|
||||
*/
|
||||
export function attackCountdown(cd, dt) {
|
||||
const left = cd - dt;
|
||||
return left > 1e-9 ? left : 0;
|
||||
}
|
||||
|
||||
export function updateAlly(b, u, dt) {
|
||||
if (u.atkCd > 0 && u.canAct) u.atkCd = Math.max(0, u.atkCd - dt);
|
||||
if (u.atkCd > 0 && u.canAct) u.atkCd = attackCountdown(u.atkCd, dt);
|
||||
if (u.blocking.length) enforceBlockCapacity(b, u);
|
||||
if (!u.canAct || !u.profile) return;
|
||||
// a rangeExtend change (buff added / expired) rebuilds the range — also for units that never attack (auras)
|
||||
@@ -542,7 +553,7 @@ export function updateEnemy(b, e, dt) {
|
||||
if (e.s.flags.levitate && e.unbalanceUntil > b.time) e.unbalanceUntil = -Infinity;
|
||||
const unbalanced = b.time < e.unbalanceUntil - 1e-9; // (the 1e-9: a float-summed end such as 35/30 s keeps its frame)
|
||||
const prevCd = e.atkCd;
|
||||
if (e.atkCd > 0 && !stunned && !e.hidden) e.atkCd = Math.max(0, e.atkCd - dt);
|
||||
if (e.atkCd > 0 && !stunned && !e.hidden) e.atkCd = attackCountdown(e.atkCd, dt);
|
||||
// a stun / freeze / sleep / 浮空 / 失衡 — or leaving the field — takes the enemy out of its attack: a swing short of its
|
||||
// damage frame does not land, and the attack starts again from its wind-up afterwards (enemyAttack)
|
||||
if (e.swing && (stunned || e.hidden || unbalanced)) e.swing = false;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
// keeps those tiles NONE (grid.js DEPLOY_REFUSED_TILES), so automatic placements never use them [ASSUMED].
|
||||
|
||||
import { COLS, ROWS } from '../constants.js';
|
||||
import { performAttack } from '../ai.js';
|
||||
import { performAttack, attackCountdown } from '../ai.js';
|
||||
import { sortEnemyTargets } from '../targeting.js';
|
||||
import { DIR_VEC, normDir, oppositeDir } from '../dir.js';
|
||||
import { hypot } from '../detmath.js';
|
||||
@@ -241,7 +241,7 @@ const TURRET_PROFILE = Object.freeze({ attack: 'ranged', dmgType: 'arts', projec
|
||||
function tickTurret(battle, u, dt) {
|
||||
const T = u.mem.turret;
|
||||
if (!u.alive || !T) return;
|
||||
T.cd -= dt;
|
||||
T.cd = attackCountdown(T.cd, dt); // (the engine's attack countdown: a whole number of ticks takes exactly that many)
|
||||
if (T.cd > 0 || u.s.flags.stun) return;
|
||||
const L = u.ownerId != null ? topLayers(battle, u.ownerId) : 0;
|
||||
const bonus = Math.min(L * T.aspdPer, T.aspdMax);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Conventions of the tier-5 kits: ../shared/tier5.js; kit contract and rules: ../README.md.
|
||||
|
||||
import { COLS } from '../../../constants.js';
|
||||
import { attackCountdown } from '../../../ai.js';
|
||||
import { toLocal } from '../../../dir.js';
|
||||
import { num, talent, skillGrid, batPct, mods, lazySkills, whileOn } from '../shared/tier5.js';
|
||||
|
||||
@@ -33,7 +34,7 @@ export default {
|
||||
attack: { noAttack: true },
|
||||
onStart({ unit }) { unit.mem.iceCd = 0; unit.mem.iceRow = 0; },
|
||||
onTick({ battle, unit, dt }) {
|
||||
unit.mem.iceCd -= dt;
|
||||
unit.mem.iceCd = attackCountdown(unit.mem.iceCd, dt); // (the engine's attack countdown, PR #402)
|
||||
if (unit.mem.iceCd > 0 || !unit.canAct || unit.s.flags.disarm) return;
|
||||
if (!battle.enemiesInKeys(unit.rangeKeys, unit, { canHitFly: true }).length) return;
|
||||
unit.mem.iceCd = unit.s.interval;
|
||||
|
||||
@@ -338,9 +338,11 @@ export class SkillRuntime {
|
||||
}
|
||||
if (cost <= 0) return 0; // free skills never recharge (see reset)
|
||||
this.sp += amt;
|
||||
while (this.sp >= cost && this.charges < this.maxCharges) {
|
||||
// within 1e-9 of the cost is the cost (the timer tolerance of `timeLeft` below; PR #402): 300 time gains of 1/30 SP
|
||||
// add up to 9.999999999999975 in floating point, which held a 10-SP charge one tick
|
||||
while (this.sp > cost - 1e-9 && this.charges < this.maxCharges) {
|
||||
this.charges++;
|
||||
if (this.charges < this.maxCharges) this.sp -= cost;
|
||||
if (this.charges < this.maxCharges) this.sp = Math.max(0, this.sp - cost);
|
||||
else this.sp = cost;
|
||||
}
|
||||
if (this.charges >= this.maxCharges) this.sp = cost;
|
||||
@@ -352,9 +354,9 @@ export class SkillRuntime {
|
||||
if (this.noSkill || this.kind === 'passive') return;
|
||||
const cost = this.spCost;
|
||||
if (cost <= 0) { if (this.sp > 0) { this.sp = 0; this.charges = this.maxCharges; } return; } // became free
|
||||
while (this.sp >= cost && this.charges < this.maxCharges) {
|
||||
while (this.sp > cost - 1e-9 && this.charges < this.maxCharges) { // (the 1e-9 of gainSp)
|
||||
this.charges++;
|
||||
this.sp = this.charges < this.maxCharges ? this.sp - cost : cost;
|
||||
this.sp = this.charges < this.maxCharges ? Math.max(0, this.sp - cost) : cost;
|
||||
}
|
||||
if (this.sp > cost) this.sp = cost;
|
||||
}
|
||||
|
||||
@@ -421,8 +421,9 @@ test('2_16 拉普兰德 S1 日晷: toggle (持续时间无限) ATK +atk; blocks
|
||||
const bb = bbAlt(id);
|
||||
for (const roll of [true, false]) {
|
||||
const seen = [];
|
||||
// 120 hits a minute at bat 0.5, each at the 5 % floor (12.5): 1500 in the 60 s, short of the normal form's 1791 HP
|
||||
const h = run({
|
||||
defs: { enemies: { e: dummy('e', { atk: 300, bat: 0.5 }) } }, units: [U(id, 9, 5, { carryState: READY })], enemies: [{ key: 'e', pos: [9, 5] }],
|
||||
defs: { enemies: { e: dummy('e', { atk: 250, bat: 0.5 }) } }, units: [U(id, 9, 5, { carryState: READY })], enemies: [{ key: 'e', pos: [9, 5] }],
|
||||
setup: (b) => { b.rng.chance = (p) => { seen.push(p); return roll; }; },
|
||||
});
|
||||
const u = h.unit(id);
|
||||
|
||||
@@ -78,6 +78,8 @@ test('every tier-6 skill × module choice (normal + elite) survives a real wave
|
||||
units: [{ chessId: id, row: 10, col: 4, skillIndex: s.index, moduleId, carryState: READY }, { chessId: 'chess_char_1_01_a', row: 9, col: 4 }, { chessId: 'chess_char_2_06_a', row: 11, col: 5 }],
|
||||
enemies: [{ key: 'enemy_1007_slime', count: 8, interval: 1.5 }, { key: 'enemy_1007_slime', route: 1, count: 8, interval: 1.5, time: 3 }],
|
||||
});
|
||||
// (a medic acts on the hurt only, and the slimes may fall before they reach anyone: the team starts at half HP)
|
||||
if (base.profession === 'MEDIC') { h.step(); for (const a of h.b.allyUnits) a.hp = a.s.maxHp / 2; }
|
||||
h.runToEnd(90);
|
||||
done(h);
|
||||
const u = h.b.allyUnits.find((x) => x.defId === id);
|
||||
@@ -258,7 +260,7 @@ test('6_03 余 S1 今日做东: taunt +1 while carried; TAKE_DAMAGE cast, HP/DEF
|
||||
const sid = 'skchr_yu_1', bb = bbOf(id, sid);
|
||||
const h = run({
|
||||
defs: { enemies: { hit: enemyRec({ key: 'hit', hp: 1e7, speed: 0, atk: 300, bat: 1 }) } },
|
||||
units: [U(id, sid, 10, 4, { carryState: READY })], enemies: [{ key: 'hit', pos: [10, 4] }],
|
||||
units: [U(id, sid, 10, 4, { carryState: READY })], enemies: [{ key: 'hit', pos: [10, 4] }], hooks: [...HOOKS, 'elementBurst'],
|
||||
});
|
||||
const u = h.unit(id);
|
||||
usesSkill(u, sid);
|
||||
@@ -270,8 +272,10 @@ test('6_03 余 S1 今日做东: taunt +1 while carried; TAKE_DAMAGE cast, HP/DEF
|
||||
approx(skillBuff(u).mods.defPct, bb.def);
|
||||
const t0 = h.b.time;
|
||||
h.run(4);
|
||||
const burns = h.hooksOf('elementHit').filter((c) => c.source === u && c.dmg.element === 'burn' && c.t > t0 && (c.dmg.tags || []).includes('skill'));
|
||||
const taken = h.hooksOf('damaged').filter((c) => c.target === u && c.dmg?.isAttack && c.t > t0);
|
||||
// the burns build a 燃烧 burst on the attacker, which refuses same-element fills while it runs: compare up to it
|
||||
const end = h.hooksOf('elementBurst').find((c) => c.element === 'burn' && c.t > t0)?.t ?? Infinity;
|
||||
const burns = h.hooksOf('elementHit').filter((c) => c.source === u && c.dmg.element === 'burn' && c.t > t0 && c.t <= end && (c.dmg.tags || []).includes('skill'));
|
||||
const taken = h.hooksOf('damaged').filter((c) => c.target === u && c.dmg?.isAttack && c.t > t0 && c.t <= end);
|
||||
assert.ok(burns.length >= 1 && burns.length === taken.length, `one burn per attack taken (${burns.length}/${taken.length})`);
|
||||
approx(burns[0].dmg.amount, u.s.atk * bb.ep_damage_ratio, 'ep_damage_ratio × ATK');
|
||||
done(h);
|
||||
|
||||
@@ -212,8 +212,9 @@ test('S1 坚守阵线 (AUTO, SP_FULL): at full SP with no enemy, 持续时间无
|
||||
const life = tokenTalent(tier, elite, mod).duration;
|
||||
assert.ok(h.runUntil(() => u.skill.active, sk.spCost + 1), `${label(f)}: cast at ${sk.spCost} s with no enemy`);
|
||||
approx(h.b.time, sk.spCost, `${label(f)}: at full SP`, 0.02);
|
||||
// the first shield expired before (life < cost) and came back at life + 30: it gets the 20 s now
|
||||
assert.ok(t.alive);
|
||||
// the first shield expired before (life < cost) and came back at life + 30: it gets the 20 s now — or, T6 (60 + 30 =
|
||||
// the 90 s cost), on its return a tick after the cast (its timers count from its deployment on the first tick)
|
||||
assert.ok(h.runUntil(() => t.alive, 0.1), `${label(f)}: the shield is on the field`);
|
||||
h.step();
|
||||
approx(u.s.atk, u.base.atk * (1 + sk.bb.atk), `${label(f)}: ATK`);
|
||||
approx(u.s.def, u.base.def * (1 + sk.bb.def + 0.18), `${label(f)}: DEF (+18 % T1)`);
|
||||
|
||||
@@ -207,7 +207,9 @@ test('S2 驱凶辟邪: passive ASPD +15 / +20; cast on his attack, the target is
|
||||
approx(h.b.time - t0, sk.bb.paper_duration, `T${tier}: after 5 s`, 0.05);
|
||||
const dmg = h.hooksOf('damaged').slice(n0);
|
||||
const burst = dmg.filter((c) => c.source === u && c.dmg.tags.includes('lmlee:burst'));
|
||||
const hits = h.hooksOf('damaged').filter((c) => c.target === t && c.source === u && !c.dmg.tags.includes('lmlee:burst') && h.b.time >= t0).length;
|
||||
// his hits on it before the burst (one of his hits in the burst's own tick lands after it and is not counted)
|
||||
const all = h.hooksOf('damaged');
|
||||
const hits = all.slice(0, all.indexOf(burst[0])).filter((c) => c.target === t && c.source === u && !c.dmg.tags.includes('lmlee:burst')).length;
|
||||
assert.deepEqual(burst.map((c) => c.target).sort((a, b) => a.id - b.id), [t, near].sort((a, b) => a.id - b.id), `T${tier}: radius ${MARK_RADIUS}, the flyer too, not 2 tiles away`);
|
||||
assert.ok(!burst.some((c) => c.target === far));
|
||||
for (const c of burst) {
|
||||
|
||||
@@ -248,9 +248,10 @@ test('S3 延异视阈: enemy shots on his range fly at 5 % of their speed (back
|
||||
for (const g of h.enemies()) h.b.applyStatus(g, 'stun', { duration: 99, source: null }); // no new shot
|
||||
const held = h.b.projectiles.list.filter((p) => p.source && p.source.side === 'enemy').length;
|
||||
assert.ok(held >= 1, `${held} shots in the air as it ends`);
|
||||
const taken = u.stats.taken;
|
||||
h.runUntil(() => !u.skill.active, 2);
|
||||
h.step();
|
||||
// (until the end a held shot still reaches him at its 5 % speed — one a second from the gun 2 tiles away)
|
||||
const taken = u.stats.taken;
|
||||
const left = h.b.projectiles.list.filter((p) => p.source && p.source.side === 'enemy');
|
||||
if (!disarm) {
|
||||
assert.equal(left.length, 0, 'cleared');
|
||||
|
||||
@@ -124,10 +124,11 @@ test('S1 旋刃 (切换: on until she leaves; data DEFAULT): range −1 (the far
|
||||
const b = h.spawn('enemy_dummy', { pos: [11, 5] }), c = h.spawn('enemy_dummy', { pos: [9, 6] });
|
||||
const far = h.spawn('enemy_dummy', { pos: [12, 5] }); // 2 from A, 1 from B: reachable from B only
|
||||
h.run(0.1);
|
||||
const n0 = atkHits(h, u).length;
|
||||
const before0 = atkHits(h, u), n0 = before0.length;
|
||||
h.run(4);
|
||||
const after = atkHits(h, u).slice(n0);
|
||||
const id = after[0].dmg.attackId;
|
||||
// the first attack thrown after that (one in flight then has already hit A before the others came)
|
||||
const id = after.find((x) => !before0.some((y) => y.dmg.attackId === x.dmg.attackId)).dmg.attackId;
|
||||
const chain = after.filter((x) => x.dmg.attackId === id);
|
||||
assert.equal(chain.length, 4, `T${tier}: the hit + 3 bounces`);
|
||||
assert.equal(chain[0].target, lone, `T${tier}: her target`);
|
||||
|
||||
+424
-424
File diff suppressed because it is too large.
Load diff
+2038
-2048
File diff suppressed because it is too large.
Load diff
+637
-669
File diff suppressed because it is too large.
Load diff
+197
-197
File diff suppressed because it is too large.
Load diff
+1180
-1181
File diff suppressed because it is too large.
Load diff
+248
-236
@@ -20,58 +20,58 @@
|
||||
"time": 170,
|
||||
"ticks": 5100,
|
||||
"reason": "timeout",
|
||||
"killed": 19,
|
||||
"killed": 17,
|
||||
"total": 50,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 544,
|
||||
"rngDraws": 557,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {
|
||||
"killed": 19,
|
||||
"killed": 17,
|
||||
"total": 50,
|
||||
"perfect": false,
|
||||
"leaks": 31,
|
||||
"leaks": 33,
|
||||
"leaksUncounted": 0,
|
||||
"coins": 4,
|
||||
"dmg": 266231,
|
||||
"dmg": 236662,
|
||||
"bossDmg": 0,
|
||||
"heal": 17643,
|
||||
"heal": 15792,
|
||||
"deaths": 24,
|
||||
"layerGains": {"raidShip":13,"visiShip":2}
|
||||
}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_3_12_a",2,null,0,0,74,4,60651,4029,0,28,3],
|
||||
["p1",2,"op","chess_char_4_09_a",0,null,0,0,1,1,29760,2984,0,18,1],
|
||||
["p1",3,"op","chess_char_3_05_a",2,null,2081.5,1,76,2,31495,11964,0,47,2],
|
||||
["p1",4,"op","chess_char_3_18_a",2,null,0,0,7,1,10578,3995,0,17,1],
|
||||
["p1",5,"op","chess_char_4_04_a",1,null,0,0,92,1,17499,7084,0,74,10],
|
||||
["p1",6,"op","chess_char_4_07_a",1,null,0,0,79,1,19230,13744,0,43,1],
|
||||
["p1",7,"op","chess_char_4_16_a",1,null,215.72,1,94,1,9789,11775,0,117,14],
|
||||
["p1",8,"op","chess_char_3_01_a",2,null,1271,1,5,0,22413,0,0,149,2],
|
||||
["p1",9,"op","chess_char_3_04_a",2,null,1218,1,86,0,0,1599,17643,36,2],
|
||||
["p1",10,"op","chess_char_3_21_a",2,null,716.85,1,6,6,42226,555,0,132,2],
|
||||
["p1",11,"op","chess_char_4_02_a",1,null,1272,1,89,1,7563,1272,0,68,1],
|
||||
["p1",12,"op","chess_char_4_13_a",1,null,0,0,83,1,15028,1624,0,33,2]
|
||||
["p1",1,"op","chess_char_3_12_a",2,null,0,0,74,3,46613,4029,0,22,2],
|
||||
["p1",2,"op","chess_char_4_09_a",0,null,0,0,1,1,29729,2984,0,18,1],
|
||||
["p1",3,"op","chess_char_3_05_a",2,null,2081.5,1,76,2,30991,12632,0,46,2],
|
||||
["p1",4,"op","chess_char_3_18_a",2,null,0,0,7,1,9726,3542,0,15,1],
|
||||
["p1",5,"op","chess_char_4_04_a",1,null,0,0,89,1,15692,6722,0,87,9],
|
||||
["p1",6,"op","chess_char_4_07_a",1,null,0,0,79,1,16650,11296,0,36,1],
|
||||
["p1",7,"op","chess_char_4_16_a",1,null,807.8,1,92,0,7403,10573,0,114,13],
|
||||
["p1",8,"op","chess_char_3_01_a",2,null,1271,1,5,1,19644,0,0,139,2],
|
||||
["p1",9,"op","chess_char_3_04_a",2,null,1218,1,87,0,0,1599,15792,34,2],
|
||||
["p1",10,"op","chess_char_3_21_a",2,null,161.7,1,6,5,40982,1110,0,138,2],
|
||||
["p1",11,"op","chess_char_4_02_a",1,null,1272,1,91,1,8881,1653,0,49,1],
|
||||
["p1",12,"op","chess_char_4_13_a",1,null,0,0,83,1,10351,1624,0,23,1]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_10001_trslim": [1,1,0,8,4860],
|
||||
"enemy_1000_gopro_2": [1,1,0,0,1836],
|
||||
"enemy_10018_sgrobh": [1,1,0,3753,8100],
|
||||
"enemy_1001_bigbo": [1,0,1,1235,2656],
|
||||
"enemy_10027_vtsk": [1,0,1,12888,1289],
|
||||
"enemy_10018_sgrobh": [1,1,0,3793,8100],
|
||||
"enemy_1001_bigbo": [1,0,1,1235,2597],
|
||||
"enemy_10027_vtsk": [1,0,1,16004,2114],
|
||||
"enemy_10031_cnvsld": [1,0,1,0,0],
|
||||
"enemy_10034_cnvsax": [1,0,1,1235,5687],
|
||||
"enemy_10034_cnvsax": [1,0,1,1235,5433],
|
||||
"enemy_10042_prtrop": [1,0,1,0,0],
|
||||
"enemy_1116_liprr_2": [21,13,8,5313,129729],
|
||||
"enemy_1119_vofsd": [12,2,8,12831,69965],
|
||||
"enemy_1121_lifbos_2": [9,1,6,15758,42109]
|
||||
"enemy_1116_liprr_2": [21,11,10,5878,116132],
|
||||
"enemy_1119_vofsd": [12,2,9,10383,58920],
|
||||
"enemy_1121_lifbos_2": [9,1,7,12260,36669]
|
||||
},
|
||||
"hooks": [1,94,5100,874,874,1402,1411,3740,43,84,41,38,0,18511,42,43,50,27,1,46,5,0,2],
|
||||
"events": {"atk":983,"bounty":2,"deploy":44,"die":57,"dmg":1411,"engage":11,"fx":90,"heal":36,"layer":5,"leak":27,"skill":79,"spawn":62,"status":157},
|
||||
"fx": {"beam":12,"blink":14,"dodge":2,"dp":7,"garrison":5,"liberate":12,"phase":13,"slash":24,"telegraph":1},
|
||||
"snaps": "8b8be66d b3674b6a 84ebce5a c4efeba6 05a2d3cd bf6f3985 249c5ebd 2bf68848 6faa6eb8 0275f0fb f4b16de1 f88b620c 3545e4d2 aa0d5a15 ecf73cfe 95a2451e a178591a"
|
||||
"hooks": [1,92,5100,827,827,1351,1361,3159,41,84,37,34,0,17166,30,38,50,31,1,43,5,0,1],
|
||||
"events": {"atk":944,"bounty":2,"deploy":42,"die":53,"dmg":1361,"engage":11,"fx":78,"heal":34,"layer":5,"leak":31,"skill":71,"spawn":62,"status":135},
|
||||
"fx": {"beam":12,"blink":12,"dodge":1,"dp":5,"garrison":5,"liberate":14,"phase":12,"slash":16,"telegraph":1},
|
||||
"snaps": "857e2323 698cb0a7 94c7a5e0 2aa6acaa f7e53f3d 9d657030 cccc9aca 21e3ad7e b37dbf1e b5cd0443 6f5b7d8d b64e245e 27c5f782 281fb1da df6dc58e f267a1fb 6cc0aa3d"
|
||||
},
|
||||
"standin-02": {
|
||||
"about": "normal band 5 as stand-ins: chess_char_4_17_a→char_610_acfend chess_char_4_18_a→char_602_cdfend chess_char_5_05_a→char_602_cdfend chess_char_4_19_a→char_608_acpion chess_char_5_01_a→char_600_cpione chess_char_4_22_a→char_609_acguad chess_char_4_23_a→char_609_acguad chess_char_5_06_a→char_609_acguad chess_char_4_20_a→char_603_csnipe chess_char_4_24_a→char_604_ccast chess_char_5_02_a→char_604_ccast chess_char_5_03_a→char_612_accast",
|
||||
@@ -92,39 +92,39 @@
|
||||
"rngDraws": 106,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":9,"total":68,"perfect":false,"leaks":59,"leaksUncounted":0,"coins":0,"dmg":99809,"bossDmg":0,"heal":0,"deaths":22,"layerGains":{"preciShip":12}}
|
||||
"p1": {"killed":9,"total":68,"perfect":false,"leaks":59,"leaksUncounted":0,"coins":0,"dmg":99471,"bossDmg":0,"heal":0,"deaths":23,"layerGains":{"preciShip":12}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_4_17_a",1,null,0,0,3,1,360,2604,0,3,1],
|
||||
["p1",2,"op","chess_char_4_18_a",1,null,0,0,85,0,2350,6810,0,6,1],
|
||||
["p1",3,"op","chess_char_5_05_a",2,null,0,0,73,0,28,4256,0,2,1],
|
||||
["p1",4,"op","chess_char_4_19_a",1,null,0,0,66,0,158,3058,0,11,1],
|
||||
["p1",5,"op","chess_char_5_01_a",2,null,154.94,1,91,0,52,3520,0,3,0],
|
||||
["p1",6,"op","chess_char_4_22_a",1,null,0,0,72,0,6886,5276,0,9,0],
|
||||
["p1",1,"op","chess_char_4_17_a",1,null,0,0,3,0,94,2604,0,4,1],
|
||||
["p1",2,"op","chess_char_4_18_a",1,null,0,0,85,0,2100,6810,0,6,1],
|
||||
["p1",3,"op","chess_char_5_05_a",2,null,0,0,73,0,240,4256,0,2,1],
|
||||
["p1",4,"op","chess_char_4_19_a",1,null,0,0,66,0,316,3058,0,10,1],
|
||||
["p1",5,"op","chess_char_5_01_a",2,null,0,0,91,0,52,3675,0,3,0],
|
||||
["p1",6,"op","chess_char_4_22_a",1,null,0,0,70,0,6886,5276,0,9,0],
|
||||
["p1",7,"op","chess_char_4_23_a",1,null,0,0,65,0,5497,5276,0,9,0],
|
||||
["p1",8,"op","chess_char_5_06_a",2,null,0,0,1,0,0,2638,0,0,0],
|
||||
["p1",9,"op","chess_char_4_20_a",1,null,1271,1,92,1,11656,2542,0,25,0],
|
||||
["p1",10,"op","chess_char_4_24_a",1,null,0,0,90,0,4203,3399,0,9,0],
|
||||
["p1",11,"op","chess_char_5_02_a",2,null,0,0,78,2,12811,2266,0,25,1],
|
||||
["p1",12,"op","chess_char_5_03_a",2,null,0,0,4,5,55808,1372,0,10,1]
|
||||
["p1",9,"op","chess_char_4_20_a",1,null,1271,1,92,0,12203,2542,0,26,0],
|
||||
["p1",10,"op","chess_char_4_24_a",1,null,0,0,90,1,4077,3399,0,9,0],
|
||||
["p1",11,"op","chess_char_5_02_a",2,null,0,0,78,3,12264,2266,0,25,1],
|
||||
["p1",12,"op","chess_char_5_03_a",2,null,0,0,4,5,55742,1372,0,10,1]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_10042_prtrop_2": [1,0,1,4245,13584],
|
||||
"enemy_10043_sailor": [1,1,0,1107,23649],
|
||||
"enemy_10044_wintun": [1,0,1,4066,10026],
|
||||
"enemy_10045_parrot": [1,0,1,0,4099],
|
||||
"enemy_10054_cjhot": [1,0,1,2423,2176],
|
||||
"enemy_1005_yokai": [27,8,19,0,30014],
|
||||
"enemy_1005_yokai_2": [27,0,24,11167,2144],
|
||||
"enemy_1005_yokai_3": [6,0,6,20008,18599],
|
||||
"enemy_10065_ftzlc": [1,0,1,0,560],
|
||||
"enemy_10042_prtrop_2": [1,0,1,4499,14163],
|
||||
"enemy_10043_sailor": [1,1,0,1347,23649],
|
||||
"enemy_10044_wintun": [1,0,1,3812,10909],
|
||||
"enemy_10045_parrot": [1,0,1,0,4930],
|
||||
"enemy_10054_cjhot": [1,0,1,2461,2249],
|
||||
"enemy_1005_yokai": [27,8,19,0,29182],
|
||||
"enemy_1005_yokai_2": [27,0,23,11721,2144],
|
||||
"enemy_1005_yokai_3": [6,0,6,19313,16526],
|
||||
"enemy_10065_ftzlc": [1,0,1,19,640],
|
||||
"enemy_10067_ftsjc": [1,0,1,0,680],
|
||||
"enemy_1006_shield": [1,0,1,0,760]
|
||||
},
|
||||
"hooks": [1,92,5700,326,326,561,533,0,31,87,6,6,0,12663,1,14,68,56,1,31,3,0,38],
|
||||
"events": {"atk":334,"deploy":24,"die":31,"dmg":533,"engage":11,"fx":77,"layer":3,"leak":56,"skill":12,"spawn":80,"status":2},
|
||||
"fx": {"aoe":4,"dodge":38,"dp":3,"explode":27,"garrison":3,"garrisonGrant":1,"zone":1},
|
||||
"snaps": "bb11ef91 9b91da1e 3c4f008c 878e68d7 24bb4a4a 8d8aeac2 afd35f69 eb5d4d7c eb84350d df25cd79 28a5ee62 7ca7b30b 51dff947 2a598d70 a2618471 b503b719 ee4a9a4a ece62e64 443cb0c6"
|
||||
"hooks": [1,92,5700,333,333,563,537,0,32,87,6,6,0,12428,1,13,68,55,1,32,3,0,36],
|
||||
"events": {"atk":341,"deploy":24,"die":32,"dmg":537,"engage":11,"fx":77,"layer":3,"leak":55,"skill":12,"spawn":80,"status":2},
|
||||
"fx": {"aoe":4,"dodge":36,"dp":3,"explode":29,"garrison":3,"garrisonGrant":1,"zone":1},
|
||||
"snaps": "bb11ef91 04ff2745 d8f916e6 a29399b5 aef2a63d 90d7e60c a0ca5872 c22c50eb 7e078fec 964b7af6 0837d8c7 6ba5bd75 485c780b 5255dfcf 1e9adc41 7e0f5468 b5284b15 3995f9cb f71908f0"
|
||||
},
|
||||
"standin-03": {
|
||||
"about": "normal band 5 as stand-ins: chess_char_5_08_a→char_610_acfend chess_char_5_14_a→char_608_acpion chess_char_5_19_a→char_617_sharp2 chess_char_5_07_a→char_601_cguard chess_char_5_13_a→char_609_acguad chess_char_5_17_a→char_615_acspec chess_char_5_10_a→char_606_csuppo chess_char_5_11_a→char_613_acmedc chess_char_5_12_a→char_614_acsupo chess_char_5_15_a→char_603_csnipe chess_char_5_18_a→char_611_acnipe chess_char_5_20_a→char_614_acsupo",
|
||||
@@ -138,44 +138,44 @@
|
||||
"time": 190,
|
||||
"ticks": 5700,
|
||||
"reason": "timeout",
|
||||
"killed": 41,
|
||||
"killed": 38,
|
||||
"total": 74,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 270,
|
||||
"rngDraws": 294,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {"p1":{"killed":41,"total":74,"perfect":false,"leaks":33,"leaksUncounted":0,"coins":8,"dmg":320925,"bossDmg":0,"heal":42417,"deaths":10,"layerGains":{}}},
|
||||
"players": {"p1":{"killed":38,"total":74,"perfect":false,"leaks":36,"leaksUncounted":0,"coins":8,"dmg":312097,"bossDmg":0,"heal":42234,"deaths":10,"layerGains":{}}},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_5_08_a",2,null,2206.8,1,91,0,5895,3841,0,57,1],
|
||||
["p1",2,"op","chess_char_5_14_a",2,null,353,1,90,24,145090,7662,0,66,6],
|
||||
["p1",3,"op","chess_char_5_19_a",0,null,784.8,1,89,6,42209,15296,0,99,3],
|
||||
["p1",4,"op","chess_char_5_07_a",2,null,2564,1,92,0,12112,3824,0,24,1],
|
||||
["p1",5,"op","chess_char_5_13_a",2,null,1520,1,11,6,55817,10325,0,121,4],
|
||||
["p1",6,"op","chess_char_5_17_a",2,null,0,0,81,1,5190,6413,0,69,0],
|
||||
["p1",7,"op","chess_char_5_10_a",2,null,932,1,2,1,9099,0,0,69,2],
|
||||
["p1",8,"op","chess_char_5_11_a",2,null,1224,1,3,0,0,0,42417,68,2],
|
||||
["p1",9,"op","chess_char_5_12_a",2,null,1160,1,4,0,19147,0,0,75,2],
|
||||
["p1",10,"op","chess_char_5_15_a",2,null,0,0,84,2,8346,13732,0,96,2],
|
||||
["p1",11,"op","chess_char_5_18_a",2,null,0,0,1,1,11149,1272,0,22,1],
|
||||
["p1",12,"op","chess_char_5_20_a",2,null,0,0,5,0,6872,1972,0,38,2]
|
||||
["p1",1,"op","chess_char_5_08_a",2,null,571.8,1,6,2,14891,7695,0,131,2],
|
||||
["p1",2,"op","chess_char_5_14_a",2,null,0,0,85,11,96636,7465,0,52,5],
|
||||
["p1",3,"op","chess_char_5_19_a",0,null,377,1,90,7,47254,14046,0,101,3],
|
||||
["p1",4,"op","chess_char_5_07_a",2,null,600,1,93,1,4886,7468,0,39,1],
|
||||
["p1",5,"op","chess_char_5_13_a",2,null,544,1,11,6,68190,10905,0,127,4],
|
||||
["p1",6,"op","chess_char_5_17_a",2,null,0,0,77,5,15138,2547,0,80,0],
|
||||
["p1",7,"op","chess_char_5_10_a",2,null,932,1,2,0,9784,0,0,81,2],
|
||||
["p1",8,"op","chess_char_5_11_a",2,null,1224,1,3,0,0,0,42234,72,2],
|
||||
["p1",9,"op","chess_char_5_12_a",2,null,1160,1,4,0,23322,0,0,90,2],
|
||||
["p1",10,"op","chess_char_5_15_a",2,null,0,0,84,2,8345,13516,0,95,3],
|
||||
["p1",11,"op","chess_char_5_18_a",2,null,1272,1,91,4,16112,1272,0,26,1],
|
||||
["p1",12,"op","chess_char_5_20_a",2,null,1972,1,92,0,7539,1972,0,44,1]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_1006_shield_2": [1,1,0,582,8000],
|
||||
"enemy_1006_shield_3": [1,0,1,11325,14488],
|
||||
"enemy_1006_shield_3": [1,0,1,9612,8819],
|
||||
"enemy_10073_mpcar": [1,1,0,12,1600],
|
||||
"enemy_1007_slime": [1,1,0,0,440],
|
||||
"enemy_10081_mpplai": [1,1,0,0,2000],
|
||||
"enemy_10087_hlchgr": [1,1,0,38,4800],
|
||||
"enemy_10094_crstf": [1,1,0,28,3200],
|
||||
"enemy_10097_crshd": [1,1,0,0,8000],
|
||||
"enemy_1166_dusbr_2": [42,27,15,2888,108284],
|
||||
"enemy_1170_dushld_2": [12,6,5,31043,51138],
|
||||
"enemy_9011_acrefr": [12,1,8,18420,118976]
|
||||
"enemy_10097_crshd": [1,0,1,869,1576],
|
||||
"enemy_1166_dusbr_2": [42,29,13,4731,113146],
|
||||
"enemy_1170_dushld_2": [12,2,8,31659,41655],
|
||||
"enemy_9011_acrefr": [12,1,4,19354,126861]
|
||||
},
|
||||
"hooks": [1,92,5700,1024,1024,1534,1535,115,51,80,26,27,0,27292,3473,49,74,29,1,52,0,0,10],
|
||||
"events": {"atk":1125,"bounty":4,"deploy":18,"die":51,"dmg":1534,"engage":11,"fx":132,"heal":109,"leak":29,"skill":55,"spawn":86,"status":626},
|
||||
"fx": {"aoe":30,"displace":1,"dodge":13,"dp":30,"phase":1,"slash":48,"sp":1,"spGain":8},
|
||||
"snaps": "530ce9ab 3259d8c0 918a3cff a85e2d90 3b23751a 8f259c98 9faf0458 b98e7e80 e64fb37d 38b17953 2458f514 b2894d2f 6c036845 395d7cfe a9ead632 07893f6c 64586b5e 9402040c 55700def"
|
||||
"hooks": [1,93,5700,1246,1246,1770,1779,131,48,75,26,27,0,29163,3246,53,74,27,1,48,0,1,11],
|
||||
"events": {"atk":1352,"bounty":4,"deploy":19,"die":48,"dmg":1773,"engage":11,"fx":151,"heal":120,"leak":27,"skill":55,"spawn":86,"status":633},
|
||||
"fx": {"aoe":60,"burst":1,"displace":4,"dodge":20,"dp":16,"phase":1,"slash":40,"sp":1,"spGain":8},
|
||||
"snaps": "530ce9ab 077d8667 72a08c6b e8e968c7 ba780244 415e96b1 b2fbf900 eeae800d cb865a16 5f7fac5a 0b386348 57872ff3 639e0975 3111f879 121dc45e 0686e918 a1655184 a964d89f e67acf8a"
|
||||
},
|
||||
"standin-04": {
|
||||
"about": "normal band 6 as stand-ins: chess_char_6_03_a→char_610_acfend chess_char_6_02_a→char_608_acpion chess_char_6_07_a→char_617_sharp2 chess_char_6_10_a→char_617_sharp2 chess_char_6_11_a→char_608_acpion chess_char_6_06_a→char_609_acguad chess_char_5_22_a→char_611_acnipe chess_char_6_01_a→char_611_acnipe chess_char_6_04_a→char_614_acsupo chess_char_6_05_a→char_611_acnipe chess_char_6_08_a→char_612_accast chess_char_6_09_a→char_613_acmedc",
|
||||
@@ -186,50 +186,62 @@
|
||||
"round": 12,
|
||||
"seed": 428893583,
|
||||
"waveId": "act1autochess_h05",
|
||||
"time": 201.43,
|
||||
"ticks": 6043,
|
||||
"time": 207.8,
|
||||
"ticks": 6234,
|
||||
"reason": "cleared",
|
||||
"killed": 158,
|
||||
"killed": 148,
|
||||
"total": 158,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 612,
|
||||
"rngDraws": 613,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":158,"total":158,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":1471553,"bossDmg":0,"heal":29310,"deaths":8,"layerGains":{"sargonShip":5}}
|
||||
"p1": {
|
||||
"killed": 148,
|
||||
"total": 158,
|
||||
"perfect": false,
|
||||
"leaks": 10,
|
||||
"leaksUncounted": 0,
|
||||
"coins": 8,
|
||||
"dmg": 1388100,
|
||||
"bossDmg": 0,
|
||||
"heal": 27495,
|
||||
"deaths": 10,
|
||||
"layerGains": {"sargonShip":5}
|
||||
}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_6_03_a",2,null,0,0,169,0,1288,5814,0,12,1],
|
||||
["p1",2,"op","chess_char_6_02_a",2,null,0,0,171,5,21360,3058,0,2,4],
|
||||
["p1",3,"op","chess_char_6_07_a",0,null,0,0,6,19,254549,1865,0,146,3],
|
||||
["p1",4,"op","chess_char_6_10_a",0,null,1865,1,177,6,128769,1865,0,109,2],
|
||||
["p1",5,"op","chess_char_6_11_a",2,null,1529,1,174,28,230418,10062,0,75,10],
|
||||
["p1",6,"op","chess_char_6_06_a",2,null,2149.08,1,158,16,114781,20845,0,115,4],
|
||||
["p1",7,"op","chess_char_5_22_a",2,null,1272,1,3,2,27889,0,0,23,2],
|
||||
["p1",8,"op","chess_char_6_01_a",2,null,1272,1,4,36,251215,0,0,157,2],
|
||||
["p1",9,"op","chess_char_6_04_a",2,null,1160,1,13,5,66116,0,0,122,2],
|
||||
["p1",10,"op","chess_char_6_05_a",2,null,1272,1,14,18,242842,2453,0,127,2],
|
||||
["p1",11,"op","chess_char_6_08_a",2,null,1372,1,5,21,132325,0,0,40,2],
|
||||
["p1",12,"op","chess_char_6_09_a",2,null,1224,1,11,0,0,0,29310,46,2],
|
||||
["p1",1,"op","chess_char_6_03_a",2,null,0,0,166,1,1712,5959,0,13,1],
|
||||
["p1",2,"op","chess_char_6_02_a",2,null,0,0,170,3,26692,3058,0,5,4],
|
||||
["p1",3,"op","chess_char_6_07_a",0,null,1449.4,1,178,14,168046,2281,0,114,2],
|
||||
["p1",4,"op","chess_char_6_10_a",0,null,0,0,177,5,96562,3730,0,103,2],
|
||||
["p1",5,"op","chess_char_6_11_a",2,null,0,0,163,24,167712,9566,0,43,7],
|
||||
["p1",6,"op","chess_char_6_06_a",2,null,2638,1,159,12,113713,20421,0,107,4],
|
||||
["p1",7,"op","chess_char_5_22_a",2,null,1272,1,3,4,34571,0,0,26,2],
|
||||
["p1",8,"op","chess_char_6_01_a",2,null,1272,1,4,42,290196,0,0,158,2],
|
||||
["p1",9,"op","chess_char_6_04_a",2,null,1160,1,13,4,65352,0,0,118,2],
|
||||
["p1",10,"op","chess_char_6_05_a",2,null,1272,1,14,15,205666,2453,0,131,2],
|
||||
["p1",11,"op","chess_char_6_08_a",2,null,1372,1,5,22,217877,0,0,51,2],
|
||||
["p1",12,"op","chess_char_6_09_a",2,null,1224,1,11,0,0,0,27495,42,2],
|
||||
["-","~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]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_10098_crhro": [1,1,0,1577,41472],
|
||||
"enemy_10098_crhro": [1,1,0,2026,41472],
|
||||
"enemy_10099_crvln": [1,1,0,2453,20736],
|
||||
"enemy_1009_lurker": [1,1,0,23,3041],
|
||||
"enemy_1009_lurker": [1,1,0,14,3041],
|
||||
"enemy_1010_demon": [1,1,0,0,10368],
|
||||
"enemy_1010_demon_2": [28,28,0,11599,580608],
|
||||
"enemy_1010_demon_2": [28,24,4,11437,555442],
|
||||
"enemy_10112_ymgds": [1,1,0,0,6912],
|
||||
"enemy_10116_ymgtop": [1,1,0,2924,13824],
|
||||
"enemy_10118_ymgprc": [1,1,0,10510,69120],
|
||||
"enemy_1071_dftman": [63,63,0,587,243855],
|
||||
"enemy_1072_dlancer": [60,60,0,16287,497664]
|
||||
"enemy_10116_ymgtop": [1,1,0,2398,13824],
|
||||
"enemy_10118_ymgprc": [1,0,1,6540,35966],
|
||||
"enemy_1071_dftman": [63,63,0,455,243855],
|
||||
"enemy_1072_dlancer": [60,55,5,22144,476588]
|
||||
},
|
||||
"hooks": [1,177,6043,1060,1060,2060,2055,76,166,166,36,35,0,37056,3588,58,158,0,1,168,2,0,13],
|
||||
"events": {"atk":1212,"bounty":4,"deploy":17,"die":166,"dmg":2055,"engage":11,"fx":181,"heal":58,"layer":2,"skill":71,"spawn":172,"status":436},
|
||||
"fx": {"aoe":5,"dodge":17,"dp":47,"garrison":2,"revive":1,"slash":91,"sp":14,"spGain":2,"telegraph":2},
|
||||
"snaps": "484fd662 4f4e076d 081948b0 d7bf1df0 c0aa2905 1b27e150 ab6cac50 d1148fdb fccd25dd 3bdf0cd3 bc78cb58 5914e59f e9a5d19b c18806ba 780d90bd f332e4d3 1b1a7814 b06c5778 2ebf5ca8 a00fc7c0 e0236981"
|
||||
"hooks": [1,178,6234,1000,1000,2074,2072,74,158,168,32,32,0,36983,4066,67,158,10,1,160,2,0,11],
|
||||
"events": {"atk":1142,"bounty":4,"deploy":18,"die":158,"dmg":2072,"engage":11,"fx":161,"heal":53,"layer":2,"leak":10,"skill":64,"spawn":172,"status":472},
|
||||
"fx": {"aoe":11,"dodge":14,"dp":38,"garrison":2,"revive":1,"slash":77,"sp":13,"spGain":3,"telegraph":2},
|
||||
"snaps": "484fd662 19a9b252 827467e6 d8836b51 4e1a5c20 f5f33eaf 009d313f 487fac84 6e33c253 481fa961 eee28282 47fecc48 ec2c4a14 046a7402 d017b22b a2a8910b b53ce9db 2504d954 222d228d 78e5e524 2b44a10f"
|
||||
},
|
||||
"standin-05": {
|
||||
"about": "normal band 6 as stand-ins: chess_char_6_17_a→char_608_acpion chess_char_6_13_a→char_615_acspec chess_char_6_19_a→char_615_acspec chess_char_6_12_a→char_612_accast chess_char_6_15_a→char_614_acsupo chess_char_6_18_a→char_612_accast chess_char_6_20_a→char_613_acmedc",
|
||||
@@ -240,47 +252,47 @@
|
||||
"round": 12,
|
||||
"seed": 4096833445,
|
||||
"waveId": "act1autochess_h05",
|
||||
"time": 216.03,
|
||||
"ticks": 6481,
|
||||
"time": 212.97,
|
||||
"ticks": 6389,
|
||||
"reason": "cleared",
|
||||
"killed": 8,
|
||||
"total": 104,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 234,
|
||||
"rngDraws": 301,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":8,"total":104,"perfect":false,"leaks":96,"leaksUncounted":0,"coins":0,"dmg":433423,"bossDmg":0,"heal":451,"deaths":22,"layerGains":{"raidShip":3}}
|
||||
"p1": {"killed":8,"total":104,"perfect":false,"leaks":96,"leaksUncounted":0,"coins":2,"dmg":460557,"bossDmg":0,"heal":451,"deaths":20,"layerGains":{"raidShip":3}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_6_17_a",2,null,0,0,130,1,102521,9556,0,46,1],
|
||||
["p1",2,"op","chess_char_6_13_a",2,null,0,0,133,1,28392,9232,0,79,0],
|
||||
["p1",3,"op","chess_char_6_19_a",2,null,514.2,1,135,4,32421,9872,0,139,0],
|
||||
["p1",4,"op","chess_char_6_12_a",2,null,671.78,1,7,0,141278,975,0,83,2],
|
||||
["p1",5,"op","chess_char_6_15_a",2,null,0,0,134,2,58508,4965,0,113,2],
|
||||
["p1",6,"op","chess_char_6_18_a",2,null,1372,1,85,0,70303,1372,0,42,2],
|
||||
["p1",1,"op","chess_char_6_17_a",2,null,0,0,126,1,104619,9556,0,47,1],
|
||||
["p1",2,"op","chess_char_6_13_a",2,null,1154,1,133,2,32325,8078,0,97,0],
|
||||
["p1",3,"op","chess_char_6_19_a",2,null,0,0,131,2,41575,8078,0,186,0],
|
||||
["p1",4,"op","chess_char_6_12_a",2,null,671.78,1,7,0,142335,975,0,76,2],
|
||||
["p1",5,"op","chess_char_6_15_a",2,null,0,0,132,3,51646,4965,0,107,2],
|
||||
["p1",6,"op","chess_char_6_18_a",2,null,1372,1,88,0,88056,1372,0,51,2],
|
||||
["p1",7,"op","chess_char_6_20_a",2,null,1224,1,4,0,0,451,451,1,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]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_10122_uacann_2": [1,0,1,7356,12074],
|
||||
"enemy_10122_uacann_2": [1,0,1,6747,13260],
|
||||
"enemy_10124_uashld_2": [1,0,1,0,5764],
|
||||
"enemy_10127_rkmbst_2": [1,0,1,1154,0],
|
||||
"enemy_10138_xdsnow": [1,0,1,0,1276],
|
||||
"enemy_10127_rkmbst_2": [1,0,1,0,1544],
|
||||
"enemy_10138_xdsnow": [1,0,1,0,638],
|
||||
"enemy_10141_xdpeng_2": [1,0,1,771,638],
|
||||
"enemy_10144_xdelk_2": [1,0,1,0,0],
|
||||
"enemy_10156_mncrer": [1,0,1,0,1476],
|
||||
"enemy_10144_xdelk_2": [1,0,1,0,42],
|
||||
"enemy_10156_mncrer": [1,1,0,535,9555],
|
||||
"enemy_10159_mntrjn": [1,0,1,0,0],
|
||||
"enemy_1381_winman": [27,6,21,3255,100648],
|
||||
"enemy_1381_winman_2": [39,1,38,9029,175774],
|
||||
"enemy_1387_winshd": [30,1,29,14859,135775]
|
||||
"enemy_1381_winman": [27,6,21,7780,137676],
|
||||
"enemy_1381_winman_2": [39,1,38,5087,154280],
|
||||
"enemy_1387_winshd": [30,0,30,12555,137161]
|
||||
},
|
||||
"hooks": [1,135,6481,604,604,990,990,2,30,128,8,24,0,14943,2502,30,104,96,1,30,1,0,0],
|
||||
"events": {"atk":635,"deploy":28,"die":32,"dmg":897,"engage":6,"fx":55,"heal":1,"layer":1,"leak":96,"skill":50,"spawn":114,"status":500},
|
||||
"fx": {"aoe":5,"blink":2,"camouflage":1,"displace":18,"dodge":2,"dp":2,"explode":7,"garrison":1,"garrisonGrant":2,"slash":8,"zone":7},
|
||||
"snaps": "7d1098cf a2545bc6 e235d106 8dfcbe4d cbd66f3e d02eb500 28229c34 df0ed6a9 90a49dcf b9747bc6 d343d0fd 88a84b18 fa841456 6ea8596f afa61e73 45aa5112 7782a063 f7161b9b d3da53b7 1175003f aae5f017 59ce2b8b"
|
||||
"hooks": [1,133,6389,675,675,1045,1045,6,28,126,8,22,0,13925,3343,28,104,96,1,28,1,0,0],
|
||||
"events": {"atk":709,"bounty":1,"deploy":26,"die":30,"dmg":967,"engage":6,"fx":53,"heal":5,"layer":1,"leak":96,"skill":46,"spawn":114,"status":516},
|
||||
"fx": {"aoe":5,"blink":2,"camouflage":1,"displace":12,"dodge":3,"dp":2,"explode":9,"garrison":1,"garrisonGrant":2,"slash":8,"zone":8},
|
||||
"snaps": "7d1098cf 59e3d11b cdb269b4 4ce1ab07 78ea8d35 932f66d3 7b5e2c7d fba1ea1a d602485a b01c1226 3b96f2b4 303da3fb e2925a99 b225a1be e78fac84 13118dda 4a2a4367 08723224 14d9e17a 730130f1 b2bb0da6 61083881"
|
||||
},
|
||||
"standin-06": {
|
||||
"about": "elite band 5 as stand-ins: chess_char_3_12_b→char_608_acpion chess_char_4_09_b→char_617_sharp2 chess_char_3_05_b→char_601_cguard chess_char_3_18_b→char_609_acguad chess_char_4_04_b→char_607_cspec chess_char_4_07_b→char_601_cguard chess_char_4_16_b→char_615_acspec chess_char_3_01_b→char_603_csnipe chess_char_3_04_b→char_605_cmedic chess_char_3_21_b→char_611_acnipe chess_char_4_02_b→char_611_acnipe chess_char_4_13_b→char_614_acsupo",
|
||||
@@ -291,49 +303,49 @@
|
||||
"round": 10,
|
||||
"seed": 1442657168,
|
||||
"waveId": "act1autochess_h03",
|
||||
"time": 185.13,
|
||||
"ticks": 5554,
|
||||
"time": 187.4,
|
||||
"ticks": 5622,
|
||||
"reason": "cleared",
|
||||
"killed": 24,
|
||||
"killed": 30,
|
||||
"total": 98,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 262,
|
||||
"rngDraws": 315,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":24,"total":98,"perfect":false,"leaks":74,"leaksUncounted":0,"coins":4,"dmg":379938,"bossDmg":0,"heal":9793,"deaths":31,"layerGains":{"raidShip":24}}
|
||||
"p1": {"killed":30,"total":98,"perfect":false,"leaks":68,"leaksUncounted":0,"coins":6,"dmg":472224,"bossDmg":0,"heal":15707,"deaths":31,"layerGains":{"raidShip":24}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_3_12_b",2,"none",1904,1,138,4,33527,4810,222,6,1],
|
||||
["p1",2,"op","chess_char_4_09_b",0,"none",0,0,6,2,10500,3510,0,5,1],
|
||||
["p1",3,"op","chess_char_3_05_b",2,"none",0,0,90,1,29453,11344,0,19,2],
|
||||
["p1",1,"op","chess_char_3_12_b",2,"none",1904,1,139,4,33527,4810,222,6,1],
|
||||
["p1",2,"op","chess_char_4_09_b",0,"none",0,0,6,0,13369,3510,0,5,1],
|
||||
["p1",3,"op","chess_char_3_05_b",2,"none",0,0,90,1,32273,11344,0,20,2],
|
||||
["p1",4,"op","chess_char_3_18_b",2,"none",0,0,12,1,32236,5744,2553,22,1],
|
||||
["p1",5,"op","chess_char_4_04_b",1,"none",0,0,137,0,21284,11506,0,43,9],
|
||||
["p1",6,"op","chess_char_4_07_b",1,"none",0,0,93,0,13230,7538,0,21,1],
|
||||
["p1",7,"op","chess_char_4_16_b",1,"none",0,0,135,2,22963,13645,0,38,12],
|
||||
["p1",8,"op","chess_char_3_01_b",2,"none",0,0,128,2,11972,3020,0,20,1],
|
||||
["p1",9,"op","chess_char_3_04_b",2,"none",0,0,4,0,0,1374,7019,10,1],
|
||||
["p1",10,"op","chess_char_3_21_b",2,"none",0,0,111,9,171439,4263,0,48,1],
|
||||
["p1",11,"op","chess_char_4_02_b",1,"none",0,0,2,0,19713,1483,0,16,1],
|
||||
["p1",12,"op","chess_char_4_13_b",1,"none",0,0,101,3,13621,3085,0,23,1]
|
||||
["p1",5,"op","chess_char_4_04_b",1,"none",0,0,138,0,13918,12430,0,38,9],
|
||||
["p1",6,"op","chess_char_4_07_b",1,"none",0,0,93,0,13096,7538,0,19,1],
|
||||
["p1",7,"op","chess_char_4_16_b",1,"none",0,0,137,3,45194,14837,0,51,13],
|
||||
["p1",8,"op","chess_char_3_01_b",2,"none",0,0,132,6,26811,3020,0,27,1],
|
||||
["p1",9,"op","chess_char_3_04_b",2,"none",0,0,4,0,0,3135,12932,15,1],
|
||||
["p1",10,"op","chess_char_3_21_b",2,"none",0,0,113,10,201155,6858,0,55,1],
|
||||
["p1",11,"op","chess_char_4_02_b",1,"none",0,0,2,2,47025,1483,0,25,1],
|
||||
["p1",12,"op","chess_char_4_13_b",1,"none",0,0,101,3,13621,2704,0,23,1]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_10162_mnctpt": [1,0,1,13739,28023],
|
||||
"enemy_10162_mnctpt": [1,0,1,12236,28023],
|
||||
"enemy_1019_jshoot": [1,1,0,769,4479],
|
||||
"enemy_1019_jshoot_2": [1,1,0,1779,6718],
|
||||
"enemy_1021_bslime": [1,1,0,2095,6121],
|
||||
"enemy_1023_jmage": [1,0,1,2948,0],
|
||||
"enemy_1025_reveng": [1,0,1,0,12429],
|
||||
"enemy_1023_jmage": [1,1,0,2403,5474],
|
||||
"enemy_1025_reveng": [1,1,0,0,12442],
|
||||
"enemy_1026_aghost": [1,1,0,0,9456],
|
||||
"enemy_1043_zomsbr": [1,0,1,0,0],
|
||||
"enemy_1251_lysyta_2": [57,15,42,6671,144893],
|
||||
"enemy_1252_lysytb_2": [21,4,17,25366,122606],
|
||||
"enemy_1329_cbshld_2": [12,1,11,17957,45213]
|
||||
"enemy_1251_lysyta_2": [57,18,39,8755,173039],
|
||||
"enemy_1252_lysytb_2": [21,5,16,29535,174396],
|
||||
"enemy_1329_cbshld_2": [12,1,11,19842,52076]
|
||||
},
|
||||
"hooks": [1,138,5554,424,424,606,623,37,55,137,32,32,0,5902,24,41,98,74,1,58,3,0,6],
|
||||
"events": {"atk":484,"bounty":2,"deploy":40,"die":63,"dmg":623,"engage":11,"fx":33,"heal":35,"layer":3,"leak":74,"skill":64,"spawn":110,"status":81},
|
||||
"fx": {"blink":8,"camouflage":1,"dodge":7,"dp":5,"explode":1,"garrison":3,"slash":8},
|
||||
"snaps": "be6d1821 33db37f0 1c42b6f6 5af04203 5e6c5512 babe8154 f176e4bc af2beda0 d11d4dd9 232a9af5 dbd39714 cdc694f1 7413a229 4dd3df34 ebd96e47 5f8b58f1 42af7a0d e3ac653d afa3953c"
|
||||
"hooks": [1,139,5622,474,474,678,694,42,61,138,33,33,0,6117,24,44,98,68,1,66,3,0,7],
|
||||
"events": {"atk":549,"bounty":3,"deploy":41,"die":70,"dmg":694,"engage":11,"fx":35,"heal":40,"layer":3,"leak":68,"skill":66,"spawn":110,"status":83},
|
||||
"fx": {"blink":9,"camouflage":1,"dodge":8,"dp":5,"explode":1,"garrison":3,"slash":8},
|
||||
"snaps": "be6d1821 33db37f0 a6ec1fa2 487058c3 2aef7534 379bf51a d87bcaba 6953291e ea8de47f e0cfe2ef c5d6d6f0 9fd5858c 99048d37 dfd46fb1 d86de307 637bf595 72c11ba9 adb364dc bb18d903"
|
||||
},
|
||||
"standin-07": {
|
||||
"about": "elite band 6 as stand-ins: chess_char_4_17_b→char_610_acfend chess_char_4_18_b→char_602_cdfend chess_char_5_05_b→char_602_cdfend chess_char_4_19_b→char_608_acpion chess_char_5_01_b→char_600_cpione chess_char_4_22_b→char_609_acguad chess_char_4_23_b→char_609_acguad chess_char_5_06_b→char_609_acguad chess_char_4_20_b→char_603_csnipe chess_char_4_24_b→char_604_ccast chess_char_5_02_b→char_604_ccast chess_char_5_03_b→char_612_accast",
|
||||
@@ -344,10 +356,10 @@
|
||||
"round": 12,
|
||||
"seed": 816286799,
|
||||
"waveId": "act1autochess_h05",
|
||||
"time": 223.57,
|
||||
"ticks": 6707,
|
||||
"time": 223.2,
|
||||
"ticks": 6696,
|
||||
"reason": "cleared",
|
||||
"killed": 10,
|
||||
"killed": 9,
|
||||
"total": 80,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
@@ -355,13 +367,13 @@
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {
|
||||
"killed": 10,
|
||||
"killed": 9,
|
||||
"total": 80,
|
||||
"perfect": false,
|
||||
"leaks": 70,
|
||||
"leaks": 71,
|
||||
"leaksUncounted": 0,
|
||||
"coins": 4,
|
||||
"dmg": 143200,
|
||||
"dmg": 146478,
|
||||
"bossDmg": 0,
|
||||
"heal": 0,
|
||||
"deaths": 25,
|
||||
@@ -377,30 +389,30 @@
|
||||
["p1",6,"op","chess_char_4_22_b",1,"none",3191,1,112,0,959,14040,0,6,1],
|
||||
["p1",7,"op","chess_char_4_23_b",1,"none",0,0,71,0,3484,6865,0,8,1],
|
||||
["p1",8,"op","chess_char_5_06_b",2,"uniequip_002_acguad",0,0,10,0,0,3820,0,0,0],
|
||||
["p1",9,"op","chess_char_4_20_b",1,"none",1255.06,1,109,2,15968,4785,0,30,1],
|
||||
["p1",10,"op","chess_char_4_24_b",1,"none",1007.59,1,111,1,5553,3072,0,19,1],
|
||||
["p1",9,"op","chess_char_4_20_b",1,"none",1255.06,1,109,2,17210,4785,0,32,1],
|
||||
["p1",10,"op","chess_char_4_24_b",1,"none",1007.59,1,111,2,5402,3072,0,19,1],
|
||||
["p1",11,"op","chess_char_5_02_b",2,"none",0,0,105,1,8684,4080,0,19,1],
|
||||
["p1",12,"op","chess_char_5_03_b",2,"uniequip_002_accast",0,0,4,5,105067,1749,0,10,1],
|
||||
["p1",12,"op","chess_char_5_03_b",2,"uniequip_002_accast",0,0,4,3,107254,1749,0,10,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]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_1005_yokai_2": [18,3,15,3234,10312],
|
||||
"enemy_1041_lazerd_2": [24,3,21,43648,33749],
|
||||
"enemy_1042_frostd": [30,2,28,0,34315],
|
||||
"enemy_1005_yokai_2": [18,3,15,3213,10312],
|
||||
"enemy_1041_lazerd_2": [24,3,21,43210,35712],
|
||||
"enemy_1042_frostd": [30,1,29,0,34310],
|
||||
"enemy_1045_hammer": [1,1,0,2029,15552],
|
||||
"enemy_1045_hammer_2": [1,0,1,3891,18162],
|
||||
"enemy_1045_hammer_2": [1,0,1,4288,18162],
|
||||
"enemy_1046_agent": [1,1,0,72,3888],
|
||||
"enemy_1050_lslime": [1,0,1,9027,5281],
|
||||
"enemy_1050_lslime": [1,0,1,9094,6601],
|
||||
"enemy_1061_zomshd": [1,0,1,61,13892],
|
||||
"enemy_1062_rager_2": [1,0,1,2632,17550],
|
||||
"enemy_1062_rager_2": [1,0,1,2628,17050],
|
||||
"enemy_1067_snslime": [1,0,1,0,0],
|
||||
"enemy_1071_dftman": [1,0,1,0,0]
|
||||
},
|
||||
"hooks": [1,112,6707,296,296,579,572,568,35,105,13,13,0,9191,8,15,80,70,1,35,2,0,7],
|
||||
"events": {"atk":322,"bounty":2,"deploy":30,"die":35,"dmg":572,"engage":11,"fx":22,"layer":2,"leak":70,"skill":26,"spawn":94,"status":113},
|
||||
"hooks": [1,112,6696,299,299,578,571,566,34,105,13,13,0,9182,8,14,80,71,1,34,2,0,7],
|
||||
"events": {"atk":324,"bounty":2,"deploy":30,"die":34,"dmg":571,"engage":11,"fx":22,"layer":2,"leak":71,"skill":26,"spawn":94,"status":111},
|
||||
"fx": {"aoe":1,"dodge":7,"dp":6,"garrison":2,"garrisonGrant":1,"palsy":2,"revive":3},
|
||||
"snaps": "801e90ec 4ebbd3e8 f780653d ed5ed324 bd024323 babc565e 46a42524 cf9f3776 b854d31f 975c3869 9b059794 4a0e03a1 6e53c58b 0baee204 14791829 482e0160 46afd15b 48ab4dc8 11b59232 d2527d0d 9a65bb0e ae5b68b3 5e9c3da0"
|
||||
"snaps": "801e90ec c1cca6cb f2a5a38b 6dc62d98 cb792a41 23ec9de6 62a40e3b eb8791c8 5cf201e4 e0c50494 b5bd31db 490ef7be f2c93ce1 ee84f980 68266f8f d66f411d 6f00ab8c 98dfa057 343e0f1c 7a9470b3 c574bda9 8be7c32a dadff196"
|
||||
},
|
||||
"standin-08": {
|
||||
"about": "elite band 6 as stand-ins: chess_char_5_08_b→char_610_acfend chess_char_5_14_b→char_608_acpion chess_char_5_19_b→char_617_sharp2 chess_char_5_07_b→char_601_cguard chess_char_5_13_b→char_609_acguad chess_char_5_17_b→char_615_acspec chess_char_5_10_b→char_606_csuppo chess_char_5_11_b→char_613_acmedc chess_char_5_12_b→char_614_acsupo chess_char_5_15_b→char_603_csnipe chess_char_5_18_b→char_611_acnipe chess_char_5_20_b→char_614_acsupo",
|
||||
@@ -411,50 +423,50 @@
|
||||
"round": 12,
|
||||
"seed": 2456427706,
|
||||
"waveId": "act1autochess_h05",
|
||||
"time": 216.37,
|
||||
"ticks": 6491,
|
||||
"time": 214.67,
|
||||
"ticks": 6440,
|
||||
"reason": "cleared",
|
||||
"killed": 44,
|
||||
"killed": 21,
|
||||
"total": 179,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 964,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {"p1":{"killed":44,"total":179,"perfect":false,"leaks":135,"leaksUncounted":0,"coins":2,"dmg":1792553,"bossDmg":0,"heal":75042,"deaths":12,"layerGains":{}}},
|
||||
"players": {"p1":{"killed":21,"total":179,"perfect":false,"leaks":158,"leaksUncounted":0,"coins":2,"dmg":1381372,"bossDmg":0,"heal":100047,"deaths":13,"layerGains":{}}},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_5_08_b",2,"uniequip_002_acfend",3328.04,1,7,6,120405,8494,0,163,4],
|
||||
["p1",2,"op","chess_char_5_14_b",2,"uniequip_002_acpion",1904,1,200,13,582727,10397,0,50,7],
|
||||
["p1",3,"op","chess_char_5_19_b",0,"uniequip_002_sharp2",0,0,164,5,264095,31935,0,79,3],
|
||||
["p1",4,"op","chess_char_5_07_b",2,"none",3334,1,204,2,41162,20656,0,35,3],
|
||||
["p1",5,"op","chess_char_5_13_b",2,"uniequip_002_acguad",0,0,130,4,91514,12473,0,48,2],
|
||||
["p1",6,"op","chess_char_5_17_b",2,"uniequip_002_acspec",1448,1,155,3,70659,22528,0,98,0],
|
||||
["p1",7,"op","chess_char_5_10_b",2,"none",1131,1,4,2,71806,0,0,146,4],
|
||||
["p1",8,"op","chess_char_5_11_b",2,"uniequip_002_acmedc",2262.4,1,5,0,0,0,75042,73,3],
|
||||
["p1",9,"op","chess_char_5_12_b",2,"uniequip_002_acsupo",1430,1,11,2,108370,0,0,138,3],
|
||||
["p1",10,"op","chess_char_5_15_b",2,"none",1510,1,13,0,84172,0,0,215,4],
|
||||
["p1",11,"op","chess_char_5_18_b",2,"uniequip_002_acnipe",2380.5,1,6,7,265158,0,0,156,3],
|
||||
["p1",12,"op","chess_char_5_20_b",2,"uniequip_002_acsupo",1430,1,14,0,92485,0,0,125,3],
|
||||
["p1",1,"op","chess_char_5_08_b",2,"uniequip_002_acfend",0,0,7,2,70503,39277,0,119,3],
|
||||
["p1",2,"op","chess_char_5_14_b",2,"uniequip_002_acpion",0,0,196,2,237060,10276,0,19,3],
|
||||
["p1",3,"op","chess_char_5_19_b",0,"uniequip_002_sharp2",4154.5,1,204,3,203174,20994,0,54,2],
|
||||
["p1",4,"op","chess_char_5_07_b",2,"none",3334,1,202,2,41436,22288,0,35,3],
|
||||
["p1",5,"op","chess_char_5_13_b",2,"uniequip_002_acguad",0,0,131,4,81334,12863,0,40,2],
|
||||
["p1",6,"op","chess_char_5_17_b",2,"uniequip_002_acspec",1448,1,122,3,87842,29575,0,142,0],
|
||||
["p1",7,"op","chess_char_5_10_b",2,"none",1131,1,4,0,72698,0,0,145,4],
|
||||
["p1",8,"op","chess_char_5_11_b",2,"uniequip_002_acmedc",2262.4,1,5,0,0,0,100047,73,3],
|
||||
["p1",9,"op","chess_char_5_12_b",2,"uniequip_002_acsupo",1430,1,11,1,90852,0,0,128,3],
|
||||
["p1",10,"op","chess_char_5_15_b",2,"none",1510,1,13,0,87700,0,0,231,4],
|
||||
["p1",11,"op","chess_char_5_18_b",2,"uniequip_002_acnipe",2380.5,1,6,4,316532,0,0,185,3],
|
||||
["p1",12,"op","chess_char_5_20_b",2,"uniequip_002_acsupo",1430,1,14,0,92242,0,0,124,3],
|
||||
["-","~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]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_1072_dlancer": [1,1,0,1609,37150],
|
||||
"enemy_1081_sotisd": [1,0,1,749,28802],
|
||||
"enemy_1092_mdgint": [1,0,1,0,0],
|
||||
"enemy_1116_liprr": [1,0,1,0,7850],
|
||||
"enemy_1116_liprr_2": [1,0,1,0,1829],
|
||||
"enemy_1081_sotisd": [1,0,1,0,27240],
|
||||
"enemy_1092_mdgint": [1,0,1,0,606],
|
||||
"enemy_1116_liprr": [1,0,1,0,3570],
|
||||
"enemy_1116_liprr_2": [1,0,1,0,2364],
|
||||
"enemy_1118_lidbox_2": [1,0,1,0,809],
|
||||
"enemy_1119_vofsd": [1,0,1,0,889],
|
||||
"enemy_1121_lifbos": [1,0,1,4806,7013],
|
||||
"enemy_1249_lysdb_2": [60,20,40,34591,927986],
|
||||
"enemy_1251_lysyta": [63,22,41,7408,522114],
|
||||
"enemy_1254_lypa_2": [48,1,47,57320,258113]
|
||||
"enemy_1119_vofsd": [1,0,1,0,919],
|
||||
"enemy_1121_lifbos": [1,0,1,1448,5072],
|
||||
"enemy_1249_lysdb_2": [60,8,52,39217,619286],
|
||||
"enemy_1251_lysyta": [63,12,51,4824,426834],
|
||||
"enemy_1254_lypa_2": [48,0,48,88175,257522]
|
||||
},
|
||||
"hooks": [1,204,6491,1773,1773,3184,3244,143,56,191,39,41,0,24792,17208,64,179,135,1,56,0,0,10],
|
||||
"events": {"atk":2011,"bounty":1,"deploy":22,"die":56,"dmg":3226,"engage":11,"fx":311,"heal":124,"leak":135,"skill":86,"spawn":194,"status":1260},
|
||||
"fx": {"aoe":120,"displace":6,"dodge":33,"dp":20,"liberate":1,"phase":1,"shieldBreak":60,"slash":56,"sp":3,"spGain":11},
|
||||
"snaps": "c4ba1bfb fae78ec3 4853328f 674d8548 bcbe6142 1a53e0eb e36dd50a c1fffc0d 6b8ca6c2 ea59d397 fcda4d5a 0b327687 9c504162 f940765a ed653c1f 40083fa0 8b28d76e faf8fc30 827f9624 f00940c5 a4839ca3 7cbbb8ee"
|
||||
"hooks": [1,204,6440,1716,1716,2812,2842,139,34,192,33,34,0,22299,16472,43,179,158,1,34,0,0,5],
|
||||
"events": {"atk":1954,"bounty":1,"deploy":22,"die":34,"dmg":2823,"engage":11,"fx":218,"heal":112,"leak":158,"skill":72,"spawn":194,"status":1233},
|
||||
"fx": {"aoe":90,"displace":6,"dodge":22,"dp":5,"shieldBreak":59,"slash":24,"spGain":12},
|
||||
"snaps": "c31057ad 32bd73d4 3d2277e9 f67b1fc5 1447b8f6 7c45e488 90e4af74 d4c9b4df 6903fd8a 2b8e8161 bee60241 1666f57f b7fe3a52 2e85cd5e bab57ab2 e6ed121a 8f131939 e4a0c14c c3a4cc3c 0ffa3610 9ae55880 0d548569"
|
||||
},
|
||||
"standin-09": {
|
||||
"about": "elite band 7 as stand-ins: chess_char_6_03_b→char_610_acfend chess_char_6_02_b→char_608_acpion chess_char_6_07_b→char_617_sharp2 chess_char_6_10_b→char_617_sharp2 chess_char_6_11_b→char_608_acpion chess_char_6_06_b→char_609_acguad chess_char_5_22_b→char_611_acnipe chess_char_6_01_b→char_611_acnipe chess_char_6_04_b→char_614_acsupo chess_char_6_05_b→char_611_acnipe chess_char_6_08_b→char_612_accast chess_char_6_09_b→char_613_acmedc",
|
||||
@@ -465,31 +477,31 @@
|
||||
"round": 13,
|
||||
"seed": 2308517178,
|
||||
"waveId": "act1autochess_h06",
|
||||
"time": 198.43,
|
||||
"ticks": 5953,
|
||||
"time": 199.07,
|
||||
"ticks": 5972,
|
||||
"reason": "cleared",
|
||||
"killed": 158,
|
||||
"total": 158,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 232,
|
||||
"rngDraws": 236,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":158,"total":158,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":924222,"bossDmg":0,"heal":29638,"deaths":1,"layerGains":{"sargonShip":20}}
|
||||
"p1": {"killed":158,"total":158,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":924222,"bossDmg":0,"heal":29282,"deaths":1,"layerGains":{"sargonShip":20}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_acfend",4974.95,1,8,0,0,0,0,0,0],
|
||||
["p1",2,"op","chess_char_6_02_b",2,"uniequip_002_acpion",1904,1,6,0,0,0,0,0,0],
|
||||
["p1",3,"op","chess_char_6_07_b",0,"uniequip_002_sharp2",2494,1,9,0,0,0,0,0,0],
|
||||
["p1",4,"op","chess_char_6_10_b",0,"uniequip_002_sharp2",2494,1,11,27,129672,0,0,173,3],
|
||||
["p1",5,"op","chess_char_6_11_b",2,"uniequip_002_acpion",1904,1,13,35,186014,11957,0,60,20],
|
||||
["p1",6,"op","chess_char_6_06_b",2,"uniequip_002_acguad",3531,1,14,18,61248,763,0,155,4],
|
||||
["p1",4,"op","chess_char_6_10_b",0,"uniequip_002_sharp2",2494,1,11,16,123097,0,0,174,3],
|
||||
["p1",5,"op","chess_char_6_11_b",2,"uniequip_002_acpion",1834,1,13,46,173899,11626,0,64,21],
|
||||
["p1",6,"op","chess_char_6_06_b",2,"uniequip_002_acguad",3531,1,14,10,57010,808,0,155,4],
|
||||
["p1",7,"op","chess_char_5_22_b",2,"uniequip_002_acnipe",1587,1,4,0,0,0,0,0,0],
|
||||
["p1",8,"op","chess_char_6_01_b",2,"uniequip_002_acnipe",1643,1,5,0,948,0,0,4,1],
|
||||
["p1",9,"op","chess_char_6_04_b",2,"uniequip_002_acsupo",2465,1,141,7,73191,2465,0,92,2],
|
||||
["p1",10,"op","chess_char_6_05_b",2,"uniequip_002_acnipe",1643,1,7,20,89868,0,0,93,2],
|
||||
["p1",11,"op","chess_char_6_08_b",2,"uniequip_002_accast",1819,1,10,51,383282,0,0,78,2],
|
||||
["p1",12,"op","chess_char_6_09_b",2,"uniequip_002_acmedc",1394,1,12,0,0,16988,29638,83,3],
|
||||
["p1",8,"op","chess_char_6_01_b",2,"uniequip_002_acnipe",1643,1,5,0,1136,0,0,4,1],
|
||||
["p1",9,"op","chess_char_6_04_b",2,"uniequip_002_acsupo",2465,1,141,7,70868,2465,0,92,2],
|
||||
["p1",10,"op","chess_char_6_05_b",2,"uniequip_002_acnipe",1643,1,7,21,100965,0,0,95,2],
|
||||
["p1",11,"op","chess_char_6_08_b",2,"uniequip_002_accast",1819,1,10,58,397247,0,0,81,2],
|
||||
["p1",12,"op","chess_char_6_09_b",2,"uniequip_002_acmedc",1324,1,12,0,0,17058,29282,83,3],
|
||||
["-","~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]
|
||||
@@ -505,12 +517,12 @@
|
||||
"enemy_1161_tidmag_2": [1,1,0,1758,7680],
|
||||
"enemy_1249_lysdb_2": [60,60,0,2085,345600],
|
||||
"enemy_1251_lysyta": [51,51,0,0,134640],
|
||||
"enemy_1329_cbshld": [39,39,0,2290,374400]
|
||||
"enemy_1329_cbshld": [39,39,0,2143,374400]
|
||||
},
|
||||
"hooks": [1,174,5953,812,812,1599,1718,168,159,159,37,36,0,29335,2593,62,158,0,1,159,3,1,17],
|
||||
"events": {"atk":917,"bounty":4,"deploy":13,"die":159,"dmg":1707,"engage":7,"fx":298,"heal":127,"layer":3,"skill":73,"spawn":173,"status":324},
|
||||
"fx": {"aoe":2,"burst":1,"dodge":19,"dp":55,"garrison":3,"shieldBreak":60,"slash":144,"sp":12,"strike":2},
|
||||
"snaps": "526d4c63 f61576c6 e1be6631 53288d14 7de80a4f 26575d3b 14b2dc7b 09bff769 03f7af9b 266de1dd a9bf82a4 d80af3de da82ae39 706186e0 9d862b1f bcccab65 19598dab ba7df686 a486add4 e9e501f2"
|
||||
"hooks": [1,174,5972,824,824,1576,1711,169,159,159,38,37,0,29559,2586,66,158,0,1,159,3,1,13],
|
||||
"events": {"atk":932,"bounty":4,"deploy":13,"die":159,"dmg":1694,"engage":7,"fx":305,"heal":128,"layer":3,"skill":75,"spawn":173,"status":321},
|
||||
"fx": {"aoe":2,"burst":1,"dodge":15,"dp":67,"garrison":3,"shieldBreak":60,"slash":145,"sp":12},
|
||||
"snaps": "526d4c63 f61576c6 6bbd0cd4 7174c0e8 a2878fe6 eb717890 641bc6bd dea6ff24 12805446 5bced5fc d42fb8a0 6da05c89 1cb24ef4 0bc3d3a8 0d40f7b7 4febd78a 059a9cdd af2722be f07b6e0b 15259ad8"
|
||||
},
|
||||
"standin-10": {
|
||||
"about": "elite band 7 as stand-ins: chess_char_6_17_b→char_608_acpion chess_char_6_13_b→char_615_acspec chess_char_6_19_b→char_615_acspec chess_char_6_12_b→char_612_accast chess_char_6_15_b→char_614_acsupo chess_char_6_18_b→char_612_accast chess_char_6_20_b→char_613_acmedc",
|
||||
@@ -524,43 +536,43 @@
|
||||
"time": 230,
|
||||
"ticks": 6900,
|
||||
"reason": "timeout",
|
||||
"killed": 29,
|
||||
"killed": 35,
|
||||
"total": 131,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 293,
|
||||
"rngDraws": 294,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":29,"total":131,"perfect":false,"leaks":102,"leaksUncounted":0,"coins":2,"dmg":542398,"bossDmg":0,"heal":10974,"deaths":25,"layerGains":{"raidShip":6}}
|
||||
"p1": {"killed":35,"total":131,"perfect":false,"leaks":96,"leaksUncounted":0,"coins":2,"dmg":619321,"bossDmg":0,"heal":10342,"deaths":25,"layerGains":{"raidShip":6}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_6_17_b",2,"uniequip_002_acpion",1904,1,164,10,209944,12495,0,67,10],
|
||||
["p1",2,"op","chess_char_6_13_b",2,"uniequip_002_acspec",0,0,162,6,51334,11872,0,120,0],
|
||||
["p1",3,"op","chess_char_6_19_b",2,"uniequip_002_acspec",0,0,165,4,76465,17808,0,154,0],
|
||||
["p1",1,"op","chess_char_6_17_b",2,"uniequip_002_acpion",1904,1,164,17,294164,12495,0,72,11],
|
||||
["p1",2,"op","chess_char_6_13_b",2,"uniequip_002_acspec",0,0,162,6,48878,11872,0,120,0],
|
||||
["p1",3,"op","chess_char_6_19_b",2,"uniequip_002_acspec",0,0,165,3,73010,17808,0,155,0],
|
||||
["p1",4,"op","chess_char_6_12_b",2,"uniequip_002_accast",2265.49,1,4,4,78264,281,0,32,2],
|
||||
["p1",5,"op","chess_char_6_15_b",2,"uniequip_002_acsupo",0,0,148,2,54506,6494,0,39,3],
|
||||
["p1",6,"op","chess_char_6_18_b",2,"uniequip_002_accast",1819,1,8,3,71885,900,0,43,2],
|
||||
["p1",7,"op","chess_char_6_20_b",2,"uniequip_002_acmedc",1464,1,9,0,0,4263,10974,19,1],
|
||||
["p1",6,"op","chess_char_6_18_b",2,"uniequip_002_accast",1819,1,8,3,70499,618,0,43,2],
|
||||
["p1",7,"op","chess_char_6_20_b",2,"uniequip_002_acmedc",1464,1,9,0,0,3912,10342,19,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]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_1006_shield_3": [21,1,20,13939,164939],
|
||||
"enemy_1043_zomsbr": [66,23,43,617,138600],
|
||||
"enemy_1162_magmot": [1,0,1,4704,11483],
|
||||
"enemy_1006_shield_3": [21,1,20,14897,198077],
|
||||
"enemy_1043_zomsbr": [66,27,39,736,157473],
|
||||
"enemy_1162_magmot": [1,0,1,4072,11483],
|
||||
"enemy_1165_duhond": [1,1,0,93,4645],
|
||||
"enemy_1165_duhond_2": [1,0,1,0,0],
|
||||
"enemy_1166_dusbr": [1,0,1,0,0],
|
||||
"enemy_1166_dusbr_2": [1,0,1,0,0],
|
||||
"enemy_1168_dumage": [1,1,0,1897,7465],
|
||||
"enemy_1168_dumage_2": [1,1,0,4286,10783],
|
||||
"enemy_1169_duphlx": [1,0,1,0,1489],
|
||||
"enemy_1402_tgshd_2": [36,2,33,28576,202995]
|
||||
"enemy_1168_dumage": [1,1,0,1476,7465],
|
||||
"enemy_1168_dumage_2": [1,1,0,2802,10783],
|
||||
"enemy_1169_duphlx": [1,1,0,0,6636],
|
||||
"enemy_1402_tgshd_2": [36,3,32,29405,222760]
|
||||
},
|
||||
"hooks": [1,165,6900,595,595,924,938,6943,54,158,18,38,0,8737,1171,47,131,101,1,54,1,1,0],
|
||||
"events": {"atk":602,"bounty":1,"deploy":32,"die":57,"dmg":868,"engage":6,"fx":580,"heal":25,"layer":1,"leak":101,"skill":76,"spawn":140,"status":383},
|
||||
"fx": {"aoe":4,"blink":3,"burst":1,"displace":21,"dodge":3,"dp":20,"expose":450,"garrison":1,"garrisonGrant":3,"slash":74},
|
||||
"snaps": "fba27448 40f8ddeb 904aa1c4 7f5fd3e3 9795959e 7e944cb9 a1f602a2 23ce8d11 bc4a8a16 bf530478 d8ce6699 3c7531f2 1723301e 3a33e4a9 1776e2c7 9f4e39b8 4a745c4f 04ba5967 cbaf6007 94a5d280 8d5c37cb 5d25eb40 2be9ff1d"
|
||||
"hooks": [1,165,6900,601,601,972,984,7120,60,158,19,39,0,8732,1171,48,131,95,1,60,1,1,0],
|
||||
"events": {"atk":606,"bounty":1,"deploy":32,"die":63,"dmg":914,"engage":6,"fx":616,"heal":23,"layer":1,"leak":95,"skill":78,"spawn":140,"status":380},
|
||||
"fx": {"aoe":4,"blink":3,"burst":1,"displace":21,"dodge":2,"dp":28,"expose":471,"garrison":1,"garrisonGrant":3,"slash":82},
|
||||
"snaps": "cecbf93c f496d3e4 d807c314 abf565d9 f7b9d0bb ee3cb80c 81f317ce d42a4241 ff69a55b 34e7bc7d 5062a64e 2487e36c 4d49be6c 617a5f43 281d4afe e2d98f64 0bab3df5 64a0694f 515878f6 902a19c4 f21a0d0e 8507b4d3 06359f6f"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,8 @@ describe('#43: a blocked 隐匿 enemy hides again only 3 s after the block ends
|
||||
h.run(0.2);
|
||||
assert.equal(hidden(h, e), true, `+${STEALTH_RESTORE + 0.1} s: 隐匿 again`);
|
||||
assert.ok(Math.abs(h.b.time - t0 - STEALTH_RESTORE - 0.1) < 0.05);
|
||||
// an arrow loosed before it hid still lands (a projectile keeps its target): count from when none is in flight
|
||||
h.runUntil(() => !h.b.projectiles.list.some((p) => p.target === e), 1);
|
||||
const after = e.stats.taken;
|
||||
h.run(2);
|
||||
assert.equal(e.stats.taken, after, 'no ranged hit once it hides');
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
// An attack interval or a time-SP cost that is a whole number of ticks takes exactly that many ticks (PR #402 by
|
||||
// @Cloudnyco, 0.2.2). Floating point alone left a residue (1/30 is not a binary fraction): 1 s counted down in thirty
|
||||
// steps of 1/30 stops at 2.1e-16, so an attack with a 1 s interval came every 31 ticks; 300 gains of 1/30 SP sum to
|
||||
// 9.999999999999975, so a 10-SP charge took 301. ai.js attackCountdown and SkillRuntime.gainSp treat what is within
|
||||
// 1e-9 as reached (docs/SIM.md §2, §7.1). Official (PRTS 作战机制/sandbox 「帧对齐机制对攻速的影响」): one frame = 1/30 s,
|
||||
// an exact 1 s is 30 frames; a non-integer count is rounded there (四舍五入 since 2019-12-24) — here it still ends on the
|
||||
// tick that crosses 0 (⌈30 × interval⌉), a separate, older difference this file locks as it is.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { attackCountdown } from '../../server/sim/ai.js';
|
||||
import { TICK } from '../../server/sim/constants.js';
|
||||
import { hasGeneratedData, getDefaultSource } from '../../server/sim/simdata.js';
|
||||
import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
|
||||
|
||||
const REAL = { skip: !hasGeneratedData() };
|
||||
|
||||
test('the residue: thirty steps of 1/30 leave 1 s above 0, 300 gains of 1/30 leave 10 SP short', () => {
|
||||
let cd = 1;
|
||||
for (let i = 0; i < 30; i++) cd = Math.max(0, cd - TICK);
|
||||
assert.ok(cd > 0 && cd < 1e-15, `${cd}`);
|
||||
let sp = 0;
|
||||
for (let i = 0; i < 300; i++) sp += TICK;
|
||||
assert.ok(sp < 10 && sp > 10 - 1e-13, `${sp}`);
|
||||
});
|
||||
|
||||
test('attackCountdown: every interval bat × 100 / aspd (bat 0.1 … 10 s, aspd 20 … 600) takes ⌈30 × interval⌉ ticks', () => {
|
||||
const wrong = [];
|
||||
for (let j = 1; j <= 100; j++) {
|
||||
const bat = j / 10;
|
||||
for (const aspd of [20, 50, 60, 75, 80, 100, 110, 120, 125, 150, 200, 240, 300, 600]) {
|
||||
const interval = (bat * 100) / aspd; // units.js _recalc
|
||||
const exact = 300 * j; // 30 × interval = 300 j / aspd, in integers
|
||||
const want = exact % aspd === 0 ? exact / aspd : Math.ceil(exact / aspd);
|
||||
let left = interval, n = 0;
|
||||
while (left > 0) { left = attackCountdown(left, TICK); n++; }
|
||||
if (n !== want) wrong.push(`${bat} s @ ${aspd}: ${n} ticks, want ${want}`);
|
||||
}
|
||||
}
|
||||
assert.deepEqual(wrong, []);
|
||||
});
|
||||
|
||||
/** Ticks between consecutive normal attacks of `id` (hook `attack`), over `seconds` of battle. */
|
||||
function attackGaps(h, id, seconds) {
|
||||
h.run(seconds);
|
||||
const t = h.hooksOf('attack').filter((c) => c.attacker.id === id && !c.isSkill).map((c) => Math.round(c.t / TICK));
|
||||
return t.slice(1).map((x, i) => x - t[i]);
|
||||
}
|
||||
|
||||
test('a 1 s operator attacks every 30 ticks, a 3 s ranged enemy every 90', () => {
|
||||
const h = makeBattle({
|
||||
defs: {
|
||||
chess: { t_one: chessRec({ id: 't_one', stats: { bat: 1, maxHp: 1e6 }, skill: null }) },
|
||||
enemies: { enemy_t_three: enemyRec({ key: 'enemy_t_three', hp: 1e9, speed: 0, bat: 3, atk: 1, range: 2.5 }) },
|
||||
},
|
||||
units: [{ chessId: 't_one', row: 10, col: 4 }],
|
||||
enemies: [{ key: 'enemy_t_three', pos: [10, 5] }],
|
||||
hooks: ['attack'], captureNoisy: true, timeLimit: 60,
|
||||
});
|
||||
h.run(0.5); // both deployed / spawned and fighting from here on
|
||||
const u = h.unit('t_one'), e = h.enemy('enemy_t_three');
|
||||
assert.equal(u.s.interval, 1);
|
||||
assert.equal(e.s.interval, 3);
|
||||
const ally = attackGaps(h, u.id, 20), enemy = h.hooksOf('attack').filter((c) => c.attacker.id === e.id).map((c) => Math.round(c.t / TICK));
|
||||
assert.ok(ally.length >= 15, `${ally.length} operator attacks`);
|
||||
assert.deepEqual([...new Set(ally)], [30]);
|
||||
const eg = enemy.slice(1).map((x, i) => x - enemy[i]);
|
||||
assert.ok(eg.length >= 5, `${eg.length} enemy attacks`);
|
||||
assert.deepEqual([...new Set(eg)], [90]);
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
|
||||
test('the non-integer control: 1.2 s takes 36 ticks (on time before as well), 1.25 s still ⌈37.5⌉ = 38', () => {
|
||||
for (const [bat, want] of [[1.2, 36], [1.25, 38]]) {
|
||||
const h = makeBattle({
|
||||
defs: {
|
||||
chess: { t_bat: chessRec({ id: 't_bat', stats: { bat, maxHp: 1e6 }, skill: null }) },
|
||||
enemies: { enemy_t_wall: enemyRec({ key: 'enemy_t_wall', hp: 1e9, speed: 0 }) },
|
||||
},
|
||||
units: [{ chessId: 't_bat', row: 10, col: 4 }],
|
||||
enemies: [{ key: 'enemy_t_wall', pos: [10, 5] }],
|
||||
hooks: ['attack'], captureNoisy: true, timeLimit: 60,
|
||||
});
|
||||
h.run(0.5);
|
||||
const u = h.unit('t_bat');
|
||||
const gaps = attackGaps(h, u.id, 20);
|
||||
assert.ok(gaps.length >= 10, `${bat} s: ${gaps.length} attacks`);
|
||||
assert.deepEqual([...new Set(gaps)], [want], `${bat} s`);
|
||||
checkInvariants(h.b);
|
||||
}
|
||||
});
|
||||
|
||||
test('a time skill of cost N at 1 SP/s gets each charge after exactly 30 × N more gains (one and two charges)', () => {
|
||||
// 4, 10, 16 and 50 were a tick late (their float sums fall short); a second charge counts on from the first's remainder
|
||||
for (const charges of [1, 2]) for (const cost of [4, 10, 16, 20, 30, 50]) {
|
||||
const h = makeBattle({
|
||||
defs: { chess: { t_sp: chessRec({ id: 't_sp', skill: { spCost: cost, initSp: 0, maxChargeTime: charges } }) } },
|
||||
units: [{ chessId: 't_sp', row: 10, col: 4 }],
|
||||
timeLimit: charges * cost + 10, autoFinish: false,
|
||||
});
|
||||
const u = h.unit('t_sp');
|
||||
const at = [];
|
||||
let gains = 0;
|
||||
while (u.skill.charges < charges && gains < 30 * charges * cost + 5) {
|
||||
const sp = u.skill.sp, n = u.skill.charges;
|
||||
h.step(1);
|
||||
if (u.skill.sp !== sp || u.skill.charges > n) gains++;
|
||||
if (u.skill.charges > n) at.push(gains);
|
||||
}
|
||||
assert.deepEqual(at, Array.from({ length: charges }, (_, i) => 30 * cost * (i + 1)), `cost ${cost}, ${charges} charge(s)`);
|
||||
checkInvariants(h.b);
|
||||
}
|
||||
});
|
||||
|
||||
test('the same countdown: a “双眼皮” turret at 0 layers (BAT 4 s) shoots every 120 ticks', REAL, () => {
|
||||
const ds = getDefaultSource();
|
||||
const d = ds.getStage('act2autochess_m01').devices.find((x) => x.raw?.alias === 'trap_1104_aclasert#1');
|
||||
assert.equal(d.raw.stats.bat, 4);
|
||||
const players = [{ playerId: 'p1', seat: 0, side: 'L', colOffset: 0, units: [],
|
||||
playerEffects: [{ id: 'aceffect_band_43', key: 'auto_chess_change_map', params: { 'trap_1104_aclasert#1': 1 } }] }];
|
||||
const h = makeBattle({
|
||||
stageId: 'act2autochess_m01', players, defs: { enemies: { enemy_t_wall: enemyRec({ key: 'enemy_t_wall', hp: 1e9, speed: 0 }) } },
|
||||
enemies: [{ key: 'enemy_t_wall', pos: [10, 9] }], hooks: ['attack'], captureNoisy: true, autoFinish: false, timeLimit: 60,
|
||||
});
|
||||
h.step();
|
||||
const t = h.b.allyUnits.find((u) => u.defId === 'trap_1104_aclasert');
|
||||
assert.ok(t && t.alive, 'turret online');
|
||||
const gaps = attackGaps(h, t.id, 30);
|
||||
assert.equal(t.s.interval, 4);
|
||||
assert.ok(gaps.length >= 5, `${gaps.length} shots`);
|
||||
assert.deepEqual([...new Set(gaps)], [120]);
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
|
||||
test('the same countdown: 寒檀 S2 drops an icicle every 15 ticks (BAT 2.9 − 2.4 = 0.5 s)', REAL, () => {
|
||||
const h = makeBattle({
|
||||
defs: { enemies: { enemy_t_wall: enemyRec({ key: 'enemy_t_wall', hp: 1e9, speed: 0 }) } },
|
||||
units: [{ chessId: 'chess_char_5_21_a', row: 10, col: 3 }],
|
||||
enemies: [{ key: 'enemy_t_wall', pos: [10, 4] }], autoFinish: false, timeLimit: 60,
|
||||
});
|
||||
h.step();
|
||||
const u = h.unit('chess_char_5_21_a');
|
||||
u.skill.gainSp(1000);
|
||||
assert.ok(h.runUntil(() => u.skill.active, 5));
|
||||
assert.ok(Math.abs(u.s.interval - 0.5) < 1e-12, `${u.s.interval}`);
|
||||
const at = [];
|
||||
for (let n = u.stats.attacks, i = 0; i < 150 && u.skill.active; i++) {
|
||||
h.step();
|
||||
if (u.stats.attacks > n) at.push(Math.round(h.b.time / TICK));
|
||||
n = u.stats.attacks;
|
||||
}
|
||||
const gaps = at.slice(1).map((x, i) => x - at[i]);
|
||||
assert.ok(gaps.length >= 5, `${gaps.length} icicles`);
|
||||
assert.deepEqual([...new Set(gaps)], [15]);
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
Reference in new issue
Block a user