0.2.5-dev: merge claude/036-sim

# Conflicts:
#	CHANGELOG.md
#	docs/history/0.2.5.md
#	test/golden/matches.json
This commit is contained in:
sganggs committed 2026-10-12 15:50:42 +08:00
commit 3dd2213e47
42 files changed
+2335 -961

No files matched your search

+7
View File
@@ -28,6 +28,13 @@
- 萨卡兹枯朽战士和组长在已经沉默时被击倒,不留下污染秽蚀。维护者 2026-10-12 的实机回忆是沉默能阻止这团雾,这与 PRTS / 游戏内文字「不可沉默」相反;同一死亡能力只有这两名敌人,其他枯朽敌人的沉默规则不变(#470)。0.2.0 起行为已是如此,这次记下的理由改为上述回忆。
- 调度中心 4 级的五阶晋升奖励可以出现五阶自选,5 级的六阶晋升奖励可以出现六阶自选;普通商店仍在 5 / 6 级才刷出;不保证出现;禁用和库存照旧(#515,维护者 2026-10-12 决定)。
- 驭械术师未释放的浮游改为本体攻击再加一份附加伤害(初始相当于攻击力 20%,同一目标每次 +15,上限 110%);技能放出的浮游仍造成技能伤害(PR #537,感谢 @Xinglan233)。
- 只改普攻的技能保留干员自己的那一击。耶拉二技能(基础与隐藏)放出浮游时仍打出 100% 的普通攻击,寒冷对自身和浮游各判一次;荒芜拉普兰德一技能开启后仍是本体一击加两份未释放浮游。只由浮游出手的技能不另加这一击。
- 干员再部署时浮游倍率回到初始值,并清掉按目标记住的倍率;自由移动仍保留。已经飞出的浮游按命中时的倍率结算(PR #536,感谢 @Xinglan233)。
- 洛洛二技能放出的浮游在目标离开攻击范围后继续锁定,只在击杀或技能结束时返回;技能期间不再叠加未释放浮游的附加伤害(PR #535,感谢 @Xinglan233)。
- 受击格按官方四舍六入五成双取整,被挡在场地边缘的敌人留在边缘那一格(PR #520,感谢 @Cloudnyco)。
- AI 选开局策略和构筑重心时,会软性让开仍在场队友已经选择的阵营;队友淘汰后取消。不锁库存,也不阻止立刻合成(PR #518 / #514,感谢 @IceCodeNew)。
## 0.2.4 — 2026-10-11
### 规则(按官方)
+6 -5
View File
@@ -554,7 +554,7 @@ returns their current `weight` (including modifiers). The same tick's count and
list and budget (DESIGN §28.27); this is local to the kit, not a change to general displacement.
**Hit areas (`body.js`, user playtest #5 item 10).** A regular enemy is a point: in a grid range when the tile of its
position (`round(y)`, `round(x)`) is a range tile, in a radius when its position is (DESIGN §3). A huge enemy (巨型单位:
position (`roundHalfEven(y)`, `roundHalfEven(x)` — PRTS 作战机制 "四舍六入五成双"; `Math.round` would take 2.5 to 3) is a range tile, in a radius when its position is (DESIGN §3). An enemy held on the field edge is inset by `FIELD_EDGE_INSET` (1/1048576) [ASSUMED] so that rounding keeps it on the edge tile; movement, knockback and a unit's standing tile for range keys still use `Math.round` (§30.20). A huge enemy (巨型单位:
`enemy.hitArea` from data/enemies.json `hitArea` — 假想敌:胄 / 管 / 盐风主教昆图斯 / 阿利斯泰尔 / “萨米的意志”, PRTS
"受击判定区域为长4.95、宽2.95的长方形,向上偏移1.0") is hit anywhere on a rectangle `w` × `h` tiles centred on its position
moved `dx` columns right / `dy` rows up: it occupies every tile the rectangle overlaps (`bodyKeys` — 5 × 3 tiles; PRTS
@@ -1132,7 +1132,7 @@ Element conventions of the kits (user playtest #5 #3; official term dictionary:
targeting: { maxTargets, rangeGrid, rangeExtend, priority, allInRange, canHitFly,
noRangeExtend /* the skill's range ignores the unit's 攻击距离 (rangeExtend): 信仰搅拌机 S3, PRTS 备注 */,
showOwnRange /* rangeGrid only selects targets, no official range change: the card keeps the unit's own range */ },
attack: { dmgType, atkScale, healScale, splashRadius, splashScale, hits, projectile, maxTargets, dmgMul,
attack: { dmgType, atkScale, healScale, splashRadius, splashScale, hits, funnelMul, funnelBodyHits, projectile, maxTargets, dmgMul,
chain: {count, falloff, radius, sluggish}, heal: {mode, count, falloff, hpAtMost /* targets at or below this HP ratio only */}, onHitStatus: {key, duration, value},
onHit(ctx), // once per attack (main target; target may be null for a splash landing)
onEachHit(ctx) }, // per victim: main, every splash / chain victim — ctx += { dealt, kind:'main'|'splash'|'chain', isSplash, isChain, main, attackId }
@@ -1217,10 +1217,11 @@ chess_char_2_07_a: (bb) => ({
```
**3. Instant burst caster — 至简 `chess_char_3_13_a` 神工意匠** (bb `atk_scale 1.3, ct 2`; next attack 130 % arts, hits
twice; 2 charges; the funnel profile already ramps damage on the same target):
twice; 2 charges; the funnel profile's unreleased drones are additional damage that ramps on the same target, and this
charged attack sets two body hits):
```js
chess_char_3_13_a: (bb) => ({
skill: { kind: 'charges', attack: { atkScale: bb.atk_scale, hits: 2, dmgType: 'arts' } },
skill: { kind: 'charges', attack: { atkScale: bb.atk_scale, hits: 2, funnelBodyHits: 2, dmgType: 'arts' } },
}),
```
An AoE instant (德克萨斯 剑雨, bb `stun 2`: two hits of 120 % arts around her + stun) uses `onStart` instead:
@@ -1359,7 +1360,7 @@ header of professions.js).
| loopshooter | 回环射手 (user playtest #3): every attack throws a boomerang (`ai.js throwBoomerang`, projectile `'boomerang'`) out to the target at 15 tiles/s — it hits on arrival — and back to the thrower's current position at 3.75 tiles/s without damage (PRTS 跃跃 "投射物飞行速度15,返回时飞行速度3.75"); attacks only while holding it (every boomerang thrown caught — "必须回收全部回旋投掷物才可以进行下一次攻击", `unit.trait.boomerangsOut`) and with the attack cooldown ready, so the real interval is the longer of the two; a target dead mid-flight is not hit (it still flies to the last position and back); knocked out / withdrawn ⇒ lost, a redeployed thrower holds a fresh one; 跃跃 S2's extra boomerangs share the one flight (cnt hits); each catch fires `boomerangCaught`, and an attack profile's `boomerangOnward(ctx)` flies it on after the first hit before it turns back — ctx `hit` (a hit of the same attack), `comeBack(x, y)` once (a content error sends it back from the hit point): 娜仁图亚 S1 bounces, S2 dashes on and hits on its way back (kits/ops/op-narant.js) |
| reaperrange | hits every enemy in range; ×1.5 (bb atk_scale) on the trait front grid (or its own line ahead) — both along its direction |
| chain | chain N (trait text/bb max_target) with −15 % per jump (bb chain.atk_scale), 1.7-tile jumps (constants.js CHAIN_RADIUS, PRTS 溅射半径一览: 链术师 1.7; 1.8 until 0.1.1), sluggish on each hit |
| funnel | drone damage 20 % → +15 %/hit on the same target → 110 % (bb init/delta/max) |
| funnel | normal attack: one 100 % ATK body hit plus separate drone additional damage, 20 % → +15 %/hit on the same target → 110 % (bb init/delta/max; modules can change init/cap). `funnelMul` holds the drone ramp; `dmgMul` applies to both. Extra drones (`hits`) do not duplicate the body; an unreleased skill attack can set `funnelBodyHits` (至简 S2: two body hits and two additions). Body and additions share an `attackId`, but only the body is `isAttack`; additions carry `addition, funnel`. [ASSUMED] body instances first at the existing impact, one ramp per volley. A skill that only buffs or retargets the normal attack keeps the body; `isSkill` does not remove it. `funnelBodyHits: 0` is drone-only (荒芜拉普兰德 S2). 耶拉 S2 detaches `funnelMul`: one 100 % `isAttack` body in range, the unreleased addition off, and `1 + attack@cnt` arts skill drones (`kjera:drone`, `isSkill`, not `isAttack`) that keep the lock until the enemy dies or the skill ends. [ASSUMED] Those drones use the trait ramp; her blackboard has no drone scale. The base form continues the per-target ramp (one step per volley on a shared target) and writes it back; the hidden form restarts each drone at init and does not write the scales back. [ASSUMED] No flight delay; an untargetable lock is dropped and retargeted; stun and disarm do not pause the drones. 澄闪's skills and 荒芜拉普兰德 S3 stay on their own `dealDamage` paths. A normal deployment resets target, scale and any per-target ramp map to init, including revival against the same living target. A free move (`moveRedeploy`, the same carry as a 秘术师's stored energy and 乌尔比安 S3) keeps the ramp. An in-flight drone recomputes the ramp on impact. 洛洛 S2 detaches this multiplier from new body shots and inherits the trait ramp in an independent skill tick: `rockr:drone`, arts, `isSkill:true`, `isAttack:false`. Older projectiles cannot change its local ramp. A living selectable lock need not remain in body range; the drone returns on a kill or when the skill ends, and ending hands the ramp back and restores the normal multiplier (§30.19) |
| mystic | 秘术师 (PRTS 分支特性信息 秘术师, GitHub #181): at its attack check (the attack ready, able to act, not disarmed) with no valid target — no target, or its kit's `canAttack` false (深靛 never picks a bound enemy) — it stores one energy (`storeEnergy`, up to bb times: 3, 深靛's MSC-X 4), an attack action: the attack interval restarts; a full store idles with the attack ready. The energies leave with its next attack that happens (`releaseEnergy` in `performAttack`, after `beforeAttack`: an attack cancelled before its shot keeps them) and land with the main hit, one arts attack hit each (`hitsFn` reads the hit's `info.energy`); a redeployment holds none [ASSUMED]. 维伊 / 黑键 plug their own `storeEnergy` (转置能量, elite energies) into the same check |
| phalanx | no attack & DEF +200 %, RES +20 (bb) while the skill is off; while on, `rangeAoe`: each attack strikes every selectable enemy on its range at once (blocked enemies included; a stealthed one only when revealed or blocked), the same damage near and far, instant (`'beam'`) — "群体法术伤害" (secondary: Terra Wiki, Phalanx Caster: "attacks hit all enemies within their range"; supporting: PRTS 林 S3 备注 "单次普攻最多触发1次效果" — one normal attack can kill several — the same 锁定攻击范围 shape as the 轰击术师, and PRTS 溅射半径一览 documents no splash radius for it (it omits the 撼地者 too, so this is not proof); no primary source states a target cap; community report E3: it used to be one bolt + a 1.1 splash). 卡涅利安's charged S1 keeps the skill-off trait, 不攻击 included (kit `canAttack`, PRTS 备注) |
| physician | heal the lowest HP% injured ally in range (a skill `targeting.maxTargets` widens any heal profile) |
+27
View File
@@ -186,6 +186,33 @@ Profession traits (default behaviours implemented once in the engine, keyed by `
---
Unreleased funnel drones deal additional arts damage alongside the ordinary attack (PRTS 分支特性信息 驭械术师, §30.17).
The engine keeps a 100 % ATK body instance and a separate drone instance, each through mitigation and shields.
`funnelMul` holds only the drone ramp; the attack's `dmgMul` (至简's talent) is shared once. Extra attached drones
raise `hits`, not the body count; 至简's charged S2 sets `funnelBodyHits` to two. Both share one `attackId`, attack
hook and SP / charge use; additions have `addition` and `funnel` tags and do not count as `isAttack`. [ASSUMED] Body
instances precede additions at the existing projectile impact; consecutive hits keep one ramp per volley. A skill
that only buffs or retargets the normal attack keeps the body; `isSkill` is not the switch. `funnelBodyHits === 0`
is drone-only (荒芜拉普兰德 S2): the ramp stays inside those hits. 耶拉 S2 detaches `funnelMul` the way 洛洛 S2 does:
one 100 % body inside her range, the unreleased addition off, and the released drones as separate skill hits that
keep the lock until the enemy dies or the skill ends (§30.17). 澄闪's skills stay on their own `dealDamage` paths.
Funnel ramps return to the initial scale on a normal deployment, including automatic revival against the same living
target (§30.18). The reset clears the current target, the scale and any per-target ramp map, and leaves other trait
state alone. A free move (`moveRedeploy`, the same carry as a 秘术师's stored energy and 乌尔比安 S3) keeps the ramp.
An in-flight shot recomputes the ramp when it lands, so a projectile launched before the reset can still step the new
ramp.
洛洛 S2 releases its trait drone into an independent skill tick (§30.19). Acquisition uses the body's normal target
selection; a living selectable lock stays valid outside the body's range and returns only when that enemy dies or the
skill ends. The body retains its own ranged ordinary attacks. The released ramp inherits the trait state but is
isolated from older projectiles, and while it is out the unreleased addition is off. Ending the skill returns that
ramp to the trait and restores the normal multiplier and the overload cap. S1 and other operators' funnel attacks keep
their existing paths. [ASSUMED] There is no flight delay; an untargetable lock is dropped and retargeted; body control
does not pause the released drone.
---
## 7. Content modules (server/sim/content + match/effectsMeta handlers)
Each domain file `server/sim/content/{tokens,bonds,garrisons,items,bands,enemies,bosses,devices,choices}.js` exports `install(battle)` (battle side; called once per Battle by `content/index.js → installContent`) and `registerMeta(registry)` (prep side; called once at server boot by `match/effectsMeta.js`, API documented in `docs/META.md`). Kits live one per file in `content/kits/ops/` (`export default { [baseChessId]: (bb, chess, def) => Kit }`), listed in `content/kits/index.js` (guide: `content/kits/README.md`). Content must be **data-driven from blackboards** (numbers never hard-coded when a blackboard key exists). Every effect gets at least one unit test in `test/content/*.test.js` using the `test/helpers/battleHarness.js` harness (provided by sim-core).
+4
View File
@@ -129,6 +129,10 @@ adjusted count and reset scope stay limited to its own operators; the DIY export
[ASSUMED] Bot purchasing applies one soft 18-point penalty to non-elite, non-DIY tier V/VI shared-pool cards whose
active bonds overlap another living teammate's opening strategy. Human and AI teammates are treated equally; it
neither reserves stock nor prevents a stronger purchase. Existing strategy presets and rehearsal counts are unchanged.
A living teammate's selected strategy also soft-reserves its bonds for bot strategy selection and focus planning
before any member is deployed (§30.21). The reservation ends when that teammate is eliminated. It does not hard-exclude
a strategy, reserve stock, or stop an immediate merge. A reserved strategy keeps a quarter of its unreserved draw
weight (`SOFT_BAND_RESERVE` = 0.25), so it can still be chosen. Mode-inactive bonds stay weight 0 (DESIGN §21.26).
[ASSUMED] AI reactions are cosmetic social choices, enabled by default and disabled with `SP_BOT_EMOTES=0`. Only
mixed human/AI matches emit them, through the existing whitelist and cooldown. A human emote gets at most one eligible
+183
View File
@@ -521,3 +521,186 @@ level-6 offers match the previous roll, including the one that shows the tier-6
allowed. The digest records
shop draws, fielded pieces, board hashes and the rng state, not an untaken reward card, so the stored scenario does
not move. The release-relative total against 0.2.4 stays 46.
### 30.17 Funnel normal attacks keep a body hit
PR #537 by @Xinglan233. [PRTS 分支特性信息 驭械术师](https://prts.wiki/w/分支特性信息/data) says a drone that has not
been released by a skill deals additional damage on top of the operator's attack: 20 % ATK at first, +15 on the same
target, cap 110 %. A skill-released drone deals skill damage.
The profession used to return that ramp as the whole normal-attack multiplier, so the body hit was missing.
`resolveHit` now keeps a 100 % ATK body instance and separate drone instances. `funnelMul` holds only the drone ramp;
an attack's `dmgMul` (至简's talent) is applied once to both. Extra attached drones raise `hits`, not the body count.
至简's charged S2 sets `funnelBodyHits`, so two body hits and two additions share one ramp step. Both share one
`attackId` and one attack hook; only the body is `isAttack`. Additions carry `addition` and `funnel` and are not also
emitted as a normal attack.
[ASSUMED] Body instances precede additions at the existing projectile impact, and a multi-hit volley takes one ramp
step. Ordinary attacks and any skill that only buffs or retargets the normal attack keep the body. `info.isSkill` is
not the switch: every attack or targeting override sets it. `funnelBodyHits === 0` means the attack is drone-only
(the ramp stays inside those hits and no body is added). 荒芜拉普兰德 S2 sets that. 至简 S2 sets `funnelBodyHits`
to two, so two body hits and two additions still share one ramp step.
耶拉 S2, base and hidden, follows the 洛洛 S2 split. `skchr_kjera_2` (docs/research/03-operators.md) says 自身与浮游单元
攻击, and the lock lasts until the enemy dies or the skill ends. While it runs, `funnelMul` is detached, so her own
shot is one 100 % `isAttack` hit inside her range and the unreleased addition is off. `1 + attack@cnt` drones tick
on their own (`kjera:drone`, arts, `isSkill`, not `isAttack`) and may stay outside her range. Cold is rolled once
on the body and once on each drone hit. Ending the skill restores the multiplier.
[ASSUMED] Those released drones use the trait ramp (20 % → +15 % on the same target → the cap). Her blackboard has
no drone scale; the branch page gives that ramp to drones that were not released. The base form continues its
per-target ramp, and two drones on one enemy in the same tick take one step. That map is written back when the skill
ends. The hidden form restarts each drone at the initial scale, and those scales are not written back onto the single
trait ramp. There is no flight delay. A lock that can no longer be targeted is dropped and the drone retargets. Stun
and disarm do not pause the released drones. An in-flight shot from before the skill can still step the live ramp;
the skill keeps its own copy, and a shot that lands after the skill ends can step the restored ramp.
[ASSUMED] 荒芜拉普兰德 S1 says 释放浮游单元 and does not say she stops attacking. The toggle is read as a retarget of
the unreleased attack: one body hit plus the two additions, at the raised ATK. A 洛洛-style release is not used.
澄闪's skills and 荒芜拉普兰德 S3 stay on their own `dealDamage` paths. 澄闪 S3 and the skill-drone simulator on
淬羽 are unchanged.
Kits that stored the ramp on `dmgMul` (至简, both 耶拉 forms, 澄闪 S2) now store it on `funnelMul`.
Tests: `test/sim/funnel-body.test.js`, and the funnel cases in `kits_t3`, `kits_t4`, `kits_t6`, `kits_alt_t6`,
`kits_alt_t2` and `op_gdglow`. The golden moves from this correction, measured against the candidate after §30.22,
are §30.23.
### 30.18 Redeploy resets the drone ramp
PR #536 by @Xinglan233. The same branch page says that changing target, or redeploying the operator, restores the
drone damage to its initial value at once.
`installFunnel` resets `funnelTarget`, `funnelScale` and the per-target `funnelMap` (耶拉 / 至简) on a normal
deployment, including automatic revival against the same living target. A free move (`moveRedeploy`, the same carry
as a 秘术师's stored energy and 乌尔比安 S3) keeps the ramp. An in-flight drone still applies the ramp it computes on
impact, so a shot launched before the reset can step the new ramp. That limit is documented and not changed.
Tests: `test/sim/funnel-redeploy.test.js`, `test/match/funnel-redeploy.test.js`.
### 30.19 洛洛 S2 keeps its lock outside her range
PR #535 by @Xinglan233. The official skill table `skchr_rockr_2`, as recorded in `docs/research/03-operators.md`,
says the released drone stays locked until the enemy is killed or the skill ends, then returns. Leaving her attack
range is not a return condition. The branch page says a skill-released drone deals skill damage, and that additional
damage belongs to drones that were not released.
S2 now runs one independent skill tick (`rockr:drone`, one drone at both ranks). While the skill is up the trait
multiplier is detached, so new body shots are ordinary attacks and the unreleased addition is off. The drone's hits
are arts skill damage (`isSkill`, not `isAttack`). It inherits the trait ramp on its own copy, so an older projectile
cannot change that ramp. A living selectable lock stays valid outside the body's range. Ending the skill writes the
ramp back and restores the multiplier and the overload cap. S1 and other operators' funnel attacks keep their
existing paths. 立于磐石 is unchanged.
[ASSUMED] There is no flight delay. A lock that becomes untargetable is dropped and the drone retargets. Body control
(stun and the like) does not pause the released drone.
Tests: `test/content/rockrock-s2-lock.test.js`, and the 洛洛 case in `kits_t1t2`.
### 30.20 Hit tiles use half-even rounding
PR #520 by @Cloudnyco. PRTS 作战机制 (oldid 433935, 「碰撞体积与位置识别」) says the struck unit's coordinates are
rounded half to even (四舍六入五成双) onto the tile they occupy. `Math.round` sends an exact .5 toward +∞, so an enemy
held on an outer half-tile was indexed off the board and dropped from the hit index.
`roundHalfEven` is used for hit tiles only: `body.js` `posKey`, the point cases of `bodyOnTile` and `bodyTileReach`,
the point-enemy index in `battle/queries.js`, and `targeting.js` `tileKeyOf`. Movement, knockback, `ai.js`, a unit's
standing tile for range keys, and `onFrontLine` still use `Math.round`. #519's signed-zero case in `powi` was already
on this candidate and is left as it is.
[ASSUMED] `FIELD_EDGE_INSET` = 1/1048576 pulls a clamped enemy just inside the outer half-tile, so half-even rounding
keeps it on the edge tile. An inset of 1/1024 was rejected because it moved unbalance steps. The inset has no
official source.
Tests: `test/sim/hit-tile-round.test.js`, `test/sim/detmath.test.js`, the edge landing in
`feedback5-raid-own-board`, the 连星 probe in `op_wang`, and the 麦哲伦 probe in `feedback5-wv-summon-triggers`.
### 30.21 Bots soft-reserve a living teammate's opening bonds
PR #518 by @IceCodeNew, for issue #514. This is not an official rule. It extends the accepted #407 card penalty.
Opening-band choice and focus planning used to ignore a living teammate's selected strategy until someone from it was
deployed, so a bot could take that faction's high cards. A living teammate's strategy now soft-reserves its bonds for
both choices, before any member is deployed. The reservation ends when that teammate is eliminated (`alivePlayers`).
It does not hard-exclude a strategy, reserve stock, or stop an immediate merge. A reserved band's draw weight is a
quarter of its unreserved weight (`SOFT_BAND_RESERVE` = 0.25) and stays above zero, so the strategy can still be
drawn. Focus planning applies the existing −6 teammate penalty to those bonds as well. Mode-inactive bonds stay
weight 0 (DESIGN §21.26). A solo match has no teammate to reserve against. The shared-pool −18 card penalty is
unchanged, and a stronger merge can still win it.
[ASSUMED] The quarter weight is a project choice. The PR text called the reservation soft; its diff hard-zeroed the
weight. This candidate follows the text. The reservation is equal for human and AI teammates.
Tests: the two `#514` cases in `test/match/bot-smarter.test.js`. One proves the focus leaves the reserved bond while
the teammate lives and returns after elimination. The other proves a reserved strategy is still drawn, and drawn more
often once that teammate is eliminated. The existing card test still shows a merge outscoring the −18 penalty.
### 30.22 Golden changes after the funnel, hit-tile and bot-reservation ports
All 287 scenarios were recomputed once after §30.17–§30.21 and compared with this candidate before those ports
(`HEAD` `7fd0478d`, `git show HEAD:test/golden/*.json`). No scenario was added or removed. 43 digests differ from
that candidate. They are additional to §30.9 and §30.16.
Against released 0.2.4 the total is now 64. Of the previous 45, 21 are byte-for-byte the digests already on this
candidate and are not repeated below: `roster-011`, `roster-012`, `roster-013`, `roster-032`, `roster-033`,
`roster-034`, `roster-039`, `roster-040`, `roster-043`, `bond-maniShip-high`, `bond-yanShip-low`,
`boss-boss_2-pair`, `boss-boss_5-solo`, `hidden-boss_8-pair`, `hidden-boss_9-solo`, `solo-NORMAL-2`,
`coop2-NORMAL-3`, `solo-HARD-9-boosted`, `coop2-ABYSS-10-boosted`, `standin-06`, `standin-07`. The other 24 of
those 45 moved again, and 19 scenarios that still matched 0.2.4 on this candidate now differ.
Opening strategy ids do not change in any of the 20 match digests. A solo match has no teammate, so §30.21 cannot
move one. Co-op seeds keep the same `bandId` and the same bot-draw counts except `coop4-ABYSS-7`. The recorded
match moves are battle totals from §30.17–§30.20, and the later gold and LP those totals change. No isolated
counterfactual was re-run; the groups below follow who is actually on the board.
| Cause | Changed scenarios |
|---|---|
| Funnel body hit plus redeploy reset, and 洛洛 S2's independent lock (§30.17–§30.19). These boards include 洛洛 | `roster-004`, `roster-005`, `roster-023`, `roster-024`, `bond-victoriaShip-low`, `bond-victoriaShip-high` |
| Funnel body hit plus redeploy reset (§30.17–§30.18). 至简 and/or 耶拉, not 洛洛 | `roster-007`, `roster-009`, `roster-026`, `roster-028`, `bond-deputShip-low`, `bond-emptyShip-low`, `bond-kjeragShip-high`, `bond-maniShip-low`, `bond-miraShip-low`, `bond-sargonShip-high`, `bond-soloShip-low`, `bond-visiShip-low` |
| Same body hit and redeploy reset on 荒芜拉普兰德 | `roster-017`, `roster-019`, `roster-036`, `roster-046`, `roster-047`, `boss-boss_3-pair`, `boss-boss_5-pair`, `boss-boss_7-pair`, `hidden-boss_9-pair` |
| 澄闪 DIY: the normal attack is a body hit plus one drone addition (§30.17) | `diy-098`, `diy-099` |
| Hit-tile half-even rounding and the edge inset (§30.20). No funnel operator is deployed; the damage total stays 1388100 and the hook counts and the snapshot sample at index 27 move | `standin-04` |
| Full matches. Opening bands are unchanged. Final lineups include a funnel operator, except `coop2-HARD-4` (both seats eliminated, lineup empty) and `coop3-ABYSS-5` (the surviving lineup has none), whose first divergence is round 7 and round 5; those two are the hit-tile change, or a funnel operator who is not left in the stored lineup | `solo-FUNNY-1`, `solo-FUNNY-2`, `solo-NORMAL-1`, `solo-HARD-1`, `solo-ABYSS-1`, `coop2-HARD-4`, `coop2-NORMAL-1-coverage-standins`, `coop2-NORMAL-5-coverage-diy`, `coop2-NORMAL-8-serverrun`, `coop2-NORMAL-70-diy`, `coop3-ABYSS-5`, `coop4-FUNNY-6`, `coop4-ABYSS-7` |
Result flips inside that match list: `solo-NORMAL-1` defeat → victory (team LP 0 → 2); `solo-FUNNY-1` team LP 15 → 23
and `solo-FUNNY-2` team LP 8 → 23, both still victories, with every settled round row unchanged; `coop2-NORMAL-8-serverrun`
team LP 26 → 27; `coop4-ABYSS-7` eliminated at round 12 → defeat at round 13, and its shop and bot draw counts change.
The other matches keep the same end reason. `standin-04` is the only battle in this set with no funnel operator on
the board.
### 30.23 Golden changes after the skill-only funnel body correction
All 287 scenarios were recomputed after the §30.17 correction (a skill that only buffs or retargets keeps the body;
耶拉 S2 uses the 洛洛 split) and compared with this candidate after §30.22 (`HEAD` `e0f37718`,
`git show HEAD:test/golden/*.json`). No scenario was added or removed. `fields`, `standins` and `diy` are unchanged
(澄闪 stays on `dealDamage`). 19 digests differ. They are additional to §30.9, §30.16 and §30.22. Seventeen of them
already moved in §30.22 and move again. `roster-038` and `coop2-NORMAL-14-standins` did not move in §30.22.
Opening strategy ids do not change in any of the 20 match digests. No isolated counterfactual was re-run. The roster
and bond rows name the skill index the corpus assigns: 耶拉 index 1 is 心随意动, 荒芜拉普兰德 index 0 is 慵怠者悲鸣.
至简 is on two of those roster boards at index 1; her S2 already kept two body hits, and her totals move because the
fight around 耶拉 changed.
| Cause | Changed scenarios |
|---|---|
| 耶拉 S2, base form, skill index 1. `roster-007` also fields 至简 S2 | `roster-007`, `roster-009` |
| 耶拉 S2, skill index 1. No 荒芜拉普兰德 on the board | `bond-emptyShip-low`, `bond-kjeragShip-high`, `bond-miraShip-low`, `bond-soloShip-low` |
| 荒芜拉普兰德 S1, skill index 0. The toggle keeps one body hit and both unreleased additions | `roster-036`, `roster-038` |
Battle-total flips in that table: `roster-007` killed 132 → 137, leaks 41 → 37, coins 4 → 6, deaths 11 → 10, damage
234357 → 243212 (耶拉's own damage 9204 → 17443; 至简 8936 → 9558). `roster-009` keeps the same kills and leaks;
耶拉's damage 2 → 3 and 至简's kills 28 → 29, damage 7594 → 7168. `roster-036` killed 75 → 76, leaks 55 → 54,
damage 1160465 → 1189341 (荒芜拉普兰德 60604 → 99946, kills 2 → 3). `roster-038` damage 3467641 → 3468742
(荒芜拉普兰德 kills 4 → 14, damage 106163 → 187571). The four bonds keep the same kills and leaks. `bond-emptyShip-low`
healing 381 → 362; 耶拉's damage 6585 → 11450 (kills 1 → 3), `bond-kjeragShip-high` 6927 → 16312,
`bond-miraShip-low` 10165 → 18617 (kills 2 → 4), `bond-soloShip-low` 1963 → 2764.
Match end and the final lineup. A bot's chosen skill is not stored. Where the final lineup still contains 耶拉, her
default skill is S2, which is the skill this correction changes.
| Final lineup | Changed scenarios and the recorded end |
|---|---|
| 耶拉, lineup unchanged | `solo-FUNNY-1` (`3_20_b`): victory, team LP 23 → 27; only round 8's bond layers move (steadShip 34 → 35). `solo-FUNNY-2` (`3_20_a`): victory, team LP 23 → 29; all eight stored round rows are identical, so the LP change is the boss round. `solo-NORMAL-1` (`3_20_b`): victory, team LP 2 → 11; first divergence round 10 (kjeragShip 13 → 14). `solo-HARD-1` (`3_20_a` and 至简 `3_13_a`): still a defeat, team LP 0, boss pool 215042 → 212054; first divergence round 8, the board hash. `coop2-NORMAL-8-serverrun` (ai_1 `3_20_a`): victory, team LP 27 → 37 (ai_0 LP 10 → 19, ai_1 LP 17 → 18); first divergence round 8, ai_1 killed 22 → 23, leaks 1 → 0. `coop2-NORMAL-5-coverage-diy` (ai_0 `3_20_a`): victory, team LP 33 → 34 (h_0 LP 27 → 28); first divergence round 13, ai_0's board hash, killed 26 → 21, leaks 17 → 22 |
| 耶拉 was on the pre-change lineup; that seat is then eliminated and the stored lineup is empty | `solo-ABYSS-1`: defeat at round 13 → eliminated at round 12, team LP 0 → null. The pre-change lineup had 耶拉 `3_20_a` and 至简 `3_13_a`. First divergence round 8: LP 27 → 18, killed 19 → 10, leaks 0 → 9. `coop4-ABYSS-7`: still a defeat at round 13, team LP 0, boss pool 4821366 → 3417504. ai_1 is eliminated at round 13; the pre-change lineup had 至简 `3_13_a` and 耶拉 `3_20_a`. First divergence round 8: ai_1 LP 19 → 20, killed 2 → 3, leaks 7 → 6. ai_0's lineup also changes and has no funnel chess id before or after |
| 耶拉 plus other funnel operators, lineup unchanged, same victory and the same team LP 130 | `coop4-FUNNY-6`: ai_0 耶拉 `3_20_a`, ai_1 荒芜拉普兰德 `6_18_a`, ai_3 洛洛 `2_10_a`. First divergence round 11, ai_0's kjeragShip layers 26 → 23 |
| No 耶拉 on the final lineup. The diverging round's pieces and skill choice are not stored | `coop2-NORMAL-1-coverage-standins`: still a defeat, team LP 0, boss pool 25040 unchanged. ai_0's final lineup includes 荒芜拉普兰德 `6_18_a`. First divergence round 7, the other seat's miraShip layer 5 → 6. `coop2-NORMAL-14-standins`: victory, team LP 31 → 40 (ai_0 LP 13 → 22). Neither final lineup contains a funnel chess id. First divergence round 10 bond layers (raidShip 26 → 28, steadShip 16 → 18); that round's board hash is unchanged |
+21 -8
View File
@@ -138,16 +138,26 @@ const DEFAULT_MELEE_RANGE = [[0, 0], [0, 1]];
* preferred). Alone, a band that withholds the first rounds' funds (老鲤 "资金暂存": no operator in R1–R2, every enemy
* leaks) is avoided — only 联防 teammates cover that. A band whose mechanic rides on a bond the mode switches off
* (gd.bandBondIds ∩ gd.modeInactiveBonds — 标准: 潘格尼尼 <拉特兰>, 克莱门莎 <阿戈尔>, 玛恩纳 <卡西米尔>) weighs 0, never taken
* (DESIGN §21.26); with every band excluded, the default band. One rng draw per call (deterministic per seed); modes
* without inactive bonds keep exactly the earlier picks.
* (DESIGN §21.26). [ASSUMED] A living teammate's opening strategy soft-reserves those bonds before anyone is deployed:
* the weight stays positive, at a quarter of the unreserved weight, so the strategy can still be drawn, and the
* reservation ends when that teammate is eliminated (alivePlayers). With every band excluded, the default band. One
* rng draw per call (deterministic per seed); a solo match has no teammate to reserve against.
*/
const SOFT_BAND_RESERVE = 0.25;
export function botPickBand(m, ps) {
const gd = ps?.gd || m.gd;
const ids = gd.bandIds();
if (!ids.length) return gd.defaultBandId;
const lateFunds = (id) => /暂存/.test(String(gd.band(id)?.desc || ''));
const offBond = (id) => gd.bandBondIds(id).some((b) => gd.modeInactiveBonds.has(b));
const pairs = ids.map((id) => [id, offBond(id) ? 0 : Math.max(1, (gd.startLp(id) - 18) ** 2) * (m.isSolo && lateFunds(id) ? 0.02 : 1)]);
const reserved = new Set(ps && typeof m.alivePlayers === 'function'
? m.alivePlayers().filter((p) => p !== ps).flatMap((p) => gd.bandBondIds(p.bandId))
: []);
const inactive = (id) => gd.bandBondIds(id).some((b) => gd.modeInactiveBonds.has(b));
const pairs = ids.map((id) => {
if (inactive(id)) return [id, 0];
const w = Math.max(1, (gd.startLp(id) - 18) ** 2) * (m.isSolo && lateFunds(id) ? 0.02 : 1);
return [id, gd.bandBondIds(id).some((b) => reserved.has(b)) ? w * SOFT_BAND_RESERVE : w];
});
let total = 0;
for (const [, w] of pairs) total += w;
let r = m.rngBots() * total;
@@ -348,12 +358,14 @@ function mainCoreBond(m, p) {
* The bonds the bot builds around (cached per round and owned set): `focus` = the core bond with the best
* owned members × 10 + reachable members (bondPoolStats, ≤ 4) + layers already banked (≤ 6) + 6 for last round's focus
* (commit instead of flip-flopping between equal bonds) − 6 when a teammate already builds it (its main core bond on
* its public bond strip, mainCoreBond — the shop pool is shared); `second` = the other live bond (core or add-on) with
* the most owned members whose next threshold is within reach (≥ 1 owned member). `ps._botFocusId` keeps the focus
* across rounds.
* its public bond strip, mainCoreBond — the shop pool is shared) or has selected that bond's opening strategy, even
* before anyone is deployed. The strategy reservation ends when that teammate is eliminated. `second` = the other live
* bond (core or add-on) with the most owned members whose next threshold is within reach (≥ 1 owned member).
* `ps._botFocusId` keeps the focus across rounds.
*/
export function bondPlan(m, ps, owned = ownedBonds(m, ps)) {
const key = `${m.round}|${ps.shop.level}|${[...owned.counts.entries()].map(([k, v]) => k + v).join()}`;
const livingBands = m.alivePlayers().filter((p) => p !== ps).flatMap((p) => m.gd.bandBondIds(p.bandId)).sort().join();
const key = `${m.round}|${ps.shop.level}|${[...owned.counts.entries()].map(([k, v]) => k + v).join()}|${livingBands}`;
if (ps._botFocus && ps._botFocus.key === key) return ps._botFocus;
const prev = ps._botFocusId ?? null;
const mates = new Set();
@@ -361,6 +373,7 @@ export function bondPlan(m, ps, owned = ownedBonds(m, ps)) {
if (p === ps) continue;
const b = mainCoreBond(m, p);
if (b) mates.add(b);
for (const id of m.gd.bandBondIds(p.bandId)) mates.add(id);
}
let focus = null;
let bestS = 0;
+17 -1
View File
@@ -318,13 +318,29 @@ export function resolveHit(b, u, prof, target, info, x, y) {
if (target && target.alive) {
let mulT = skillMul;
if (prof.dmgMul) { const m = typeof prof.dmgMul === 'function' ? prof.dmgMul(b, u, target) : prof.dmgMul; if (Number.isFinite(m)) mulT *= m; }
const funnelMul = prof.funnelMul ? prof.funnelMul(b, u, target) : 1;
// Unreleased drones are additional damage on the caster's attack (PRTS 驭械术师), including a skill that only
// buffs or retargets that attack. `info.isSkill` is set for every attack or targeting override, so it must not
// decide this. `funnelBodyHits === 0` is the drone-only opt-out (the ramp stays inside the hits, no body).
// A volley shares one talent roll and attackId; extra drones never duplicate the body.
// [ASSUMED] Body instances precede additions at the existing projectile impact; a multi-hit volley keeps one ramp.
const attachedFunnel = !!prof.funnelMul && prof.funnelBodyHits !== 0;
if (!attachedFunnel) mulT *= funnelMul;
const hits = prof.hitsFn ? prof.hitsFn(b, u, info) : Math.max(1, prof.hits || 1);
// `hitDmgMul` (professions.js header): each instance's 伤害倍率 — the DamageInfo `mul`, after DEF / RES — and only the
// first instance may give 受击回复 (砾's two 50 % hits, PRTS 砾 特性备注)
const split = Number.isFinite(prof.hitDmgMul) && prof.hitDmgMul > 0 ? prof.hitDmgMul : null;
let dealtMain = 0;
if (attachedFunnel && info.index === 0) {
const bodyHits = Math.max(1, prof.funnelBodyHits > 0 ? prof.funnelBodyHits : 1);
for (let h = 0; h < bodyHits && target.alive; h++) {
dealtMain += b.dealDamage(u, target, { amount: atk * scale * mulT, type: baseType,
isAttack: true, isSkill: info.isSkill, tags: prof.tags || [], attackId });
}
}
for (let h = 0; h < hits && target.alive; h++) {
const d = { amount: atk * scale * mulT, type: baseType, isAttack: true, isSkill: info.isSkill, tags: prof.tags || [], attackId };
const d = { amount: atk * scale * mulT * (attachedFunnel ? funnelMul : 1), type: baseType,
isAttack: !attachedFunnel, isSkill: info.isSkill, tags: attachedFunnel ? [...(prof.tags || []), 'addition', 'funnel'] : (prof.tags || []), attackId };
if (split != null) { d.mul = split; if (h > 0) d.noSp = true; }
dealtMain += b.dealDamage(u, target, d);
}
+2 -1
View File
@@ -6,6 +6,7 @@
import { ROWS, COLS } from '../constants.js';
import { absoluteRangeKeys, canTargetEnemy, extendedGrid, enemyStealthed } from '../targeting.js';
import { bodyKeys, bodyInKeys, bodyInRadius } from '../body.js';
import { roundHalfEven } from '../detmath.js';
export class BattleQueries {
/**
@@ -21,7 +22,7 @@ export class BattleQueries {
for (const k of bodyKeys(e)) { const b = this._eb[k]; if (!b.length) this._ebUsed.push(k); b.push(e); }
continue;
}
const r = Math.round(e.y), c = Math.round(e.x);
const r = roundHalfEven(e.y), c = roundHalfEven(e.x); // the tile body.js gives a point enemy
if (r < 0 || r >= ROWS || c < 0 || c >= COLS) continue;
const k = r * COLS + c;
const b = this._eb[k];
+6 -6
View File
@@ -4,7 +4,7 @@
// and the list compaction.
// Installed on Battle.prototype by server/sim/Battle.js (a method container: never instantiated; `this` is the battle).
import { MAX_ALIVE_ENEMIES } from '../constants.js';
import { MAX_ALIVE_ENEMIES, FIELD_EDGE_INSET } from '../constants.js';
import { Unit } from '../units.js';
import { compileRoute } from '../ai.js';
import { unitInfo } from '../snapshot.js';
@@ -201,11 +201,11 @@ export class BattleSpawns {
}
_clampPos(e) {
const R = this.rect;
if (e.x < R.c0 - 0.5) e.x = R.c0 - 0.5;
if (e.x > R.c1 + 0.5) e.x = R.c1 + 0.5;
if (e.y < R.r0 - 0.5) e.y = R.r0 - 0.5;
if (e.y > R.r1 + 0.5) e.y = R.r1 + 0.5;
const R = this.rect, m = 0.5 - FIELD_EDGE_INSET; // inside the edge: on the edge tile, never halfway (body.js)
if (e.x < R.c0 - m) e.x = R.c0 - m;
if (e.x > R.c1 + m) e.x = R.c1 + m;
if (e.y < R.r0 - m) e.y = R.r0 - m;
if (e.y > R.r1 + m) e.y = R.r1 + m;
}
_compactEnemies() {
+7 -6
View File
@@ -1,8 +1,9 @@
// server/sim/body.js — where a unit can be hit: the ONE helper behind every range test that targets enemies (user
// playtest #5 item 10: "大体型的关底boss实际受击判定范围很小…原版是很大的一片区域").
//
// Regular units are a point: in a grid range when the tile containing their position (round(y), round(x)) is a range
// tile, in a radius when their position is (DESIGN §3). Huge units (巨型单位 — enemy data `hitArea`, tools/build-data.mjs
// Regular units are a point: in a grid range when the tile containing their position is a range tile — the position
// rounded half to even (detmath roundHalfEven; PRTS 作战机制 "受击方坐标经round函数取整(四舍六入五成双)得到其所属格
// 坐标") —, in a radius when their position is (DESIGN §3). Huge units (巨型单位 — enemy data `hitArea`, tools/build-data.mjs
// HIT_AREAS, from PRTS "巨型单位:受击判定区域为长4.95、宽2.95的长方形,向上偏移1.0") are hit anywhere on a rectangle
// `w` tiles along the columns × `h` along the rows, centred on their position moved `dx` columns right and `dy` rows
// up:
@@ -24,7 +25,7 @@
// `hitRect`).
import { ROWS, COLS } from './constants.js';
import { hypot } from './detmath.js';
import { hypot, roundHalfEven } from './detmath.js';
/**
* Validated hit area of a data record (`{ w, h, dx, dy }`, tiles) or null for a regular (point) unit.
@@ -47,7 +48,7 @@ export function hitRect(u) {
/** Tile key of a unit's position (-1 off the grid). */
function posKey(u) {
const r = Math.round(u.y), c = Math.round(u.x);
const r = roundHalfEven(u.y), c = roundHalfEven(u.x);
return r < 0 || r >= ROWS || c < 0 || c >= COLS ? -1 : r * COLS + c;
}
@@ -68,7 +69,7 @@ export function bodyKeys(u) {
/** Does the unit occupy tile (r, c)? */
export function bodyOnTile(u, r, c) {
const R = hitRect(u);
if (!R) return Math.round(u.y) === r && Math.round(u.x) === c;
if (!R) return roundHalfEven(u.y) === r && roundHalfEven(u.x) === c;
return c + 0.5 > R.x0 + 1e-9 && c - 0.5 < R.x1 - 1e-9 && r + 0.5 > R.y0 + 1e-9 && r - 0.5 < R.y1 - 1e-9;
}
@@ -100,7 +101,7 @@ export function bodyInRadius(u, x, y, r) {
* around it; …): "周围八格"-style square areas centred on a tile.
*/
export function bodyTileReach(u, r, c) {
if (!u.hitArea) return Math.max(Math.abs(Math.round(u.y) - r), Math.abs(Math.round(u.x) - c));
if (!u.hitArea) return Math.max(Math.abs(roundHalfEven(u.y) - r), Math.abs(roundHalfEven(u.x) - c));
let best = Infinity;
for (const k of bodyKeys(u)) {
const kr = Math.floor(k / COLS), kc = k % COLS;
+9
View File
@@ -220,6 +220,15 @@ export const MAX_ALIVE_ENEMIES = 600;
/** Heal-over-time / regen events are aggregated and only emitted when they reach this amount. */
export const REGEN_EVENT_MIN = 1;
/**
* How far inside the field rectangle an enemy is held (tiles; Battle._clampPos). [ASSUMED] The rectangle's edge lies
* exactly halfway between two tiles, where the tile of a position — rounded half to even (body.js; PRTS 作战机制
* 四舍六入五成双) — would depend on whether the row or column number is even. Held this little inside, an enemy at the
* edge stays on the edge tile. 2^-20 is exact in binary and too small to move a slide of 0.1-tile steps; a 1/1024 inset
* did move those steps.
*/
export const FIELD_EDGE_INSET = 1 / 1048576;
/** Row offset mapping board rows (9..12) onto boss-field rows (2..5). */
export const BOSS_ROW_OFFSET = -7;
@@ -1,21 +1,30 @@
// server/sim/content/kits/ops/chess_char_2_10-rockr.js — 洛洛 (char_4040_rockr) kit, tier 2.
// Conventions of the tier-2 kits: ../shared/tier2.js; kit contract and rules: ../README.md.
import { canTargetEnemy } from '../../../targeting.js';
import { bodyInKeys } from '../../../body.js';
import { canTargetEnemy, sortEnemyTargets } from '../../../targeting.js';
import { num, talentBb, up } from '../shared/tier1.js';
import { onDefaultSkill } from '../shared/tier2.js';
export const DRONE_TAG = 'rockr:drone';
const firstTarget = (battle, unit) => {
const prof = unit.profile;
const candidates = battle.enemiesInKeys(unit.rangeKeys, unit, prof);
for (const e of battle.blockedTargets(unit, prof)) if (!candidates.includes(e)) candidates.push(e);
sortEnemyTargets(battle, unit, candidates, prof.priority);
return candidates[0] ?? null;
};
export default {
// ---------------------------------------------------------------------------------------------------------------
// 2_10 洛洛 自负此轭: ASPD +attack_speed; the drones lock on their target until it dies or the skill ends.
// 2_10 洛洛 自负此轭: ASPD +attack_speed. The skill releases its drone, which keeps the lock after the target leaves
// her range and returns only when that enemy dies or the skill ends (docs/research/03-operators.md, skchr_rockr_2).
// While it is out, the unreleased drone's additional damage is off and the drone's own hits are skill damage.
// 过载 (term ba.overdrive "技能进行到一半时触发额外效果"): the second half of the duration — ATK +atk and the funnel cap
// ×scale; when the skill ends she is stunned as long as the overload lasted. 立于磐石: ATK +atk per `interval` s on the
// field, up to max_stack_cnt stacks.
// S1 战术咏唱·γ型 (alt): ASPD +attack_speed; the target lock belongs to 自负此轭 only.
chess_char_2_10_a: (bb, chess) => {
const t = talentBb(chess, 0);
const s2 = onDefaultSkill(chess);
const endOverload = (battle, unit) => {
if (unit.mem.rockFunnel) { unit.profile.funnel = unit.mem.rockFunnel; unit.mem.rockFunnel = null; }
battle.removeBuff(unit, 'rockr:overload');
@@ -26,19 +35,53 @@ export default {
onStart({ battle, unit, skill }) {
unit.mem.rockOverAt = battle.time + skill.duration / 2;
unit.mem.rockOver = false;
unit.mem.rockLock = null;
// The released drone inherits the trait's ramp; the body still attacks only inside its own range.
// `funnelMul` separates the addition; older profiles fold it into `dmgMul`. Keep launched shots unchanged.
const key = typeof unit.profile.funnelMul === 'function' ? 'funnelMul' : 'dmgMul';
const mul = unit.profile[key];
unit.profile = { ...unit.profile, [key]: null };
const lock = firstTarget(battle, unit);
unit.mem.rockDrone = { lock, cd: 0, key, mul,
target: unit.trait.funnelTarget, scale: unit.trait.funnelScale };
unit.mem.rockLock = lock;
},
onTick({ battle, unit }) {
if (unit.mem.rockOver || battle.time + 1e-9 < unit.mem.rockOverAt) return;
unit.mem.rockOver = true;
onTick({ battle, unit, dt }) {
if (!unit.mem.rockOver && battle.time + 1e-9 >= unit.mem.rockOverAt) {
unit.mem.rockOver = true;
const f = unit.profile.funnel;
if (f) { unit.mem.rockFunnel = f; unit.profile.funnel = { ...f, max: f.max * num(bb.scale, 1) }; }
battle.addBuff(unit, { key: 'rockr:overload', mods: { atkPct: num(bb.atk) }, visible: true, tags: ['skill'] });
battle.fx('overload', { x: unit.x, y: unit.y, id: unit.id });
}
const d = unit.mem.rockDrone;
if (!d || !unit.alive || !unit.skill.active) return;
d.cd = Math.max(0, d.cd - dt);
// [ASSUMED] A newly unselectable lock is dropped and the drone retargets. No flight delay, and body control
// (stun and the like) does not pause the released drone — same as the other independent skill drones.
if (d.lock && !canTargetEnemy(unit, d.lock, unit.profile)) d.lock = null;
if (!d.lock) d.lock = firstTarget(battle, unit);
unit.mem.rockLock = d.lock;
if (!d.lock || d.cd > 1e-9) return;
d.cd = unit.s.interval;
// Official S2 releases one drone (1 + attack@cnt = 1 at both ranks). The ramp lives on the drone, so a
// pre-skill projectile that lands later cannot change it.
const f = unit.profile.funnel;
if (f) { unit.mem.rockFunnel = f; unit.profile.funnel = { ...f, max: f.max * num(bb.scale, 1) }; }
battle.addBuff(unit, { key: 'rockr:overload', mods: { atkPct: num(bb.atk) }, visible: true, tags: ['skill'] });
battle.fx('overload', { x: unit.x, y: unit.y, id: unit.id });
d.scale = d.target === d.lock.id ? Math.min(f.max, (d.scale ?? f.init) + f.delta) : f.init;
d.target = d.lock.id;
battle.fx('drone', { x: d.lock.x, y: d.lock.y, id: unit.id });
battle.dealDamage(unit, d.lock, { amount: unit.s.atk * unit.s.atkScaleMul * d.scale,
type: 'arts', isSkill: true, isAttack: false, tags: ['skill', 'drone', DRONE_TAG] });
},
onEnd({ battle, unit, reason }) {
const over = unit.mem.rockOver ? battle.time - unit.mem.rockOverAt : 0;
const d = unit.mem.rockDrone;
unit.mem.rockDrone = null;
endOverload(battle, unit);
if (d) {
unit.trait.funnelTarget = d.target;
unit.trait.funnelScale = d.scale;
unit.profile = { ...unit.profile, [d.key]: d.mul };
}
unit.mem.rockOver = false;
unit.mem.rockLock = null;
if (over > 0 && reason !== 'death' && unit.alive) battle.applyStatus(unit, 'stun', { duration: over, source: unit });
@@ -46,12 +89,6 @@ export default {
},
skills: { 'skcom_magic_rage[3]': { kind: 'duration', mods: { aspd: num(bb.attack_speed) } } },
talents: [{ install(battle, unit) {
if (s2) battle.on('beforeAttack', (ctx) => {
if (ctx.attacker !== unit || !unit.skill?.active) return;
const L = unit.mem.rockLock;
if (L && L.alive && bodyInKeys(L, unit.rangeKeySet) && canTargetEnemy(unit, L, ctx.profile || unit.profile)) ctx.targets = [L];
else unit.mem.rockLock = ctx.targets[0] ?? null;
}, { owner: unit });
const iv = num(t.interval), max = Math.floor(num(t.max_stack_cnt)), v = num(t.atk);
if (!(iv > 0) || !(max > 0) || !v) return;
battle.on('tick', () => {
@@ -12,10 +12,10 @@ export default {
const hits = textNum(d.skill?.description, /连续攻击(\d+|[一二两三四五])次/, 2);
const insight = (battle) => (battle.rng.chance(num(t0.prob, 0)) ? num(t0.atk_scale, 1) : 1);
return {
trait: { dmgMul: (battle, unit, target) => funnelMap(battle, unit, target) * insight(battle) },
trait: { funnelMul: funnelMap, dmgMul: insight },
skill: {
kind: charges > 1 ? 'charges' : 'instant',
attack: { atkScale: num(bb.atk_scale, 1), hits, dmgType: 'arts', dmgMul: (battle) => insight(battle) },
attack: { atkScale: num(bb.atk_scale, 1), hits, funnelBodyHits: hits, dmgType: 'arts', dmgMul: insight },
},
// S1 迅捷打击·γ型: ATK / ASPD + (the drones' ramp and 忽有所悟 stay on every attack through the trait)
skills: altSkills(chess, d, bb, { 'skcom_quickattack[3]': statSkill }),
@@ -2,42 +2,136 @@
// Conventions of the tier-3 kits: ../shared/tier3.js; kit contract and rules: ../README.md.
import { COLS } from '../../../constants.js';
import { canTargetEnemy, sortEnemyTargets } from '../../../targeting.js';
import { num, defOf, talentBb, altSkills, statSkill, funnelMap, installFunnelPrune } from '../shared/tier3.js';
export const DRONE_TAG = 'kjera:drone';
// One step of the per-target ramp. Two drones that hit the same enemy in the same tick share the step (funnelMap).
function stepMap(ramp, id, time, f) {
const prev = ramp.get(id);
if (prev && prev.t === time) return prev.s;
const s = prev == null ? f.init : Math.min(f.max, prev.s + f.delta);
ramp.set(id, { s, t: time });
return s;
}
function acquire(battle, unit, rel) {
const prof = unit.profile;
const ok = (e) => !!e && e.alive && canTargetEnemy(unit, e, prof);
const cands = battle.enemiesInKeys(unit.rangeKeys, unit, prof);
for (const e of battle.blockedTargets(unit, prof)) if (!cands.includes(e)) cands.push(e);
sortEnemyTargets(battle, unit, cands, prof.priority);
const usable = cands.filter(ok);
const held = new Set();
for (const d of rel.drones) {
if (d.lock && ok(d.lock)) held.add(d.lock);
else { d.lock = null; d.scale = null; }
}
for (const d of rel.drones) {
if (d.lock) continue;
const e = usable.find((x) => !held.has(x)) ?? usable[0] ?? rel.drones.find((x) => x.lock)?.lock ?? null;
if (!e) continue;
held.add(e);
d.lock = e;
d.scale = null;
}
}
/**
* 心随意动 (skchr_kjera_2, docs/research/03-operators.md): release `1 + attack@cnt` drones that stay locked until the
* enemy dies or the skill ends, ATK +, and a cold roll on her own attack and on each drone hit. The body keeps its
* ordinary attack inside her range; the unreleased addition is off while the drones are out.
* `restart` (hidden form): each drone begins at the trait's initial scale and is not written back.
* Otherwise the drones continue the per-target ramp and that map is restored when the skill ends.
* [ASSUMED] The released drones use the trait ramp (init / +delta / cap). Her blackboard has no drone scale.
* [ASSUMED] No flight delay. A lock that can no longer be targeted is dropped and the drone retargets. Stun and
* disarm do not pause the released drones (the skill tick still runs).
*/
export function kjeraRelease(bb, { restart = false, announce = false } = {}) {
const n = 1 + Math.max(0, Math.floor(num(bb['attack@cnt'], 0)));
const prob = num(bb['attack@prob'], 0), cold = num(bb['attack@cold'], 0);
return {
skill: {
kind: 'duration',
mods: { atkPct: num(bb.atk) },
onStart({ battle, unit }) {
const key = typeof unit.profile.funnelMul === 'function' ? 'funnelMul' : 'dmgMul';
const mul = unit.profile[key];
unit.profile = { ...unit.profile, [key]: null };
const ramp = restart ? null : new Map();
if (ramp && unit.trait.funnelMap) {
for (const [id, v] of unit.trait.funnelMap) ramp.set(id, { s: v.s, t: v.t });
}
unit.mem.kjeraRel = {
key, mul, restart, ramp, cd: 0,
target: unit.trait.funnelTarget ?? null,
scale: unit.trait.funnelScale,
drones: Array.from({ length: n }, () => ({ lock: null, scale: null })),
};
if (announce) battle.fx('drones', { x: unit.x, y: unit.y, id: unit.id, n });
},
onTick({ battle, unit, dt }) {
const rel = unit.mem.kjeraRel;
if (!rel || !unit.alive || !unit.skill?.active) return;
rel.cd = Math.max(0, rel.cd - dt);
acquire(battle, unit, rel);
if (!rel.drones.some((d) => d.lock) || rel.cd > 1e-9) return;
rel.cd = unit.s.interval;
const f = unit.profile.funnel || { init: 0.2, delta: 0.15, max: 1.1 };
for (const d of rel.drones) {
if (!d.lock || !d.lock.alive) continue;
const scale = rel.restart
? (d.scale = d.scale == null ? f.init : Math.min(f.max, d.scale + f.delta))
: stepMap(rel.ramp, d.lock.id, battle.time, f);
battle.fx('drone', { x: d.lock.x, y: d.lock.y, id: unit.id });
battle.dealDamage(unit, d.lock, {
amount: unit.s.atk * unit.s.atkScaleMul * scale, type: 'arts',
isSkill: true, isAttack: false, tags: ['skill', 'drone', DRONE_TAG],
});
if (d.lock.alive && cold > 0 && battle.rng.chance(prob)) {
battle.applyStatus(d.lock, 'cold', { duration: cold, source: unit });
}
}
},
onEnd({ unit }) {
const rel = unit.mem.kjeraRel;
unit.mem.kjeraRel = null;
if (!rel) return;
unit.trait.funnelTarget = rel.target;
unit.trait.funnelScale = rel.scale;
if (rel.ramp) unit.trait.funnelMap = rel.ramp;
if (unit.profile && rel.key) unit.profile = { ...unit.profile, [rel.key]: rel.mul };
},
},
install(battle, unit) {
// 自身攻击: one cold roll on the ordinary body hit. Drone hits roll in onTick, so they are not rolled again.
battle.on('damaged', (ctx) => {
if (!unit.mem.kjeraRel || ctx.source !== unit || !ctx.target?.alive || !ctx.dmg) return;
if (!ctx.dmg.isAttack || ctx.dmg.isSkill) return;
const tags = ctx.dmg.tags || [];
if (tags.includes('addition') || tags.includes('funnel') || tags.includes(DRONE_TAG)) return;
if (!(cold > 0) || !battle.rng.chance(prob)) return;
battle.applyStatus(ctx.target, 'cold', { duration: cold, source: unit });
}, { owner: unit });
},
};
}
export default {
// ---- 3_20 耶拉 · 驭械术师 — S2 心随意动: +1 drone (2 locks; a lone enemy gets both), ATK +, cold procs; 低眉: ATK +
// (more with ≥cnt ground tiles in range)
// (more with ≥cnt ground tiles in range). S1 攻击力强化·γ型: ATK + only (one unreleased drone, the trait ramp).
chess_char_3_20_a: (bb, chess, def) => {
const d = defOf(chess, def);
const t0 = talentBb(d, 0);
const extra = Math.floor(num(bb['attack@cnt'], 0));
const prob = num(bb['attack@prob'], 0), cold = num(bb['attack@cold'], 0);
const kit = {
trait: { dmgMul: funnelMap },
skill: {
kind: 'duration',
mods: { atkPct: num(bb.atk) },
attack: { onHit({ battle, unit, target }) {
if (target && target.alive && cold > 0 && battle.rng.chance(prob)) battle.applyStatus(target, 'cold', { duration: cold, source: unit });
} },
},
// S1 攻击力强化·γ型: ATK + (one drone, the trait ramp as usual)
const rel = kjeraRelease(bb, { restart: false });
return {
trait: { funnelMul: funnelMap },
skill: rel.skill,
skills: altSkills(chess, d, bb, { 'skcom_atk_up[3]': statSkill }),
install(battle, unit) {
installFunnelPrune(battle, unit);
// "浮游单元+1": every drone locks an enemy — with fewer enemies in range than drones, the spare drone joins a
// lock (both attack it, each hit rolls the cold proc; they ramp in parallel, see funnelMap)
if (extra > 0) {
battle.on('beforeAttack', (ctx) => {
if (ctx.attacker !== unit || !unit.skill?.active || !ctx.targets.length) return;
const n = 1 + extra;
if (ctx.targets.length >= n) return;
const base = ctx.targets.slice();
const out = base.slice();
for (let i = 0; out.length < n; i++) out.push(base[i % base.length]);
ctx.targets = out;
}, { owner: unit, priority: -50 });
}
rel.install(battle, unit);
},
talents: [{ install(battle, unit) {
battle.on('deploy', (ctx) => {
@@ -52,7 +146,5 @@ export default {
}, { owner: unit });
} }],
};
if (extra > 0) kit.skill.targeting = { maxTargets: 1 + extra };
return kit;
},
};
@@ -2,35 +2,18 @@
// Conventions of the tier-4 kits: ../shared/tier4.js; kit contract and rules: ../README.md.
import { COLS } from '../../../constants.js';
import { canTargetEnemy } from '../../../targeting.js';
import { num, tbb, skillActive, withDefaults } from '../shared/tier4.js';
import { num, tbb, withDefaults } from '../shared/tier4.js';
import { kjeraRelease } from './chess_char_3_20-kjera.js';
export default withDefaults({
// ===== 耶拉 (funnel, hidden) S2 心随意动 — +1 drone locking targets, ATK up, chance to chill; talent 低眉
// ===== 耶拉 (funnel, hidden) S2 心随意动 — +1 drone locking targets, ATK up, chance to chill; talent 低眉.
// Each released drone restarts at the trait's initial scale (it does not continue the pre-skill ramp) and those
// scales are not written back onto the single trait ramp. The body stays an ordinary in-range attack.
chess_char_4_03_a: (bb, chess, def) => {
const t0 = tbb(def, 0);
const n = 1 + Math.max(0, Math.floor(num(bb['attack@cnt'], 1)));
const prob = num(bb['attack@prob'], 0), cold = num(bb['attack@cold'], 0);
const funnel = (unit) => unit.profile.funnel || { init: 0.2, delta: 0.15, max: 1.1 };
const rel = kjeraRelease(bb, { restart: true, announce: true });
return {
skill: {
kind: 'duration',
mods: { atkPct: num(bb.atk) },
targeting: { maxTargets: n },
attack: {
// every drone ramps on its own locked target (trait init/delta/max): the multipliers are queued per target
// by the beforeAttack hook below (two drones on the same enemy ramp independently)
dmgMul: (battle, unit, target) => {
const q = unit.mem.kjeraQueue && unit.mem.kjeraQueue.get(target.id);
return q && q.length ? q.shift() : funnel(unit).init;
},
onHit({ battle, unit, target }) {
if (target && target.alive && cold > 0 && battle.rng.chance(prob)) battle.applyStatus(target, 'cold', { duration: cold, source: unit });
},
},
onStart({ battle, unit }) { unit.mem.kjeraDrones = []; unit.mem.kjeraQueue = new Map(); battle.fx('drones', { x: unit.x, y: unit.y, id: unit.id, n }); },
onEnd({ unit }) { unit.mem.kjeraDrones = []; unit.mem.kjeraQueue = null; },
},
skill: rel.skill,
talents: [{ install(battle, unit) { // 低眉: ATK +10 %, +16 % with ≥ 2 ground tiles in range
battle.on('deploy', (c) => {
if (c.unit !== unit) return;
@@ -40,38 +23,7 @@ export default withDefaults({
battle.addBuff(unit, { key: 'kjera:t1', mods: { atkPct: v } });
}, { owner: unit });
} }],
install(battle, unit) {
// n drones, each locked on its enemy until that enemy dies (while at least one enemy is in her range). A free
// drone takes an enemy no other drone holds, else doubles up on the best target (a lone enemy/boss gets both).
battle.on('beforeAttack', (c) => {
if (c.attacker !== unit || !skillActive(unit)) return;
const ok = (e) => !!e && e.alive && canTargetEnemy(unit, e, { canHitFly: true });
const cands = c.targets.filter(ok);
const drones = unit.mem.kjeraDrones || (unit.mem.kjeraDrones = []);
const held = new Set();
for (let i = 0; i < n; i++) { if (drones[i] && ok(drones[i].e)) held.add(drones[i].e); else drones[i] = null; }
for (let i = 0; i < n; i++) {
if (drones[i]) continue;
const e = cands.find((x) => !held.has(x)) ?? cands[0] ?? drones.find((d) => d)?.e;
if (!e) continue;
held.add(e);
drones[i] = { e, scale: null };
}
const f = funnel(unit);
const q = unit.mem.kjeraQueue || (unit.mem.kjeraQueue = new Map());
const out = [];
for (const d of drones) {
if (!d) continue;
d.scale = d.scale == null ? f.init : Math.min(f.max, d.scale + f.delta);
out.push(d.e);
const l = q.get(d.e.id);
if (l) l.push(d.scale); else q.set(d.e.id, [d.scale]);
}
if (out.length) c.targets = out;
}, { owner: unit, priority: 10 });
// queued multipliers of shots that never landed (target died mid-flight) are dropped with the target
battle.on('death', (c) => { if (c.unit.side === 'enemy' && unit.mem.kjeraQueue) unit.mem.kjeraQueue.delete(c.unit.id); }, { owner: unit });
},
install(battle, unit) { rel.install(battle, unit); },
};
},
});
@@ -124,8 +124,10 @@ function whitw2(bb, chess, def) {
const skills = {
// S1 慵怠者悲鸣: passive 浮游单元+1 (trait: one more hit per attack); toggled on: ATK +atk and the drones lock a random
// non-moving enemy anywhere on the field (re-locking when it moves or falls; install), else her range. The whole-field
// grid only selects those targets — no rangeId, no 攻击范围 in the text — so the card keeps her 3-1 (showOwnRange)
// non-moving enemy anywhere on the field (re-locking when it moves or falls; install), else her range. The toggle
// retargets her attack; the text does not say she stops attacking, so the body and both unreleased additions stay.
// The whole-field grid only selects those targets — no rangeId, no 攻击范围 in the text — so the card keeps her 3-1
// (showOwnRange)
skchr_whitw2_1: {
kind: 'toggle',
// [ASSUMED] her drones lock enemies only (install): 白铁's 铁钳号 alone does not open S1 / S2 (skills.js allyTargetsOk)
@@ -143,7 +145,9 @@ function whitw2(bb, chess, def) {
...(skillGridW ? { targeting: { rangeGrid: skillGridW } } : {}),
attack: {
hits: 1,
dmgMul(battle, unit, target) {
// The skill names the released drones, not a second hit from her. 0 keeps the ramp inside these hits.
funnelBodyHits: 0,
funnelMul(battle, unit, target) {
const f = unit.profile?.funnel || { init: 0.2, delta: 0.15, max: 1.1 };
const m = unit.mem.hunt;
if (!m) return f.init;
+1 -1
View File
@@ -17,7 +17,7 @@
// projectile_chr_gdglow_funnel_s1_1 … s3_3 (`_lifeTimeType` 2: until stopped, `_stopWhenSourceInvalid`, its crash
// AdvancedApplyDamage MAGICAL at atk_scale_2) and their s12 / s3 blast projectiles.
// - Trait (驭械术师) "操作浮游单元造成法术伤害;单元攻击同一敌人伤害提升(最高造成干员110%攻击力的伤害)" (trait bb init / delta /
// max_atk_scale): the engine's funnel profile (professions.js: her normal attack = one drone hit at init → +delta per hit on
// max_atk_scale): the engine's funnel profile (professions.js: her normal attack = a body hit plus one drone addition at init → +delta per hit on
// the same target → max). FUN-X: init 0.35 ("单元初始伤害提高"); FUN-Y: max 1.2. Ranged arts, 3-1, hits air (PRTS "可对空"),
// blocks 1, ground enemies target her.
// - Skill drones (the three skills "浮游单元+N,释放浮游单元锁定敌人攻击 … 锁敌后直至敌人被击杀、自爆或技能结束后返回干员身边"): while a
+12
View File
@@ -10,6 +10,7 @@
// test/sim/detmath.test.js scans server/sim/).
//
// hypot(x, y) √(x² + y²) as Math.sqrt(x*x + y*y), rescaled by exact powers of two outside 2^±500
// roundHalfEven(x) nearest integer, ties to even (四舍六入五成双); Math.round and Math.floor, never −0
// powi(x, n) xⁿ for an integer n: square-and-multiply in double-double, one final rounding
// sin(x), cos(x) fdlibm 5.3 (__kernel_sin / __kernel_cos / __ieee754_rem_pio2)
// atan2(y, x) fdlibm (FreeBSD msun e_atan2.c / s_atan.c)
@@ -46,6 +47,17 @@ export function hypot(x, y) {
return Math.sqrt(x * x + y * y);
}
/**
* x rounded to an integer, ties to even (2.5 → 2, 3.5 → 4, −2.5 → −2): the rule PRTS 作战机制 gives for the tile of a
* target — 受击方坐标经round函数取整(四舍六入五成双)得到其所属格坐标. Math.round rounds ties up (2.5 → 3). Exact; never −0.
* @param {number} x
*/
export function roundHalfEven(x) {
const f = Math.floor(x);
if (x - f !== 0.5) return Math.round(x) + 0;
return (f % 2 === 0 ? f : f + 1) + 0;
}
// ---- integer powers ----------------------------------------------------------------------------------------------
const SPLIT = 134217729; // 2^27 + 1 (Dekker)
+15 -3
View File
@@ -21,6 +21,9 @@
// noAttack bool (never attacks) noAttackUnlessSkill bool (attacks only while its skill is active)
// noHeal bool (cannot be healed by others) blockFly bool onHitStatus {key, duration, value}
// dmgMul(battle, unit, target) → number afterHit(battle, unit, target, {dealt,x,y})
// funnelMul(battle, unit, target) → number (drone ramp, separate from the caster's attack multiplier)
// funnelBodyHits n (body hits kept beside that ramp. Omit it for one. 0: drone-only, ramp folded into the hits,
// no body — 荒芜拉普兰德 S2. >0: that many body hits — 至简 S2. Not keyed off the skill flag)
// canAttack(battle, unit) → bool afterAttack(battle, unit, targets)
// skipEnemy(enemy) → bool (an enemy the unit never selects — targeting.js canTargetEnemy; 嵯峨 "不攻击重伤单位")
// healThrough(healer, ally) → bool (a healer that selects and heals that ally through its 禁疗 — Battle
@@ -385,8 +388,17 @@ const installTactician = (battle, unit) => {
};
const installFunnel = (battle, unit) => {
unit.trait.funnelTarget = null;
unit.trait.funnelScale = unit.profile.funnel?.init ?? 0.2;
// PRTS 分支特性信息 驭械术师: changing the target, or redeploying, resets the drone ramp at once, even against the
// same living enemy. The per-target map (耶拉 / 至简) resets with it. A free move (moveRedeploy, the same carry as a
// 秘术师's stored energy and 乌尔比安 S3) keeps the ramp. An in-flight drone still applies the ramp it computes on
// impact, so a shot launched before the reset can step the new ramp.
const reset = () => {
unit.trait.funnelTarget = null;
unit.trait.funnelScale = unit.profile.funnel?.init ?? 0.2;
unit.trait.funnelMap?.clear();
};
reset();
battle.on('deploy', (ctx) => { if (ctx.unit === unit && !ctx.move) reset(); }, { owner: unit });
};
/**
@@ -508,7 +520,7 @@ export const SUB = Object.freeze({
blastcaster: P({ rangeAoe: true }),
chain: P({ chain: { count: 3, falloff: 0.15, radius: CHAIN_RADIUS, sluggish: 0.5 } }),
funnel: P({ projectile: 'drone', install: installFunnel,
dmgMul: (battle, unit, target) => {
funnelMul: (battle, unit, target) => {
const f = unit.profile.funnel || { init: 0.2, delta: 0.15, max: 1.1 };
if (unit.trait.funnelTarget === target.id) unit.trait.funnelScale = Math.min(f.max, (unit.trait.funnelScale ?? f.init) + f.delta);
else { unit.trait.funnelTarget = target.id; unit.trait.funnelScale = f.init; }
+4 -3
View File
@@ -2,7 +2,7 @@
//
// Grid ranges: `[dRow, dCol]` offsets relative to facing RIGHT, rotated by the unit's direction (sim/dir.js: RIGHT
// (dr,dc), UP (dc,−dr), LEFT (−dr,−dc), DOWN (−dc,dr); row 0 = bottom). An enemy is in range when the tile containing
// it (round(y), round(x)) is one of the absolute range tiles — a huge enemy (巨型单位) when any tile its hit rectangle
// it (rounded half to even, detmath roundHalfEven; PRTS 作战机制 四舍六入五成双) is one of the absolute range tiles — a huge enemy (巨型单位) when any tile its hit rectangle
// occupies is (body.js; user playtest #5 item 10). `rangeExtend` (ability_range_forward_extend) adds N tiles
// past the furthest cell of every row, along +dCol BEFORE rotating (DESIGN §3).
// Operator priority: (1) enemies it blocks (every blocker, ranged ones on melee tiles included — user playtest #6
@@ -17,6 +17,7 @@
import { COLS, ROWS } from './constants.js';
import { normDir, rotateOffset } from './dir.js';
import { bodyDist } from './body.js';
import { roundHalfEven } from './detmath.js';
/**
* Build the absolute tile-key list of a grid for a unit standing at (r,c) facing `dir` ('UP'|'RIGHT'|'DOWN'|'LEFT';
@@ -50,9 +51,9 @@ export function absoluteRangeKeys(grid, r, c, dir, extend = 0) {
// record range (shared/loadoutRecord.js attackRangeGrid), re-exported here for the battle (Battle._refreshRange).
export { extendedGrid } from '../../shared/loadoutRecord.js';
/** Tile key of a unit's current position. */
/** Tile key of a unit's current position (rounded half to even, as body.js). */
export function tileKeyOf(u) {
const r = Math.round(u.y), c = Math.round(u.x);
const r = roundHalfEven(u.y), c = roundHalfEven(u.x);
if (r < 0 || r >= ROWS || c < 0 || c >= COLS) return -1;
return r * COLS + c;
}
@@ -50,7 +50,8 @@ test('#2 麦哲伦 S1: an enemy on a standing drone\'s range (air units too) cas
const { h, u, ps } = field(MG, 0, [[DRONE_F, 12, 9]]);
assert.equal(u.skill.rule, 'DEFAULT');
assert.ok(ps[0].alive && ps[0].rangeKeySet.has(12 * COLS + 10) && outOfHerRange(u, 12, 10), 'the setup');
h.spawn('enemy_dummy', { pos: [11, 13] }); // outside every area
// (11, 13) would be held at the field edge, on the drone's tile (11, 10). Stay on the field and outside every area.
h.spawn('enemy_dummy', { pos: [11, 6] });
assert.ok(!casts(h, u), 'nobody in her range or a drone\'s: no cast');
h.spawn('enemy_dummy', { pos: [12, 10] });
assert.ok(h.runUntil(() => u.skill.activations === 1, 1), 'an enemy on the drone\'s range casts S1');
+2 -2
View File
@@ -659,9 +659,9 @@ test('modules: removing the elite module changes the trait / talent behaviour th
const id = 'chess_char_2_10_b';
const [a, b] = withAndWithout((m) => {
const h = run({ defs: { enemies: { e: dummy('e') } }, units: [{ chessId: id, row: 10, col: 4, carryState: IDLE, ...mod(m) }], enemies: [{ key: 'e', pos: [10, 6] }] });
h.runUntil(() => dealt(h, h.unit(id)).length > 0, 5);
h.runUntil(() => dealt(h, h.unit(id), (c) => c.dmg.tags.includes('funnel')).length > 0, 5);
const u = h.unit(id);
const r = dealt(h, u)[0].amount / u.s.atk;
const r = dealt(h, u, (c) => c.dmg.tags.includes('funnel'))[0].amount / u.s.atk;
done(h);
return r;
});
+4 -2
View File
@@ -1070,7 +1070,7 @@ test('6_17 耀骑士临光 S2 逐夜烁光: on deploy ATK + and 3 护盾 layers
// =================================================================================================================
// 6_18 荒芜拉普兰德
test('6_18 荒芜拉普兰德 S1 慵怠者悲鸣: passive 浮游单元+1 (2 hits per attack); toggled on: ATK + and the drones lock still enemies anywhere', () => {
test('6_18 荒芜拉普兰德 S1 慵怠者悲鸣: passive 浮游单元+1 (one body plus two additions); toggled on: ATK + and the drones lock still enemies anywhere', () => {
for (const id of both('chess_char_6_18')) {
const sid = 'skchr_whitw2_1', bb = bbOf(id, sid);
const idle = run({ defs: { enemies: { e: dummy('e') } }, units: [U(id, sid, 10, 4, { carryState: IDLE })], enemies: [{ key: 'e', pos: [10, 6] }] });
@@ -1079,7 +1079,9 @@ test('6_18 荒芜拉普兰德 S1 慵怠者悲鸣: passive 浮游单元+1 (2 hits
const a0 = idle.hooksOf('attack').find((c) => c.attacker === iu);
assert.ok(a0);
idle.run(1);
assert.equal(dealt(idle, iu, (c) => c.dmg.attackId === dealt(idle, iu)[0].dmg.attackId).length, 2, 'drone +1');
const volley = dealt(idle, iu, (c) => c.dmg.attackId === dealt(idle, iu)[0].dmg.attackId);
assert.equal(volley.filter((c) => c.dmg.isAttack).length, 1, 'one body hit');
assert.equal(volley.filter((c) => c.dmg.tags.includes('funnel')).length, 2, 'drone +1');
done(idle);
const h = run({
+4 -1
View File
@@ -7,6 +7,7 @@ import { makeBattle, enemyRec, chessRec, checkInvariants } from '../helpers/batt
import { getDefaultSource } from '../../server/sim/simdata.js';
import { ELEMENT_GAUGE_MAX, PROJECTILE_SPEEDS, BOOMERANG_RETURN_SPEED } from '../../server/sim/constants.js';
import { sortEnemyTargets } from '../../server/sim/targeting.js';
import { DRONE_TAG as ROCKROCK_DRONE } from '../../server/sim/content/kits/ops/chess_char_2_10-rockr.js';
const ds = getDefaultSource();
const raw = (id) => ds.rawChess(id);
@@ -1341,7 +1342,9 @@ test('2_10 洛洛: 自负此轭 drones stay locked on their target while the ski
const t0 = h.b.time;
h.run(4);
const atks = h.hooksOf('attack').filter((c) => c.attacker === u && c.t > t0);
assert.ok(atks.length > 0 && atks.every((c) => c.targets.length === 1 && c.targets[0] === first), 'locked');
assert.ok(atks.length > 0 && atks.every((c) => c.targets.length === 1 && c.targets[0] === other), 'body keeps normal targeting');
const drones = h.hooksOf('damaged').filter((c) => c.source === u && c.t > t0 && c.dmg.tags?.includes(ROCKROCK_DRONE));
assert.ok(drones.length > 0 && drones.every((c) => c.target === first && c.dmg.isSkill && !c.dmg.isAttack), 'drone stays locked');
done(h);
});
+32 -14
View File
@@ -488,13 +488,13 @@ test('3_13 至简: 神工意匠 charges: ATK% arts ×2 per cast; 忽有所悟 cr
const u = h.unit(id);
assert.equal(u.skill.maxCharges, bb.ct);
h.run(60);
const normal = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.isAttack && !c.dmg.isSkill).map((c) => c.amount / u.s.atk);
const normal = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.tags.includes('funnel') && !c.dmg.isSkill).map((c) => c.amount / u.s.atk);
const ramp = (v) => [tb.max_atk_scale, tb.max_atk_scale * t0.atk_scale].some((x) => Math.abs(v - x) < 1e-6);
assert.ok(normal.slice(10).every(ramp), 'ramped drone hits: max or max × crit');
assert.ok(normal.some((v) => Math.abs(v - tb.max_atk_scale * t0.atk_scale) < 1e-6), 'some crits');
assert.ok(normal.some((v) => Math.abs(v - tb.max_atk_scale) < 1e-6), 'some plain hits');
const skillAtks = h.hooksOf('attack').filter((c) => c.attacker === u && c.isSkill).length;
const sk = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.isSkill).map((c) => c.amount / u.s.atk);
const sk = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.isSkill && c.dmg.isAttack).map((c) => c.amount / u.s.atk);
assert.ok(skillAtks >= 2);
assert.equal(sk.length, skillAtks * 2, 'two hits per cast');
for (const v of sk) assert.ok([bb.atk_scale, bb.atk_scale * t0.atk_scale].some((x) => Math.abs(v - x) < 1e-6), `skill hit ${v}`);
@@ -790,16 +790,25 @@ test('3_20 耶拉: 低眉 ATK (ground tiles in range); 心随意动 +1 drone, AT
h.step();
approx(u.s.atk, u.base.atk * (1 + t0['kjera_t_1[high].atk']));
h.run(4);
const first = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.isAttack).map((c) => c.amount / u.s.atk);
const first = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.tags.includes('funnel')).map((c) => c.amount / u.s.atk);
assert.ok(first[1] > first[0], 'drone ramps on the same target');
fill(u);
assert.ok(h.runUntil(() => u.skill.active, 5));
const tOn = h.b.time;
approx(u.s.atk, u.base.atk * (1 + t0['kjera_t_1[high].atk'] + bb.atk));
const full = u.s.atk * u.s.atkScaleMul;
h.runUntil(() => !u.skill.active, 30);
const sk = h.hooksOf('attack').filter((c) => c.attacker === u && c.isSkill);
assert.ok(sk.length > 5 && sk.every((c) => c.targets.length === 1 + bb['attack@cnt']), 'two drone locks');
const during = (c) => c.t + 1e-9 >= tOn - h.b.dt && c.t + 1e-9 < h.b.time;
const atks = h.hooksOf('attack').filter((c) => c.attacker === u && during(c) && !c.isSkill);
assert.ok(atks.length > 5 && atks.every((c) => c.targets.length === 1), 'the body keeps a single in-range target');
const drones = h.hooksOf('damaged').filter((c) => c.source === u && during(c) && c.dmg?.tags?.includes('kjera:drone'));
assert.ok(drones.length >= atks.length, 'released drones keep firing');
const bodies = h.hooksOf('damaged').filter((c) => c.source === u && during(c) && c.dmg?.isAttack && !c.dmg.isSkill
&& Math.abs(c.amount - full) < 1e-4);
assert.ok(bodies.length >= 2, 'her own hits stay at 100% ATK');
const colds = h.hooksOf('statusApplied').filter((c) => c.source === u && c.status === 'cold');
assert.ok(colds.length >= 1 && colds.length < sk.length * 2, `cold procs (${colds.length}/${sk.length * 2})`);
const chances = bodies.length + drones.length;
assert.ok(colds.length >= 1 && colds.length < chances, `cold procs (${colds.length}/${chances})`);
approx(colds[0].duration, bb['attack@cold']);
done(h);
});
@@ -1076,24 +1085,33 @@ test('3_19 伺夜: the pack never takes a later board unit’s tile; a 狼群 pi
});
test('3_20 耶拉: 心随意动 with a single enemy — both drones lock it and ramp in parallel', () => {
const id = 'chess_char_3_20_b', bb = BB(id), tb = TR(id);
const id = 'chess_char_3_20_b', tb = TR(id);
const h = makeBattle({
defs: { enemies: { enemy_a: dummy('enemy_a') } }, timeLimit: 80, hooks: ['damaged', 'attack'], captureNoisy: true,
units: [{ chessId: id, row: 10, col: 2 }], enemies: [{ key: 'enemy_a', pos: [10, 4] }],
});
const u = h.unit(id);
h.run(12);
const plain = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.isAttack).map((c) => c.amount / u.s.atk);
const plain = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg?.tags.includes('funnel')).map((c) => c.amount / u.s.atk);
approx(plain[plain.length - 1], tb.max_atk_scale, 1e-6, 'module ramp cap');
fill(u);
assert.ok(h.runUntil(() => u.skill.active, 5));
const t0 = h.b.time;
const n0 = h.hooksOf('damaged').length;
h.run(8);
const sk = h.hooksOf('attack').filter((c) => c.attacker === u && c.isSkill);
assert.ok(sk.length >= 3 && sk.every((c) => c.targets.length === 1 + bb['attack@cnt'] && c.targets.every((t) => t.defId === 'enemy_a')));
const hits = h.hooksOf('damaged').slice(n0).filter((c) => c.source === u && c.dmg?.isAttack);
assert.ok(hits.length >= 2 * (sk.length - 1));
for (let i = 0; i + 1 < hits.length; i += 2) approx(hits[i].amount, hits[i + 1].amount, 1e-9, 'same volley, same scale');
const atks = h.hooksOf('attack').filter((c) => c.attacker === u && c.t + 1e-9 >= t0 - h.b.dt && !c.isSkill);
assert.ok(atks.length >= 3 && atks.every((c) => c.targets.length === 1 && c.targets.every((t) => t.defId === 'enemy_a')), 'one body target');
const drones = h.hooksOf('damaged').slice(n0).filter((c) => c.source === u && c.dmg?.tags?.includes('kjera:drone'));
assert.ok(drones.length >= 4, 'both drones stay on the lone enemy');
const byT = new Map();
for (const c of drones) (byT.get(c.t) ?? byT.set(c.t, []).get(c.t)).push(c);
const pairs = [...byT.values()].filter((v) => v.length === 2);
assert.ok(pairs.length >= 2, 'the two drones share a volley');
for (const v of pairs) approx(v[0].amount, v[1].amount, 1e-9, 'same volley, same scale');
const full = u.s.atk * u.s.atkScaleMul;
const body = h.hooksOf('damaged').slice(n0).filter((c) => c.source === u && c.dmg?.isAttack && !c.dmg.isSkill
&& Math.abs(c.amount - full) < 1e-4);
assert.ok(body.length >= 2, 'body stays at 100% ATK while the drones ramp');
done(h);
});
@@ -1159,7 +1177,7 @@ test('精锐 numbers from the golden blackboards (module traits handled by the p
const ml = m.unit(e13);
assert.equal(ml.skill.maxCharges, BB(e13).ct);
m.run(25);
const ramps = m.hooksOf('damaged').filter((c) => c.source === ml && c.dmg?.isAttack && !c.dmg.isSkill).map((c) => c.amount / ml.s.atk);
const ramps = m.hooksOf('damaged').filter((c) => c.source === ml && c.dmg?.tags.includes('funnel') && !c.dmg.isSkill).map((c) => c.amount / ml.s.atk);
assert.ok(ramps.some((v) => Math.abs(v - TR(e13).max_atk_scale) < 1e-6), 'module cap 120 %');
assert.ok(ramps.every((v) => v <= TR(e13).max_atk_scale * TB(e13, 0).atk_scale + 1e-6));
done(m);
+10 -3
View File
@@ -138,12 +138,16 @@ test('耶拉 S2: two drones ramp independently on two targets, ATK up; 低眉 +1
const n0 = dmgBy(h, u).length;
h.run(8);
const hits = dmgBy(h, u).slice(n0);
const onA = hits.filter((c) => c.target === a).map((c) => c.amount), onB = hits.filter((c) => c.target === b).map((c) => c.amount);
const drones = hits.filter((c) => c.dmg?.tags?.includes('kjera:drone'));
const onA = drones.filter((c) => c.target === a).map((c) => c.amount), onB = drones.filter((c) => c.target === b).map((c) => c.amount);
assert.ok(onA.length >= 3 && onB.length >= 3, 'both locked targets attacked');
const atk = u.s.atk;
approx(onA[0], atk * tr.init_atk_scale, 1e-6, 'ramp start');
approx(onA[1], atk * (tr.init_atk_scale + tr.delta_atk_scale), 1e-6, 'ramp +15 %');
approx(onB[0], atk * tr.init_atk_scale, 1e-6, 'second drone starts its own ramp');
approx(onB[1], atk * (tr.init_atk_scale + tr.delta_atk_scale), 1e-6, 'second drone ramps on its own');
const body = hits.filter((c) => c.dmg?.isAttack && !c.dmg.isSkill);
assert.ok(body.length >= 1 && body.some((c) => Math.abs(c.amount - atk) < 1e-4), 'her own hit stays at 100% ATK');
h.run(15);
assert.ok(noisy(h, 'statusApplied').some((c) => c.source === u && c.status === 'cold' && c.duration === bb['attack@cold']), 'cold proc');
checkInvariants(h.b);
@@ -1032,14 +1036,17 @@ test('耶拉 S2: against a lone enemy both drones lock it and ramp independently
const n0 = dmgBy(h, u).length;
h.run(4);
const hits = dmgBy(h, u).slice(n0);
const drones = hits.filter((c) => c.dmg?.tags?.includes('kjera:drone'));
const byT = new Map();
for (const c of hits) (byT.get(c.t) ?? byT.set(c.t, []).get(c.t)).push(c.amount / u.s.atk);
for (const c of drones) (byT.get(c.t) ?? byT.set(c.t, []).get(c.t)).push(c.amount / u.s.atk);
const volleys = [...byT.values()];
assert.ok(volleys.length >= 3);
assert.ok(volleys.every((v) => v.length === 2), 'two drone hits per attack');
assert.ok(volleys.every((v) => v.length === 2), 'two drone hits per tick');
approx(volleys[0][0], tr.init_atk_scale, 1e-6);
approx(volleys[0][1], tr.init_atk_scale, 1e-6, 'second drone starts its own ramp');
approx(volleys[1][1], tr.init_atk_scale + tr.delta_atk_scale, 1e-6);
const full = u.s.atk * u.s.atkScaleMul;
assert.ok(hits.some((c) => c.dmg?.isAttack && !c.dmg.isSkill && Math.abs(c.amount - full) < 1e-4), 'body at 100% ATK');
checkInvariants(h.b);
});
+5 -3
View File
@@ -997,8 +997,9 @@ test('荒芜拉普兰德: 叙拉古的荣幸 +5 initial SP on every deployment;
// (S3 may be running — its drones do not normal-attack): wait for a normal attack after stage 3
assert.ok(h.runUntil(() => h.dmg.some((d) => d.src === u.id && d.attack && d.tgt === e.id && d.t > ts), 60));
const last = h.dmg.filter((d) => d.src === u.id && d.attack && d.tgt === e.id).at(-1);
const same = h.dmg.filter((d) => d.src === u.id && d.attack && d.t === last.t);
assert.equal(same.length, 2, 'two drone hits per attack');
const same = h.dmg.filter((d) => d.src === u.id && d.t === last.t);
assert.equal(same.filter((d) => d.attack).length, 1, 'one body hit per attack');
assert.equal(same.filter((d) => d.tags.includes('funnel')).length, 2, 'two drone additions per attack');
});
test('缪尔赛思: 流形 copies stats/range/damage type but not the attack shape (锏 2-hit); a capped melee copy steals nothing more', () => {
@@ -1120,7 +1121,8 @@ test('异客: the S3 storm is range x-1 — the 13-tile diamond — around the t
// in the diamond (|Δrow| + |Δcol| ≤ 2 by tile): (2, 0) / (0, −2) / (1.95, 0.4) lay outside the old 1.5 circle
for (const off of [[0, 0], [2, 0], [0, -2], [-2, 0], [1.45, 1.45], [1.95, 0.4]]) assert.equal(strikes(off), 8, `(${off}) struck by all 8 strikes`);
// outside it: tile (+2, +1), and tile (+3, 0) — (1.55, 1.05) was inside the old circle around the target's position
for (const off of [[2, 1], [1.55, 1.05], [0, 2.6]]) assert.equal(strikes(off), 0, `(${off}) never struck`);
// three tiles off along the columns: the field has no row 13 (a probe there is held on row 12, inside the diamond)
for (const off of [[2, 1], [1.55, 1.05], [2.6, 0]]) assert.equal(strikes(off), 0, `(${off}) never struck`);
});
test('蕾缪安: 通缉 needs a continuous 8 s stay in a 拉特兰 range (leaving restarts the count)', () => {
+7 -3
View File
@@ -80,18 +80,22 @@ test('a 自选 pick: 澄闪 is offered at tiers 5 and 6 and a roster with her pa
{ ok: true, picks: { [SLOT[6]]: { charId: GD, skillIndex: 2, uniEquipId: FY } } });
});
test('her normal attack (no skill): one drone hit per attack — init, +delta per hit on the same target, up to the cap (FUN-X from 0.35, FUN-Y to 1.2); 精准导流 lowers the RES it meets', () => {
for (const f of [[5, false, null], [5, true, FX], [6, true, FY]]) {
test('her normal attack (no skill): a body hit and one drone addition — init, +delta per hit on the same target, up to the cap (FUN-X from 0.35, FUN-Y to 1.2); 精准导流 lowers the RES of both', () => {
for (const f of FORMS_ALL) {
const [tier, elite, mod] = f;
const { h, u } = field({ tier, elite, mod, skill: 2 });
const e = h.spawn('enemy_res', { pos: [10, 6] });
h.run(12);
const hits = mine(h, u).filter((c) => c.target === e && c.dmg.isAttack);
const drones = mine(h, u).filter((c) => c.target === e && c.dmg.tags.includes('funnel'));
assert.ok(hits.length >= 8, `${label(f)}: ${hits.length} attacks`);
assert.equal(drones.length, hits.length, `${label(f)}: one addition per body hit`);
const tb = traitOf(tier, elite, mod).bb, pen = talentOf(tier, elite, mod, 1).bb.magic_resist_penetrate_fixed;
hits.slice(0, 8).forEach((c, i) => {
const ramp = Math.min(tb.max_atk_scale, tb.init_atk_scale + i * tb.delta_atk_scale);
approx(c.amount, u.s.atk * ramp * (1 - (50 - pen) / 100), `${label(f)}: attack ${i + 1} at ${ramp}`);
approx(c.amount, u.s.atk * (1 - (50 - pen) / 100), `${label(f)}: body attack ${i + 1}`);
approx(drones[i].amount, c.amount * ramp, `${label(f)}: drone at ${ramp}`);
assert.equal(drones[i].dmg.attackId, c.dmg.attackId, 'same attack action');
assert.equal(c.type, 'arts');
});
done(h);
+1 -1
View File
@@ -330,7 +330,7 @@ test('S2 连星 (AUTO, SP_FULL): a triggered piece hits every enemy on its conne
assert.deepEqual([sk.spCost, sk.bb['attack@atk_scale'], sk.bb['attack@move_speed'], sk.bb['attack@duration']], elite ? [16, 4.8, -0.4, 6] : [17, 4.2, -0.35, 6], `T${tier}`);
const { h, u } = field({ tier, elite, skill: 1, stones: [[10, 6], [10, 7]] });
const onLine = h.spawn('enemy_fly', { pos: [10, 9] }); // 3 tiles right of (10,6)…(10,7)+2: on the horizontal line
const beyond = h.spawn('enemy_dummy', { pos: [10, 11] }); // 4 tiles past (10,7)
const beyond = h.spawn('enemy_dummy', { pos: [10, 2] }); // 4 tiles before (10,6) (the field ends at column 10)
const vertical = h.spawn('enemy_dummy', { pos: [12, 7] }); // its battle-start 跟子 (11,7) is 上 of it: the vertical line is on
const off = h.spawn('enemy_dummy', { pos: [9, 4] }); // on neither line
const trig = h.spawn('enemy_runner', { pos: [10, 7] });
+267
View File
@@ -0,0 +1,267 @@
// Controlled regression inputs: real kit, seeded Battle, synthetic enemy records and authored routes.
// No live enemy movement/HP edits. These cases are distinct from the normal Match/browser route.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { bodyInKeys } from '../../server/sim/body.js';
import { DRONE_TAG } from '../../server/sim/content/kits/ops/chess_char_2_10-rockr.js';
import { getDefaultSource } from '../../server/sim/simdata.js';
const route = {
motion: 'FLY', start: [10, 6], end: [9, 2],
steps: [{ t: 'wait', s: 3 }, { t: 'move', p: [12, 6] }, { t: 'wait', s: 8 },
{ t: 'move', p: [10, 6] }, { t: 'wait', s: 40 }, { t: 'move', p: [9, 2] }],
};
const stationary = { motion: 'FLY', start: [10, 5], end: [9, 2], steps: [{ t: 'wait', s: 90 }, { t: 'move', p: [9, 2] }] };
const setup = (id, { skillIndex = 1, moduleId, newcomer = false, staysOutside = false, fragile = false,
outsideHp, stationaryLock = false, killer = false } = {}) => {
const lockRoute = staysOutside ? { ...route, steps: [...route.steps.slice(0, 2), { t: 'wait', s: 90 }, { t: 'move', p: [9, 2] }] } : route;
const h = makeBattle({ seed: 5, timeLimit: 100, autoFinish: false, captureNoisy: true,
hooks: ['damaged', 'attack', 'skillStart', 'skillEnd'],
defs: { enemies: {
enemy_lock: enemyRec({ key: 'enemy_lock', hp: 1e7, speed: 1, motion: 'FLY' }),
enemy_fragile: enemyRec({ key: 'enemy_fragile', hp: 300, speed: 1, motion: 'FLY' }),
enemy_outside: enemyRec({ key: 'enemy_outside', hp: outsideHp, speed: 1, motion: 'FLY' }),
enemy_killer: enemyRec({ key: 'enemy_killer', hp: 1e7, atk: 1e5, range: 4, motion: 'FLY' }),
} },
units: [{ chessId: id, row: 10, col: 4, skillIndex, moduleId, carryState: { sp: 999 } }],
enemies: [{ key: fragile ? 'enemy_fragile' : outsideHp ? 'enemy_outside' : 'enemy_lock',
route: fragile || stationaryLock ? stationary : lockRoute },
...(newcomer ? [{ key: 'enemy_lock', route: stationary, time: 7 }] : []),
...(killer ? [{ key: 'enemy_killer', route: stationary, time: 7 }] : [])],
});
h.step();
return { h, u: h.unit(id), target: h.enemies()[0] };
};
const hits = (h, u, target, after) => h.hooksOf('damaged').filter(c => c.source === u && c.target === target && c.t >= after && c.amount > 0);
const drone = c => c.dmg.tags?.includes(DRONE_TAG);
const approx = (actual, expected) => assert.ok(Math.abs(actual - expected) < 1e-7, `${actual} vs ${expected}`);
const done = h => { checkInvariants(h.b); assert.deepEqual(h.b.errors, []); };
for (const id of ['chess_char_2_10_a', 'chess_char_2_10_b']) {
test(`${id} S2: damage continues after a living target leaves the body range`, () => {
const { h, u, target } = setup(id);
assert.ok(u.skill.active);
assert.ok(h.runUntil(() => !bodyInKeys(target, u.rangeKeySet), 10));
assert.ok(hits(h, u, target, 0).length > 0, 'the in-range control receives damage before leaving');
h.run(2); // discard any projectile already in flight at the boundary
const t = h.b.time;
const bodyAttacks = u.stats.attacks;
h.run(4);
assert.ok(target.alive && u.alive && u.skill.active && !bodyInKeys(target, u.rangeKeySet));
const outHits = hits(h, u, target, t);
assert.ok(outHits.length > 0, 'a living out-of-range lock must still receive drone damage');
assert.ok(outHits.every(c => drone(c) && c.type === 'arts' && c.dmg.isSkill && !c.dmg.isAttack), 'pursuit damage must be an independent arts skill drone');
assert.equal(u.stats.attacks, bodyAttacks, 'the body cannot make attacks with no enemy in range');
done(h);
});
test(`${id} S2: an in-range newcomer cannot steal a living out-of-range drone lock`, () => {
const { h, u, target } = setup(id, { newcomer: true });
assert.ok(h.runUntil(() => h.enemies().length === 2, 10));
assert.ok(target.alive && !bodyInKeys(target, u.rangeKeySet));
h.run(2);
const t = h.b.time;
h.run(3);
const outHits = hits(h, u, target, t);
assert.ok(outHits.length > 0, 'the original target keeps receiving drone damage with another target in range');
assert.ok(outHits.every(c => drone(c) && c.dmg.isSkill && !c.dmg.isAttack), 'the body cannot attack the out-of-range lock');
const other = h.enemies().find(e => e !== target);
assert.equal(u.mem.rockLock, target);
assert.equal(hits(h, u, other, t).filter(drone).length, 0, 'the drone ignores the newcomer');
const body = hits(h, u, other, t).filter(c => c.dmg.isAttack);
assert.ok(body.length > 0, 'the body still attacks the in-range newcomer');
assert.ok(body.every(c => !c.dmg.isSkill && !drone(c)));
body.forEach(c => approx(c.amount, u.s.atk * u.s.atkScaleMul));
done(h);
});
test(`${id} S2: a target returning into range receives damage`, () => {
const { h, u, target } = setup(id);
assert.ok(h.runUntil(() => !bodyInKeys(target, u.rangeKeySet), 10));
assert.ok(h.runUntil(() => bodyInKeys(target, u.rangeKeySet), 20));
const t = h.b.time;
h.run(3);
const ds = hits(h, u, target, 0).filter(drone);
assert.ok(ds.some(c => c.t >= t));
assert.equal(u.mem.rockLock, target);
ds.slice(1).forEach((c, i) => approx(c.t - ds[i].t, Math.ceil(u.s.interval * 30 - 1e-9) / 30));
ds.slice(-3).forEach(c => approx(c.amount, u.s.atk * u.s.atkScaleMul * u.profile.funnel.max));
done(h);
});
test(`${id} S2: a target killed by combat releases the lock for another in-range enemy`, () => {
const { h, u, target } = setup(id, { fragile: true, newcomer: true });
assert.equal(u.mem.rockLock, target);
assert.ok(h.runUntil(() => !target.alive, 7));
assert.ok(h.runUntil(() => h.enemies().some(e => e !== target && e.alive), 10));
const other = h.enemies().find(e => e !== target && e.alive);
const t = h.b.time;
h.run(3);
assert.ok(u.alive && u.skill.active && other.alive);
assert.equal(u.mem.rockLock, other);
assert.ok(hits(h, u, other, t).length > 0);
done(h);
});
test(`${id} S2: the duration end clears the lock and stops out-of-range damage`, () => {
const { h, u, target } = setup(id, { staysOutside: true });
assert.ok(h.runUntil(() => !bodyInKeys(target, u.rangeKeySet), 10));
assert.ok(h.runUntil(() => !u.skill.active, 45));
assert.equal(h.hooksOf('skillEnd').find(c => c.unit === u)?.reason, 'duration');
assert.equal(u.mem.rockLock, null);
h.run(2);
const t = h.b.time;
h.run(4);
assert.ok(target.alive && u.alive && !bodyInKeys(target, u.rangeKeySet));
assert.equal(hits(h, u, target, t).length, 0);
done(h);
});
test(`${id} S1: damage stops outside the body range`, () => {
const { h, u, target } = setup(id, { skillIndex: 0 });
assert.ok(u.skill.active);
assert.ok(h.runUntil(() => !bodyInKeys(target, u.rangeKeySet), 10));
h.run(2);
const t = h.b.time;
h.run(4);
assert.equal(hits(h, u, target, t).length, 0);
done(h);
});
test(`${id} S2: an out-of-range combat kill waits for a candidate and restarts the trait ramp`, () => {
const { h, u, target } = setup(id, { outsideHp: id.endsWith('_a') ? 4000 : 5000, newcomer: true });
assert.ok(h.runUntil(() => !bodyInKeys(target, u.rangeKeySet), 10));
assert.ok(target.alive);
assert.ok(h.runUntil(() => !target.alive, 10));
assert.ok(drone(hits(h, u, target, 0).at(-1)), 'the independent drone delivers the killing blow');
if (!h.enemies().some(e => e !== target && e.alive)) {
h.step(); assert.equal(u.mem.rockLock, null, 'no out-of-range candidate is acquired');
}
assert.ok(h.runUntil(() => h.enemies().some(e => e !== target && e.alive), 10));
const other = h.enemies().find(e => e !== target && e.alive);
assert.ok(h.runUntil(() => hits(h, u, other, 0).some(drone), 2));
const first = hits(h, u, other, 0).find(drone);
approx(first.amount, u.s.atk * u.s.atkScaleMul * u.profile.funnel.init);
assert.equal(u.mem.rockLock, other);
done(h);
});
test(`${id} S2: explicit stop restores the normal multiplier and clears released state`, () => {
const { h, u, target } = setup(id, { staysOutside: true });
const saved = u.mem.rockDrone.mul, key = u.mem.rockDrone.key;
assert.ok(h.runUntil(() => !bodyInKeys(target, u.rangeKeySet), 10));
u.skill.stop();
assert.equal(u.profile[key], saved);
assert.equal(u.mem.rockDrone, null); assert.equal(u.mem.rockLock, null);
h.run(2); const t = h.b.time; h.run(4);
assert.equal(hits(h, u, target, t).length, 0);
done(h);
});
test(`${id} S2: caster combat death clears the released state`, () => {
const { h, u, target } = setup(id, { killer: true, staysOutside: true });
assert.ok(h.runUntil(() => !u.alive, 12));
assert.equal(u.skill.active, false); assert.equal(u.mem.rockDrone, null); assert.equal(u.mem.rockLock, null);
h.run(2); const t = h.b.time; h.run(3);
assert.equal(hits(h, u, target, t).length, 0);
done(h);
});
test(`${id} S2: live ASPD controls drone cadence; overload uses the live trait cap`, () => {
const { h, u } = setup(id, { stationaryLock: true });
const f = { ...u.profile.funnel }, scales = [];
h.b.on('damaged', c => { if (c.source === u && drone(c)) scales.push({ t: h.b.time, scale: c.amount / (u.s.atk * u.s.atkScaleMul) }); });
h.run(4);
h.b.addBuff(u, { key: 'test:aspd', mods: { aspd: 100 } });
const interval = u.s.interval, t = h.b.time;
h.run(4);
const fast = scales.filter(c => c.t > t + 1.3);
assert.ok(fast.length > 3);
fast.slice(1).forEach((c, i) => approx(c.t - fast[i].t, Math.ceil(interval * 30 - 1e-9) / 30));
h.run(15);
approx(scales.at(-1).scale, f.max * u.def.skill.bb.scale);
u.skill.stop();
assert.deepEqual(u.profile.funnel, f);
assert.ok(u.s.flags.stun, 'stopping during overload keeps the existing post-overload stun');
done(h);
});
}
for (const moduleId of ['none', 'uniequip_002_rockr']) {
test(`elite S2 ${moduleId}: the resolved trait supplies initial ramp and increment`, () => {
const { h, u, target } = setup('chess_char_2_10_b', { moduleId, stationaryLock: true });
const f = u.profile.funnel;
h.run(3);
hits(h, u, target, 0).filter(drone).forEach((c, i) => approx(c.amount, u.s.atk * u.s.atkScaleMul * (f.init + i * f.delta)));
assert.equal(f.init, moduleId === 'none' ? 0.2 : 0.35);
done(h);
});
}
for (const sameTarget of [false, true]) {
test(`S2: a pre-skill projectile at ${sameTarget ? 'the same' : 'another'} target cannot change the released ramp`, () => {
const h = makeBattle({ seed: 5, autoFinish: false, captureNoisy: true, hooks: ['damaged', 'attack'],
defs: { enemies: { old: enemyRec({ key: 'old', hp: 1e7, speed: 0, motion: 'FLY' }),
preferred: enemyRec({ key: 'preferred', hp: 1e7, speed: 0, motion: 'FLY', taunt: 5 }) } },
units: [{ chessId: 'chess_char_2_10_a', row: 10, col: 4, carryState: { sp: 0 } }],
enemies: [{ key: 'old', pos: [10, 6] }],
});
h.step(); // launch an ordinary shot, which has not landed yet
const u = h.unit('chess_char_2_10_a'), old = h.enemies()[0];
assert.equal(h.hooksOf('attack').length, 1); assert.equal(h.hooksOf('damaged').length, 0);
const target = sameTarget ? old : h.spawn('preferred', { pos: [10, 5] });
h.step(); // update the spatial index for the second target
u.skill.gainSp(999); u.skill.activate('test');
assert.equal(u.mem.rockLock, target);
h.run(2);
assert.ok(hits(h, u, old, 0).some(c => c.dmg.isAttack), 'the old shot really lands');
const ds = hits(h, u, target, 0).filter(drone);
assert.ok(ds.length >= 3);
ds.slice(0, 3).forEach((c, i) => approx(c.amount, u.s.atk * u.s.atkScaleMul * (u.profile.funnel.init + i * u.profile.funnel.delta)));
done(h);
});
}
test('S2: the shared targetability filter releases an unselectable lock and acquires a legal candidate', () => {
const { h, u, target } = setup('chess_char_2_10_a', { newcomer: true });
assert.ok(h.runUntil(() => h.enemies().length === 2, 10));
const other = h.enemies().find(e => e !== target);
h.b.addBuff(target, { key: 'test:untargetable', flags: { untargetable: true } });
h.run(2); const t = h.b.time; h.run(2);
assert.equal(hits(h, u, target, t).length, 0);
assert.equal(u.mem.rockLock, other);
assert.ok(hits(h, u, other, t).some(drone));
done(h);
});
for (const [id, moduleId] of [['chess_char_2_10_a', undefined], ['chess_char_2_10_b', 'none'], ['chess_char_2_10_b', 'uniequip_002_rockr']]) {
test(`${id} ${moduleId ?? 'normal'}: skill data, DEFAULT trigger, range and talent remain intact`, () => {
for (const skillIndex of [0, 1]) {
const raw = getDefaultSource().getChess(id, { skillIndex, moduleId }).raw;
const h = makeBattle({ seed: 5, autoFinish: false, timeLimit: 100, captureNoisy: true,
defs: { enemies: { e: enemyRec({ key: 'e', hp: 1e7, speed: 0 }) } },
units: [{ chessId: id, row: 10, col: 4, skillIndex, moduleId, carryState: { sp: 999 } }],
});
h.run(2);
const u = h.unit(id);
assert.equal(u.skill.active, false, 'DEFAULT waits for a target despite full SP');
assert.deepEqual([u.skill.id, u.skill.rule, u.skill.spCost, u.skill.initSp, u.skill.duration, u.skill.spType],
[raw.skill.skillId, raw.skill.trigger.rule, raw.skill.spCost, raw.skill.initSp, raw.skill.duration, 'time']);
assert.deepEqual(u.liveRangeGrid, raw.rangeGrid);
assert.deepEqual([u.profile.canHitFly, u.profile.dmgType, u.profile.attack, u.s.blockCnt], [true, 'arts', 'ranged', 1]);
h.spawn('e', { pos: [10, 6] });
assert.ok(h.runUntil(() => u.skill.active, 3));
approx(u.s.aspd - u.base.aspd, raw.skill.bb.attack_speed);
const t = raw.talents.find(v => v.index === 0).bb;
h.runUntil(() => h.b.time >= 15.1, 20);
approx(u.findBuff('rockr:rock').stacks, 1);
approx(u.findBuff('rockr:rock').mods.atkPct, t.atk);
u.skill.stop();
assert.deepEqual(u.liveRangeGrid, raw.rangeGrid);
h.runUntil(() => h.b.time >= t.interval * (t.max_stack_cnt + 1), 80);
assert.equal(u.findBuff('rockr:rock').stacks, t.max_stack_cnt);
done(h);
}
});
}
+119 -119
View File
@@ -93,33 +93,33 @@
"round": 5,
"seed": 4108057433,
"waveId": "act1autochess_05",
"time": 51.27,
"ticks": 1538,
"time": 48.13,
"ticks": 1444,
"reason": "cleared",
"killed": 21,
"total": 21,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 28,
"rngDraws": 27,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":21,"total":21,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":68325,"bossDmg":0,"heal":0,"deaths":0,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_3_12_a",2,null,1393.34,1,3,6,11192,1174,0,24,1],
["p1",1,"op","chess_char_3_12_a",2,null,1529.25,1,3,6,7131,1038,0,19,1],
["p1",2,"op","chess_char_1_06_a",1,null,1250.7,1,4,2,2639,0,0,12,1],
["p1",3,"op","chess_char_1_13_a",1,null,1004.3,1,6,4,2502,0,0,11,1],
["p1",4,"op","chess_char_3_08_a",1,null,1753.4,1,8,1,8314,0,0,10,1],
["p1",5,"op","chess_char_3_09_a",1,null,1393.7,1,9,0,15349,0,0,26,1],
["p1",6,"op","chess_char_3_10_a",1,null,1815,1,10,0,7744,0,0,8,1],
["p1",7,"op","chess_char_3_11_a",1,null,1447.6,1,5,8,15366,0,0,18,2],
["p1",8,"op","chess_char_3_13_a",1,null,1170.4,1,7,0,5220,0,0,29,6],
["p1",7,"op","chess_char_3_11_a",1,null,1447.6,1,5,7,12933,0,0,16,2],
["p1",8,"op","chess_char_3_13_a",1,null,1170.4,1,7,1,11714,0,0,29,6],
["-","~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_1249_lysdb_2":[5,5,0,168,27000],"enemy_1251_lysyta":[15,15,0,36,37125],"enemy_1328_cbjedi":[1,1,0,970,9000]},
"hooks": [1,31,1538,152,152,197,192,0,21,21,14,13,0,8070,8,11,21,0,1,21,0,0,0],
"events": {"atk":171,"deploy":8,"die":21,"dmg":192,"engage":8,"fx":38,"skill":27,"spawn":31,"status":15},
"enemies": {"enemy_1249_lysdb_2":[5,5,0,56,27000],"enemy_1251_lysyta":[15,15,0,12,37125],"enemy_1328_cbjedi":[1,1,0,970,9000]},
"hooks": [1,31,1444,137,137,208,203,0,21,21,14,13,0,7412,7,9,21,0,1,21,0,0,0],
"events": {"atk":156,"deploy":8,"die":21,"dmg":203,"engage":8,"fx":38,"skill":27,"spawn":31,"status":14},
"fx": {"aoe":1,"displace":13,"pull":13,"shieldBreak":5,"strike":2,"taunt":1,"volley":2,"zone":1},
"snaps": "81dd16a7 8822f255 d9175ef3 a516292e 44ea0bd2 1e3df8ec"
"snaps": "81dd16a7 afef1090 f721859c df68d4ec 22578dbf"
},
"bond-deputShip-high": {
"about": "助力 high: tier 2 layers 999; chess_char_4_11_b chess_char_1_06_b chess_char_1_13_b chess_char_2_14_b chess_char_1_06_a chess_char_1_13_a chess_char_4_10_b chess_char_4_12_b token_10041_cathy_catsld token_10041_cathy_catsld",
@@ -257,31 +257,31 @@
"round": 5,
"seed": 3165180428,
"waveId": "act1autochess_05",
"time": 64.67,
"ticks": 1940,
"time": 64.27,
"ticks": 1928,
"reason": "cleared",
"killed": 17,
"total": 17,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 87,
"rngDraws": 97,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":90450,"bossDmg":0,"heal":395,"deaths":2,"layerGains":{}}},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":90450,"bossDmg":0,"heal":362,"deaths":2,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_4_01_a",2,null,2901.8,1,4,0,479,0,0,3,0],
["p1",2,"op","chess_char_4_04_a",1,null,1936,1,6,2,9803,0,0,13,2],
["p1",1,"op","chess_char_4_01_a",2,null,2901.8,1,4,0,1278,0,0,8,0],
["p1",2,"op","chess_char_4_04_a",1,null,1936,1,6,1,11213,0,0,19,2],
["p1",3,"op","chess_char_2_14_a",1,null,1355.2,1,1,0,0,0,0,0,0],
["p1",4,"op","chess_char_3_10_a",1,null,1815,1,2,0,0,0,0,0,0],
["p1",5,"op","chess_char_3_20_a",1,null,1233.1,1,3,1,5410,0,0,25,1],
["p1",6,"op","chess_char_3_21_a",2,null,0,0,7,4,28473,1622,122,43,1],
["p1",7,"op","chess_char_4_02_a",2,null,1570.8,1,5,3,26148,0,0,18,1],
["p1",8,"op","chess_char_4_06_a",1,null,0,0,8,7,20136,1644,273,40,1]
["p1",5,"op","chess_char_3_20_a",1,null,1233.1,1,3,3,11450,0,0,24,1],
["p1",6,"op","chess_char_3_21_a",2,null,0,0,7,6,23766,1606,106,38,1],
["p1",7,"op","chess_char_4_02_a",2,null,1570.8,1,5,4,23679,0,0,18,1],
["p1",8,"op","chess_char_4_06_a",1,null,0,0,8,3,19064,1627,256,38,1]
],
"enemies": {"enemy_10042_prtrop":[4,4,0,1099,21600],"enemy_10042_prtrop_2":[2,2,0,1706,14400],"enemy_10043_sailor":[11,11,0,461,54450]},
"hooks": [1,25,1940,162,162,235,235,373,19,19,6,5,0,7198,16,10,17,0,1,19,0,0,0],
"events": {"atk":190,"deploy":8,"die":19,"dmg":234,"engage":6,"fx":32,"skill":11,"spawn":25,"status":43},
"fx": {"crit":9,"displace":6,"ripple":7,"shadowWeave":5,"shield":2,"shieldBreak":1,"stealth":2},
"snaps": "6de03b40 4dd7bab5 7a43012b 232aff6d fa4140b1 96914be3 e3a548b2"
"enemies": {"enemy_10042_prtrop":[4,4,0,1429,21600],"enemy_10042_prtrop_2":[2,2,0,1606,14400],"enemy_10043_sailor":[11,11,0,197,54450]},
"hooks": [1,25,1928,162,162,247,247,342,19,19,6,5,0,7171,19,8,17,0,1,19,0,0,0],
"events": {"atk":171,"deploy":8,"die":19,"dmg":246,"engage":6,"fx":65,"skill":11,"spawn":25,"status":48},
"fx": {"crit":9,"displace":5,"drone":34,"ripple":7,"shadowWeave":5,"shield":2,"shieldBreak":1,"stealth":2},
"snaps": "6de03b40 bcb3ddb5 0d638656 71757fb2 ed5fc1b0 be14aa0b 29f78bf7"
},
"bond-emptyShip-high": {
"about": "协防干员 high: tier 1 layers 999; chess_char_4_17_b chess_char_4_18_b chess_char_4_19_b chess_char_4_22_b chess_char_2_14_b chess_char_3_10_b chess_char_4_20_b chess_char_4_21_b",
@@ -623,25 +623,25 @@
"total": 17,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 9,
"rngDraws": 13,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":177984,"bossDmg":0,"heal":2132,"deaths":0,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_1_02_b",1,"uniequip_002_yak",4680.5,1,2,0,0,0,0,0,0],
["p1",2,"op","chess_char_5_11_b",1,"uniequip_002_demkni",6111.11,1,1,0,0,0,1531,0,4],
["p1",3,"op","chess_char_2_05_b",1,"uniequip_002_harold",17101.41,1,4,0,0,50,600,7,1],
["p1",4,"op","chess_char_3_11_b",1,"uniequip_002_snhunt",2356.25,1,7,10,115541,1041,0,21,9],
["p1",5,"op","chess_char_3_14_b",1,"uniequip_002_slbell",2170.63,1,5,1,3944,50,0,1,1],
["p1",6,"op","chess_char_3_20_b",1,"uniequip_002_kjera",1993.75,1,8,0,5820,50,0,7,1],
["p1",4,"op","chess_char_3_11_b",1,"uniequip_002_snhunt",2356.25,1,7,10,108776,1041,0,21,9],
["p1",5,"op","chess_char_3_14_b",1,"uniequip_002_slbell",2170.63,1,5,1,840,50,0,1,1],
["p1",6,"op","chess_char_3_20_b",1,"uniequip_002_kjera",1993.75,1,8,0,16312,50,0,7,1],
["p1",7,"op","chess_char_4_13_b",1,"uniequip_002_gnosis",2684.88,1,3,1,1414,50,0,1,2],
["p1",8,"op","chess_char_5_12_b",0,"uniequip_002_dusk",2407.13,1,6,5,48718,1141,0,10,10],
["p1",8,"op","chess_char_5_12_b",0,"uniequip_002_dusk",2407.13,1,6,5,48094,1141,0,10,10],
["p1","~1","token","token_10015_dusk_drgn",null,null,0,0,12,0,2547,1997,0,8,null]
],
"enemies": {"enemy_1267_nhpbr_2":[11,11,0,2135,69696],"enemy_1270_nhstlk_2":[4,4,0,0,73728],"enemy_1272_nhtank_2":[2,2,0,2243,34560]},
"hooks": [1,26,2174,65,65,115,115,12,18,18,28,28,0,7475,1579,3,17,0,1,18,0,0,0],
"events": {"atk":69,"deploy":9,"die":18,"dmg":115,"engage":6,"fx":40,"heal":12,"skill":56,"spawn":26,"status":20},
"fx": {"coldWind":2,"frostNova":2,"healAoe":4,"strike":9,"summon":1,"volley":9,"zone":13},
"snaps": "cc4cf53b 9139c2c7 206b1332 d27de872 77344198 6c0c2544 4d5c5c01 7258305b"
"hooks": [1,26,2174,65,65,121,121,12,18,18,28,28,0,7475,1579,3,17,0,1,18,0,0,0],
"events": {"atk":65,"deploy":9,"die":18,"dmg":121,"engage":6,"fx":48,"heal":12,"skill":56,"spawn":26,"status":20},
"fx": {"coldWind":2,"drone":8,"frostNova":2,"healAoe":4,"strike":9,"summon":1,"volley":9,"zone":13},
"snaps": "cc4cf53b 9139c2c7 206b1332 d27de872 bcb0ffd8 0b210404 84dba741 37d26448"
},
"bond-lateranoShip-low": {
"about": "拉特兰 low: tier 1 layers 1; chess_char_3_06_a chess_char_3_05_a chess_char_1_01_a chess_char_2_01_a chess_char_3_01_a chess_char_3_08_a chess_char_3_09_a chess_char_3_10_a",
@@ -724,34 +724,34 @@
"round": 5,
"seed": 1709081824,
"waveId": "act1autochess_05",
"time": 46.1,
"ticks": 1383,
"time": 45.7,
"ticks": 1371,
"reason": "cleared",
"killed": 53,
"total": 16,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 19,
"rngDraws": 17,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":53,"total":16,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":30278,"bossDmg":0,"heal":0,"deaths":0,"layerGains":{}}},
"players": {"p1":{"killed":53,"total":16,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":30448,"bossDmg":0,"heal":0,"deaths":0,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_3_12_a",2,null,2567.4,1,7,0,0,0,0,0,0],
["p1",2,"op","chess_char_3_16_a",1,null,2390.3,1,8,0,0,0,0,0,0],
["p1",3,"op","chess_char_6_11_a",2,null,1634.6,1,3,6,559,0,0,9,1],
["p1",4,"op","chess_char_1_03_a",1,null,1145.1,1,5,1,3,0,0,6,1],
["p1",5,"op","chess_char_2_04_a",1,null,1074.7,1,10,20,7319,0,0,25,1],
["p1",3,"op","chess_char_6_11_a",2,null,1634.6,1,3,1,1,0,0,9,1],
["p1",4,"op","chess_char_1_03_a",1,null,1145.1,1,5,0,0,0,0,5,1],
["p1",5,"op","chess_char_2_04_a",1,null,1074.7,1,10,16,7786,0,0,24,1],
["p1",6,"op","chess_char_3_11_a",1,null,1447.6,1,11,6,8144,0,0,15,2],
["p1",7,"op","chess_char_3_13_a",1,null,1170.4,1,6,4,4460,0,0,23,6],
["p1",8,"op","chess_char_3_14_a",1,null,1376.1,1,9,6,8729,0,0,22,1],
["p1",9,"token","token_10030_mlyss_wtrman",null,null,936.9,1,4,3,1064,0,0,7,1],
["p1",7,"op","chess_char_3_13_a",1,null,1170.4,1,6,6,6718,0,0,23,6],
["p1",8,"op","chess_char_3_14_a",1,null,1376.1,1,9,8,6949,0,0,22,1],
["p1",9,"token","token_10030_mlyss_wtrman",null,null,936.9,1,4,5,851,0,0,7,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_1195_sfyin":[11,11,0,0,19800],"enemy_1196_msfyin":[22,22,0,0,44],"enemy_1197_sfshu":[5,5,0,0,11250],"enemy_1198_msfshu":[15,15,0,0,45]},
"hooks": [1,64,1383,107,107,174,174,0,53,53,13,10,0,8024,30,0,53,0,1,53,0,0,0],
"events": {"atk":138,"deploy":9,"die":53,"dmg":174,"engage":7,"fx":25,"skill":23,"spawn":64,"status":44},
"hooks": [1,64,1371,105,105,177,177,0,53,53,13,10,0,7976,31,0,53,0,1,53,0,0,0],
"events": {"atk":135,"deploy":9,"die":53,"dmg":177,"engage":7,"fx":25,"skill":23,"spawn":64,"status":42},
"fx": {"copy":1,"dp":1,"sleep":3,"strike":2,"summon":16,"volley":2},
"snaps": "ccd30115 f5d257e4 89df9ecc 0a718fd3 10bdb391"
"snaps": "ccd30115 c7745b19 5c5ce90e 017253c9 61763456"
},
"bond-maniShip-high": {
"about": "调和 high: tier 1 layers 999; chess_char_5_19_b chess_char_5_17_b chess_char_6_11_b chess_char_1_03_a chess_char_2_04_a chess_char_5_15_b chess_char_5_20_b chess_char_5_21_b token_10030_mlyss_wtrman",
@@ -810,24 +810,24 @@
"total": 17,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 35,
"rngDraws": 55,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":126144,"bossDmg":0,"heal":0,"deaths":0,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_4_01_a",2,null,2901.8,1,3,0,0,0,0,0,0],
["p1",2,"op","chess_char_2_11_a",1,null,2257.29,1,6,0,0,0,0,0,0],
["p1",3,"op","chess_char_3_18_a",2,null,1629.1,1,8,0,0,0,0,0,0],
["p1",4,"op","chess_char_3_01_a",2,null,1663.13,1,1,5,24785,0,0,23,1],
["p1",5,"op","chess_char_3_17_a",1,null,2470.6,1,4,4,38664,0,0,32,3],
["p1",6,"op","chess_char_3_20_a",1,null,913.22,1,5,1,6272,320,0,30,1],
["p1",7,"op","chess_char_3_21_a",2,null,1500.4,1,2,4,24122,0,0,21,1],
["p1",8,"op","chess_char_4_02_a",2,null,723.8,1,7,3,32301,847,0,17,1]
["p1",4,"op","chess_char_3_01_a",2,null,1663.13,1,1,2,24889,0,0,22,1],
["p1",5,"op","chess_char_3_17_a",1,null,2470.6,1,4,3,34513,0,0,30,3],
["p1",6,"op","chess_char_3_20_a",1,null,913.22,1,5,4,18617,320,0,30,1],
["p1",7,"op","chess_char_3_21_a",2,null,1500.4,1,2,7,15387,0,0,19,1],
["p1",8,"op","chess_char_4_02_a",2,null,264,1,7,1,32738,1307,0,17,1]
],
"enemies": {"enemy_1116_liprr":[11,11,0,920,69696],"enemy_1116_liprr_2":[4,4,0,247,34560],"enemy_1118_lidbox_2":[2,2,0,0,21888]},
"hooks": [1,25,1569,131,131,278,278,0,17,17,7,6,0,4875,9,8,17,0,1,17,0,0,0],
"events": {"atk":163,"deploy":8,"die":17,"dmg":277,"engage":5,"fx":20,"skill":13,"spawn":25,"status":62},
"fx": {"buff":1,"displace":8,"ripple":5,"shield":2,"shieldBreak":1,"volley":3},
"snaps": "cb2e289d 5504ba16 91f48812 b5b92713 b5b86756 360f3526"
"enemies": {"enemy_1116_liprr":[11,11,0,620,69696],"enemy_1116_liprr_2":[4,4,0,741,34560],"enemy_1118_lidbox_2":[2,2,0,266,21888]},
"hooks": [1,25,1569,126,126,283,283,0,17,17,7,5,0,4873,12,7,17,0,1,17,0,0,0],
"events": {"atk":137,"deploy":8,"die":17,"dmg":283,"engage":5,"fx":55,"skill":12,"spawn":25,"status":62},
"fx": {"buff":1,"displace":7,"drone":37,"ripple":5,"shield":2,"volley":3},
"snaps": "84698390 95c61d5c f4fb1346 74a078bf f8644cfb 64bec820"
},
"bond-miraShip-high": {
"about": "奇迹 high: tier 1 layers 999; chess_char_4_01_b chess_char_2_11_b chess_char_4_04_b chess_char_4_07_b chess_char_3_01_b chess_char_5_22_b chess_char_4_02_b chess_char_4_06_b",
@@ -1091,24 +1091,24 @@
"total": 30,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 45,
"rngDraws": 42,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":30,"total":30,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":262819,"bossDmg":0,"heal":0,"deaths":1,"layerGains":{}}},
"players": {"p1":{"killed":30,"total":30,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":262899,"bossDmg":0,"heal":0,"deaths":1,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_1_12_b",1,"uniequip_002_estell",2847.9,1,2,0,0,0,0,0,0],
["p1",2,"op","chess_char_2_08_b",1,"uniequip_002_bubble",3710.3,1,3,0,0,0,0,0,0],
["p1",3,"op","chess_char_3_06_b",1,"uniequip_002_philae",3462.8,1,4,0,0,0,0,0,0],
["p1",4,"op","chess_char_4_23_b",2,"uniequip_002_gvial2",1532.04,1,5,16,168462,1560,0,77,1],
["p1",5,"op","chess_char_4_22_b",2,"uniequip_002_svrash",0,0,6,12,52198,2826,0,33,1],
["p1",4,"op","chess_char_4_23_b",2,"uniequip_002_gvial2",2117.06,1,5,15,140375,975,0,70,1],
["p1",5,"op","chess_char_4_22_b",2,"uniequip_002_svrash",0,0,6,10,44559,2826,0,33,1],
["p1",6,"op","chess_char_2_06_b",0,"uniequip_002_papyrs",1802.9,1,7,0,0,0,0,0,0],
["p1",7,"op","chess_char_3_13_b",1,"uniequip_002_malist",1512.5,1,8,2,42159,0,0,46,11],
["p1",7,"op","chess_char_3_13_b",1,"uniequip_002_malist",1512.5,1,8,5,77965,0,0,42,11],
["p1",8,"op","chess_char_4_25_b",2,"uniequip_002_cetsyr",1838.1,1,1,0,0,0,0,0,1]
],
"enemies": {"enemy_1006_shield_3":[3,3,0,2843,138240],"enemy_1043_zomsbr":[23,23,0,0,69875],"enemy_1402_tgshd_2":[4,4,0,1251,59904]},
"hooks": [1,38,2462,165,165,397,597,1388,31,31,14,14,0,6375,0,5,30,0,1,43,0,0,0],
"events": {"atk":207,"deploy":8,"die":31,"dmg":597,"engage":3,"fx":110,"skill":28,"spawn":38,"status":41},
"enemies": {"enemy_1006_shield_3":[3,3,0,2550,138240],"enemy_1043_zomsbr":[23,23,0,0,69635],"enemy_1402_tgshd_2":[4,4,0,1251,59904]},
"hooks": [1,38,2462,153,153,408,408,1297,31,31,14,14,0,6375,0,4,30,0,1,40,0,0,0],
"events": {"atk":183,"deploy":8,"die":31,"dmg":408,"engage":3,"fx":110,"skill":28,"spawn":38,"status":39},
"fx": {"expose":58,"jungleSoul":1,"mote":14,"redistribute":15,"reweave":1,"slash":20,"truesilver":1},
"snaps": "d81207a4 e5f41037 e0b88fa7 7a6a3918 dbdfa4d8 a6f93588 e957bb33 9d7565d2 294af894"
"snaps": "d252a2b9 064fa22f 580a6127 93f56817 48dfb65c c53e2705 8414849f 496b43f5 c88e5e4d"
},
"bond-siracusaShip-low": {
"about": "叙拉古 low: tier 1 layers 1; chess_char_3_06_a chess_char_1_08_a chess_char_2_16_a chess_char_3_02_a chess_char_3_03_a chess_char_3_04_a chess_char_3_05_a chess_char_1_07_a",
@@ -1275,29 +1275,29 @@
"total": 17,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 4,
"rngDraws": 6,
"errors": {"count":0,"kinds":[]},
"players": {
"p1": {"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":126144,"bossDmg":0,"heal":0,"deaths":2,"layerGains":{"siracusaShip":4}}
"p1": {"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":126144,"bossDmg":0,"heal":0,"deaths":2,"layerGains":{"siracusaShip":6}}
},
"units": [
["p1",1,"op","chess_char_3_16_a",1,null,2987.88,1,3,0,0,0,0,0,0],
["p1",2,"op","chess_char_4_01_a",2,null,4077.11,1,5,2,8508,566,0,10,1],
["p1",3,"op","chess_char_1_08_a",1,null,0,0,6,1,7992,2615,0,13,1],
["p1",4,"op","chess_char_3_18_a",2,null,0,0,10,5,40927,2036,0,38,1],
["p1",5,"op","chess_char_3_19_a",2,null,1978.63,1,7,2,10333,0,0,21,1],
["p1",6,"op","chess_char_3_20_a",1,null,1541.38,1,9,2,682,0,0,8,1],
["p1",7,"op","chess_char_3_21_a",2,null,1875.5,1,11,1,19449,0,0,23,1],
["p1",5,"op","chess_char_3_19_a",2,null,1978.63,1,7,3,9846,0,0,20,1],
["p1",6,"op","chess_char_3_20_a",1,null,1541.38,1,9,0,2764,0,0,6,1],
["p1",7,"op","chess_char_3_21_a",2,null,1875.5,1,11,2,17854,0,0,23,1],
["p1",8,"op","chess_char_4_02_a",2,null,1963.5,1,4,4,37037,0,0,7,1],
["p1",9,"token","token_10028_vigil_wolf",null,null,852.9,1,8,0,1216,27,0,2,null],
["-","~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_1116_liprr":[11,11,0,41,69696],"enemy_1116_liprr_2":[4,4,0,297,34560],"enemy_1118_lidbox_2":[2,2,0,4906,21888]},
"hooks": [1,28,1502,150,150,266,266,0,19,19,7,4,3,6742,29,17,17,0,1,20,2,0,0],
"events": {"atk":183,"deploy":9,"die":19,"dmg":264,"engage":8,"fx":38,"layer":2,"skill":11,"spawn":28,"status":92},
"fx": {"aoe":1,"camouflage":1,"counter":3,"displace":16,"dp":2,"garrison":2,"liberate":2,"phase":3,"ripple":4,"sermon":1,"shield":2,"wolfShadow":1},
"snaps": "a9326071 ba5f4858 674158f2 668d5d48 ab9377c5"
"hooks": [1,28,1502,147,147,266,266,0,19,19,7,4,3,6742,29,17,17,0,1,20,3,0,0],
"events": {"atk":178,"deploy":9,"die":19,"dmg":264,"engage":8,"fx":43,"layer":3,"skill":11,"spawn":28,"status":92},
"fx": {"aoe":1,"camouflage":1,"counter":3,"displace":16,"dp":2,"drone":4,"garrison":3,"liberate":2,"phase":3,"ripple":4,"sermon":1,"shield":2,"wolfShadow":1},
"snaps": "44b7a79e a057c22e 1399d939 c2bd253f 9479758a"
},
"bond-soloShip-high": {
"about": "独行 high: tier 1 layers 999; chess_char_5_19_b chess_char_1_08_b chess_char_5_13_b chess_char_5_14_b chess_char_5_17_b chess_char_5_12_b chess_char_5_15_b chess_char_5_20_b",
@@ -1575,8 +1575,8 @@
"round": 5,
"seed": 4091762637,
"waveId": "act1autochess_05",
"time": 55.83,
"ticks": 1675,
"time": 51.33,
"ticks": 1540,
"reason": "cleared",
"killed": 17,
"total": 17,
@@ -1584,16 +1584,16 @@
"bossHpLeft": null,
"rngDraws": 6,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":123047,"bossDmg":0,"heal":3612,"deaths":0,"layerGains":{}}},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":123085,"bossDmg":0,"heal":2666,"deaths":0,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_3_06_a",1,null,3577.42,1,6,0,15374,3173,0,15,1],
["p1",2,"op","chess_char_3_02_a",1,null,2102.1,1,7,7,38048,0,0,26,1],
["p1",1,"op","chess_char_3_06_a",1,null,3577.42,1,6,2,8709,2130,0,11,1],
["p1",2,"op","chess_char_3_02_a",1,null,2102.1,1,7,6,32218,0,0,25,1],
["p1",3,"op","chess_char_3_03_a",1,null,1515.8,1,5,0,0,0,0,0,0],
["p1",4,"op","chess_char_3_04_a",1,null,2050.4,1,8,1,28010,0,0,0,0],
["p1",5,"op","chess_char_3_05_a",2,null,5978.83,1,9,4,20606,245,0,18,1],
["p1",6,"op","chess_char_1_06_a",1,null,1250.7,1,3,4,15626,0,1411,30,1],
["p1",7,"op","chess_char_2_05_a",1,null,1552.32,1,4,0,0,0,2201,17,1],
["p1",8,"op","chess_char_2_10_a",1,null,1185.8,1,10,0,5382,0,0,29,1],
["p1",5,"op","chess_char_3_05_a",2,null,5978.83,1,9,3,21417,342,0,18,1],
["p1",6,"op","chess_char_1_06_a",1,null,1250.7,1,3,2,14787,0,1005,26,1],
["p1",7,"op","chess_char_2_05_a",1,null,1552.32,1,4,0,0,0,1661,14,1],
["p1",8,"op","chess_char_2_10_a",1,null,1185.8,1,10,1,17944,0,0,29,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],
["p1","~1","token","token_10031_swire2_gdtrap",null,null,1000,0,11,0,0,0,0,0,null],
@@ -1614,11 +1614,11 @@
["p1","~16","token","token_10031_swire2_gdtrap",null,null,1000,0,43,0,0,0,0,0,null],
["p1","~17","token","token_10031_swire2_gdtrap",null,null,1000,1,44,0,0,0,0,0,null]
],
"enemies": {"enemy_1116_liprr":[11,11,0,192,69696],"enemy_1116_liprr_2":[4,4,0,199,34560],"enemy_1118_lidbox_2":[2,2,0,3027,21888]},
"hooks": [1,44,1675,165,165,298,312,28,17,33,6,2,0,6349,15,14,17,0,1,17,0,0,0],
"events": {"atk":165,"deploy":25,"die":33,"dmg":312,"engage":5,"fx":104,"heal":28,"skill":10,"spawn":44,"status":43},
"fx": {"aoe":5,"coin":18,"counter":4,"explode":16,"liberate":1,"overload":1,"phase":3,"strike":38,"summon":17,"taunt":1},
"snaps": "950a6182 a670e309 094b33b8 126a0a37 d2dc7eef 6d3cae8b"
"enemies": {"enemy_1116_liprr":[11,11,0,108,69696],"enemy_1116_liprr_2":[4,4,0,307,34560],"enemy_1118_lidbox_2":[2,2,0,2057,21888]},
"hooks": [1,44,1540,146,146,307,314,24,17,33,6,2,0,6067,15,14,17,0,1,17,0,0,0],
"events": {"atk":146,"deploy":25,"die":33,"dmg":314,"engage":5,"fx":115,"heal":24,"skill":10,"spawn":44,"status":43},
"fx": {"aoe":3,"coin":17,"counter":4,"drone":23,"explode":16,"liberate":1,"overload":1,"phase":2,"strike":30,"summon":17,"taunt":1},
"snaps": "d1974070 80b823c0 1cdb05ab d65e859c c593343d 34f0b4a2"
},
"bond-victoriaShip-high": {
"about": "维多利亚 high: tier 2 layers 999; chess_char_4_11_b chess_char_4_07_b chess_char_1_06_b chess_char_2_05_b chess_char_2_10_b chess_char_3_08_b chess_char_4_13_b chess_char_4_14_b token_10041_cathy_catsld token_10041_cathy_catsld",
@@ -1629,8 +1629,8 @@
"round": 10,
"seed": 11223320,
"waveId": "act1autochess_h03",
"time": 62.87,
"ticks": 1886,
"time": 48.8,
"ticks": 1464,
"reason": "cleared",
"killed": 12,
"total": 12,
@@ -1638,27 +1638,27 @@
"bossHpLeft": null,
"rngDraws": 0,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":12,"total":12,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":141088,"bossDmg":0,"heal":6750,"deaths":0,"layerGains":{}}},
"players": {"p1":{"killed":12,"total":12,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":141088,"bossDmg":0,"heal":3250,"deaths":0,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_4_11_b",1,"uniequip_002_cathy",2908.4,1,5,0,0,0,0,0,0],
["p1",2,"op","chess_char_4_07_b",1,"uniequip_002_bpipe",2621.3,1,7,0,0,0,0,0,0],
["p1",3,"op","chess_char_1_06_b",1,"uniequip_002_vendla",1542.2,1,8,5,28240,0,1739,7,1],
["p1",4,"op","chess_char_2_05_b",1,"uniequip_002_harold",17910.32,1,10,0,0,5469,5011,10,1],
["p1",5,"op","chess_char_2_10_b",1,"uniequip_002_rockr",1546.6,1,11,7,93826,1281,0,42,1],
["p1",3,"op","chess_char_1_06_b",1,"uniequip_002_vendla",1542.2,1,8,0,0,0,0,0,0],
["p1",4,"op","chess_char_2_05_b",1,"uniequip_002_harold",17910.32,1,10,0,0,2609,3250,6,1],
["p1",5,"op","chess_char_2_10_b",1,"uniequip_002_rockr",1546.6,1,11,12,131060,641,0,23,1],
["p1",6,"op","chess_char_3_08_b",1,"uniequip_002_mint",2184.6,1,4,0,0,0,0,0,0],
["p1",7,"op","chess_char_4_13_b",1,"uniequip_002_gnosis",2187.9,1,6,0,0,0,0,0,0],
["p1",8,"op","chess_char_4_14_b",1,"uniequip_002_lionhd",1788.6,1,9,0,19021,0,0,7,6],
["p1",8,"op","chess_char_4_14_b",1,"uniequip_002_lionhd",1788.6,1,9,0,10028,0,0,3,4],
["p1",9,"token","token_10041_cathy_catsld",null,null,100,1,12,0,0,0,0,0,null],
["p1",10,"token","token_10041_cathy_catsld",null,null,100,1,13,0,0,0,0,0,null],
["-","~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_1005_yokai_2":[4,4,0,1532,15428],"enemy_1041_lazerd_2":[3,3,0,5218,44790],"enemy_1042_frostd":[5,5,0,0,80870]},
"hooks": [1,25,1886,79,79,76,76,12,12,12,9,9,0,4756,266,0,12,0,1,12,0,0,0],
"events": {"atk":79,"deploy":10,"die":12,"dmg":76,"engage":3,"fx":10,"heal":12,"skill":18,"spawn":25,"status":17},
"fx": {"counter":2,"explosion":6,"overload":1,"taunt":1},
"snaps": "baf019b9 04dccd49 7607a313 d5443e4e 65c3d507 5c447217 1a74a703"
"enemies": {"enemy_1005_yokai_2":[4,4,0,641,15428],"enemy_1041_lazerd_2":[3,3,0,2609,44790],"enemy_1042_frostd":[5,5,0,0,80870]},
"hooks": [1,25,1464,38,38,59,59,6,12,12,6,5,0,3288,194,0,12,0,1,12,0,0,0],
"events": {"atk":38,"deploy":10,"die":12,"dmg":59,"engage":2,"fx":28,"heal":6,"skill":11,"spawn":25,"status":17},
"fx": {"drone":23,"explosion":4,"overload":1},
"snaps": "41450a5d 84679dbf e939cdb3 4cc777cb 3c9f9b60"
},
"bond-visiShip-low": {
"about": "远见 low: tier 1 layers 1; chess_char_3_12_a chess_char_3_03_a chess_char_2_02_a chess_char_3_08_a chess_char_3_09_a chess_char_3_10_a chess_char_3_11_a chess_char_3_13_a token_10000_silent_healrb",
@@ -1669,32 +1669,32 @@
"round": 5,
"seed": 3923365115,
"waveId": "act1autochess_05",
"time": 54.2,
"ticks": 1626,
"time": 64.23,
"ticks": 1927,
"reason": "cleared",
"killed": 17,
"total": 17,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 36,
"rngDraws": 34,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":98550,"bossDmg":0,"heal":4275,"deaths":0,"layerGains":{}}},
"players": {"p1":{"killed":17,"total":17,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":98550,"bossDmg":0,"heal":4764,"deaths":2,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_3_12_a",2,null,2567.4,1,3,0,0,0,0,0,0],
["p1",1,"op","chess_char_3_12_a",2,null,412.94,1,3,2,1572,2154,0,9,1],
["p1",2,"op","chess_char_3_03_a",1,null,1515.8,1,6,0,0,0,0,0,0],
["p1",3,"op","chess_char_2_02_a",1,null,1540,1,1,0,0,0,3047,13,2],
["p1",4,"op","chess_char_3_08_a",1,null,1724.8,1,4,3,17803,29,0,8,1],
["p1",5,"op","chess_char_3_09_a",1,null,1393.7,1,5,3,25124,547,0,26,1],
["p1",6,"op","chess_char_3_10_a",1,null,1815,1,2,2,7065,1716,0,9,1],
["p1",7,"op","chess_char_3_11_a",1,null,1405.8,1,7,6,38190,825,0,25,3],
["p1",8,"op","chess_char_3_13_a",1,null,914,1,8,3,10369,1485,0,36,7],
["p1",9,"token","token_10000_silent_healrb",null,null,1000,1,29,0,0,0,1229,16,null]
["p1",3,"op","chess_char_2_02_a",1,null,1540,1,1,0,0,0,3246,15,2],
["p1",4,"op","chess_char_3_08_a",1,null,1753.4,1,4,3,11114,0,0,8,1],
["p1",5,"op","chess_char_3_09_a",1,null,1393.7,1,5,3,26048,1077,0,32,1],
["p1",6,"op","chess_char_3_10_a",1,null,0,0,2,1,10166,3109,0,9,1],
["p1",7,"op","chess_char_3_11_a",1,null,0,0,7,4,27868,2323,0,20,2],
["p1",8,"op","chess_char_3_13_a",1,null,1170.4,1,8,4,21783,1518,0,34,7],
["p1",9,"token","token_10000_silent_healrb",null,null,1000,0,29,0,0,0,1518,19,null]
],
"enemies": {"enemy_1116_liprr":[11,11,0,2103,54450],"enemy_1116_liprr_2":[4,4,0,783,27000],"enemy_1118_lidbox_2":[2,2,0,1716,17100]},
"hooks": [1,28,1626,168,168,178,178,29,17,19,15,15,0,7317,2,24,17,0,1,17,0,0,0],
"events": {"atk":195,"deploy":11,"die":19,"dmg":178,"engage":5,"fx":47,"heal":29,"skill":30,"spawn":26,"status":23},
"fx": {"aoe":1,"displace":16,"liberate":2,"phase":4,"pull":16,"strike":3,"summon":2,"volley":3},
"snaps": "1a69c505 b8848494 3f8ff510 ec364fad 577e2d85 ed7ffada"
"enemies": {"enemy_1116_liprr":[11,11,0,1531,54450],"enemy_1116_liprr_2":[4,4,0,1291,27000],"enemy_1118_lidbox_2":[2,2,0,7359,17100]},
"hooks": [1,28,1927,192,192,223,223,34,19,22,15,14,0,8243,1,23,17,0,1,19,0,0,0],
"events": {"atk":215,"deploy":11,"die":22,"dmg":223,"engage":6,"fx":36,"heal":34,"skill":29,"spawn":26,"status":22},
"fx": {"aoe":1,"displace":11,"liberate":2,"phase":5,"pull":11,"strike":2,"summon":2,"volley":2},
"snaps": "78218668 baf3658a cf85bac1 a4b51e2f ad4c883e fe1c9c59 f50febd4"
},
"bond-visiShip-high": {
"about": "远见 high: tier 1 layers 999; chess_char_4_17_b chess_char_4_18_b chess_char_3_03_b chess_char_4_19_b chess_char_4_16_b chess_char_2_02_b chess_char_4_20_b chess_char_4_21_b token_10000_silent_healrb",
+39 -39
View File
@@ -4155,29 +4155,29 @@
"bossHpLeft": null,
"rngDraws": 1138,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":0,"total":138,"perfect":false,"leaks":138,"leaksUncounted":0,"coins":0,"dmg":455852,"bossDmg":0,"heal":0,"deaths":15,"layerGains":{}}},
"players": {"p1":{"killed":0,"total":138,"perfect":false,"leaks":138,"leaksUncounted":0,"coins":0,"dmg":545909,"bossDmg":0,"heal":0,"deaths":15,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_5_diy1_a",0,null,1236.4,1,8,0,61914,0,0,80,3],
["p1",2,"op","chess_char_5_diy2_a",1,null,1236.4,1,11,0,64924,0,0,51,1],
["p1",3,"op","chess_char_5_diy1_a",2,null,1236.4,1,13,0,62811,0,0,93,3],
["p1",4,"op","chess_char_5_diy2_b",0,"none",1496,1,15,0,74201,0,0,82,3],
["p1",5,"op","chess_char_5_diy1_b",1,"none",1496,1,4,0,72338,0,0,44,1],
["p1",6,"op","chess_char_5_diy2_b",2,"none",1496,1,9,0,97519,0,0,75,3],
["p1",7,"op","chess_char_5_diy1_b",0,"uniequip_002_gdglow",1595,1,163,0,6333,3190,0,4,1],
["p1",8,"op","chess_char_5_diy2_b",1,"uniequip_002_gdglow",0,0,95,0,1891,3190,0,16,0],
["p1",9,"op","chess_char_5_diy1_b",2,"uniequip_002_gdglow",0,0,157,0,3203,4785,0,25,0],
["p1",10,"op","chess_char_5_diy2_b",0,"uniequip_003_gdglow",0,0,152,0,2419,4488,0,22,0],
["p1",11,"op","chess_char_5_diy1_b",1,"uniequip_003_gdglow",0,0,149,0,1370,4488,0,15,0],
["p1",12,"op","chess_char_5_diy2_b",2,"uniequip_003_gdglow",0,0,107,0,6927,2992,0,13,1],
["p1",1,"op","chess_char_5_diy1_a",0,null,1236.4,1,8,0,74713,0,0,80,3],
["p1",2,"op","chess_char_5_diy2_a",1,null,1236.4,1,11,0,73083,0,0,51,1],
["p1",3,"op","chess_char_5_diy1_a",2,null,1236.4,1,13,0,77690,0,0,93,3],
["p1",4,"op","chess_char_5_diy2_b",0,"none",1496,1,15,0,88835,0,0,82,3],
["p1",5,"op","chess_char_5_diy1_b",1,"none",1496,1,4,0,80271,0,0,44,1],
["p1",6,"op","chess_char_5_diy2_b",2,"none",1496,1,9,0,110904,0,0,75,3],
["p1",7,"op","chess_char_5_diy1_b",0,"uniequip_002_gdglow",1595,1,163,0,7094,3190,0,4,1],
["p1",8,"op","chess_char_5_diy2_b",1,"uniequip_002_gdglow",0,0,95,0,4933,3190,0,16,0],
["p1",9,"op","chess_char_5_diy1_b",2,"uniequip_002_gdglow",0,0,157,0,7955,4785,0,25,0],
["p1",10,"op","chess_char_5_diy2_b",0,"uniequip_003_gdglow",0,0,152,0,6694,4488,0,22,0],
["p1",11,"op","chess_char_5_diy1_b",1,"uniequip_003_gdglow",0,0,149,0,4284,4488,0,15,0],
["p1",12,"op","chess_char_5_diy2_b",2,"uniequip_003_gdglow",0,0,107,0,9453,2992,0,13,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_1166_dusbr_2":[45,0,45,7678,132417],"enemy_1169_duphlx_2":[51,0,51,6281,141717],"enemy_1170_dushld_2":[42,0,42,9174,181718]},
"hooks": [1,163,6073,559,559,2092,2092,0,15,153,16,13,0,24679,578,15,138,138,1,15,0,0,0],
"events": {"atk":559,"deploy":22,"die":15,"dmg":2092,"engage":12,"fx":1777,"leak":138,"skill":29,"spawn":153,"status":576},
"enemies": {"enemy_1166_dusbr_2":[45,0,45,7678,168139],"enemy_1169_duphlx_2":[51,0,51,6281,168619],"enemy_1170_dushld_2":[42,0,42,9174,209150]},
"hooks": [1,163,6073,559,559,2612,2612,0,15,153,16,13,0,24679,578,15,138,138,1,15,0,0,0],
"events": {"atk":559,"deploy":22,"die":15,"dmg":2612,"engage":12,"fx":1777,"leak":138,"skill":29,"spawn":153,"status":576},
"fx": {"drone":1138,"droneLock":518,"drones":16,"explode":105},
"snaps": "bdd99668 c46a9ee9 9c11177a eebd0b2c 8cd16121 d2197dca fedac0f3 43f32cf5 bf91603f 06844f89 604fed15 8020ffd5 cb5d37fc 02479270 70c2225e 7397b81e 4dddf649 d98396d8 2f92ae08 3954d416 2533bfc0"
"snaps": "92781428 6430fa6b c6dc707c f08a198d fc3a79fb 860d747b c0bc2e24 fbd9411c b6d17260 56587aa5 c13636cb 72ee3e4c f6c337e7 09705474 b4dd8303 227da0fa c51ac9e5 c5fff7d6 5fdb73d0 7ad219bb 0c191fb1"
},
"diy-099": {
"about": "6_diy1_a=gdglow/S1 6_diy2_a=gdglow/S2 6_diy1_a=gdglow/S3 6_diy2_b=gdglow/S1 6_diy1_b=gdglow/S2 6_diy2_b=gdglow/S3 6_diy1_b=gdglow/S1/002_gdglow 6_diy2_b=gdglow/S2/002_gdglow 6_diy1_b=gdglow/S3/002_gdglow 6_diy2_b=gdglow/S1/003_gdglow 6_diy1_b=gdglow/S2/003_gdglow 6_diy2_b=gdglow/S3/003_gdglow",
@@ -4188,37 +4188,37 @@
"round": 13,
"seed": 213318073,
"waveId": "act1autochess_h06",
"time": 215.43,
"ticks": 6463,
"time": 214.47,
"ticks": 6434,
"reason": "cleared",
"killed": 68,
"killed": 75,
"total": 129,
"unspawned": 0,
"bossHpLeft": null,
"rngDraws": 1845,
"rngDraws": 1833,
"errors": {"count":0,"kinds":[]},
"players": {"p1":{"killed":68,"total":129,"perfect":false,"leaks":61,"leaksUncounted":0,"coins":0,"dmg":1469349,"bossDmg":0,"heal":0,"deaths":6,"layerGains":{}}},
"players": {"p1":{"killed":75,"total":129,"perfect":false,"leaks":54,"leaksUncounted":0,"coins":0,"dmg":1599812,"bossDmg":0,"heal":0,"deaths":6,"layerGains":{}}},
"units": [
["p1",1,"op","chess_char_6_diy1_a",0,null,1236.4,1,3,10,114795,0,0,95,3],
["p1",2,"op","chess_char_6_diy2_a",1,null,1236.4,1,4,6,98029,0,0,44,1],
["p1",3,"op","chess_char_6_diy1_a",2,null,1236.4,1,11,1,115795,0,0,50,3],
["p1",4,"op","chess_char_6_diy2_b",0,"none",1496,1,13,1,39972,0,0,45,3],
["p1",5,"op","chess_char_6_diy1_b",1,"none",1496,1,5,10,174655,0,0,43,1],
["p1",6,"op","chess_char_6_diy2_b",2,"none",1496,1,8,5,130906,0,0,91,3],
["p1",7,"op","chess_char_6_diy1_b",0,"uniequip_002_gdglow",1633.5,1,12,11,200948,0,0,91,4],
["p1",8,"op","chess_char_6_diy2_b",1,"uniequip_002_gdglow",1633.5,1,14,6,298003,0,0,53,1],
["p1",9,"op","chess_char_6_diy1_b",2,"uniequip_002_gdglow",1633.5,1,9,10,201809,0,0,87,3],
["p1",10,"op","chess_char_6_diy2_b",0,"uniequip_003_gdglow",1496,1,144,2,38398,2992,0,33,2],
["p1",11,"op","chess_char_6_diy1_b",1,"uniequip_003_gdglow",1496,1,138,1,10182,2992,0,57,0],
["p1",12,"op","chess_char_6_diy2_b",2,"uniequip_003_gdglow",1496,1,132,5,45856,2992,0,15,1],
["p1",1,"op","chess_char_6_diy1_a",0,null,1236.4,1,3,4,106436,0,0,92,3],
["p1",2,"op","chess_char_6_diy2_a",1,null,1236.4,1,4,4,131514,0,0,43,1],
["p1",3,"op","chess_char_6_diy1_a",2,null,1236.4,1,11,2,122309,0,0,46,3],
["p1",4,"op","chess_char_6_diy2_b",0,"none",1496,1,13,0,53284,0,0,46,3],
["p1",5,"op","chess_char_6_diy1_b",1,"none",1496,1,5,13,162190,0,0,43,1],
["p1",6,"op","chess_char_6_diy2_b",2,"none",1496,1,8,7,158296,0,0,91,3],
["p1",7,"op","chess_char_6_diy1_b",0,"uniequip_002_gdglow",1633.5,1,12,21,277787,0,0,91,4],
["p1",8,"op","chess_char_6_diy2_b",1,"uniequip_002_gdglow",1633.5,1,14,8,261532,0,0,53,1],
["p1",9,"op","chess_char_6_diy1_b",2,"uniequip_002_gdglow",1633.5,1,9,7,186106,0,0,87,3],
["p1",10,"op","chess_char_6_diy2_b",0,"uniequip_003_gdglow",0,0,92,2,67871,2992,0,23,2],
["p1",11,"op","chess_char_6_diy1_b",1,"uniequip_003_gdglow",0,0,91,1,35064,2992,0,57,0],
["p1",12,"op","chess_char_6_diy2_b",2,"uniequip_003_gdglow",1496,1,136,5,37424,2992,0,23,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_10124_uashld_2":[18,4,14,4488,546846],"enemy_1043_zomsbr":[66,50,16,912,309132],"enemy_1061_zomshd":[45,14,31,3576,649372]},
"hooks": [1,149,6463,724,724,4112,4112,49312,74,135,25,20,0,34562,907,8,129,61,1,74,0,0,0],
"events": {"atk":724,"deploy":18,"die":74,"dmg":4112,"engage":12,"fx":2496,"leak":61,"skill":45,"spawn":143,"status":473},
"fx": {"drone":1845,"droneLock":450,"drones":25,"explode":176},
"snaps": "f541f090 c32b0887 8a0d0ec8 0025b950 5d8fbbd2 abfb2750 083f5116 896707cd 0f55d1b0 2db8f520 09351c4c 9ef017f3 d1c0123c 8ea2215f d2213fdc 38a8b05f 2c5a266c cbe1b254 464f79f1 fb548a9b 31a8d689 3650bdc6"
"enemies": {"enemy_10124_uashld_2":[18,8,10,2992,638700],"enemy_1043_zomsbr":[66,53,13,912,328686],"enemy_1061_zomshd":[45,14,31,5072,669451]},
"hooks": [1,147,6434,716,716,4774,4774,49638,81,135,25,19,0,34415,861,9,129,54,1,81,0,0,0],
"events": {"atk":716,"deploy":16,"die":81,"dmg":4774,"engage":12,"fx":2485,"leak":54,"skill":44,"spawn":143,"status":469},
"fx": {"drone":1833,"droneLock":445,"drones":25,"explode":182},
"snaps": "8997e50d 3106dc76 e94c98b3 86739ec6 32b588ca 7728ff26 deca17c2 9c61006c 87a4e62c 83004cb1 3efd9d05 00bc8ef7 6b6d9f39 14e1ea96 9b5a8ef8 297316e3 3bc788c7 32245b95 f1986285 2cfa6f21 bd536ac3 ce7828b3"
},
"diy-100": {
"about": "5_diy1_a=haak/S1 5_diy2_a=haak/S2 5_diy1_a=haak/S3 5_diy2_b=haak/S1 5_diy1_b=haak/S2 5_diy2_b=haak/S3 5_diy1_b=haak/S1/002_haak 5_diy2_b=haak/S2/002_haak 5_diy1_b=haak/S3/002_haak 5_diy2_b=haak/S1/003_haak 5_diy1_b=haak/S2/003_haak 5_diy2_b=haak/S3/003_haak",
+123 -120
View File
@@ -227,50 +227,50 @@
"round": 14,
"seed": 1428555614,
"waveId": "act1autochess_h07_03",
"time": 169.2,
"ticks": 5076,
"time": 170.4,
"ticks": 5112,
"reason": "cleared",
"killed": 18,
"killed": 19,
"total": 6,
"unspawned": 0,
"bossHpLeft": 0,
"rngDraws": 1416,
"errors": {"count":0,"kinds":[]},
"players": {
"p1": {"killed":18,"total":6,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1516502,"bossDmg":1398136,"heal":10352,"deaths":1,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":2667879,"bossDmg":2601864,"heal":41836,"deaths":3,"layerGains":{}}
"p1": {"killed":19,"total":6,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1542879,"bossDmg":1424512,"heal":11484,"deaths":2,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":2641521,"bossDmg":2575488,"heal":50009,"deaths":3,"layerGains":{}}
},
"units": [
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_yu",4070,1,7,0,0,0,6873,0,1],
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_yu",4070,1,7,0,0,0,7258,0,1],
["p1",2,"op","chess_char_6_06_b",2,"uniequip_002_pepe",3232.9,1,11,0,0,0,0,0,0],
["p1",3,"op","chess_char_6_07_b",2,"uniequip_002_siege2",3411.1,1,9,1,29,1184,0,29,1],
["p1",4,"op","chess_char_6_01_b",2,"uniequip_002_lemuen",2344.65,1,13,5,815234,3173,0,52,7],
["p1",5,"op","chess_char_6_02_b",2,"uniequip_002_sbell2",2106.51,1,17,0,248050,6003,751,41,2],
["p1",6,"op","chess_char_6_04_b",2,"uniequip_002_skadi2",162.95,1,59,1,26550,16018,1505,0,3],
["p1",7,"op","chess_char_6_05_b",2,"uniequip_002_pasngr",1664.48,1,21,1,284438,9843,1204,82,7],
["p1",3,"op","chess_char_6_07_b",2,"uniequip_002_siege2",3411.1,1,9,1,47,6231,541,47,1],
["p1",4,"op","chess_char_6_01_b",2,"uniequip_002_lemuen",2344.65,1,13,6,837990,7545,698,53,7],
["p1",5,"op","chess_char_6_02_b",2,"uniequip_002_sbell2",1834.46,1,17,1,262042,7260,906,41,2],
["p1",6,"op","chess_char_6_04_b",2,"uniequip_002_skadi2",0,0,59,1,26548,14647,1235,0,3],
["p1",7,"op","chess_char_6_05_b",2,"uniequip_002_pasngr",814.83,1,21,0,273606,9866,827,82,6],
["p1",8,"op","chess_char_6_08_b",2,"uniequip_002_reed2",1834.8,1,5,0,30,0,19,13,1],
["p1",9,"op","chess_char_6_09_b",0,"uniequip_002_cello",1454.2,1,15,0,37,0,0,9,9],
["p1",10,"op","chess_char_6_11_b",2,"uniequip_002_mlyss",2082.3,1,23,0,103926,1501,0,178,4],
["p1",11,"token","token_10017_skadi2_dedant",null,null,138,0,26,0,0,0,0,0,null],
["p2",12,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",4181.76,1,31,1,476210,0,0,176,3],
["p2",13,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",3043.7,1,62,1,28,3044,0,9,1],
["p2",12,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",4181.76,1,31,1,481322,0,0,177,3],
["p2",13,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",3043.7,1,62,1,27,3044,0,8,1],
["p2",14,"op","chess_char_5_01_b",1,"uniequip_002_excu2",2545.4,1,56,0,14,3710,780,14,1],
["p2",15,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",6916.53,1,32,0,279951,2036,0,70,3],
["p2",16,"op","chess_char_6_12_b",1,"uniequip_002_rosmon",3493.03,1,16,4,223610,3571,443,62,3],
["p2",17,"op","chess_char_6_13_b",1,"uniequip_002_angel2",2680.15,1,20,3,1466393,5212,1901,316,5],
["p2",18,"op","chess_char_6_14_b",2,"uniequip_002_lumen",2297.79,1,22,0,0,3550,6225,52,1],
["p2",19,"op","chess_char_6_16_b",2,"uniequip_002_halo2",1741.19,1,25,1,72989,1414,0,121,4],
["p2",20,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",1695.1,1,58,1,122067,1695,0,22,2],
["p2",21,"op","chess_char_6_20_b",2,"uniequip_002_agoat2",1828.31,1,18,0,0,1775,32488,54,2],
["p2",15,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",6916.53,1,32,0,283256,2036,0,71,3],
["p2",16,"op","chess_char_6_12_b",1,"uniequip_002_rosmon",3493.03,1,16,4,224007,3644,370,62,3],
["p2",17,"op","chess_char_6_13_b",1,"uniequip_002_angel2",2653.35,1,20,3,1430530,5238,1847,317,5],
["p2",18,"op","chess_char_6_14_b",2,"uniequip_002_lumen",2297.79,1,22,0,0,3550,6333,55,1],
["p2",19,"op","chess_char_6_16_b",2,"uniequip_002_halo2",1741.19,1,25,1,73665,1414,0,122,4],
["p2",20,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",1695.1,1,58,1,122083,1695,0,20,2],
["p2",21,"op","chess_char_6_20_b",2,"uniequip_002_agoat2",1828.31,1,18,0,0,2296,40680,56,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],
["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null],
["-","~4","device","trap_1105_accrate",null,null,100,1,4,0,0,0,0,0,null],
["p1","~1","token","token_10030_mlyss_wtrman",null,null,1586.2,1,24,0,38205,0,0,76,1],
["p1","~1","token","token_10030_mlyss_wtrman",null,null,1586.2,1,24,0,38652,0,0,77,1],
["p2","~1","token","token_10019_nearl2_sword",null,null,8280,0,41,0,10647,0,0,0,null],
["p1","~2","token","token_10030_mlyss_wtrman",null,null,1989.96,0,42,0,0,0,0,0,null],
["p1","~1","token","token_10017_skadi2_dedant",null,null,100,0,49,0,0,0,0,0,null],
["p1","~3","token","token_10030_mlyss_wtrman",null,null,1586.2,0,50,0,3,0,0,3,null],
["p1","~3","token","token_10030_mlyss_wtrman",null,null,1586.2,0,50,0,2,0,0,3,null],
["p2","~2","token","token_10019_nearl2_sword",null,null,6600,0,51,0,10647,0,0,0,null],
["p1","~1","token","token_10040_siege2_vlion",null,null,4000,0,53,0,0,0,0,0,null],
["p1","~4","token","token_10030_mlyss_wtrman",null,null,1989.96,0,55,0,0,0,0,0,null],
@@ -284,19 +284,19 @@
"enemy_1209_sfden_2": [2,2,0,1501,154793],
"enemy_1210_msfden_2": [2,2,0,0,386],
"enemy_9021_acduml": [1,1,0,0,4000000],
"enemy_9023_acdums": [8,6,0,51353,291]
"enemy_9023_acdums": [8,7,0,61276,310]
},
"hooks": [1,63,5076,1385,1385,3756,4577,2685,23,35,61,57,333,38781,1915,4,21,0,1,22,0,8,1],
"events": {"atk":1650,"deploy":38,"die":35,"dmg":4308,"engage":17,"fx":1132,"heal":400,"skill":118,"spawn":57,"status":797},
"hooks": [1,63,5112,1410,1410,3944,4887,3003,25,37,60,56,333,38109,1949,4,21,0,1,24,0,10,1],
"events": {"atk":1660,"deploy":38,"die":37,"dmg":4617,"engage":17,"fx":1143,"heal":456,"skill":116,"spawn":57,"status":840},
"fx": {
"airstrike": 109,
"airstrike": 97,
"appear": 1,
"beam": 10,
"blink": 2,
"bombard": 56,
"bombardShell": 57,
"bombard": 60,
"bombardShell": 60,
"buff": 3,
"burst": 8,
"burst": 10,
"copy": 1,
"disappear": 1,
"displace": 1,
@@ -305,23 +305,23 @@
"drone": 211,
"droneLock": 18,
"drones": 2,
"explode": 368,
"explode": 396,
"extraAttack": 3,
"finale": 1,
"firewall": 1,
"garrisonGrant": 1,
"lightning": 76,
"link": 7,
"lightning": 65,
"link": 6,
"lock": 60,
"lure": 2,
"phase": 35,
"phase": 37,
"radiantSword": 3,
"scorchBurst": 1,
"slash": 11,
"snow": 35,
"snow": 32,
"split": 4,
"steal": 5,
"storm": 7,
"storm": 6,
"summon": 14,
"sunBurst": 1,
"talent": 6,
@@ -329,7 +329,7 @@
"tide": 3,
"wanted": 1
},
"snaps": "b66f8306 b821cb0a 25c089ba 9c4aeabf ff5b59a1 042e449b f5822070 07445b3e ac69ddc0 37b52b7d c59632d4 a8b2eca1 6bbfab6e afcc528d e64bf70f bd7aa0ef 2bd32f6f"
"snaps": "b66f8306 b821cb0a 25c089ba 9c4aeabf ff5b59a1 81ad00f2 65ec46c4 9c8b1887 7078d3f4 c6f903d8 e7e0653d f8ed103e 4c094f35 defa0e76 715cdfde 21af37d1 18687ace"
},
"boss-boss_3-solo": {
"about": "假想敌:管 solo pool 2000000: chess_char_5_08_b chess_char_5_11_b chess_char_5_05_b chess_char_5_06_b chess_char_5_13_b chess_char_5_07_b chess_char_5_02_b chess_char_5_03_b chess_char_5_10_b chess_char_5_12_b",
@@ -518,98 +518,101 @@
"round": 14,
"seed": 2302764647,
"waveId": "act2autochess_h07_05",
"time": 102.9,
"ticks": 3087,
"time": 113.93,
"ticks": 3418,
"reason": "cleared",
"killed": 16,
"killed": 18,
"total": 8,
"unspawned": 0,
"bossHpLeft": 0,
"rngDraws": 908,
"rngDraws": 1040,
"errors": {"count":0,"kinds":[]},
"players": {
"p1": {"killed":16,"total":8,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1233427,"bossDmg":928200,"heal":24829,"deaths":1,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1040342,"bossDmg":631800,"heal":41304,"deaths":1,"layerGains":{}}
"p1": {"killed":18,"total":8,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1216056,"bossDmg":897045,"heal":28286,"deaths":1,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1143710,"bossDmg":662955,"heal":48827,"deaths":1,"layerGains":{}}
},
"units": [
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_yu",4070,1,7,1,8305,1825,6494,6,1],
["p1",2,"op","chess_char_6_06_b",2,"uniequip_002_pepe",0,0,12,0,25770,5629,769,5,1],
["p1",3,"op","chess_char_6_07_b",2,"uniequip_002_siege2",3411.1,1,14,0,76065,2161,834,30,1],
["p1",4,"op","chess_char_6_01_b",2,"uniequip_002_lemuen",1447.37,1,1,3,514889,991,821,31,4],
["p1",5,"op","chess_char_6_02_b",2,"uniequip_002_sbell2",2126.3,1,16,1,128892,1418,956,23,2],
["p1",6,"op","chess_char_6_04_b",2,"uniequip_002_skadi2",1757.8,1,3,0,4001,5151,438,0,2],
["p1",7,"op","chess_char_6_05_b",2,"uniequip_002_pasngr",1586.2,1,18,0,141216,3329,1053,18,5],
["p1",8,"op","chess_char_6_08_b",2,"uniequip_002_reed2",1834.8,1,5,0,74259,868,10288,45,2],
["p1",9,"op","chess_char_6_09_b",0,"uniequip_002_cello",1454.2,1,20,4,160370,6470,1752,23,23],
["p1",10,"op","chess_char_6_11_b",2,"uniequip_002_mlyss",2082.3,1,9,0,52150,6246,961,65,3],
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_yu",5616.6,1,7,0,40882,5641,10343,19,1],
["p1",2,"op","chess_char_6_06_b",2,"uniequip_002_pepe",0,0,12,0,45219,4832,0,9,1],
["p1",3,"op","chess_char_6_07_b",2,"uniequip_002_siege2",4707.32,1,14,0,69280,1067,12,29,1],
["p1",4,"op","chess_char_6_01_b",2,"uniequip_002_lemuen",2231.46,1,1,4,556823,2311,2052,34,5],
["p1",5,"op","chess_char_6_02_b",2,"uniequip_002_sbell2",2934.29,1,16,1,57925,311,62,13,2],
["p1",6,"op","chess_char_6_04_b",2,"uniequip_002_skadi2",2425.76,1,3,1,8028,8274,2281,0,3],
["p1",7,"op","chess_char_6_05_b",2,"uniequip_002_pasngr",2188.96,1,18,0,132719,2320,583,10,4],
["p1",8,"op","chess_char_6_08_b",2,"uniequip_002_reed2",2532.02,1,5,0,66232,4273,8665,35,2],
["p1",9,"op","chess_char_6_09_b",0,"uniequip_002_cello",2006.8,1,20,4,150463,4798,603,22,22],
["p1",10,"op","chess_char_6_11_b",2,"uniequip_002_mlyss",2873.57,1,9,0,58683,4198,2160,70,3],
["p1",11,"token","token_10017_skadi2_dedant",null,null,138,0,22,0,0,0,0,0,null],
["p1",12,"token","token_10030_mlyss_wtrman",null,null,1668,1,10,0,35402,874,464,52,1],
["p2",13,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",4181.76,1,55,4,378608,9705,860,100,3],
["p2",14,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",2069.61,1,13,2,128245,3313,0,22,2],
["p2",15,"op","chess_char_5_01_b",1,"uniequip_002_excu2",1908.49,1,15,1,32435,2117,1225,22,1],
["p2",16,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",6521.3,1,53,1,164109,10334,0,40,2],
["p2",17,"op","chess_char_6_12_b",1,"uniequip_002_rosmon",5557.09,1,2,0,150406,888,888,18,1],
["p2",18,"op","chess_char_6_13_b",1,"uniequip_002_angel2",3437.9,1,17,0,76446,5687,2518,8,1],
["p2",19,"op","chess_char_6_14_b",2,"uniequip_002_lumen",2088.9,1,4,0,0,2258,6052,8,1],
["p2",20,"op","chess_char_6_16_b",2,"uniequip_002_halo2",1741.19,1,19,0,17095,1031,0,18,2],
["p2",21,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",0,0,6,0,83803,1695,0,12,1],
["p2",22,"op","chess_char_6_20_b",2,"uniequip_002_agoat2",1828.31,1,21,0,0,2305,29761,25,1],
["p1",12,"token","token_10030_mlyss_wtrman",null,null,0,0,10,0,19817,3192,1524,31,1],
["p2",13,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",5144.83,1,57,5,403688,10468,0,108,4],
["p2",14,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",4200.31,1,13,1,134710,5030,0,28,2],
["p2",15,"op","chess_char_5_01_b",1,"uniequip_002_excu2",2908.6,1,15,1,37774,1799,1225,28,1],
["p2",16,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",6853.26,1,59,1,179630,12262,0,45,3],
["p2",17,"op","chess_char_6_12_b",1,"uniequip_002_rosmon",6763.77,1,2,1,180722,1758,1758,21,2],
["p2",18,"op","chess_char_6_13_b",1,"uniequip_002_angel2",5067.92,1,17,0,84079,6189,3393,8,1],
["p2",19,"op","chess_char_6_14_b",2,"uniequip_002_lumen",2882.68,1,4,0,0,1505,8590,12,1],
["p2",20,"op","chess_char_6_16_b",2,"uniequip_002_halo2",2184.4,1,19,0,17625,2062,0,20,3],
["p2",21,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",0,0,6,0,87978,1695,0,12,1],
["p2",22,"op","chess_char_6_20_b",2,"uniequip_002_agoat2",2293.7,1,21,0,0,2305,33861,30,2],
["p2","~1","token","token_10019_nearl2_sword",null,null,1907.57,0,32,0,9195,6372,0,12,null],
["p1","~1","token","token_10030_mlyss_wtrman",null,null,2301.84,0,36,0,5259,0,0,12,null],
["p1","~1","token","token_10040_siege2_vlion",null,null,136.97,0,39,0,4275,4590,0,10,null],
["p1","~2","token","token_10030_mlyss_wtrman",null,null,0,0,45,0,2575,1668,0,7,null],
["p1","~1","token","token_10040_siege2_vlion",null,null,1489.93,0,39,0,2850,3276,0,7,null],
["p2","~2","token","token_10019_nearl2_sword",null,null,5742.56,0,46,0,0,857,0,0,null],
["p1","~1","token","token_10017_skadi2_dedant",null,null,100,0,48,0,0,0,0,0,null],
["p1","~3","token","token_10030_mlyss_wtrman",null,null,1668,1,56,0,0,0,0,0,null]
["p1","~2","token","token_10030_mlyss_wtrman",null,null,0,0,54,0,1875,1668,0,4,null],
["p2","~3","token","token_10019_nearl2_sword",null,null,8280,1,60,0,8308,0,0,0,null]
],
"enemies": {
"enemy_1010_demon_2": [2,2,0,1457,128995],
"enemy_2009_csaudc": [4,4,0,2694,137594],
"enemy_2010_csdcr": [2,2,0,5885,103196],
"enemy_2016_csphtm": [2,2,0,67552,1560000],
"enemy_2017_csphts": [8,8,0,1223,343985]
"enemy_2009_csaudc": [4,4,0,3423,137594],
"enemy_2010_csdcr": [2,2,0,3368,103196],
"enemy_2016_csphtm": [2,2,0,77468,1560000],
"enemy_2017_csphts": [10,10,0,2141,429982]
},
"hooks": [1,54,3087,673,673,1759,2039,3851,21,34,60,52,50,26592,1290,30,18,0,1,19,0,17,86],
"events": {"atk":826,"deploy":36,"die":34,"dmg":1888,"engage":22,"fx":534,"heal":254,"skill":112,"spawn":47,"status":632},
"hooks": [1,58,3418,689,689,1884,2194,4917,24,39,65,54,61,28062,1207,34,20,0,1,23,0,16,86],
"events": {"atk":868,"deploy":38,"die":39,"dmg":2022,"engage":22,"fx":575,"heal":290,"skill":119,"spawn":49,"status":603},
"fx": {
"airstrike": 15,
"blink": 15,
"bombard": 33,
"bombardShell": 33,
"burst": 17,
"airstrike": 20,
"blink": 19,
"bombard": 34,
"bombardShell": 35,
"burst": 16,
"cleanse": 1,
"copy": 1,
"displace": 4,
"displace": 3,
"dodge": 86,
"dp": 3,
"drone": 102,
"droneLock": 3,
"drones": 1,
"explode": 24,
"extraAttack": 7,
"emergency": 1,
"explode": 27,
"extraAttack": 12,
"finale": 2,
"firewall": 1,
"garrisonGrant": 1,
"lightning": 45,
"lightning": 49,
"link": 3,
"lock": 33,
"lock": 42,
"lure": 2,
"radiantSword": 2,
"scorchBurst": 1,
"shield": 8,
"palsy": 2,
"radiantSword": 3,
"scorchBurst": 2,
"shield": 7,
"slash": 22,
"snow": 24,
"split": 3,
"split": 2,
"steal": 1,
"storm": 5,
"storm": 4,
"strike": 3,
"summon": 11,
"sunBurst": 4,
"summon": 14,
"sunBurst": 5,
"talent": 4,
"telegraph": 2,
"tide": 2,
"wanted": 11
"telegraph": 3,
"tide": 3,
"wanted": 12
},
"snaps": "d3cd88f1 0b40f2d2 3fada850 9d166f76 eb1c5713 8daf7ec1 58aeec40 fd26682e adab14c8 5be402ff eb823ff1"
"snaps": "d3cd88f1 0b40f2d2 3fada850 9d166f76 d6a2dc2f c102808a ed0ca02a c983beea 73a86f16 1366a22a c494f9ea 1ff19f73"
},
"boss-boss_5-solo": {
"about": "卢西恩,“猩红血钻” solo pool 780000: chess_char_5_08_b chess_char_5_11_b chess_char_5_05_b chess_char_5_06_b chess_char_5_13_b chess_char_5_07_b chess_char_5_02_b chess_char_5_03_b chess_char_5_10_b chess_char_5_12_b",
@@ -810,41 +813,41 @@
"round": 14,
"seed": 120974514,
"waveId": "act1autochess_h07_07",
"time": 173.63,
"ticks": 5209,
"time": 173.17,
"ticks": 5195,
"reason": "cleared",
"killed": 16,
"total": 16,
"unspawned": 0,
"bossHpLeft": 0,
"rngDraws": 918,
"rngDraws": 910,
"errors": {"count":0,"kinds":[]},
"players": {
"p1": {"killed":16,"total":16,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1730751,"bossDmg":1610239,"heal":24718,"deaths":0,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":2742228,"bossDmg":2389761,"heal":40810,"deaths":0,"layerGains":{}}
"p1": {"killed":16,"total":16,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":1709189,"bossDmg":1588676,"heal":24718,"deaths":0,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":2763791,"bossDmg":2411324,"heal":40783,"deaths":0,"layerGains":{}}
},
"units": [
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_yu",4070,1,5,0,0,0,0,0,0],
["p1",2,"op","chess_char_6_06_b",2,"uniequip_002_pepe",3232.9,1,7,0,0,0,0,0,0],
["p1",3,"op","chess_char_6_07_b",2,"uniequip_002_siege2",3411.1,1,11,0,0,0,0,0,0],
["p1",4,"op","chess_char_6_01_b",2,"uniequip_002_lemuen",1617,1,1,2,1075028,0,0,78,8],
["p1",4,"op","chess_char_6_01_b",2,"uniequip_002_lemuen",1617,1,1,3,1053668,0,0,78,8],
["p1",5,"op","chess_char_6_02_b",2,"uniequip_002_sbell2",2126.3,1,9,0,0,0,0,0,0],
["p1",6,"op","chess_char_6_04_b",2,"uniequip_002_skadi2",1669.91,1,17,0,43766,18917,1278,0,5],
["p1",7,"op","chess_char_6_05_b",2,"uniequip_002_pasngr",1586.2,1,3,0,0,0,0,0,0],
["p1",8,"op","chess_char_6_08_b",2,"uniequip_002_reed2",1834.8,1,13,0,165894,0,20171,122,3],
["p1",8,"op","chess_char_6_08_b",2,"uniequip_002_reed2",1834.8,1,13,0,165894,0,20171,121,3],
["p1",9,"op","chess_char_6_09_b",0,"uniequip_002_cello",1454.2,1,15,1,261942,1172,0,45,45],
["p1",10,"op","chess_char_6_11_b",2,"uniequip_002_mlyss",2082.3,1,19,1,142272,12632,1260,172,4],
["p1",10,"op","chess_char_6_11_b",2,"uniequip_002_mlyss",2082.3,1,19,1,142069,12632,1260,172,4],
["p1",11,"token","token_10017_skadi2_dedant",null,null,138,0,22,0,0,0,0,0,null],
["p1",12,"token","token_10030_mlyss_wtrman",null,null,0,0,20,0,8204,2977,0,18,1],
["p2",13,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",4435.2,1,26,3,408287,0,0,133,3],
["p2",14,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",3043.7,1,2,0,0,0,0,0,0],
["p2",15,"op","chess_char_5_01_b",1,"uniequip_002_excu2",2545.4,1,6,0,0,0,0,0,0],
["p2",16,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",6916.53,1,31,1,136739,14292,0,40,3],
["p2",17,"op","chess_char_6_12_b",1,"uniequip_002_rosmon",2540.38,1,16,4,396919,10380,0,65,3],
["p2",18,"op","chess_char_6_13_b",1,"uniequip_002_angel2",2680.15,1,21,4,1362550,5319,2968,297,6],
["p2",17,"op","chess_char_6_12_b",1,"uniequip_002_rosmon",2540.38,1,16,3,395884,10380,0,65,3],
["p2",18,"op","chess_char_6_13_b",1,"uniequip_002_angel2",2653.35,1,21,4,1355054,5319,2941,295,6],
["p2",19,"op","chess_char_6_14_b",2,"uniequip_002_lumen",2088.9,1,8,0,0,0,0,0,0],
["p2",20,"op","chess_char_6_16_b",2,"uniequip_002_halo2",1582.9,1,12,0,145556,0,0,103,4],
["p2",21,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",1695.1,1,14,1,292178,0,0,77,3],
["p2",20,"op","chess_char_6_16_b",2,"uniequip_002_halo2",1582.9,1,12,0,144110,0,0,103,4],
["p2",21,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",1695.1,1,14,1,323718,0,0,77,3],
["p2",22,"op","chess_char_6_20_b",2,"uniequip_002_agoat2",1828.31,1,18,0,0,1103,37842,58,2],
["p1","~1","token","token_10030_mlyss_wtrman",null,null,0,0,34,0,10960,2454,630,13,null],
["p1","~2","token","token_10030_mlyss_wtrman",null,null,0,0,41,0,5575,1593,0,9,1],
@@ -856,10 +859,10 @@
["p1","~3","token","token_10017_skadi2_dedant",null,null,100,1,51,0,0,0,0,0,null]
],
"enemies": {"enemy_1067_snslime":[8,8,0,11760,111795],"enemy_1081_sotisd":[4,4,0,0,257989],"enemy_1249_lysdb_2":[4,4,0,0,103196],"enemy_9033_acdeer":[1,1,0,40235,4000000]},
"hooks": [1,49,5209,1281,1281,3051,3357,2765,22,27,93,88,305,37705,1418,3,17,0,1,21,0,10,0],
"events": {"atk":1445,"deploy":32,"die":27,"dmg":3088,"engage":16,"fx":675,"heal":436,"skill":181,"spawn":47,"status":511},
"fx": {"airstrike":104,"beam":5,"blink":2,"bombard":63,"bombardShell":64,"burst":10,"column":45,"copy":4,"dp":4,"drone":245,"droneLock":15,"drones":3,"explode":6,"garrisonGrant":1,"link":1,"lock":69,"phase":1,"scorchBurst":2,"shieldBreak":4,"snow":5,"split":2,"steal":6,"sunBurst":4,"talent":4,"tide":5,"wanted":1},
"snaps": "e8f77b71 c1cf2cef a6688abd b9a6fe99 07c13245 40140044 ddfccb97 273b0a5a 3f6c7803 621a62a4 561c43b2 75e4ac28 41579a2d 3b4b24fa 4aa3b38d e05ffd35 6d9a4f36 45587dcb"
"hooks": [1,49,5195,1278,1278,3120,3426,2763,22,27,93,88,303,37593,1413,3,17,0,1,21,0,10,0],
"events": {"atk":1442,"deploy":32,"die":27,"dmg":3157,"engage":16,"fx":670,"heal":436,"skill":181,"spawn":47,"status":511},
"fx": {"airstrike":104,"beam":5,"blink":2,"bombard":62,"bombardShell":63,"burst":10,"column":45,"copy":4,"dp":4,"drone":242,"droneLock":15,"drones":3,"explode":6,"garrisonGrant":1,"link":1,"lock":69,"phase":1,"scorchBurst":2,"shieldBreak":4,"snow":5,"split":2,"steal":6,"sunBurst":4,"talent":4,"tide":5,"wanted":1},
"snaps": "cbd449f6 0fc766d0 b5a9198a 1965b1bc 8e6f8d60 822d854f ceed08a1 a52227ff 7ea8a6e4 a812122a 48bcd4d6 32e527fa ea780f22 4030b232 09f24b6e 2211aae3 ab22490c adfcf0bd"
},
"boss-boss_7-solo": {
"about": "“萨米的意志” solo pool 2000000: chess_char_5_08_b chess_char_5_11_b chess_char_5_05_b chess_char_5_06_b chess_char_5_13_b chess_char_5_07_b chess_char_5_02_b chess_char_5_03_b chess_char_5_10_b chess_char_5_12_b",
@@ -1074,12 +1077,12 @@
"killed": 8,
"total": 8,
"unspawned": 0,
"bossHpLeft": 2992511,
"bossHpLeft": 2988263,
"rngDraws": 1828,
"errors": {"count":0,"kinds":[]},
"players": {
"p1": {"killed":8,"total":8,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":2840728,"bossDmg":1130176,"heal":26454,"deaths":3,"layerGains":{}},
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":3891716,"bossDmg":1427465,"heal":133966,"deaths":7,"layerGains":{}}
"p2": {"killed":0,"total":0,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":0,"dmg":3904460,"bossDmg":1431713,"heal":133966,"deaths":7,"layerGains":{}}
},
"units": [
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_yu",7326,1,15,0,3237,9163,15665,31,3],
@@ -1094,7 +1097,7 @@
["p1",10,"op","chess_char_6_11_b",2,"uniequip_002_mlyss",2082.3,1,59,0,30083,11261,306,74,2],
["p1",11,"token","token_10017_skadi2_dedant",null,null,138,0,28,0,0,0,0,0,null],
["p1",12,"token","token_10030_mlyss_wtrman",null,null,0,0,24,0,0,1670,348,4,1],
["p2",13,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",903.1,1,68,4,817795,32754,0,248,4],
["p2",13,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",903.1,1,68,4,819088,32754,0,248,4],
["p2",14,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",0,0,64,0,355848,15836,0,48,4],
["p2",15,"op","chess_char_5_01_b",1,"uniequip_002_excu2",1415.78,1,66,0,123216,11064,6422,44,2],
["p2",16,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",1602.9,1,65,1,499184,28500,0,76,3],
@@ -1102,7 +1105,7 @@
["p2",18,"op","chess_char_6_13_b",1,"uniequip_002_angel2",2436.5,1,14,0,526339,8805,4488,259,5],
["p2",19,"op","chess_char_6_14_b",2,"uniequip_002_lumen",3342.24,1,20,0,0,0,19549,78,1],
["p2",20,"op","chess_char_6_16_b",2,"uniequip_002_halo2",1582.9,1,10,0,103786,0,0,127,3],
["p2",21,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",1859.61,1,27,0,346061,5155,0,25,3],
["p2",21,"op","chess_char_6_18_b",2,"uniequip_002_whitw2",1859.61,1,27,0,357512,5155,0,25,3],
["p2",22,"op","chess_char_6_20_b",2,"uniequip_002_agoat2",1758.31,1,25,0,0,14000,103507,78,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],
@@ -1126,13 +1129,13 @@
"enemies": {
"enemy_1267_nhpbr_2": [6,6,0,1900,141894],
"enemy_9007_acelem": [2,2,0,14390,309587],
"enemy_9017_achunt_2": [2,0,0,57663,2607489],
"enemy_9018_actrpa": [1,0,0,53759,1092472],
"enemy_9019_actrpb": [1,0,0,24773,1015854],
"enemy_9020_actrpc": [1,0,0,22601,1668902]
"enemy_9017_achunt_2": [2,0,0,57663,2611737],
"enemy_9018_actrpa": [1,0,0,53759,1094596],
"enemy_9019_actrpb": [1,0,0,24773,1018036],
"enemy_9020_actrpc": [1,0,0,22601,1673092]
},
"hooks": [1,66,6000,1649,1649,8552,17196,2968,22,35,96,88,305,47649,3685,17,13,0,1,31,0,19,0],
"events": {"atk":2230,"deploy":47,"die":35,"dmg":16662,"engage":22,"fx":2182,"heal":905,"skill":184,"spawn":53,"status":898},
"hooks": [1,66,6000,1649,1649,8574,17284,2968,22,35,96,88,305,47649,3706,17,13,0,1,31,0,19,0],
"events": {"atk":2230,"deploy":47,"die":35,"dmg":16750,"engage":22,"fx":2182,"heal":905,"skill":184,"spawn":53,"status":898},
"fx": {
"airstrike": 93,
"beam": 26,
@@ -1173,7 +1176,7 @@
"wanted": 6,
"zone": 6
},
"snaps": "8b102142 0561d2e7 b88fff99 8716a28b 1badf400 91b895ee 78b15f27 974adf64 c118d65e 831cdc6f 0c7385df d5ab8494 2e6d06b7 f460f583 e7a7bafc 6ab1c142 80a01218 1de18f0f 84c4afee 5fb9b9bc"
"snaps": "8b102142 0561d2e7 b88fff99 8716a28b 029ba95f b318b100 89a71563 dbd3fc50 39edd668 e8bad5d2 6041dbb0 1d54607c baabef98 3f4c928d 4b565fc8 77ef652f 56feb3e3 b839d42c 8bf608c0 5b35e9d9"
},
"hidden-boss_9-solo": {
"about": "假想敌:铳 solo pool 2800000: chess_char_5_08_b chess_char_5_11_b chess_char_5_05_b chess_char_5_06_b chess_char_5_13_b chess_char_5_07_b chess_char_5_02_b chess_char_5_03_b chess_char_5_10_b chess_char_5_12_b",
+175 -175
View File
@@ -16,7 +16,7 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m01","bossId":"boss_5","hiddenBossId":null,"factions":["TIMES","DOT","INVISIBLE"]},
"end": {"victory":true,"roundsPassed":9,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":15,"bossPoolLeft":0,"virtualMs":68100},
"end": {"victory":true,"roundsPassed":9,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":27,"bossPoolLeft":0,"virtualMs":68100},
"rng": {"setup":16,"shop":87,"waves":0,"draft":0,"bots":5205,"meta":0},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -27,7 +27,7 @@
{"round":5,"ai_0":[1,27,8,0,0,3,8,"93b57353",25,"deputShip 2/6, indomShip 2/14, preciShip 0/2, sargonShip 0/4, steadShip 1/5",53,16,0,30]},
{"round":6,"ai_0":[1,27,9,0,0,4,8,"95660cdd",46,"deputShip 2/10, indomShip 1/22, preciShip 0/2, sargonShip 0/4, steadShip 2/14",28,28,0,38]},
{"round":7,"ai_0":[1,27,10,0,0,4,8,"00b23401",75,"deputShip 1/12, emptyShip 1/2, indomShip 1/37, preciShip 0/2, sargonShip 0/4, steadShip 2/24",27,27,0,48]},
{"round":8,"ai_0":[1,27,11,0,0,4,8,"a344d4b9",115,"deputShip 2/16, emptyShip 1/6, indomShip 1/59, preciShip 0/2, sargonShip 0/4, steadShip 2/34",14,14,0,60]}
{"round":8,"ai_0":[1,27,11,0,0,4,8,"a344d4b9",116,"deputShip 2/16, emptyShip 1/6, indomShip 1/59, preciShip 0/2, sargonShip 0/4, steadShip 2/35",14,14,0,60]}
],
"players": {
"ai_0": {
@@ -35,14 +35,14 @@
"victory": true,
"roundsPassed": 9,
"eliminatedRound": null,
"lp": 15,
"lp": 27,
"bandId": "band_ermengard",
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 0,
"reward": 113,
"stats": {"activatedLayers":133,"bossDamage":200000,"dmgDealt":753151,"gold":72,"itemsEquipped":14,"kills":170,"leaks":0,"lpLost":0,"merges":3,"perfectRounds":8,"refreshes":5},
"stats": {"activatedLayers":134,"bossDamage":200000,"dmgDealt":737575,"gold":72,"itemsEquipped":14,"kills":168,"leaks":0,"lpLost":0,"merges":3,"perfectRounds":8,"refreshes":5},
"lineup": ["2_17_b@12,8","1_13_b@11,8","3_20_b@10,3[5_02_e_b+3_07_e_a]","2_08_a@10,4[4_11_e_a+4_03_e_a]","1_12_a@10,7[3_05_e_a]","5_13_a@10,8[4_02_e_a]","3_16_a@9,4[2_04_e_a+5_02_e_b]","5_02_a@9,8[3_02_e_a+1_01_e_b]"],
"bonds": ["deputShip 1/18","emptyShip 0/6","indomShip 1/63","preciShip 0/2","sargonShip 1/6","steadShip 2/46"]
"bonds": ["deputShip 1/18","emptyShip 0/6","indomShip 1/63","preciShip 0/2","sargonShip 1/6","steadShip 2/47"]
}
}
},
@@ -56,7 +56,7 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m01","bossId":"boss_5","hiddenBossId":null,"factions":["ELEMENT","DOT","REFLECTION"]},
"end": {"victory":true,"roundsPassed":9,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":8,"bossPoolLeft":0,"virtualMs":68100},
"end": {"victory":true,"roundsPassed":9,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":29,"bossPoolLeft":0,"virtualMs":68100},
"rng": {"setup":16,"shop":154,"waves":0,"draft":0,"bots":5211,"meta":39},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -81,12 +81,12 @@
"victory": true,
"roundsPassed": 9,
"eliminatedRound": null,
"lp": 8,
"lp": 29,
"bandId": "band_ducklord",
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 0,
"reward": 113,
"stats": {"activatedLayers":160,"bossDamage":200000,"dmgDealt":684272,"gold":76,"itemsEquipped":11,"kills":133,"leaks":0,"lpLost":0,"merges":2,"perfectRounds":8,"refreshes":16},
"stats": {"activatedLayers":160,"bossDamage":200000,"dmgDealt":677516,"gold":76,"itemsEquipped":11,"kills":133,"leaks":0,"lpLost":0,"merges":2,"perfectRounds":8,"refreshes":16},
"lineup": ["5_10_a@12,3","1_06_a@11,3[3_01_e_a]","3_11_a@11,8[1_01_e_a+3_11_e_a]","4_14_a@10,3","2_18_b@10,4[4_11_e_a]","1_02_b@10,8[5_02_e_a+1_05_e_a]","3_20_a@9,8","2_14_a@9,9"],
"bonds": ["deputShip 2/24","emptyShip 1/18","indomShip 0/6","kjeragShip 1/27","preciShip 1/21","steadShip 1/70","swiftShip 0/7","yanShip 0/1"]
}
@@ -102,7 +102,7 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m03","bossId":"boss_5","hiddenBossId":"boss_8","factions":["TIMES","DOT","INVISIBLE"]},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":32843,"virtualMs":106900},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":11,"bossPoolLeft":0,"virtualMs":106900},
"rng": {"setup":25,"shop":159,"waves":0,"draft":10,"bots":8211,"meta":1},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -129,35 +129,35 @@
},
{
"round": 10,
"ai_0": [1,27,12,0,0,5,8,"e01e0f99",87,"deputShip 1/10, kazimierzShip 0/8, kjeragShip 1/13, miraShip 0/3, preciShip 0/5, sargonShip 0/8, soloShip 1/11, steadShip 1/25, suntShip 1/6, swiftShip 1/22, yanShip 0/6",24,24,0,86]
"ai_0": [1,27,12,0,0,5,8,"e01e0f99",88,"deputShip 1/10, kazimierzShip 0/8, kjeragShip 1/14, miraShip 0/3, preciShip 0/5, sargonShip 0/8, soloShip 1/11, steadShip 1/25, suntShip 1/6, swiftShip 1/22, yanShip 0/6",24,24,0,86]
},
{
"round": 11,
"ai_0": [1,26,12,0,2,5,8,"1df90477",118,"deputShip 1/12, kazimierzShip 0/8, kjeragShip 1/23, miraShip 0/3, preciShip 0/5, sargonShip 0/8, soloShip 1/13, steadShip 1/30, suntShip 1/8, swiftShip 1/32, yanShip 0/6",23,24,1,97]
"ai_0": [1,26,12,0,2,5,8,"1df90477",114,"deputShip 1/12, kazimierzShip 0/8, kjeragShip 1/19, miraShip 0/3, preciShip 0/5, sargonShip 0/8, soloShip 1/13, steadShip 1/30, suntShip 1/8, swiftShip 1/32, yanShip 0/6",23,24,1,97]
},
{
"round": 12,
"ai_0": [1,16,14,0,0,6,8,"ceba966e",140,"deputShip 1/14, kazimierzShip 0/8, kjeragShip 1/26, miraShip 0/3, preciShip 0/5, sargonShip 0/8, soloShip 1/15, steadShip 1/33, suntShip 1/10, swiftShip 1/42, yanShip 0/6",15,31,16,109]
"ai_0": [1,16,14,0,0,6,8,"436a1bec",140,"deputShip 1/14, kazimierzShip 0/8, kjeragShip 1/22, miraShip 0/3, preciShip 0/5, sargonShip 0/8, soloShip 1/15, steadShip 1/37, suntShip 1/10, swiftShip 1/42, yanShip 0/6",18,31,13,109]
},
{
"round": 13,
"ai_0": [1,6,12,0,0,6,8,"3be0fd4e",166,"deputShip 1/16, kazimierzShip 0/8, kjeragShip 1/33, miraShip 0/3, preciShip 0/5, sargonShip 0/8, skillfulShip 1/7, soloShip 1/17, steadShip 1/37, suntShip 1/12, swiftShip 1/44, yanShip 0/6",97,35,12,119]
"ai_0": [1,11,12,0,0,6,8,"f559af38",166,"deputShip 1/16, kazimierzShip 0/8, kjeragShip 1/29, miraShip 0/3, preciShip 0/5, sargonShip 0/8, skillfulShip 1/7, soloShip 1/17, steadShip 1/41, suntShip 1/12, swiftShip 1/44, yanShip 0/6",109,35,5,119]
}
],
"players": {
"ai_0": {
"alive": true,
"victory": false,
"roundsPassed": 13,
"victory": true,
"roundsPassed": 14,
"eliminatedRound": null,
"lp": 0,
"lp": 11,
"bandId": "band_ermengard",
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 0,
"reward": 320,
"stats": {"activatedLayers":173,"bossDamage":357157,"dmgDealt":2127067,"gold":130,"itemsEquipped":17,"kills":359,"leaks":29,"lpLost":21,"merges":3,"perfectRounds":10,"refreshes":9},
"reward": 400,
"stats": {"activatedLayers":173,"bossDamage":390000,"dmgDealt":2233950,"gold":130,"itemsEquipped":17,"kills":373,"leaks":19,"lpLost":16,"merges":3,"perfectRounds":10,"refreshes":9},
"lineup": ["4_21_a@12,7","3_16_a@12,8[4_10_e_a+2_04_e_a]","6_05_a@11,5","4_13_a@11,8[3_06_e_a]","3_20_b@10,3[5_02_e_b+4_08_e_a]","1_19_b@10,8[4_11_e_a]","1_02_a@9,4[5_02_e_b+3_08_e_b]","6_03_a@9,5"],
"bonds": ["deputShip 1/18","kazimierzShip 0/8","kjeragShip 1/40","miraShip 0/3","preciShip 0/5","sargonShip 0/8","skillfulShip 1/14","soloShip 0/17","steadShip 2/41","suntShip 1/14","swiftShip 1/46","yanShip 0/6"]
"bonds": ["deputShip 1/18","kazimierzShip 0/8","kjeragShip 1/36","miraShip 0/3","preciShip 0/5","sargonShip 0/8","skillfulShip 1/14","soloShip 0/17","steadShip 2/45","suntShip 1/14","swiftShip 1/46","yanShip 0/6"]
}
}
},
@@ -246,7 +246,7 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m03","bossId":"boss_5","hiddenBossId":"boss_8","factions":["TIMES","DOT","INVISIBLE"]},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":347913,"virtualMs":107800},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":212054,"virtualMs":107800},
"rng": {"setup":25,"shop":215,"waves":0,"draft":42,"bots":8070,"meta":1},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -265,27 +265,27 @@
},
{
"round": 8,
"ai_0": [1,25,11,0,0,4,8,"82c473bd",58,"deputShip 2/10, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/21, skillfulShip 1/8, soloShip 1/11, steadShip 0/9, suntShip 1/8, swiftShip 0/11",17,19,2,58]
"ai_0": [1,27,11,0,0,4,8,"66ac5818",58,"deputShip 2/10, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/21, skillfulShip 1/8, soloShip 1/11, steadShip 0/9, suntShip 1/8, swiftShip 0/11",19,19,0,58]
},
{
"round": 9,
"ai_0": [1,25,12,0,0,4,8,"4fb70cbc",81,"deputShip 1/12, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/25, skillfulShip 1/10, soloShip 0/11, steadShip 1/11, suntShip 1/10, swiftShip 1/13",34,34,0,71]
"ai_0": [1,27,12,0,0,4,8,"4fb70cbc",81,"deputShip 1/12, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/25, skillfulShip 1/10, soloShip 0/11, steadShip 1/11, suntShip 1/10, swiftShip 1/13",34,34,0,71]
},
{
"round": 10,
"ai_0": [1,25,12,0,0,5,8,"b380bd34",99,"deputShip 1/14, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/29, skillfulShip 1/14, soloShip 1/13, steadShip 0/11, suntShip 1/12, swiftShip 1/17",24,24,0,84]
"ai_0": [1,27,12,0,0,5,8,"b380bd34",99,"deputShip 1/14, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/29, skillfulShip 1/14, soloShip 1/13, steadShip 0/11, suntShip 1/12, swiftShip 1/17",24,24,0,84]
},
{
"round": 11,
"ai_0": [1,25,12,0,1,5,8,"b74ff3d8",133,"deputShip 2/18, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/35, skillfulShip 1/20, soloShip 0/13, steadShip 0/11, suntShip 1/16, swiftShip 1/44",34,34,0,96]
"ai_0": [1,27,12,0,1,5,8,"b74ff3d8",133,"deputShip 2/18, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/35, skillfulShip 1/20, soloShip 0/13, steadShip 0/11, suntShip 1/16, swiftShip 1/44",34,34,0,96]
},
{
"round": 12,
"ai_0": [1,19,13,0,0,6,8,"b64e6caf",168,"deputShip 2/22, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/39, skillfulShip 1/24, soloShip 0/13, steadShip 0/11, suntShip 1/20, swiftShip 1/63",25,31,6,108]
"ai_0": [1,19,13,0,0,6,8,"3445b39c",168,"deputShip 2/22, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/39, skillfulShip 1/24, soloShip 0/13, steadShip 0/11, suntShip 1/20, swiftShip 1/63",23,31,8,108]
},
{
"round": 13,
"ai_0": [1,11,12,0,2,6,8,"bb4537a0",229,"deputShip 1/24, kazimierzShip 1/26, kjeragShip 0/10, sargonShip 1/41, skillfulShip 1/26, soloShip 1/15, steadShip 0/11, suntShip 1/22, swiftShip 1/75",107,35,8,120]
"ai_0": [1,19,12,0,2,6,8,"bb4537a0",229,"deputShip 1/24, kazimierzShip 1/26, kjeragShip 0/10, sargonShip 1/41, skillfulShip 1/26, soloShip 1/15, steadShip 0/11, suntShip 1/22, swiftShip 1/75",115,35,0,120]
}
],
"players": {
@@ -299,7 +299,7 @@
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"trophies": 0,
"reward": 340,
"stats": {"activatedLayers":212,"bossDamage":432087,"dmgDealt":2238324,"gold":135,"itemsEquipped":16,"kills":400,"leaks":16,"lpLost":16,"merges":4,"perfectRounds":10,"refreshes":17},
"stats": {"activatedLayers":212,"bossDamage":567946,"dmgDealt":2349477,"gold":135,"itemsEquipped":16,"kills":408,"leaks":8,"lpLost":8,"merges":4,"perfectRounds":12,"refreshes":17},
"lineup": ["3_13_a@12,5[1_01_e_b+3_08_e_a]","3_20_a@11,8[5_02_e_a]","4_13_a@10,3","6_19_a@10,5[1_02_e_a+3_11_e_a]","6_17_a@10,8[2_01_e_a+5_01_e_a]","2_08_a@9,3[4_02_e_a+3_07_e_b]","1_19_b@9,4","1_12_b@9,5[4_10_e_a]"],
"bonds": ["deputShip 0/24","kazimierzShip 1/26","kjeragShip 1/15","sargonShip 1/41","skillfulShip 1/31","soloShip 0/15","steadShip 0/11","suntShip 1/22","swiftShip 1/77"]
}
@@ -384,8 +384,8 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m03","bossId":"boss_5","hiddenBossId":"boss_8","factions":["TIMES","DOT","INVISIBLE"]},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":2848970,"virtualMs":107800},
"rng": {"setup":25,"shop":215,"waves":0,"draft":42,"bots":8070,"meta":1},
"end": {"victory":false,"roundsPassed":12,"hiddenReached":false,"hiddenCleared":false,"reason":"eliminated","teamLp":null,"bossPoolLeft":null,"virtualMs":101900},
"rng": {"setup":25,"shop":184,"waves":0,"draft":42,"bots":7846,"meta":1},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
{"round":1,"ai_0":[1,27,4,0,0,1,2,"cc1bac8f",0,"sargonShip 0/2, soloShip 1/0",5,5,0,4]},
@@ -403,43 +403,43 @@
},
{
"round": 8,
"ai_0": [1,27,11,0,0,4,8,"3545bf74",58,"deputShip 2/10, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/21, skillfulShip 1/8, soloShip 1/11, steadShip 0/9, suntShip 1/8, swiftShip 0/11",19,19,0,58]
"ai_0": [1,18,11,0,0,4,8,"48fc92cc",58,"deputShip 2/10, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/21, skillfulShip 1/8, soloShip 1/11, steadShip 0/9, suntShip 1/8, swiftShip 0/11",10,19,9,58]
},
{
"round": 9,
"ai_0": [1,27,12,0,0,4,8,"4fb70cbc",81,"deputShip 1/12, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/25, skillfulShip 1/10, soloShip 0/11, steadShip 1/11, suntShip 1/10, swiftShip 1/13",34,34,0,71]
"ai_0": [1,18,12,0,0,4,8,"4fb70cbc",81,"deputShip 1/12, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/25, skillfulShip 1/10, soloShip 0/11, steadShip 1/11, suntShip 1/10, swiftShip 1/13",34,34,0,71]
},
{
"round": 10,
"ai_0": [1,27,12,0,0,5,8,"b380bd34",99,"deputShip 1/14, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/29, skillfulShip 1/14, soloShip 1/13, steadShip 0/11, suntShip 1/12, swiftShip 1/17",24,24,0,84]
"ai_0": [1,18,12,0,0,5,8,"b380bd34",99,"deputShip 1/14, kazimierzShip 0/8, kjeragShip 0/2, sargonShip 1/29, skillfulShip 1/14, soloShip 1/13, steadShip 0/11, suntShip 1/12, swiftShip 1/17",24,24,0,84]
},
{
"round": 11,
"ai_0": [1,27,12,0,1,5,8,"b74ff3d8",133,"deputShip 2/18, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/35, skillfulShip 1/20, soloShip 0/13, steadShip 0/11, suntShip 1/16, swiftShip 1/44",34,34,0,96]
"ai_0": [1,18,12,0,1,5,8,"b74ff3d8",133,"deputShip 2/18, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/35, skillfulShip 1/20, soloShip 0/13, steadShip 0/11, suntShip 1/16, swiftShip 1/44",34,34,0,96]
},
{
"round": 12,
"ai_0": [1,17,13,0,0,6,8,"b64e6caf",176,"deputShip 2/22, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/39, skillfulShip 1/24, soloShip 0/13, steadShip 0/11, suntShip 1/20, swiftShip 1/71",17,31,14,108]
"ai_0": [1,8,13,0,0,6,8,"b64e6caf",176,"deputShip 2/22, kazimierzShip 0/16, kjeragShip 0/10, sargonShip 1/39, skillfulShip 1/24, soloShip 0/13, steadShip 0/11, suntShip 1/20, swiftShip 1/71",13,31,18,108]
},
{
"round": 13,
"ai_0": [1,8,12,0,2,6,8,"4640459d",237,"deputShip 1/24, kazimierzShip 1/26, kjeragShip 0/10, sargonShip 1/41, skillfulShip 1/26, soloShip 1/15, steadShip 0/11, suntShip 1/22, swiftShip 1/83",106,35,9,120]
"ai_0": [0,0,12,0,0,6,0,"811c9dc5",0,"deputShip 0/24, kazimierzShip 0/26, kjeragShip 0/10, sargonShip 0/41, skillfulShip 0/26, soloShip 0/15, steadShip 0/11, suntShip 0/22, swiftShip 0/83",107,35,8,120]
}
],
"players": {
"ai_0": {
"alive": true,
"alive": false,
"victory": false,
"roundsPassed": 13,
"eliminatedRound": null,
"roundsPassed": 12,
"eliminatedRound": 13,
"lp": 0,
"bandId": "band_ermengard",
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 0,
"reward": 340,
"stats": {"activatedLayers":220,"bossDamage":151030,"dmgDealt":3014025,"gold":135,"itemsEquipped":16,"kills":384,"leaks":23,"lpLost":19,"merges":4,"perfectRounds":11,"refreshes":17},
"lineup": ["3_20_a@12,5[5_02_e_a]","4_13_a@11,8","3_13_a@10,3[1_01_e_b+3_08_e_a]","2_08_a@10,5[4_02_e_a+3_07_e_b]","6_17_a@10,8","1_12_b@9,4[4_10_e_a]","6_19_a@9,5[1_02_e_a+3_11_e_a]","1_19_b@9,9[2_01_e_a+5_01_e_a]"],
"bonds": ["deputShip 0/24","kazimierzShip 1/26","kjeragShip 1/15","sargonShip 1/41","skillfulShip 1/31","soloShip 0/15","steadShip 0/11","suntShip 1/22","swiftShip 1/85"]
"reward": 298,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":2572124,"gold":120,"itemsEquipped":14,"kills":364,"leaks":35,"lpLost":27,"merges":3,"perfectRounds":10,"refreshes":14},
"lineup": [],
"bonds": ["deputShip 0/24","kazimierzShip 0/26","kjeragShip 0/10","sargonShip 0/41","skillfulShip 0/26","soloShip 0/15","steadShip 0/11","suntShip 0/22","swiftShip 0/83"]
}
}
},
@@ -669,37 +669,37 @@
},
{
"round": 7,
"ai_0": [1,25,10,0,0,4,8,"5e6dea30",22,"arcaneShip 0/2, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 1/3, skillfulShip 1/6, soloShip 1/3, steadShip 2/10, swiftShip 0/2",28,28,0,51],
"ai_0": [1,25,10,0,0,4,8,"5e6dea30",18,"arcaneShip 0/2, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 1/1, skillfulShip 1/6, soloShip 1/3, steadShip 2/8, swiftShip 0/2",28,28,0,51],
"ai_1": [1,26,10,0,0,4,8,"84796658",33,"arcaneShip 0/2, kazimierzShip 0/8, preciShip 0/2, raidShip 1/10, skillfulShip 1/6, soloShip 1/0, swiftShip 1/17",28,28,0,52]
},
{
"round": 8,
"ai_0": [1,23,11,0,0,4,8,"ee56690b",37,"arcaneShip 1/7, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 0/6, siracusaShip 1/2, skillfulShip 1/9, soloShip 1/3, steadShip 1/16, swiftShip 0/2",7,9,2,62],
"ai_0": [1,23,11,0,0,4,8,"ee56690b",35,"arcaneShip 1/7, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 0/4, siracusaShip 1/2, skillfulShip 1/9, soloShip 1/3, steadShip 1/14, swiftShip 0/2",7,9,2,62],
"ai_1": [1,21,11,0,0,4,8,"2a3a7cc5",57,"arcaneShip 0/2, indomShip 1/2, kazimierzShip 1/10, preciShip 0/2, raidShip 1/15, skillfulShip 1/8, steadShip 2/3, swiftShip 1/19",4,9,5,63]
},
{
"round": 9,
"ai_0": [1,21,12,0,1,4,8,"54e834bc",107,"arcaneShip 1/16, egirShip 1/31, indomShip 1/20, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 0/6, siracusaShip 1/15, skillfulShip 0/9, soloShip 1/6, steadShip 1/19, suntShip 1/0, swiftShip 0/2",19,23,4,74],
"ai_0": [1,23,12,0,1,4,8,"54e834bc",105,"arcaneShip 1/16, egirShip 1/31, indomShip 1/20, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 0/4, siracusaShip 1/15, skillfulShip 0/9, soloShip 1/6, steadShip 1/17, suntShip 1/0, swiftShip 0/2",20,23,3,74],
"ai_1": [1,21,12,0,2,4,8,"e274f661",73,"arcaneShip 0/2, indomShip 2/4, kazimierzShip 1/12, preciShip 0/2, raidShip 1/20, skillfulShip 1/10, steadShip 2/6, swiftShip 1/21",23,23,0,78]
},
{
"round": 10,
"ai_0": [1,21,13,0,0,5,8,"86f1603a",178,"arcaneShip 1/18, egirShip 1/59, indomShip 1/45, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 1/6, siracusaShip 1/21, skillfulShip 0/9, soloShip 1/6, steadShip 1/23, suntShip 1/0, swiftShip 0/2",5,8,3,87],
"ai_0": [1,22,13,0,0,5,8,"69323f46",165,"arcaneShip 1/18, egirShip 1/57, indomShip 1/40, kazimierzShip 0/2, kjeragShip 0/2, preciShip 0/2, raidShip 1/4, siracusaShip 1/21, skillfulShip 0/9, soloShip 1/6, steadShip 1/19, suntShip 1/0, swiftShip 0/2",6,8,2,87],
"ai_1": [1,21,14,0,0,5,8,"ae756c5d",63,"arcaneShip 0/2, indomShip 2/4, kazimierzShip 1/13, preciShip 0/2, raidShip 1/25, skillfulShip 1/12, steadShip 2/9, suntShip 1/0, swiftShip 0/23",8,8,0,92]
},
{
"round": 11,
"ai_0": [1,11,12,0,1,5,8,"bcd5af08",264,"arcaneShip 1/27, egirShip 1/94, indomShip 1/70, kazimierzShip 0/2, kjeragShip 0/4, preciShip 0/2, raidShip 1/7, siracusaShip 1/31, skillfulShip 0/9, soloShip 1/6, steadShip 1/29, suntShip 1/0, swiftShip 0/2",14,27,13,101],
"ai_1": [1,11,12,0,1,5,8,"f768d00b",82,"arcaneShip 0/2, indomShip 2/6, kazimierzShip 1/15, preciShip 0/2, raidShip 1/31, skillfulShip 1/12, steadShip 2/13, suntShip 1/0, swiftShip 0/23, visiShip 1/5",13,27,14,103]
"ai_0": [1,12,12,0,1,5,8,"3a91bf48",222,"arcaneShip 1/24, egirShip 1/77, indomShip 1/55, kazimierzShip 0/2, kjeragShip 0/4, preciShip 0/2, raidShip 1/4, siracusaShip 1/31, skillfulShip 0/9, soloShip 1/6, steadShip 1/25, suntShip 1/0, swiftShip 0/2",13,27,14,101],
"ai_1": [1,11,12,0,1,5,8,"762c49a7",82,"arcaneShip 0/2, indomShip 2/6, kazimierzShip 1/15, preciShip 0/2, raidShip 1/31, skillfulShip 1/12, steadShip 2/13, suntShip 1/0, swiftShip 0/23, visiShip 1/5",15,27,12,103]
},
{
"round": 12,
"ai_0": [1,1,13,0,0,6,8,"7362d1fb",320,"arcaneShip 1/32, egirShip 1/118, indomShip 1/85, kazimierzShip 0/2, kjeragShip 0/4, preciShip 0/2, raidShip 1/8, siracusaShip 1/37, skillfulShip 0/9, soloShip 1/6, steadShip 1/34, suntShip 1/0, swiftShip 0/2",29,50,21,112],
"ai_0": [1,2,13,0,0,6,8,"7362d1fb",278,"arcaneShip 1/29, egirShip 1/101, indomShip 1/70, kazimierzShip 0/2, kjeragShip 0/4, preciShip 0/2, raidShip 1/5, siracusaShip 1/37, skillfulShip 0/9, soloShip 1/6, steadShip 1/30, suntShip 1/0, swiftShip 0/2",35,50,15,112],
"ai_1": [1,1,13,0,2,6,8,"67c5e7d6",103,"arcaneShip 0/2, indomShip 2/10, kazimierzShip 1/18, preciShip 0/2, raidShip 1/37, skillfulShip 1/12, steadShip 2/16, suntShip 1/0, swiftShip 0/23, visiShip 1/10",20,50,30,114]
},
{
"round": 13,
"ai_0": [0,0,12,0,0,6,0,"811c9dc5",0,"arcaneShip 0/44, egirShip 0/143, indomShip 0/105, kazimierzShip 0/2, kjeragShip 0/4, preciShip 0/2, raidShip 0/8, siracusaShip 0/53, skillfulShip 0/9, soloShip 0/6, steadShip 0/38, swiftShip 0/2",10,49,39,123],
"ai_0": [0,0,12,0,0,6,0,"811c9dc5",0,"arcaneShip 0/44, egirShip 0/131, indomShip 0/90, kazimierzShip 0/2, kjeragShip 0/4, preciShip 0/2, raidShip 0/7, siracusaShip 0/53, skillfulShip 0/9, soloShip 0/6, steadShip 0/36, swiftShip 0/2",11,49,38,123],
"ai_1": [0,0,14,0,0,6,0,"811c9dc5",0,"arcaneShip 0/2, indomShip 0/10, kazimierzShip 0/19, preciShip 0/2, raidShip 0/37, skillfulShip 0/12, steadShip 0/20, swiftShip 0/23, visiShip 0/10",16,49,33,127]
}
],
@@ -714,9 +714,9 @@
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 3,
"reward": 298,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":2672612,"gold":123,"itemsEquipped":7,"kills":200,"leaks":82,"lpLost":34,"merges":3,"perfectRounds":7,"refreshes":19},
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":2884020,"gold":123,"itemsEquipped":7,"kills":208,"leaks":74,"lpLost":33,"merges":3,"perfectRounds":7,"refreshes":19},
"lineup": [],
"bonds": ["arcaneShip 0/44","egirShip 0/143","indomShip 0/105","kazimierzShip 0/2","kjeragShip 0/4","preciShip 0/2","raidShip 0/8","siracusaShip 0/53","skillfulShip 0/9","soloShip 0/6","steadShip 0/38","swiftShip 0/2"]
"bonds": ["arcaneShip 0/44","egirShip 0/131","indomShip 0/90","kazimierzShip 0/2","kjeragShip 0/4","preciShip 0/2","raidShip 0/7","siracusaShip 0/53","skillfulShip 0/9","soloShip 0/6","steadShip 0/36","swiftShip 0/2"]
},
"ai_1": {
"alive": false,
@@ -728,7 +728,7 @@
"title": {"id":"comment_5","name":"万事俱备","picId":"comment_icon_5","text":"装备配发数量最多"},
"trophies": 3,
"reward": 298,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":2798748,"gold":127,"itemsEquipped":17,"kills":205,"leaks":82,"lpLost":35,"merges":3,"perfectRounds":9,"refreshes":16},
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":2958982,"gold":127,"itemsEquipped":17,"kills":206,"leaks":80,"lpLost":35,"merges":3,"perfectRounds":9,"refreshes":16},
"lineup": [],
"bonds": ["arcaneShip 0/2","indomShip 0/10","kazimierzShip 0/19","preciShip 0/2","raidShip 0/37","skillfulShip 0/12","steadShip 0/20","swiftShip 0/23","visiShip 0/10"]
}
@@ -774,7 +774,7 @@
},
{
"round": 5,
"ai_0": [1,23,10,0,0,3,8,"072ffdf0",22,"deputShip 1/12, kazimierzShip 0/2, soloShip 1/4, swiftShip 1/6",45,16,8,34],
"ai_0": [1,23,10,0,0,3,8,"2953d5b4",22,"deputShip 1/12, kazimierzShip 0/2, soloShip 1/4, swiftShip 1/6",53,16,0,34],
"ai_1": [1,45,9,0,0,2,8,"255ecf36",11,"kazimierzShip 0/11, lateranoShip 1/0, soloShip 1/0, suntShip 1/0, swiftShip 1/11",53,16,0,31],
"ai_2": [1,27,9,0,0,3,8,"d3b8e94d",12,"deputShip 1/2, siracusaShip 1/2, soloShip 1/8, yanShip 0/1",48,16,5,32]
},
@@ -798,31 +798,31 @@
},
{
"round": 9,
"ai_0": [1,3,12,2,1,4,8,"fbb2ffe2",128,"arcaneShip 1/24, deputShip 2/40, indomShip 0/10, kazimierzShip 0/2, soloShip 1/8, suntShip 1/16, swiftShip 0/37, victoriaShip 1/28, visiShip 1/12",40,22,12,77],
"ai_0": [1,3,12,2,1,4,8,"fbb2ffe2",132,"arcaneShip 1/24, deputShip 2/40, indomShip 0/10, kazimierzShip 0/2, soloShip 1/8, suntShip 1/16, swiftShip 0/37, victoriaShip 1/30, visiShip 1/14",42,22,10,77],
"ai_1": [1,35,12,0,1,4,8,"07eb7cb9",93,"indomShip 0/1, kazimierzShip 0/11, lateranoShip 1/24, skillfulShip 1/21, soloShip 1/0, steadShip 2/31, suntShip 2/0, swiftShip 1/17",63,22,4,72],
"ai_2": [1,13,12,0,0,4,8,"80de288d",111,"deputShip 1/12, indomShip 1/12, raidShip 1/2, siracusaShip 1/47, soloShip 1/23, steadShip 1/5, suntShip 1/10, yanShip 0/1",49,22,8,75]
},
{
"round": 10,
"ai_0": [0,0,15,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/34, visiShip 0/16",11,18,7,90],
"ai_0": [0,0,15,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/42, visiShip 0/24",11,18,7,90],
"ai_1": [1,31,13,0,0,5,8,"0398042e",130,"indomShip 0/1, kazimierzShip 0/11, lateranoShip 1/36, skillfulShip 1/29, soloShip 1/0, steadShip 2/46, suntShip 2/0, swiftShip 1/19",14,18,4,84],
"ai_2": [1,3,12,0,0,5,8,"dc3116d5",134,"deputShip 1/14, indomShip 1/16, raidShip 1/4, siracusaShip 1/55, soloShip 1/25, steadShip 1/8, suntShip 1/12, yanShip 0/1",3,18,15,86]
},
{
"round": 11,
"ai_0": [0,0,0,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/34, visiShip 0/16",null,null,null,90],
"ai_0": [0,0,0,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/42, visiShip 0/24",null,null,null,90],
"ai_1": [1,27,12,0,1,5,8,"94474806",168,"indomShip 0/1, kazimierzShip 0/11, lateranoShip 1/48, raidShip 1/1, skillfulShip 1/37, soloShip 1/0, steadShip 2/61, suntShip 1/0, swiftShip 1/21",21,25,4,96],
"ai_2": [0,0,12,0,0,5,0,"811c9dc5",0,"deputShip 0/16, indomShip 0/20, raidShip 0/7, siracusaShip 0/81, soloShip 0/25, steadShip 0/15, suntShip 0/14, yanShip 0/1",10,25,15,99]
},
{
"round": 12,
"ai_0": [0,0,0,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/34, visiShip 0/16",null,null,null,90],
"ai_0": [0,0,0,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/42, visiShip 0/24",null,null,null,90],
"ai_1": [1,17,13,0,0,6,8,"951e9b91",161,"indomShip 0/1, kazimierzShip 0/11, lateranoShip 1/54, raidShip 1/2, siracusaShip 1/6, skillfulShip 0/45, soloShip 1/0, steadShip 2/70, suntShip 2/0, swiftShip 1/29",14,57,43,110],
"ai_2": [0,0,0,0,0,5,0,"811c9dc5",0,"deputShip 0/16, indomShip 0/20, raidShip 0/7, siracusaShip 0/81, soloShip 0/25, steadShip 0/15, suntShip 0/14, yanShip 0/1",null,null,null,99]
},
{
"round": 13,
"ai_0": [0,0,0,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/34, visiShip 0/16",null,null,null,90],
"ai_0": [0,0,0,0,0,5,0,"811c9dc5",0,"arcaneShip 0/32, deputShip 0/52, indomShip 0/10, kazimierzShip 0/2, soloShip 0/12, suntShip 0/20, swiftShip 0/37, victoriaShip 0/42, visiShip 0/24",null,null,null,90],
"ai_1": [1,7,12,0,0,6,8,"28aefa85",202,"indomShip 0/1, kazimierzShip 0/11, kjeragShip 0/5, lateranoShip 1/60, raidShip 1/3, siracusaShip 0/6, skillfulShip 1/50, soloShip 1/0, steadShip 2/89, suntShip 1/0, swiftShip 0/29",9,26,17,124],
"ai_2": [0,0,0,0,0,5,0,"811c9dc5",0,"deputShip 0/16, indomShip 0/20, raidShip 0/7, siracusaShip 0/81, soloShip 0/25, steadShip 0/15, suntShip 0/14, yanShip 0/1",null,null,null,99]
}
@@ -838,9 +838,9 @@
"title": {"id":"comment_5","name":"万事俱备","picId":"comment_icon_5","text":"装备配发数量最多"},
"trophies": 2,
"reward": 191,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":1467309,"gold":90,"itemsEquipped":8,"kills":205,"leaks":43,"lpLost":27,"merges":4,"perfectRounds":6,"refreshes":11},
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":1544691,"gold":90,"itemsEquipped":8,"kills":220,"leaks":33,"lpLost":27,"merges":4,"perfectRounds":7,"refreshes":11},
"lineup": [],
"bonds": ["arcaneShip 0/32","deputShip 0/52","indomShip 0/10","kazimierzShip 0/2","soloShip 0/12","suntShip 0/20","swiftShip 0/37","victoriaShip 0/34","visiShip 0/16"]
"bonds": ["arcaneShip 0/32","deputShip 0/52","indomShip 0/10","kazimierzShip 0/2","soloShip 0/12","suntShip 0/20","swiftShip 0/37","victoriaShip 0/42","visiShip 0/24"]
},
"ai_1": {
"alive": true,
@@ -852,7 +852,7 @@
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"trophies": 3,
"reward": 340,
"stats": {"activatedLayers":222,"bossDamage":1242587,"dmgDealt":6378339,"gold":137,"itemsEquipped":10,"kills":329,"leaks":78,"lpLost":38,"merges":7,"perfectRounds":7,"refreshes":18},
"stats": {"activatedLayers":222,"bossDamage":1242587,"dmgDealt":6378278,"gold":137,"itemsEquipped":10,"kills":316,"leaks":78,"lpLost":38,"merges":7,"perfectRounds":7,"refreshes":18},
"lineup": ["6_09_a@12,8[3_04_e_a]","4_13_a@11,6","3_21_b@11,7[3_02_e_a+3_11_e_a]","6_09_a@11,8[3_03_e_a+6_09_e_a]","4_01_a@10,7[4_02_e_a+4_04_e_b]","4_16_b@10,8","2_17_b@9,6[4_05_e_a]","3_05_a@9,9"],
"bonds": ["indomShip 0/1","kazimierzShip 0/11","kjeragShip 0/5","lateranoShip 1/66","raidShip 1/3","siracusaShip 0/6","skillfulShip 1/56","soloShip 1/0","steadShip 2/97","suntShip 1/0","swiftShip 0/29"]
},
@@ -958,7 +958,7 @@
},
{
"round": 11,
"ai_0": [1,26,12,0,2,5,8,"9d2a55eb",168,"deputShip 2/33, kjeragShip 1/25, preciShip 2/75, sargonShip 0/11, steadShip 0/8, swiftShip 1/35, victoriaShip 0/21",28,28,0,98],
"ai_0": [1,26,12,0,2,5,8,"9d2a55eb",166,"deputShip 2/33, kjeragShip 1/23, preciShip 2/75, sargonShip 0/11, steadShip 0/8, swiftShip 1/35, victoriaShip 0/21",28,28,0,98],
"ai_1": [1,45,12,0,0,5,8,"65f29644",72,"deputShip 0/2, emptyShip 1/0, preciShip 1/6, sargonShip 0/2, siracusaShip 1/61, steadShip 0/31, visiShip 1/5",28,28,0,97],
"ai_2": [1,28,12,0,0,5,8,"81bc5ae1",140,"deputShip 1/18, kjeragShip 0/5, preciShip 2/89, sargonShip 1/33, yanShip 0/6",28,28,0,91],
"ai_3": [1,31,16,2,0,5,7,"566cbb6d",147,"deputShip 0/10, emptyShip 0/6, preciShip 1/93, siracusaShip 0/6, swiftShip 0/17, victoriaShip 1/10, visiShip 1/44, yanShip 0/1",28,28,0,104]
@@ -973,7 +973,7 @@
{
"round": 13,
"ai_0": [1,26,12,0,0,6,8,"57172cf7",239,"deputShip 1/39, emptyShip 1/2, kjeragShip 1/32, preciShip 2/105, sargonShip 0/11, steadShip 0/8, swiftShip 1/61, victoriaShip 0/21",32,32,0,123],
"ai_1": [1,45,14,0,0,6,8,"ced5ebe3",150,"deputShip 0/4, emptyShip 1/2, preciShip 2/16, sargonShip 0/2, siracusaShip 1/101, steadShip 1/31, visiShip 0/12",32,32,0,124],
"ai_1": [1,45,14,0,0,6,8,"ced5ebe3",146,"deputShip 0/4, emptyShip 1/2, preciShip 2/16, sargonShip 0/2, siracusaShip 1/97, steadShip 1/31, visiShip 0/12",32,32,0,124],
"ai_2": [1,28,12,0,0,6,8,"d0aeb38e",201,"deputShip 1/24, kjeragShip 0/5, preciShip 2/124, sargonShip 1/53, yanShip 0/6",32,32,0,117],
"ai_3": [1,31,14,0,0,6,7,"9015cc77",220,"deputShip 0/10, emptyShip 0/6, preciShip 2/119, siracusaShip 0/6, swiftShip 1/27, victoriaShip 1/14, visiShip 1/60, yanShip 0/1",32,32,0,132]
}
@@ -989,7 +989,7 @@
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 3,
"reward": 250,
"stats": {"activatedLayers":271,"bossDamage":524820,"dmgDealt":1950923,"gold":135,"itemsEquipped":22,"kills":292,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":23},
"stats": {"activatedLayers":271,"bossDamage":508388,"dmgDealt":1934491,"gold":135,"itemsEquipped":22,"kills":291,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":23},
"lineup": ["4_25_a@11,3","1_06_b@11,6","6_12_a@11,7[2_01_e_a]","3_20_a@10,3[1_05_e_b]","5_14_a@10,4[3_08_e_a+5_02_e_a]","4_22_b@9,4[4_11_e_a+3_02_e_b]","4_14_b@9,8[2_01_e_b+3_01_e_a]","3_11_b@9,9[3_07_e_a+4_03_e_b]"],
"bonds": ["deputShip 1/41","emptyShip 1/4","kjeragShip 1/34","preciShip 2/119","sargonShip 0/11","steadShip 0/8","swiftShip 1/73","victoriaShip 0/21"]
},
@@ -1003,9 +1003,9 @@
"title": {"id":"comment_3","name":"坚若磐石","picId":"comment_icon_3","text":"目标生命值损失最少"},
"trophies": 3,
"reward": 250,
"stats": {"activatedLayers":158,"bossDamage":263706,"dmgDealt":1676109,"gold":135,"itemsEquipped":16,"kills":283,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":17},
"stats": {"activatedLayers":154,"bossDamage":248974,"dmgDealt":1661338,"gold":135,"itemsEquipped":16,"kills":283,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":17},
"lineup": ["6_12_a@11,7[2_04_e_b+4_03_e_a]","5_10_a@11,8[1_02_e_a]","6_18_a@10,3","4_10_b@10,4[4_08_e_a+4_03_e_b]","3_05_b@10,8[4_06_e_a+4_05_e_a]","1_10_b@9,4","6_05_a@9,8","6_05_a@9,9"],
"bonds": ["deputShip 0/4","emptyShip 1/2","preciShip 1/16","sargonShip 0/2","siracusaShip 1/109","steadShip 1/31","visiShip 0/12"]
"bonds": ["deputShip 0/4","emptyShip 1/2","preciShip 1/16","sargonShip 0/2","siracusaShip 1/105","steadShip 1/31","visiShip 0/12"]
},
"ai_2": {
"alive": true,
@@ -1017,7 +1017,7 @@
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 3,
"reward": 250,
"stats": {"activatedLayers":223,"bossDamage":147316,"dmgDealt":1570670,"gold":129,"itemsEquipped":20,"kills":283,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":16},
"stats": {"activatedLayers":223,"bossDamage":147188,"dmgDealt":1570539,"gold":129,"itemsEquipped":20,"kills":283,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":16},
"lineup": ["3_06_a@12,6[5_01_e_a+4_06_e_b]","2_14_a@11,6","4_20_b@11,7[3_08_e_a]","4_24_a@11,8","1_12_b@10,8[2_01_e_a+4_02_e_a]","6_03_a@9,4[1_01_e_b+4_05_e_a]","4_14_a@9,8[3_11_e_a+3_05_e_a]","6_05_a@9,9[1_05_e_b+4_07_e_b]"],
"bonds": ["deputShip 1/26","kjeragShip 0/5","preciShip 2/135","sargonShip 1/55","swiftShip 1/7","yanShip 0/6"]
},
@@ -1031,7 +1031,7 @@
"title": {"id":"comment_5","name":"万事俱备","picId":"comment_icon_5","text":"装备配发数量最多"},
"trophies": 3,
"reward": 250,
"stats": {"activatedLayers":198,"bossDamage":204157,"dmgDealt":1784967,"gold":142,"itemsEquipped":31,"kills":294,"leaks":0,"lpLost":0,"merges":2,"perfectRounds":13,"refreshes":34},
"stats": {"activatedLayers":198,"bossDamage":235450,"dmgDealt":1816298,"gold":142,"itemsEquipped":31,"kills":294,"leaks":0,"lpLost":0,"merges":2,"perfectRounds":13,"refreshes":34},
"lineup": ["6_01_a@11,7","2_01_b@10,3[4_09_e_a+6_03_e_b]","4_11_a@10,4[3_11_e_a+4_07_e_a]","4_07_a@9,3[4_11_e_a+2_01_e_a]","6_06_a@9,4[4_06_e_b+5_01_e_a]","2_10_a@9,8","4_14_a@9,9[1_01_e_a+4_04_e_a]"],
"bonds": ["deputShip 0/10","emptyShip 0/6","indomShip 1/0","preciShip 2/124","siracusaShip 0/6","swiftShip 0/32","victoriaShip 1/14","visiShip 1/60","yanShip 0/1"]
}
@@ -1047,8 +1047,8 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act2autochess_m01","bossId":"boss_1","hiddenBossId":"boss_8","factions":["DOT","INVISIBLE","REFLECTION"]},
"end": {"victory":false,"roundsPassed":12,"hiddenReached":false,"hiddenCleared":false,"reason":"eliminated","teamLp":null,"bossPoolLeft":null,"virtualMs":130250},
"rng": {"setup":25,"shop":675,"waves":0,"draft":57,"bots":21916,"meta":62},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":3417504,"virtualMs":139500},
"rng": {"setup":25,"shop":790,"waves":0,"draft":57,"bots":22692,"meta":66},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
{
@@ -1095,82 +1095,82 @@
},
{
"round": 7,
"ai_0": [1,28,10,0,0,4,8,"8091958a",45,"arcaneShip 0/4, kazimierzShip 0/8, kjeragShip 0/5, preciShip 2/19, suntShip 1/0, swiftShip 1/26",12,21,9,52],
"ai_1": [1,20,10,0,0,4,8,"6f0ccfc7",36,"arcaneShip 0/2, kazimierzShip 0/7, kjeragShip 0/4, preciShip 0/2, sargonShip 1/19, siracusaShip 0/6, soloShip 1/0, steadShip 2/4, swiftShip 1/13",15,21,6,51],
"ai_2": [1,20,10,0,2,4,8,"e9ee2d5d",83,"arcaneShip 0/2, deputShip 1/23, egirShip 0/4, kazimierzShip 0/2, kjeragShip 0/12, raidShip 0/4, soloShip 1/10, steadShip 2/24, swiftShip 0/4, victoriaShip 1/26, yanShip 0/2",17,21,4,52],
"ai_0": [1,30,10,0,0,4,8,"8091958a",45,"arcaneShip 0/4, kazimierzShip 0/8, kjeragShip 0/5, preciShip 2/19, suntShip 1/0, swiftShip 1/26",12,21,9,52],
"ai_1": [1,26,10,0,0,4,8,"6f0ccfc7",36,"arcaneShip 0/2, kazimierzShip 0/7, kjeragShip 0/4, preciShip 0/2, sargonShip 1/19, siracusaShip 0/6, soloShip 1/0, steadShip 2/4, swiftShip 1/13",21,21,0,51],
"ai_2": [1,21,10,0,2,4,8,"e9ee2d5d",83,"arcaneShip 0/2, deputShip 1/23, egirShip 0/4, kazimierzShip 0/2, kjeragShip 0/12, raidShip 0/4, soloShip 1/10, steadShip 2/24, swiftShip 0/4, victoriaShip 1/26, yanShip 0/2",17,21,4,52],
"ai_3": [1,8,10,0,0,4,8,"34745c3a",14,"arcaneShip 0/2, preciShip 0/2, sargonShip 0/4, siracusaShip 1/3, soloShip 1/11, steadShip 1/0",3,21,18,49]
},
{
"round": 8,
"ai_0": [1,26,11,0,0,4,8,"c8fd6622",73,"arcaneShip 1/4, kazimierzShip 0/8, kjeragShip 1/12, preciShip 2/24, skillfulShip 0/5, suntShip 1/0, swiftShip 1/33",7,9,2,63],
"ai_1": [1,13,11,0,0,4,8,"9a145335",54,"arcaneShip 0/2, deputShip 1/2, kazimierzShip 0/7, kjeragShip 1/11, preciShip 0/2, sargonShip 1/26, siracusaShip 0/6, skillfulShip 1/7, soloShip 1/2, steadShip 1/6, swiftShip 0/13",2,9,7,60],
"ai_2": [1,19,13,0,0,4,8,"3ce91083",115,"arcaneShip 1/8, deputShip 1/25, egirShip 0/6, kazimierzShip 0/2, kjeragShip 0/14, lateranoShip 0/2, raidShip 0/6, soloShip 1/12, steadShip 1/35, suntShip 1/2, swiftShip 0/4, victoriaShip 1/33, yanShip 0/12",8,9,1,66],
"ai_0": [1,28,11,0,0,4,8,"c8fd6622",73,"arcaneShip 1/4, kazimierzShip 0/8, kjeragShip 1/12, preciShip 2/24, skillfulShip 0/5, suntShip 1/0, swiftShip 1/33",7,9,2,63],
"ai_1": [1,20,11,0,0,4,8,"9a145335",54,"arcaneShip 0/2, deputShip 1/2, kazimierzShip 0/7, kjeragShip 1/11, preciShip 0/2, sargonShip 1/26, siracusaShip 0/6, skillfulShip 1/7, soloShip 1/2, steadShip 1/6, swiftShip 0/13",3,9,6,60],
"ai_2": [1,20,13,0,0,4,8,"c394bdcb",119,"arcaneShip 1/8, deputShip 1/27, egirShip 0/6, kazimierzShip 0/2, kjeragShip 0/14, lateranoShip 0/2, raidShip 0/6, soloShip 1/12, steadShip 1/34, suntShip 1/2, swiftShip 0/4, victoriaShip 1/36, yanShip 0/10",8,9,1,66],
"ai_3": [0,0,11,0,0,4,0,"811c9dc5",0,"arcaneShip 0/2, kjeragShip 0/5, preciShip 0/2, sargonShip 0/4, siracusaShip 0/7, skillfulShip 0/5, soloShip 0/12",0,9,9,59]
},
{
"round": 9,
"ai_0": [1,26,12,0,2,4,8,"2ff9d045",108,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/19, preciShip 2/33, skillfulShip 1/10, suntShip 1/0, swiftShip 1/38",9,19,10,74],
"ai_1": [1,11,12,0,0,4,8,"2b472f66",81,"arcaneShip 0/2, deputShip 2/6, kazimierzShip 0/7, kjeragShip 1/15, preciShip 0/2, sargonShip 1/39, siracusaShip 0/6, skillfulShip 1/11, soloShip 0/2, steadShip 1/10, swiftShip 0/13",13,19,6,72],
"ai_2": [1,19,12,0,1,4,8,"5c0ea571",121,"arcaneShip 1/12, deputShip 0/25, egirShip 0/8, indomShip 1/12, kazimierzShip 0/2, kjeragShip 0/20, lateranoShip 0/4, raidShip 0/6, soloShip 1/12, steadShip 1/46, suntShip 1/2, swiftShip 0/4, victoriaShip 1/37, yanShip 0/12",19,19,0,78],
"ai_0": [1,28,12,0,2,4,8,"2ff9d045",108,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/19, preciShip 2/33, skillfulShip 1/10, suntShip 1/0, swiftShip 1/38",9,19,10,74],
"ai_1": [1,20,12,0,3,4,8,"2b472f66",90,"arcaneShip 0/2, deputShip 2/6, kazimierzShip 0/7, kjeragShip 1/15, preciShip 0/2, sargonShip 1/48, siracusaShip 0/6, skillfulShip 1/11, soloShip 0/2, steadShip 1/10, swiftShip 0/13",16,19,3,72],
"ai_2": [1,20,12,0,1,4,8,"5c0ea571",123,"arcaneShip 1/12, deputShip 0/27, egirShip 0/8, indomShip 1/12, kazimierzShip 0/2, kjeragShip 0/20, lateranoShip 0/4, raidShip 0/6, soloShip 1/12, steadShip 1/45, suntShip 1/2, swiftShip 0/4, victoriaShip 1/40, yanShip 0/10",19,19,0,78],
"ai_3": [0,0,0,0,0,4,0,"811c9dc5",0,"arcaneShip 0/2, kjeragShip 0/5, preciShip 0/2, sargonShip 0/4, siracusaShip 0/7, skillfulShip 0/5, soloShip 0/12",null,null,null,59]
},
{
"round": 10,
"ai_0": [1,26,14,0,0,5,8,"f12b88a9",121,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/22, preciShip 2/38, skillfulShip 1/10, suntShip 1/0, swiftShip 1/43",25,25,0,87],
"ai_1": [1,11,12,0,0,5,8,"19319da9",151,"arcaneShip 0/2, deputShip 2/10, kazimierzShip 0/15, kjeragShip 1/47, preciShip 0/2, sargonShip 1/61, siracusaShip 0/6, skillfulShip 1/15, soloShip 0/2, steadShip 1/18, swiftShip 0/21",22,25,3,84],
"ai_2": [1,19,13,0,2,5,8,"4592c36e",157,"arcaneShip 1/16, deputShip 0/27, egirShip 0/8, indomShip 1/34, kazimierzShip 0/2, kjeragShip 0/20, lateranoShip 0/6, raidShip 0/6, skillfulShip 0/2, soloShip 1/12, steadShip 1/50, suntShip 1/2, swiftShip 0/4, victoriaShip 1/43, yanShip 0/12",24,25,1,90],
"ai_0": [1,28,14,0,0,5,8,"f12b88a9",121,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/22, preciShip 2/38, skillfulShip 1/10, suntShip 1/0, swiftShip 1/43",25,25,0,87],
"ai_1": [1,20,15,0,0,5,8,"0230fafb",152,"arcaneShip 0/2, deputShip 2/10, kazimierzShip 0/15, kjeragShip 1/39, preciShip 0/2, sargonShip 1/70, siracusaShip 0/6, skillfulShip 1/15, soloShip 0/2, steadShip 1/18, swiftShip 0/21",23,25,2,85],
"ai_2": [1,20,13,0,2,5,8,"4592c36e",154,"arcaneShip 1/16, deputShip 0/29, egirShip 0/8, indomShip 1/29, kazimierzShip 0/2, kjeragShip 0/20, lateranoShip 0/6, raidShip 0/6, skillfulShip 0/2, soloShip 1/12, steadShip 1/49, suntShip 1/2, swiftShip 0/4, victoriaShip 1/46, yanShip 0/10",25,25,0,90],
"ai_3": [0,0,0,0,0,4,0,"811c9dc5",0,"arcaneShip 0/2, kjeragShip 0/5, preciShip 0/2, sargonShip 0/4, siracusaShip 0/7, skillfulShip 0/5, soloShip 0/12",null,null,null,59]
},
{
"round": 11,
"ai_0": [1,16,12,0,0,5,8,"57c3bbc6",141,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/32, preciShip 2/43, skillfulShip 1/10, suntShip 1/0, swiftShip 1/48",14,24,10,99],
"ai_1": [1,8,12,0,2,5,8,"6dd048bb",208,"arcaneShip 0/2, deputShip 2/14, kazimierzShip 0/15, kjeragShip 1/59, preciShip 0/2, sargonShip 1/83, siracusaShip 0/6, skillfulShip 1/19, soloShip 0/2, steadShip 0/18, swiftShip 1/33",21,24,3,97],
"ai_2": [1,16,14,0,0,5,8,"ca66dbec",198,"arcaneShip 1/20, deputShip 0/27, egirShip 0/8, indomShip 1/51, kazimierzShip 0/2, kjeragShip 0/22, lateranoShip 0/6, raidShip 0/6, skillfulShip 1/6, soloShip 1/14, steadShip 1/58, suntShip 1/2, swiftShip 0/4, victoriaShip 1/47, yanShip 0/12",21,24,3,103],
"ai_0": [1,25,12,0,0,5,8,"57c3bbc6",141,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/32, preciShip 2/43, skillfulShip 1/10, suntShip 1/0, swiftShip 1/48",14,24,10,99],
"ai_1": [1,18,12,0,2,5,8,"ebc4eef2",209,"arcaneShip 0/2, deputShip 2/14, kazimierzShip 0/15, kjeragShip 1/51, preciShip 0/2, sargonShip 1/92, siracusaShip 0/6, skillfulShip 1/19, soloShip 0/2, steadShip 0/18, swiftShip 1/33",20,24,4,98],
"ai_2": [1,20,14,0,0,5,8,"8777b0c2",193,"arcaneShip 1/24, deputShip 0/29, egirShip 0/8, indomShip 1/44, kazimierzShip 0/2, kjeragShip 0/22, lateranoShip 0/6, raidShip 0/6, skillfulShip 1/4, soloShip 1/12, steadShip 1/55, suntShip 1/2, swiftShip 0/4, victoriaShip 1/52, yanShip 0/12",24,24,0,103],
"ai_3": [0,0,0,0,0,4,0,"811c9dc5",0,"arcaneShip 0/2, kjeragShip 0/5, preciShip 0/2, sargonShip 0/4, siracusaShip 0/7, skillfulShip 0/5, soloShip 0/12",null,null,null,59]
},
{
"round": 12,
"ai_0": [1,6,12,0,0,6,8,"db751bba",157,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/38, preciShip 2/48, skillfulShip 1/10, suntShip 1/0, swiftShip 1/53",12,47,35,110],
"ai_1": [0,0,14,0,0,6,0,"811c9dc5",0,"arcaneShip 0/2, deputShip 0/16, kazimierzShip 0/15, kjeragShip 0/82, preciShip 0/2, sargonShip 0/94, siracusaShip 0/6, skillfulShip 0/26, soloShip 0/2, steadShip 0/20, swiftShip 0/51",12,47,35,112],
"ai_2": [1,6,12,0,0,6,8,"8777b0c2",226,"arcaneShip 1/20, deputShip 0/29, egirShip 0/10, indomShip 1/63, kazimierzShip 0/2, kjeragShip 0/22, lateranoShip 0/6, raidShip 0/6, skillfulShip 1/8, soloShip 1/16, steadShip 1/64, suntShip 1/2, swiftShip 0/4, victoriaShip 1/53, yanShip 0/12",15,47,32,115],
"ai_0": [1,15,12,0,0,6,8,"db751bba",157,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/38, preciShip 2/48, skillfulShip 1/10, suntShip 1/0, swiftShip 1/53",12,47,35,110],
"ai_1": [1,8,14,0,0,6,8,"2246afd5",264,"arcaneShip 0/4, deputShip 1/16, kazimierzShip 0/15, kjeragShip 1/61, preciShip 0/4, sargonShip 1/103, siracusaShip 0/6, skillfulShip 1/21, soloShip 0/2, steadShip 1/20, swiftShip 1/43",11,47,36,113],
"ai_2": [1,10,12,0,0,6,8,"fc2ff295",221,"arcaneShip 1/24, deputShip 0/31, egirShip 0/10, indomShip 1/56, kazimierzShip 0/2, kjeragShip 0/22, lateranoShip 0/6, raidShip 0/6, skillfulShip 1/6, soloShip 1/14, steadShip 1/61, suntShip 1/2, swiftShip 0/4, victoriaShip 1/58, yanShip 0/12",16,47,31,115],
"ai_3": [0,0,0,0,0,4,0,"811c9dc5",0,"arcaneShip 0/2, kjeragShip 0/5, preciShip 0/2, sargonShip 0/4, siracusaShip 0/7, skillfulShip 0/5, soloShip 0/12",null,null,null,59]
},
{
"round": 13,
"ai_0": [0,0,12,0,0,6,0,"811c9dc5",0,"arcaneShip 0/8, kazimierzShip 0/8, kjeragShip 0/89, preciShip 0/53, skillfulShip 0/10, swiftShip 0/58",28,39,11,120],
"ai_1": [0,0,0,0,0,6,0,"811c9dc5",0,"arcaneShip 0/2, deputShip 0/16, kazimierzShip 0/15, kjeragShip 0/82, preciShip 0/2, sargonShip 0/94, siracusaShip 0/6, skillfulShip 0/26, soloShip 0/2, steadShip 0/20, swiftShip 0/51",null,null,null,112],
"ai_2": [0,0,12,0,0,6,0,"811c9dc5",0,"arcaneShip 0/34, deputShip 0/29, egirShip 0/12, indomShip 0/65, kazimierzShip 0/2, kjeragShip 0/24, lateranoShip 0/6, raidShip 0/6, skillfulShip 0/18, soloShip 0/16, steadShip 0/70, suntShip 0/2, swiftShip 0/4, victoriaShip 0/59, yanShip 0/12",17,39,22,125],
"ai_0": [1,5,12,0,0,6,8,"cd4ad4bf",218,"arcaneShip 1/8, kazimierzShip 0/8, kjeragShip 1/89, preciShip 2/53, skillfulShip 1/10, suntShip 1/0, swiftShip 1/58",28,39,11,120],
"ai_1": [0,0,12,0,0,6,0,"811c9dc5",0,"arcaneShip 0/4, deputShip 0/20, kazimierzShip 0/15, kjeragShip 0/82, preciShip 0/4, sargonShip 0/107, siracusaShip 0/6, skillfulShip 0/25, soloShip 0/2, steadShip 0/24, suntShip 0/4, swiftShip 0/55",27,39,12,125],
"ai_2": [0,0,12,0,0,6,0,"811c9dc5",0,"arcaneShip 0/34, deputShip 0/31, egirShip 0/10, indomShip 0/56, kazimierzShip 0/2, kjeragShip 0/28, lateranoShip 0/6, raidShip 0/6, skillfulShip 0/8, soloShip 0/14, steadShip 0/67, suntShip 0/2, swiftShip 0/4, victoriaShip 0/64, yanShip 0/14",23,39,16,127],
"ai_3": [0,0,0,0,0,4,0,"811c9dc5",0,"arcaneShip 0/2, kjeragShip 0/5, preciShip 0/2, sargonShip 0/4, siracusaShip 0/7, skillfulShip 0/5, soloShip 0/12",null,null,null,59]
}
],
"players": {
"ai_0": {
"alive": true,
"victory": false,
"roundsPassed": 13,
"eliminatedRound": null,
"lp": 0,
"bandId": "band_sarkazb",
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"trophies": 3,
"reward": 340,
"stats": {"activatedLayers":228,"bossDamage":182496,"dmgDealt":5951691,"gold":132,"itemsEquipped":14,"kills":164,"leaks":87,"lpLost":40,"merges":3,"perfectRounds":6,"refreshes":27},
"lineup": ["4_21_a@12,4","1_17_b@12,8[4_06_e_a+5_07_e_a]","4_14_a@11,4[4_04_e_a]","3_11_a@11,8[3_04_e_b+1_02_e_a]","4_02_a@10,4","4_22_a@10,7[4_02_e_a+4_10_e_a]","1_19_b@10,8[1_05_e_a+2_04_e_a]","4_13_a@9,8[3_06_e_b+3_04_e_a]"],
"bonds": ["arcaneShip 1/8","kazimierzShip 0/8","kjeragShip 1/89","preciShip 2/58","skillfulShip 1/10","suntShip 1/0","swiftShip 1/63"]
},
"ai_1": {
"alive": false,
"victory": false,
"roundsPassed": 12,
"eliminatedRound": 13,
"lp": 0,
"bandId": "band_sarkazb",
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 3,
"reward": 298,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":5604542,"gold":120,"itemsEquipped":13,"kills":164,"leaks":87,"lpLost":49,"merges":3,"perfectRounds":6,"refreshes":17},
"lineup": [],
"bonds": ["arcaneShip 0/8","kazimierzShip 0/8","kjeragShip 0/89","preciShip 0/53","skillfulShip 0/10","swiftShip 0/58"]
},
"ai_1": {
"alive": false,
"victory": false,
"roundsPassed": 11,
"eliminatedRound": 12,
"lp": 0,
"bandId": "band_kirara",
"title": {"id":"comment_6","name":"挥金如土","picId":"comment_icon_6","text":"消耗资金最多"},
"trophies": 2,
"reward": 255,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":3777039,"gold":112,"itemsEquipped":8,"kills":162,"leaks":60,"lpLost":28,"merges":1,"perfectRounds":6,"refreshes":22},
"trophies": 3,
"reward": 298,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":6090165,"gold":125,"itemsEquipped":13,"kills":206,"leaks":63,"lpLost":28,"merges":2,"perfectRounds":7,"refreshes":25},
"lineup": [],
"bonds": ["arcaneShip 0/2","deputShip 0/16","kazimierzShip 0/15","kjeragShip 0/82","preciShip 0/2","sargonShip 0/94","siracusaShip 0/6","skillfulShip 0/26","soloShip 0/2","steadShip 0/20","swiftShip 0/51"]
"bonds": ["arcaneShip 0/4","deputShip 0/20","kazimierzShip 0/15","kjeragShip 0/82","preciShip 0/4","sargonShip 0/107","siracusaShip 0/6","skillfulShip 0/25","soloShip 0/2","steadShip 0/24","suntShip 0/4","swiftShip 0/55"]
},
"ai_2": {
"alive": false,
@@ -1179,12 +1179,12 @@
"eliminatedRound": 13,
"lp": 0,
"bandId": "band_bldsk",
"title": {"id":"comment_5","name":"万事俱备","picId":"comment_icon_5","text":"装备配发数量最多"},
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 3,
"reward": 298,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":5789462,"gold":125,"itemsEquipped":21,"kills":189,"leaks":73,"lpLost":32,"merges":3,"perfectRounds":4,"refreshes":13},
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":6858444,"gold":127,"itemsEquipped":22,"kills":210,"leaks":62,"lpLost":28,"merges":3,"perfectRounds":6,"refreshes":14},
"lineup": [],
"bonds": ["arcaneShip 0/34","deputShip 0/29","egirShip 0/12","indomShip 0/65","kazimierzShip 0/2","kjeragShip 0/24","lateranoShip 0/6","raidShip 0/6","skillfulShip 0/18","soloShip 0/16","steadShip 0/70","suntShip 0/2","swiftShip 0/4","victoriaShip 0/59","yanShip 0/12"]
"bonds": ["arcaneShip 0/34","deputShip 0/31","egirShip 0/10","indomShip 0/56","kazimierzShip 0/2","kjeragShip 0/28","lateranoShip 0/6","raidShip 0/6","skillfulShip 0/8","soloShip 0/14","steadShip 0/67","suntShip 0/2","swiftShip 0/4","victoriaShip 0/64","yanShip 0/14"]
},
"ai_3": {
"alive": false,
@@ -1193,7 +1193,7 @@
"eliminatedRound": 8,
"lp": 0,
"bandId": "band_cathy",
"title": null,
"title": {"id":"comment_5","name":"万事俱备","picId":"comment_icon_5","text":"装备配发数量最多"},
"trophies": 1,
"reward": 149,
"stats": {"activatedLayers":0,"bossDamage":0,"dmgDealt":692486,"gold":59,"itemsEquipped":6,"kills":55,"leaks":41,"lpLost":27,"merges":0,"perfectRounds":3,"refreshes":3},
@@ -1212,7 +1212,7 @@
"combat": "server",
"boost": null,
"setup": {"stageId":"act1autochess_m01","bossId":"boss_1","hiddenBossId":"boss_9","factions":["FLY","DOT","REFLECTION"]},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":26,"bossPoolLeft":0,"virtualMs":118400},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":37,"bossPoolLeft":0,"virtualMs":119900},
"rng": {"setup":25,"shop":482,"waves":0,"draft":34,"bots":18094,"meta":81},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -1254,7 +1254,7 @@
{
"round": 8,
"ai_0": [1,30,13,0,4,4,8,"dd94b4a8",45,"arcaneShip 0/2, preciShip 1/7, siracusaShip 1/26, soloShip 1/3, steadShip 1/9",24,24,0,69],
"ai_1": [1,28,12,0,0,4,8,"ebb394d0",121,"arcaneShip 1/16, deputShip 1/8, kjeragShip 1/29, preciShip 1/35, soloShip 1/2, steadShip 1/19, suntShip 1/8, victoriaShip 1/4",23,23,0,62]
"ai_1": [1,28,12,0,0,4,8,"a16d247e",121,"arcaneShip 1/16, deputShip 1/8, kjeragShip 1/29, preciShip 1/35, soloShip 1/2, steadShip 1/19, suntShip 1/8, victoriaShip 1/4",23,23,0,62]
},
{
"round": 9,
@@ -1274,12 +1274,12 @@
{
"round": 12,
"ai_0": [1,20,12,0,0,6,8,"6c0894ab",123,"arcaneShip 1/19, indomShip 0/8, preciShip 1/29, siracusaShip 1/67, soloShip 1/3, steadShip 0/9, suntShip 1/0, swiftShip 1/5, victoriaShip 0/8, visiShip 0/8",29,46,17,125],
"ai_1": [1,18,12,0,0,6,8,"3c8a5177",207,"arcaneShip 1/34, deputShip 1/16, indomShip 0/8, kjeragShip 1/49, preciShip 1/53, soloShip 1/10, steadShip 2/29, suntShip 2/16, victoriaShip 0/12, visiShip 0/8",34,46,12,109]
"ai_1": [1,18,12,0,0,6,8,"3c8a5177",207,"arcaneShip 1/34, deputShip 1/16, indomShip 0/8, kjeragShip 1/49, preciShip 1/53, soloShip 1/10, steadShip 2/29, suntShip 2/16, victoriaShip 0/12, visiShip 0/8",36,46,10,109]
},
{
"round": 13,
"ai_0": [1,10,12,0,0,6,8,"542c547b",165,"arcaneShip 2/23, indomShip 0/8, lateranoShip 1/0, maniShip 1/0, preciShip 1/39, raidShip 1/10, siracusaShip 1/75, soloShip 1/3, steadShip 0/9, suntShip 1/0, swiftShip 1/15, victoriaShip 0/8, visiShip 0/8",20,39,19,138],
"ai_1": [1,16,12,0,0,6,8,"31109540",221,"arcaneShip 1/36, deputShip 1/18, indomShip 0/8, kjeragShip 1/51, preciShip 1/55, soloShip 1/12, steadShip 2/31, suntShip 2/18, victoriaShip 0/12, visiShip 0/8",37,39,2,120]
"ai_0": [1,19,12,0,0,6,8,"542c547b",165,"arcaneShip 2/23, indomShip 0/8, lateranoShip 1/0, maniShip 1/0, preciShip 1/39, raidShip 1/10, siracusaShip 1/75, soloShip 1/3, steadShip 0/9, suntShip 1/0, swiftShip 1/15, victoriaShip 0/8, visiShip 0/8",20,39,19,138],
"ai_1": [1,18,12,0,0,6,8,"20ec6e25",221,"arcaneShip 1/36, deputShip 1/18, indomShip 0/8, kjeragShip 1/51, preciShip 1/55, soloShip 1/12, steadShip 2/31, suntShip 2/18, victoriaShip 0/12, visiShip 0/8",39,39,0,120]
}
],
"players": {
@@ -1288,12 +1288,12 @@
"victory": true,
"roundsPassed": 14,
"eliminatedRound": null,
"lp": 10,
"lp": 19,
"bandId": "band_doberm",
"title": {"id":"comment_6","name":"挥金如土","picId":"comment_icon_6","text":"消耗资金最多"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":195,"bossDamage":340203,"dmgDealt":3208513,"gold":149,"itemsEquipped":22,"kills":253,"leaks":43,"lpLost":20,"merges":3,"perfectRounds":9,"refreshes":25},
"stats": {"activatedLayers":195,"bossDamage":340203,"dmgDealt":3208513,"gold":149,"itemsEquipped":22,"kills":253,"leaks":43,"lpLost":11,"merges":3,"perfectRounds":9,"refreshes":25},
"lineup": ["5_10_a@11,3[3_11_e_b+4_04_e_b]","6_11_a@11,6","1_01_b@11,7","1_17_a@10,3[1_01_e_a]","4_14_b@10,7[6_09_e_a+3_11_e_a]","4_16_a@10,8","4_02_a@9,8[6_01_e_a+3_03_e_b]","1_08_a@9,9[1_02_e_b+1_02_e_a]"],
"bonds": ["arcaneShip 1/23","indomShip 0/8","lateranoShip 1/0","maniShip 1/0","preciShip 1/49","raidShip 1/20","siracusaShip 1/75","soloShip 1/3","steadShip 0/9","suntShip 1/0","swiftShip 1/25","victoriaShip 0/8","visiShip 0/8"]
},
@@ -1302,12 +1302,12 @@
"victory": true,
"roundsPassed": 14,
"eliminatedRound": null,
"lp": 16,
"lp": 18,
"bandId": "band_malkie",
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":243,"bossDamage":1009797,"dmgDealt":4614790,"gold":130,"itemsEquipped":29,"kills":261,"leaks":14,"lpLost":12,"merges":5,"perfectRounds":11,"refreshes":16},
"stats": {"activatedLayers":243,"bossDamage":1009797,"dmgDealt":5234069,"gold":130,"itemsEquipped":29,"kills":283,"leaks":10,"lpLost":10,"merges":5,"perfectRounds":12,"refreshes":16},
"lineup": ["1_06_b@12,3[5_07_e_a+4_03_e_b]","1_02_b@12,4[5_02_e_a+4_11_e_b]","1_17_b@11,6[4_03_e_a+1_01_e_b]","3_11_b@11,7[3_01_e_a+3_02_e_a]","3_20_a@10,3[1_05_e_a+1_05_e_b]","1_10_b@10,8[4_02_e_a+6_11_e_a]","5_11_a@9,4[4_08_e_a+1_02_e_a]","5_12_a@9,9[4_10_e_a]"],
"bonds": ["arcaneShip 1/40","deputShip 1/20","indomShip 0/8","kjeragShip 1/56","preciShip 1/57","soloShip 1/14","steadShip 2/36","suntShip 2/20","victoriaShip 0/12","visiShip 0/8"]
}
@@ -1518,8 +1518,8 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m01","bossId":"boss_5","hiddenBossId":"boss_10","factions":["DOT","INVISIBLE","REFLECTION"]},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":31,"bossPoolLeft":0,"virtualMs":116900},
"rng": {"setup":25,"shop":403,"waves":0,"draft":34,"bots":18116,"meta":10},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":40,"bossPoolLeft":0,"virtualMs":116900},
"rng": {"setup":25,"shop":403,"waves":0,"draft":34,"bots":18127,"meta":10},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
{
@@ -1569,23 +1569,23 @@
},
{
"round": 10,
"h_0": [1,28,12,0,0,5,8,"8437aa19",124,"arcaneShip 0/8, deputShip 1/6, emptyShip 1/6, kazimierzShip 0/4, preciShip 1/35, raidShip 1/26, skillfulShip 0/2, soloShip 1/6, steadShip 1/16, swiftShip 1/29, yanShip 0/1",31,31,0,87],
"h_0": [1,28,12,0,0,5,8,"8437aa19",128,"arcaneShip 0/8, deputShip 1/6, emptyShip 1/6, kazimierzShip 0/4, preciShip 1/35, raidShip 1/28, skillfulShip 0/2, soloShip 1/6, steadShip 1/18, swiftShip 1/29, yanShip 0/1",31,31,0,87],
"ai_0": [1,23,12,0,0,5,8,"0147bc65",104,"arcaneShip 2/16, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/5, preciShip 1/19, raidShip 1/32, sargonShip 0/2, suntShip 1/8, swiftShip 1/24",31,31,0,87]
},
{
"round": 11,
"h_0": [1,28,12,0,0,5,8,"b5da5048",139,"arcaneShip 0/8, deputShip 0/6, emptyShip 1/6, kazimierzShip 0/4, preciShip 1/42, raidShip 1/31, skillfulShip 0/2, soloShip 1/6, steadShip 1/20, swiftShip 1/34, yanShip 0/1",25,25,0,98],
"ai_0": [1,23,12,0,0,5,8,"083c8c02",161,"arcaneShip 1/19, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/11, preciShip 2/30, raidShip 1/64, sargonShip 0/2, suntShip 1/8, swiftShip 1/29",25,25,0,99]
"h_0": [1,28,12,0,0,5,8,"b5da5048",149,"arcaneShip 0/8, deputShip 0/6, emptyShip 1/6, kazimierzShip 0/4, preciShip 1/42, raidShip 1/36, skillfulShip 0/2, soloShip 1/6, steadShip 1/25, swiftShip 1/34, yanShip 0/1",25,25,0,98],
"ai_0": [1,23,12,0,0,5,8,"083c8c02",149,"arcaneShip 1/19, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/5, preciShip 2/24, raidShip 1/64, sargonShip 0/2, suntShip 1/8, swiftShip 1/29",25,25,0,99]
},
{
"round": 12,
"h_0": [1,28,12,0,0,5,8,"093d3c03",157,"arcaneShip 0/8, deputShip 0/6, egirShip 1/3, emptyShip 0/6, kazimierzShip 0/4, preciShip 1/49, raidShip 1/36, skillfulShip 0/2, soloShip 1/6, steadShip 1/24, suntShip 1/0, swiftShip 1/39, yanShip 0/1",23,31,8,109],
"ai_0": [1,23,12,0,0,6,8,"7258fcd5",206,"arcaneShip 1/24, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/17, preciShip 2/43, raidShip 1/80, sargonShip 0/2, suntShip 1/8, swiftShip 1/34",31,31,0,112]
"h_0": [1,28,12,0,0,5,8,"e54d1d0c",169,"arcaneShip 0/8, deputShip 0/6, egirShip 1/5, emptyShip 0/6, kazimierzShip 0/4, preciShip 1/49, raidShip 1/41, skillfulShip 0/2, soloShip 1/6, steadShip 1/29, suntShip 1/0, swiftShip 1/39, yanShip 0/1",21,31,10,109],
"ai_0": [1,23,12,0,0,6,8,"1cd60f15",191,"arcaneShip 1/21, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/11, preciShip 2/37, raidShip 1/80, sargonShip 0/2, suntShip 1/8, swiftShip 1/34",31,31,0,112]
},
{
"round": 13,
"h_0": [1,18,12,0,0,6,8,"ba279997",190,"arcaneShip 0/8, deputShip 0/6, egirShip 1/11, emptyShip 0/6, kazimierzShip 0/4, preciShip 1/54, raidShip 1/44, skillfulShip 0/2, soloShip 1/6, steadShip 1/31, suntShip 1/0, swiftShip 1/44, yanShip 0/1",22,57,35,120],
"ai_0": [1,13,12,0,0,6,8,"284baa2f",246,"arcaneShip 0/24, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/23, preciShip 2/54, raidShip 1/112, sargonShip 0/2, siracusaShip 0/6, soloShip 1/0, steadShip 1/4, suntShip 1/8, swiftShip 1/45",31,57,26,122]
"h_0": [1,18,12,0,0,6,8,"80188da8",196,"arcaneShip 0/8, deputShip 0/6, egirShip 1/11, emptyShip 0/6, kazimierzShip 0/4, preciShip 1/54, raidShip 1/47, skillfulShip 0/2, soloShip 1/6, steadShip 1/34, suntShip 1/0, swiftShip 1/44, yanShip 0/1",30,57,27,120],
"ai_0": [1,22,12,0,0,6,8,"d2a2d8aa",218,"arcaneShip 0/21, deputShip 0/8, kazimierzShip 0/8, lateranoShip 1/17, preciShip 2/48, raidShip 1/96, sargonShip 0/2, siracusaShip 0/6, soloShip 1/0, steadShip 1/4, suntShip 1/8, swiftShip 1/45",56,57,1,122]
}
],
"players": {
@@ -1596,26 +1596,26 @@
"eliminatedRound": null,
"lp": 18,
"bandId": "band_amedic",
"title": {"id":"comment_3","name":"坚若磐石","picId":"comment_icon_3","text":"目标生命值损失最少"},
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":172,"bossDamage":189876,"dmgDealt":2565610,"gold":131,"itemsEquipped":16,"kills":273,"leaks":43,"lpLost":10,"merges":4,"perfectRounds":11,"refreshes":13},
"stats": {"activatedLayers":175,"bossDamage":191721,"dmgDealt":2653536,"gold":131,"itemsEquipped":16,"kills":280,"leaks":37,"lpLost":10,"merges":4,"perfectRounds":11,"refreshes":13},
"lineup": ["4_14_a@12,3[4_07_e_b+4_03_e_a]","3_10_b@11,3","6_04_a@11,4","3_09_a@11,8[3_08_e_a]","1_17_b@10,3[1_01_e_a+6_05_e_a]","5_05_a@10,4[3_04_e_a+4_02_e_a]","3_05_b@10,8[5_02_e_b+3_03_e_a]","2_17_a@9,4"],
"bonds": ["arcaneShip 1/8","deputShip 0/6","egirShip 1/11","emptyShip 0/6","kazimierzShip 0/8","preciShip 1/59","raidShip 0/44","skillfulShip 0/2","soloShip 1/6","steadShip 1/35","suntShip 1/0","swiftShip 1/53","yanShip 0/1"]
"bonds": ["arcaneShip 1/8","deputShip 0/6","egirShip 1/11","emptyShip 0/6","kazimierzShip 0/8","preciShip 1/59","raidShip 0/47","skillfulShip 0/2","soloShip 1/6","steadShip 1/38","suntShip 1/0","swiftShip 1/53","yanShip 0/1"]
},
"ai_0": {
"alive": true,
"victory": true,
"roundsPassed": 14,
"eliminatedRound": null,
"lp": 13,
"lp": 22,
"bandId": "band_chiave",
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":282,"bossDamage":590124,"dmgDealt":3843408,"gold":134,"itemsEquipped":19,"kills":276,"leaks":26,"lpLost":10,"merges":4,"perfectRounds":12,"refreshes":18},
"stats": {"activatedLayers":251,"bossDamage":588279,"dmgDealt":4174649,"gold":134,"itemsEquipped":19,"kills":303,"leaks":1,"lpLost":1,"merges":4,"perfectRounds":12,"refreshes":18},
"lineup": ["4_10_a@12,3","4_01_a@12,8[6_02_e_a+2_01_e_a]","6_12_a@11,3[3_05_e_a+3_11_e_a]","4_14_a@11,8","1_01_b@10,3[1_05_e_b+3_01_e_b]","5_07_a@10,7[3_07_e_a+3_05_e_b]","1_18_b@10,8[4_11_e_a+4_05_e_a]","2_01_b@9,8[3_02_e_a+3_06_e_a]"],
"bonds": ["arcaneShip 1/30","deputShip 0/8","kazimierzShip 0/8","lateranoShip 1/23","preciShip 2/59","raidShip 1/112","sargonShip 0/2","siracusaShip 0/6","steadShip 0/4","suntShip 1/8","swiftShip 1/50"]
"bonds": ["arcaneShip 1/27","deputShip 0/8","kazimierzShip 0/8","lateranoShip 1/17","preciShip 2/53","raidShip 1/96","sargonShip 0/2","siracusaShip 0/6","steadShip 0/4","suntShip 1/8","swiftShip 1/50"]
}
},
"standIns": {
@@ -1666,32 +1666,32 @@
},
{
"round": 8,
"h_0": [1,27,14,0,0,5,8,"c80e44c9",164,"indomShip 1/12, miraShip 0/3, preciShip 2/45, sargonShip 1/61, soloShip 1/0, steadShip 1/34, visiShip 1/12, yanShip 0/6",18,18,0,62],
"h_0": [1,27,14,0,0,5,8,"3cd8d174",180,"indomShip 1/12, miraShip 0/3, preciShip 2/49, sargonShip 1/74, soloShip 1/0, steadShip 1/33, visiShip 1/12, yanShip 0/6",18,18,0,62],
"ai_0": [1,28,13,0,0,4,8,"b30dbdae",23,"kjeragShip 0/5, preciShip 2/14, sargonShip 0/2, siracusaShip 1/0, skillfulShip 1/4, soloShip 1/0, steadShip 0/2, suntShip 1/0, swiftShip 1/5, yanShip 0/2",16,18,2,66]
},
{
"round": 9,
"h_0": [1,27,12,0,0,5,8,"e46d5bda",184,"indomShip 1/12, miraShip 1/3, preciShip 2/50, sargonShip 1/61, soloShip 1/0, steadShip 1/41, suntShip 1/0, swiftShip 1/5, visiShip 1/12, yanShip 0/6",23,23,0,74],
"h_0": [1,27,12,0,0,5,8,"e46d5bda",200,"indomShip 1/12, miraShip 1/3, preciShip 2/54, sargonShip 1/74, soloShip 1/0, steadShip 1/40, suntShip 1/0, swiftShip 1/5, visiShip 1/12, yanShip 0/6",23,23,0,74],
"ai_0": [1,28,12,0,0,4,8,"d2da736a",45,"kjeragShip 0/5, preciShip 2/23, sargonShip 0/2, siracusaShip 1/4, skillfulShip 1/6, soloShip 1/0, steadShip 0/2, suntShip 1/0, swiftShip 1/12, victoriaShip 0/5, yanShip 0/7",23,23,0,78]
},
{
"round": 10,
"h_0": [1,27,12,0,0,5,8,"5d239142",228,"indomShip 2/12, miraShip 0/3, preciShip 2/69, sargonShip 1/75, soloShip 1/0, steadShip 1/50, suntShip 1/0, swiftShip 1/10, visiShip 1/12, yanShip 0/6",31,31,0,86],
"h_0": [1,27,12,0,0,5,8,"5d239142",240,"indomShip 2/12, miraShip 0/3, preciShip 2/71, sargonShip 1/86, soloShip 1/0, steadShip 1/49, suntShip 1/0, swiftShip 1/10, visiShip 1/12, yanShip 0/6",31,31,0,86],
"ai_0": [1,28,12,0,0,5,8,"e30157f7",67,"kjeragShip 0/5, preciShip 2/32, sargonShip 0/2, siracusaShip 1/8, skillfulShip 1/8, soloShip 1/0, steadShip 0/2, suntShip 1/0, swiftShip 1/19, victoriaShip 0/5, yanShip 0/7",31,31,0,88]
},
{
"round": 11,
"h_0": [1,27,12,0,0,6,8,"ef68553f",246,"indomShip 1/12, miraShip 0/3, preciShip 2/103, sargonShip 1/99, steadShip 0/50, suntShip 1/0, swiftShip 1/20, visiShip 1/12, yanShip 0/6",19,19,0,99],
"h_0": [1,27,12,0,0,6,8,"ef68553f",259,"indomShip 1/12, miraShip 0/3, preciShip 2/105, sargonShip 1/110, steadShip 0/49, suntShip 1/0, swiftShip 1/20, visiShip 1/12, yanShip 0/6",19,19,0,99],
"ai_0": [1,28,12,0,0,5,8,"bea07e3c",94,"kjeragShip 0/10, preciShip 2/46, sargonShip 0/2, siracusaShip 1/12, skillfulShip 1/10, soloShip 1/0, steadShip 0/2, suntShip 1/0, swiftShip 1/26, victoriaShip 0/5, yanShip 0/7",19,19,0,99]
},
{
"round": 12,
"h_0": [1,27,12,0,0,6,8,"9985f529",313,"indomShip 1/12, miraShip 0/3, preciShip 2/125, sargonShip 2/139, steadShip 0/50, suntShip 1/0, swiftShip 1/25, visiShip 1/12, yanShip 0/6",33,33,0,112],
"h_0": [1,27,12,0,0,6,8,"9985f529",324,"indomShip 1/12, miraShip 0/3, preciShip 2/126, sargonShip 2/149, steadShip 0/49, suntShip 1/0, swiftShip 1/25, visiShip 1/12, yanShip 0/6",33,33,0,112],
"ai_0": [1,28,12,0,0,6,8,"0f82a984",112,"kjeragShip 0/10, preciShip 2/55, sargonShip 0/2, siracusaShip 1/12, skillfulShip 1/12, soloShip 1/0, steadShip 0/2, suntShip 1/0, swiftShip 1/33, victoriaShip 0/5, yanShip 0/7",25,33,8,110]
},
{
"round": 13,
"h_0": [1,27,12,0,0,6,8,"1b404257",322,"indomShip 1/12, miraShip 0/3, preciShip 2/133, sargonShip 2/147, steadShip 0/50, suntShip 1/0, swiftShip 1/30, visiShip 0/12, yanShip 0/6",50,50,0,123],
"h_0": [1,27,12,0,0,6,8,"1b404257",329,"indomShip 1/12, miraShip 0/3, preciShip 2/132, sargonShip 2/155, steadShip 0/49, suntShip 1/0, swiftShip 1/30, visiShip 0/12, yanShip 0/6",50,50,0,123],
"ai_0": [1,28,12,0,0,6,8,"de362a61",127,"kjeragShip 0/10, preciShip 2/60, sargonShip 0/2, siracusaShip 0/16, skillfulShip 1/14, soloShip 1/0, steadShip 0/2, suntShip 1/0, swiftShip 1/40, victoriaShip 0/5, yanShip 1/13",50,50,0,121]
}
],
@@ -1706,9 +1706,9 @@
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":342,"bossDamage":1134957,"dmgDealt":4776446,"gold":134,"itemsEquipped":31,"kills":299,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":27},
"stats": {"activatedLayers":349,"bossDamage":1184876,"dmgDealt":4807844,"gold":134,"itemsEquipped":31,"kills":299,"leaks":0,"lpLost":0,"merges":5,"perfectRounds":13,"refreshes":27},
"lineup": ["5_02_a@12,8[4_03_e_a+2_04_e_b]","3_13_b@11,7[4_07_e_b+6_07_e_a]","4_14_b@11,8","6_05_a@10,6[3_03_e_a+5_01_e_b]","4_23_b@10,8[3_11_e_a+3_05_e_b]","5_06_a@9,7[4_11_e_a+4_04_e_a]","4_07_b@9,8[1_01_e_a+4_10_e_a]","6_06_b@9,9[3_11_e_b+2_01_e_a]"],
"bonds": ["indomShip 2/12","miraShip 0/3","preciShip 2/143","sargonShip 1/147","skillfulShip 1/0","steadShip 0/50","suntShip 2/0","swiftShip 1/40","visiShip 0/12","yanShip 0/6"]
"bonds": ["indomShip 2/12","miraShip 0/3","preciShip 2/142","sargonShip 1/155","skillfulShip 1/0","steadShip 0/49","suntShip 2/0","swiftShip 1/40","visiShip 0/12","yanShip 0/6"]
},
"ai_0": {
"alive": true,
@@ -1720,7 +1720,7 @@
"title": {"id":"comment_3","name":"坚若磐石","picId":"comment_icon_3","text":"目标生命值损失最少"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":155,"bossDamage":440043,"dmgDealt":3337243,"gold":133,"itemsEquipped":18,"kills":291,"leaks":10,"lpLost":0,"merges":4,"perfectRounds":11,"refreshes":26},
"stats": {"activatedLayers":155,"bossDamage":390124,"dmgDealt":3287213,"gold":133,"itemsEquipped":18,"kills":289,"leaks":10,"lpLost":0,"merges":4,"perfectRounds":11,"refreshes":26},
"lineup": ["1_09_b@12,8","5_03_a@11,7","6_05_a@11,8[4_08_e_b]","2_04_b@10,5[3_08_e_a+3_04_e_a]","3_11_b@10,6","2_13_b@10,8[4_02_e_a+4_04_e_a]","6_15_a@9,8[4_11_e_b]","1_08_b@9,9[1_02_e_a+4_06_e_a]"],
"bonds": ["kjeragShip 0/20","preciShip 2/70","sargonShip 0/2","siracusaShip 0/16","skillfulShip 1/21","soloShip 1/0","steadShip 0/2","suntShip 2/0","swiftShip 1/44","victoriaShip 0/5","yanShip 1/20"]
}
@@ -1747,7 +1747,7 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act1autochess_m03","bossId":"boss_5","hiddenBossId":"boss_8","factions":["TIMES","DOT","INVISIBLE"]},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":21206,"virtualMs":122900},
"end": {"victory":false,"roundsPassed":13,"hiddenReached":false,"hiddenCleared":false,"reason":"defeat","teamLp":0,"bossPoolLeft":25040,"virtualMs":121400},
"rng": {"setup":25,"shop":507,"waves":0,"draft":40,"bots":16572,"meta":17},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -1760,53 +1760,53 @@
},
{
"round": 4,
"h_0": [1,27,8,0,1,2,8,"8773f667",1,"kazimierzShip 0/4, preciShip 1/1, soloShip 1/0, swiftShip 0/4",9,9,0,21],
"h_0": [1,27,8,0,1,2,8,"8773f667",4,"kazimierzShip 0/4, preciShip 1/4, soloShip 1/0, swiftShip 0/4",9,9,0,21],
"ai_0": [1,45,8,0,1,2,8,"1da186ca",10,"deputShip 1/2, kazimierzShip 0/2, sargonShip 0/4, soloShip 1/2, swiftShip 1/6",11,9,0,23]
},
{
"round": 5,
"h_0": [1,27,9,0,0,3,8,"bf0d47c1",9,"kazimierzShip 0/8, kjeragShip 0/5, preciShip 2/9, soloShip 1/0, swiftShip 0/8",21,21,0,30],
"h_0": [1,27,9,0,0,3,8,"bf0d47c1",12,"kazimierzShip 0/8, kjeragShip 0/5, preciShip 2/12, soloShip 1/0, swiftShip 0/8",21,21,0,30],
"ai_0": [1,45,9,0,0,3,8,"99cb32b3",18,"deputShip 1/4, kazimierzShip 0/2, sargonShip 0/4, soloShip 1/4, swiftShip 1/10",21,21,0,32]
},
{
"round": 6,
"h_0": [1,27,9,0,0,3,8,"78da96d9",16,"kazimierzShip 0/8, kjeragShip 0/5, miraShip 1/3, preciShip 2/13, soloShip 1/0, swiftShip 0/8",64,19,0,39],
"h_0": [1,27,9,0,0,3,8,"78da96d9",19,"kazimierzShip 0/8, kjeragShip 0/5, miraShip 1/3, preciShip 2/16, soloShip 1/0, swiftShip 0/8",64,19,0,39],
"ai_0": [1,45,9,0,0,3,8,"975c05db",38,"deputShip 2/8, kazimierzShip 0/4, sargonShip 0/4, skillfulShip 1/4, soloShip 1/8, swiftShip 1/18",64,19,0,40]
},
{
"round": 7,
"h_0": [1,27,10,0,2,4,8,"00ea2b4a",21,"kazimierzShip 0/8, kjeragShip 0/5, miraShip 1/5, preciShip 2/16, soloShip 1/0, swiftShip 0/8",28,28,0,49],
"h_0": [1,27,10,0,2,4,8,"00ea2b4a",25,"kazimierzShip 0/8, kjeragShip 0/5, miraShip 1/6, preciShip 2/19, soloShip 1/0, swiftShip 0/8",28,28,0,49],
"ai_0": [1,45,10,0,0,4,8,"fda860c6",60,"deputShip 2/12, kazimierzShip 0/4, sargonShip 0/4, skillfulShip 1/10, soloShip 1/12, swiftShip 1/26",28,28,0,49]
},
{
"round": 8,
"h_0": [1,27,13,0,0,4,8,"acad3972",57,"kazimierzShip 0/8, kjeragShip 1/10, miraShip 1/8, preciShip 1/21, skillfulShip 1/5, swiftShip 1/13",19,19,0,63],
"h_0": [1,27,13,0,0,4,8,"acad3972",61,"kazimierzShip 0/8, kjeragShip 1/10, miraShip 1/9, preciShip 1/24, skillfulShip 1/5, swiftShip 1/13",19,19,0,63],
"ai_0": [1,45,11,0,0,4,8,"15e7305f",98,"deputShip 2/16, kazimierzShip 0/4, sargonShip 0/4, siracusaShip 1/10, skillfulShip 1/16, soloShip 1/16, swiftShip 1/40",19,19,0,60]
},
{
"round": 9,
"h_0": [1,27,12,0,0,4,8,"e3eb5ec0",64,"kazimierzShip 0/8, kjeragShip 1/10, miraShip 0/8, preciShip 2/27, skillfulShip 1/7, soloShip 1/0, suntShip 1/0, swiftShip 1/20",19,19,0,76],
"h_0": [1,27,12,0,0,4,8,"e3eb5ec0",67,"kazimierzShip 0/8, kjeragShip 1/10, miraShip 0/9, preciShip 2/30, skillfulShip 1/7, soloShip 1/0, suntShip 1/0, swiftShip 1/20",19,19,0,76],
"ai_0": [1,45,12,0,1,4,8,"7290040a",128,"deputShip 2/20, kazimierzShip 0/4, sargonShip 0/4, siracusaShip 1/14, skillfulShip 1/22, soloShip 1/20, suntShip 1/4, swiftShip 1/48",19,19,0,74]
},
{
"round": 10,
"h_0": [1,27,12,0,0,5,8,"63e7f103",87,"kazimierzShip 0/8, kjeragShip 1/11, miraShip 1/8, preciShip 2/32, skillfulShip 1/9, soloShip 1/0, suntShip 1/0, swiftShip 1/27",24,24,0,89],
"h_0": [1,27,12,0,0,5,8,"63e7f103",91,"kazimierzShip 0/8, kjeragShip 1/11, miraShip 1/9, preciShip 2/35, skillfulShip 1/9, soloShip 1/0, suntShip 1/0, swiftShip 1/27",24,24,0,89],
"ai_0": [1,45,13,0,0,5,8,"435b20af",170,"deputShip 2/24, kazimierzShip 0/4, raidShip 1/12, sargonShip 0/4, siracusaShip 1/18, skillfulShip 1/28, soloShip 1/24, suntShip 1/8, swiftShip 1/56",22,24,2,86]
},
{
"round": 11,
"h_0": [1,27,12,0,0,5,8,"d027ae1c",135,"kazimierzShip 0/16, kjeragShip 1/27, miraShip 0/8, preciShip 2/42, skillfulShip 1/11, soloShip 1/0, suntShip 1/0, swiftShip 1/55",24,24,0,100],
"ai_0": [1,45,12,0,0,5,8,"de415c2a",188,"deputShip 2/28, kazimierzShip 0/4, raidShip 0/12, sargonShip 0/4, siracusaShip 1/22, skillfulShip 1/34, soloShip 1/28, suntShip 1/12, swiftShip 1/64",20,24,4,98]
"h_0": [1,24,12,0,0,5,8,"d027ae1c",170,"kazimierzShip 0/16, kjeragShip 1/43, miraShip 0/9, preciShip 2/45, skillfulShip 1/11, soloShip 1/0, suntShip 1/0, swiftShip 1/71",21,24,3,100],
"ai_0": [1,41,12,0,0,5,8,"de415c2a",188,"deputShip 2/28, kazimierzShip 0/4, raidShip 0/12, sargonShip 0/4, siracusaShip 1/22, skillfulShip 1/34, soloShip 1/28, suntShip 1/12, swiftShip 1/64",20,24,4,98]
},
{
"round": 12,
"h_0": [1,25,12,0,0,6,8,"e434765b",191,"kazimierzShip 0/16, kjeragShip 1/43, miraShip 0/8, preciShip 2/52, skillfulShip 1/13, soloShip 1/0, suntShip 1/0, swiftShip 1/83",29,31,2,111],
"ai_0": [1,35,12,0,0,6,8,"158fd843",218,"deputShip 2/32, kazimierzShip 0/4, raidShip 0/12, sargonShip 0/4, siracusaShip 1/26, skillfulShip 1/40, soloShip 1/32, suntShip 1/16, swiftShip 1/72",10,31,21,110]
"h_0": [1,23,12,0,0,6,8,"e434765b",226,"kazimierzShip 0/16, kjeragShip 1/59, miraShip 0/9, preciShip 2/55, skillfulShip 1/13, soloShip 1/0, suntShip 1/0, swiftShip 1/99",30,31,1,111],
"ai_0": [1,31,12,0,0,6,8,"158fd843",218,"deputShip 2/32, kazimierzShip 0/4, raidShip 0/12, sargonShip 0/4, siracusaShip 1/26, skillfulShip 1/40, soloShip 1/32, suntShip 1/16, swiftShip 1/72",10,31,21,110]
},
{
"round": 13,
"h_0": [1,25,12,0,0,6,8,"42bc3ae3",273,"kazimierzShip 1/34, kjeragShip 1/64, miraShip 0/8, preciShip 2/62, skillfulShip 0/20, soloShip 1/0, suntShip 1/0, swiftShip 1/113",110,35,5,124],
"ai_0": [1,35,12,0,0,6,8,"638d3c38",242,"deputShip 2/36, emptyShip 1/4, kazimierzShip 0/8, raidShip 0/12, sargonShip 0/4, siracusaShip 1/52, skillfulShip 1/46, soloShip 0/32, suntShip 1/20, swiftShip 1/84",115,35,0,122]
"h_0": [1,23,12,0,0,6,8,"42bc3ae3",308,"kazimierzShip 1/34, kjeragShip 1/80, miraShip 0/9, preciShip 2/65, skillfulShip 0/20, soloShip 1/0, suntShip 1/0, swiftShip 1/129",112,35,3,124],
"ai_0": [1,31,12,0,0,6,8,"638d3c38",262,"deputShip 2/36, emptyShip 1/4, kazimierzShip 0/8, raidShip 0/12, sargonShip 0/4, siracusaShip 1/72, skillfulShip 1/46, soloShip 0/32, suntShip 1/20, swiftShip 1/84",115,35,0,122]
}
],
"players": {
@@ -1820,9 +1820,9 @@
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"trophies": 3,
"reward": 320,
"stats": {"activatedLayers":306,"bossDamage":536472,"dmgDealt":3677035,"gold":136,"itemsEquipped":10,"kills":390,"leaks":22,"lpLost":2,"merges":4,"perfectRounds":9,"refreshes":18},
"stats": {"activatedLayers":342,"bossDamage":479336,"dmgDealt":3356086,"gold":136,"itemsEquipped":10,"kills":385,"leaks":22,"lpLost":4,"merges":4,"perfectRounds":8,"refreshes":18},
"lineup": ["4_14_b@12,5","6_05_a@12,6","4_13_a@12,7[3_02_e_a]","3_11_a@11,8[5_02_e_a+5_03_e_a]","4_20_a@10,3","1_19_b@10,8[4_11_e_a]","6_19_a@9,4[4_07_e_b]","5_11_a@9,5"],
"bonds": ["kazimierzShip 1/34","kjeragShip 1/66","miraShip 1/11","preciShip 2/72","skillfulShip 0/20","soloShip 1/0","steadShip 0/2","suntShip 1/0","swiftShip 1/123","yanShip 0/6"]
"bonds": ["kazimierzShip 1/34","kjeragShip 1/82","miraShip 1/12","preciShip 2/75","skillfulShip 0/20","soloShip 1/0","steadShip 0/2","suntShip 1/0","swiftShip 1/139","yanShip 0/6"]
},
"ai_0": {
"alive": true,
@@ -1834,9 +1834,9 @@
"title": {"id":"comment_4","name":"精英云集","picId":"comment_icon_4","text":"晋升精锐次数最多"},
"trophies": 3,
"reward": 320,
"stats": {"activatedLayers":280,"bossDamage":222321,"dmgDealt":2569515,"gold":133,"itemsEquipped":15,"kills":375,"leaks":27,"lpLost":10,"merges":4,"perfectRounds":10,"refreshes":27},
"stats": {"activatedLayers":300,"bossDamage":275624,"dmgDealt":2633560,"gold":133,"itemsEquipped":15,"kills":373,"leaks":27,"lpLost":14,"merges":4,"perfectRounds":10,"refreshes":27},
"lineup": ["6_18_a@12,5[1_05_e_a+3_06_e_b]","1_13_b@12,6","6_12_a@12,7[5_02_e_b]","1_06_b@11,8","5_10_a@10,3[3_11_e_b+3_11_e_a]","2_13_a@10,7[4_05_e_b+4_02_e_a]","3_18_a@10,8[4_10_e_b+4_04_e_a]","4_21_a@9,6"],
"bonds": ["deputShip 2/40","emptyShip 1/8","kazimierzShip 0/16","kjeragShip 0/8","raidShip 0/12","sargonShip 0/8","siracusaShip 1/56","skillfulShip 1/52","soloShip 0/32","suntShip 1/24","swiftShip 1/100"]
"bonds": ["deputShip 2/40","emptyShip 1/8","kazimierzShip 0/16","kjeragShip 0/8","raidShip 0/12","sargonShip 0/8","siracusaShip 1/76","skillfulShip 1/52","soloShip 0/32","suntShip 1/24","swiftShip 1/100"]
}
},
"standIns": {
@@ -1868,7 +1868,7 @@
"combat": "client",
"boost": null,
"setup": {"stageId":"act2autochess_m03","bossId":"boss_4","hiddenBossId":"boss_9","factions":["FLY","TIMES","REFLECTION"]},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":33,"bossPoolLeft":0,"virtualMs":121400},
"end": {"victory":true,"roundsPassed":14,"hiddenReached":false,"hiddenCleared":false,"reason":"victory","teamLp":34,"bossPoolLeft":0,"virtualMs":121400},
"rng": {"setup":25,"shop":690,"waves":0,"draft":40,"bots":19229,"meta":10},
"errors": {"engine":0,"logged":0,"sim":0,"dispatcher":0},
"rounds": [
@@ -1927,7 +1927,7 @@
{
"round": 13,
"h_0": [1,28,12,0,0,6,8,"d867f422",180,"deputShip 1/26, indomShip 1/24, investShip 0/8, kazimierzShip 0/2, kjeragShip 0/8, preciShip 2/19, skillfulShip 1/20, soloShip 0/20, steadShip 0/76, swiftShip 1/66, victoriaShip 1/19, visiShip 1/6",35,43,8,121],
"ai_0": [1,6,18,0,0,6,8,"95334040",368,"deputShip 1/52, emptyShip 0/6, investShip 0/8, kazimierzShip 0/8, kjeragShip 1/35, miraShip 1/2, raidShip 1/21, siracusaShip 1/120, soloShip 0/24, suntShip 1/6, swiftShip 1/83, visiShip 1/49, yanShip 0/1",22,43,21,133]
"ai_0": [1,6,18,0,0,6,8,"4b1d99d4",370,"deputShip 1/52, emptyShip 0/6, investShip 0/8, kazimierzShip 0/8, kjeragShip 1/37, miraShip 1/2, raidShip 1/21, siracusaShip 1/120, soloShip 0/24, suntShip 1/6, swiftShip 1/83, visiShip 1/49, yanShip 0/1",21,43,22,133]
}
],
"players": {
@@ -1936,12 +1936,12 @@
"victory": true,
"roundsPassed": 14,
"eliminatedRound": null,
"lp": 27,
"lp": 28,
"bandId": "band_sarkazb",
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"title": {"id":"comment_3","name":"坚若磐石","picId":"comment_icon_3","text":"目标生命值损失最少"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":226,"bossDamage":770783,"dmgDealt":4300218,"gold":132,"itemsEquipped":21,"kills":287,"leaks":22,"lpLost":17,"merges":1,"perfectRounds":9,"refreshes":42},
"stats": {"activatedLayers":226,"bossDamage":706034,"dmgDealt":4237334,"gold":132,"itemsEquipped":21,"kills":287,"leaks":22,"lpLost":17,"merges":1,"perfectRounds":9,"refreshes":42},
"lineup": ["4_21_a@12,7","4_14_b@12,8[2_01_e_a+3_02_e_a]","1_06_a@11,6[3_11_e_a+2_01_e_b]","6_11_a@11,7","6_12_a@11,8[3_05_e_b+4_08_e_b]","6_05_a@10,5[3_06_e_b+4_07_e_a]","4_07_a@10,8[3_01_e_b+6_09_e_a]","5_06_a@9,9"],
"bonds": ["deputShip 1/28","indomShip 1/29","investShip 0/8","kazimierzShip 0/2","kjeragShip 0/8","maniShip 1/2","preciShip 2/31","skillfulShip 1/22","soloShip 0/20","steadShip 0/76","swiftShip 1/78","victoriaShip 1/25","visiShip 1/11"]
},
@@ -1952,12 +1952,12 @@
"eliminatedRound": null,
"lp": 6,
"bandId": "band_lmlee",
"title": {"id":"comment_2","name":"不朽盟约","picId":"comment_icon_2","text":"激活的盟约层数总和最高"},
"title": {"id":"comment_1","name":"卫戍之星","picId":"comment_icon_1","text":"对敌方领袖造成伤害最高(仅胜利时)"},
"trophies": 4,
"reward": 400,
"stats": {"activatedLayers":402,"bossDamage":646717,"dmgDealt":3433831,"gold":145,"itemsEquipped":12,"kills":236,"leaks":53,"lpLost":21,"merges":3,"perfectRounds":7,"refreshes":29},
"stats": {"activatedLayers":404,"bossDamage":711466,"dmgDealt":3498882,"gold":145,"itemsEquipped":12,"kills":236,"leaks":54,"lpLost":21,"merges":3,"perfectRounds":7,"refreshes":29},
"lineup": ["2_14_b@12,7","3_20_a@12,8","3_14_a@11,7","5_10_a@11,8","6_19_a@10,6[4_04_e_a]","4_04_a@10,7","3_18_b@10,8[3_04_e_b+5_02_e_a]","4_16_a@9,9[4_05_e_a+4_11_e_a]"],
"bonds": ["deputShip 1/54","emptyShip 1/8","investShip 0/8","kazimierzShip 0/8","kjeragShip 1/37","miraShip 0/2","raidShip 1/28","siracusaShip 1/126","soloShip 0/24","suntShip 1/8","swiftShip 1/85","visiShip 1/56","yanShip 0/1"]
"bonds": ["deputShip 1/54","emptyShip 1/8","investShip 0/8","kazimierzShip 0/8","kjeragShip 1/39","miraShip 0/2","raidShip 1/28","siracusaShip 1/126","soloShip 0/24","suntShip 1/8","swiftShip 1/85","visiShip 1/56","yanShip 0/1"]
}
},
"diy": {
+333 -332
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -238,10 +238,10 @@
"enemy_1071_dftman": [63,63,0,455,243855],
"enemy_1072_dlancer": [60,55,5,22144,476588]
},
"hooks": [1,178,6234,1000,1000,2074,2072,74,158,168,32,32,0,36983,4066,67,158,10,1,160,2,0,11],
"hooks": [1,178,6234,1000,1000,2074,2072,74,158,168,32,32,0,36983,4064,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"
"snaps": "484fd662 19a9b252 827467e6 5c638330 c6d0b532 c1538ba9 691c2e95 65eab1de e256c73c 337bd270 302985e3 18a84929 737e1169 1cc75867 71696cfe c0e56f12 25c880fa 10b7e655 a65f5fd8 02e1a041 602de50a"
},
"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",
+66 -1
View File
@@ -7,12 +7,77 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { PHASE } from '../../shared/constants.js';
import { botPickCard, bountyKillChance, itemTarget, arrange, botPrepBegin, botPrepEnd, bondPlan, rangeTiles, effDps, rangeRec, buyScoreOf } from '../../server/match/bot.js';
import { botPickBand, botPickCard, bountyKillChance, itemTarget, arrange, botPrepBegin, botPrepEnd, bondPlan, rangeTiles, effDps, rangeRec, buyScoreOf } from '../../server/match/bot.js';
import { parseKey, tileKey } from '../../server/match/board.js';
import { makeMatch, checkInvariants, give, giveItem, legalTileFor, DATA } from './harness.js';
const soloBot = (o = {}) => makeMatch({ mode: 'solo', difficulty: 'NORMAL', seats: [{ seat: 0, playerId: 'ai_0', name: 'AI', isBot: true, connected: true }], ...o });
test('#514: a living teammate soft-reserves an opening bond, and elimination releases it', () => {
const { m } = makeMatch({ humans: 2, difficulty: 'HARD', seed: 11 }).start().toPrep();
const [human, bot] = m.order;
try {
bot.isBot = true;
human.bandId = null;
const chessOf = (bond) => Object.values(DATA.chess).find((c) => c.visible && !c.isGolden && c.tier <= 3
&& Array.isArray(c.bonds) && c.bonds.includes(bond)
&& c.bonds.filter((b) => m.gd.bond(b)?.isCore).length === 1);
const usable = m.gd.bondIds.filter((id) => m.gd.bond(id)?.isCore && !m.gd.modeInactiveBonds.has(id) && chessOf(id));
assert.ok(usable.length >= 2, 'two core bonds with a single-core chess');
const [a, b] = usable;
give(m, bot, chessOf(a).chessId, 'hand');
give(m, bot, chessOf(b).chessId, 'hand');
const focus = () => { bot._botFocus = null; bot._botFocusId = null; return bondPlan(m, bot).focus; };
const natural = focus();
assert.ok(natural === a || natural === b, natural);
const other = natural === a ? b : a;
let found = false;
for (let layers = 10; layers <= 60 && !found; layers += 10) {
bot.layers[other] = layers;
if (focus() === other) found = true;
}
assert.equal(focus(), other, 'one layer step is enough for the other bond to lead');
const band = m.gd.bandIds().find((id) => {
const bonds = m.gd.bandBondIds(id);
return bonds.includes(other) && !bonds.includes(natural);
});
assert.ok(band, `a strategy names ${other} and not ${natural}`);
human.bandId = band;
assert.notEqual(focus(), other, 'the opening strategy pulls focus off the reserved bond');
human.alive = false;
assert.equal(focus(), other, 'elimination ends the reservation');
} finally { m.dispose(); }
});
test('#514: strategy selection stays possible, and less likely, while a teammate holds that opening', () => {
const { m } = makeMatch({ humans: 2, difficulty: 'HARD', seed: 3 }).start().toPrep();
const [human, bot] = m.order;
try {
bot.isBot = true;
human.bandId = null;
const tally = (id, n = 400) => {
let hits = 0;
for (let i = 0; i < n; i++) if (botPickBand(m, bot) === id) hits++;
return hits;
};
const open = new Map();
for (let i = 0; i < 400; i++) {
const id = botPickBand(m, bot);
open.set(id, (open.get(id) || 0) + 1);
}
const ranked = [...open.entries()].filter(([id]) => m.gd.bandBondIds(id).length > 0).sort((x, y) => y[1] - x[1]);
const [band, base] = ranked[0];
assert.ok(base > 5, `${band} is drawn often enough to compare (${base})`);
human.bandId = band;
const reserved = tally(band);
assert.ok(reserved > 0, 'a soft reservation can still draw the strategy');
assert.ok(reserved < base, `reserved ${reserved} times, unreserved ${base}`);
human.alive = false;
const released = tally(band);
assert.ok(released > reserved, `elimination raises the rate from ${reserved} to ${released}`);
} finally { m.dispose(); }
});
test('user: Given a faction strategy teammate, When scoring shared high-tier chess, Then humans and bots receive the same preference even with full stock', () => {
const { m } = makeMatch({ humans: 3, seed: 11 }).start().toPrep();
const [ps, mate, other] = m.order;
+75
View File
@@ -0,0 +1,75 @@
// Real production Match + Battle, legal normal intents from an empty board. Seed 8 fixes the shop/wave route.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { Battle } from '../../server/sim/Battle.js';
import { makeMatch } from './harness.js';
test('Rockrock killed by a real enemy and automatically revived by Ermengard starts the same target at init', () => {
const observed = [];
class ObservedBattle extends Battle {
constructor(opts) {
super(opts);
const log = { round: opts.round, deaths: [], deploys: [], firstHits: [] };
observed.push(log);
const seen = new Set(), launches = new Map();
this.on('death', c => {
if (c.unit.defId === 'chess_char_2_10_a') log.deaths.push({ t: this.time, seq: c.unit.deploySeq,
target: c.unit.trait.funnelTarget, scale: c.unit.trait.funnelScale, reason: c.reason });
}, { priority: 1000 });
this.on('death', c => {
if (c.unit.defId === 'chess_char_2_10_a') log.deaths.at(-1).revivedBy = c.revivedBy;
}, { priority: -1000 });
this.on('deploy', c => {
if (c.unit.defId === 'chess_char_2_10_a') log.deploys.push({ seq: c.unit.deploySeq,
target: c.unit.trait.funnelTarget, scale: c.unit.trait.funnelScale });
}, { priority: -1000 });
this.on('attack', c => {
if (c.attacker.defId !== 'chess_char_2_10_a') return;
// This unmodified Rockrock route has no nested attack callback. The attack hook follows its shot creation.
launches.set(this._attackSeq, { t: this.time, seq: c.attacker.deploySeq });
});
this.on('damaged', c => {
const u = c.source;
const launch = launches.get(c.dmg?.attackId);
if (u?.defId !== 'chess_char_2_10_a' || seen.has(u.deploySeq) || launch?.seq !== u.deploySeq) return;
seen.add(u.deploySeq);
log.firstHits.push({ t: this.time, launchAt: launch.t, seq: u.deploySeq, target: c.target.id,
scale: u.trait.funnelScale, hpBefore: c.target.hp + c.amount });
});
}
}
const h = makeMatch({ mode: 'solo', seed: 8 });
h.m.BattleClass = ObservedBattle; // read-only observers, no combat state writes
const p = h.ps('p_0'), act = msg => assert.deepEqual(h.m.handle('p_0', msg), { ok: true });
try {
h.start().toPrep(1, { band: 'band_ermengard' });
act({ t: 'g.buy', slot: 0 });
act({ t: 'g.move', uid: p.hand.find(x => x?.id === 'chess_char_1_09_a').uid,
to: { area: 'board', row: 12, col: 6 }, dir: 'RIGHT' });
h.toPrep(2, { band: 'band_ermengard' });
act({ t: 'g.levelUp' });
h.toPrep(5, { band: 'band_ermengard' });
assert.equal(p.shop.slots[3].id, 'chess_char_2_10_a');
act({ t: 'g.buy', slot: 3 });
act({ t: 'g.move', uid: p.hand.find(x => x?.id === 'chess_char_2_10_a').uid,
to: { area: 'board', row: 12, col: 8 }, dir: 'RIGHT' });
h.toPrep(7, { band: 'band_ermengard' });
const log = observed.find(x => x.round === 6);
assert.ok(log?.deaths.length > 0);
const paired = log.deaths.map(d => ({ death: d, hit: log.firstHits.find(x => x.seq > d.seq) }))
.filter(x => x.hit && x.death.target === x.hit.target && x.death.scale > 0.2);
assert.ok(paired.length > 0, JSON.stringify(log));
for (const { death, hit } of paired) {
assert.equal(death.reason, 'killed');
assert.equal(death.revivedBy, 'band');
assert.ok(hit.launchAt >= death.t, 'fresh attack after the knockout and revival');
assert.ok(hit.hpBefore > 0, 'the same enemy was alive when the fresh drone hit');
const deploy = log.deploys.find(x => x.seq === hit.seq);
assert.equal(deploy.target, null);
assert.ok(Math.abs(deploy.scale - 0.2) < 1e-8);
assert.ok(Math.abs(hit.scale - 0.2) < 1e-8, JSON.stringify({ death, hit }));
}
assert.deepEqual(h.logs.error, []);
h.invariants();
} finally { h.m.dispose(); }
});
+11 -2
View File
@@ -177,8 +177,8 @@ for (const kind of ['boss', 'hidden']) for (const side of ['L', 'R']) {
});
}
test('#475: even buildable hand, temporary-storage, side-margin and off-rect tiles remain invalid Raid landings', () => {
for (const pos of [[0, 3], [1, 3], [0, 17], [1, 17], [3, 1], [3, 19], [6, 17]]) {
test('#475: even buildable hand, temporary-storage and side-margin tiles remain invalid Raid landings', () => {
for (const pos of [[0, 3], [1, 3], [0, 17], [1, 17], [3, 1], [3, 19]]) {
const h = emptyHalfLanding({ pos, ranged: true });
const u = h.unit('probe'), home = [u.tileR, u.tileC];
h.run(11);
@@ -187,6 +187,15 @@ test('#475: even buildable hand, temporary-storage, side-margin and off-rect til
}
});
test('#475: no Raid lands off the rectangle — an enemy spawned on (6,17) is held on the edge row and stands on (5,17)', () => {
// Battle._clampPos keeps an enemy FIELD_EDGE_INSET inside the field, so its tile is the edge tile (body.js).
const h = emptyHalfLanding({ pos: [6, 17], ranged: true });
const u = h.unit('probe');
h.run(11);
assert.deepEqual([u.tileR, u.tileC], [5, 17]);
checkInvariants(h.b);
});
test('#475: empty-half Raid still respects melee/high-ground, water and occupied/downed-unit reservations', () => {
for (const glyph of ['h', 'd']) {
const h = emptyHalfLanding({ pos: [3, 17], glyph });
+334
View File
@@ -0,0 +1,334 @@
// Unreleased funnel drones add damage to the caster's attack (PRTS 分支特性信息 驭械术师).
// Controlled Battle inputs; the production Match / browser reproduction is recorded separately.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { hitCount } from '../../server/sim/content/enemies/helpers.js';
import { bodyInKeys } from '../../server/sim/body.js';
import { DRONE_TAG } from '../../server/sim/content/kits/ops/chess_char_3_20-kjera.js';
const near = (a, b, label) => assert.ok(Math.abs(a - b) < 1e-6, `${label}: ${a} vs ${b}`);
const ordinary = ['2_10', '3_13', '3_20', '4_03', '6_18'].flatMap((id) => ['a', 'b'].map((f) => ({ chessId: `chess_char_${id}_${f}` })));
const glow = [5, 6].flatMap((slot) => [false, true].flatMap((elite) => (elite ? [null, 'uniequip_002_gdglow', 'uniequip_003_gdglow'] : [null]).map((uniEquipId) => ({
diy: { slot, charId: 'char_377_gdglow', skillIndex: 2, uniEquipId }, elite,
}))));
function field(unit, enemy = {}, opts = {}) {
const h = makeBattle({
seed: 3, autoFinish: false, timeLimit: 120, captureNoisy: true, hooks: ['damaged', 'attack'],
defs: { enemies: { enemy_dummy: enemyRec({ key: 'enemy_dummy', hp: 1e8, speed: 0, mass: 0, ...enemy }) } },
units: [{ uid: 1, row: 10, col: 4, ...unit }], ...opts,
});
h.step();
return { h, u: h.unit(1), e: h.spawn('enemy_dummy', { pos: [10, 6] }) };
}
const mine = (h, u) => h.hooksOf('damaged').filter((c) => c.source === u);
const volleys = (h, u) => {
const out = new Map();
for (const c of mine(h, u)) {
const key = c.dmg.attackId;
if (key > 0) { const l = out.get(key) ?? []; l.push(c); out.set(key, l); }
}
return [...out.values()];
};
function done(h) { checkInvariants(h.b); assert.deepEqual(h.b.errors, []); }
test('all normal/elite funnel casters and eight Goldenglow forms: a body hit plus a separate ramped addition', () => {
for (const unit of [...ordinary, ...glow]) {
const { h, u, e } = field(unit);
h.run(2);
const vs = volleys(h, u);
assert.ok(vs.length >= 2, `${u.defId}: two attacks`);
for (const [i, v] of vs.slice(0, 2).entries()) {
assert.equal(v.length, 2, `${u.defId}: body and drone, attack ${i + 1}`);
const [body, drone] = v;
assert.ok(body.dmg.isAttack && !body.dmg.tags.includes('addition'));
assert.ok(!drone.dmg.isAttack && drone.dmg.tags.includes('addition') && drone.dmg.tags.includes('funnel'));
const crit = u.def.charId === 'char_4054_malist' ? u.def.talents[0].bb.atk_scale : 1;
assert.ok([u.s.atk, u.s.atk * crit].some((n) => Math.abs(body.amount - n) < 1e-6));
near(drone.amount / body.amount, u.profile.funnel.init + i * u.profile.funnel.delta, 'independent drone ramp');
}
near(1e8 - e.hp, mine(h, u).reduce((sum, c) => sum + c.amount, 0), 'actual HP agrees with all damage events');
done(h);
}
});
test('Lolo ATK 283: each component passes through RES, hit-count HP and a one-hit barrier separately', () => {
for (const mode of ['plain', 'res', 'times', 'barrier']) {
const { h, u, e } = field({ chessId: 'chess_char_2_10_a' }, { res: mode === 'res' ? 50 : 0, hp: mode === 'times' ? 100 : 1e8 });
near(u.s.atk, 283, 'unbuffed Lolo');
if (mode === 'times') hitCount(h.b, e, true);
if (mode === 'barrier') h.b.addBuff(e, { key: 'test:barrier', shieldHits: 1 });
h.run(0.7);
const loss = (mode === 'times' ? 100 : 1e8) - e.hp;
near(loss, { plain: 339.6, res: 169.8, times: 2, barrier: 56.6 }[mode], mode);
assert.equal(h.hooksOf('attack').filter((c) => c.attacker === u).length, 1, 'one attack action');
done(h);
}
});
test('unreleased attribute skills keep a body hit; released Kjera drones and Lolo S2 do not gain one', () => {
// S1 (skillIndex 0) keeps the unreleased pair. S2 (skillIndex 1) releases the drone; rockrock-s2-lock covers it.
for (const id of ['chess_char_2_10_a', 'chess_char_2_10_b']) {
const { h, u } = field({ chessId: id, skillIndex: 0 });
u.skill.gainSp(999);
assert.ok(h.runUntil(() => u.skill.active, 2));
const start = mine(h, u).length;
h.run(2);
const active = mine(h, u).slice(start);
assert.ok(active.some((c) => c.dmg.isAttack && !c.dmg.tags.includes('addition')), `${id} S1: body`);
assert.ok(active.some((c) => c.dmg.tags.includes('funnel')), `${id} S1: drone`);
for (const v of volleys(h, u)) assert.equal(v.length, 2, `${id}: one pair per attack`);
done(h);
}
for (const id of ['chess_char_3_20_a', 'chess_char_3_20_b', 'chess_char_4_03_a', 'chess_char_4_03_b']) {
const { h, u } = field({ chessId: id });
h.run(2);
const before = mine(h, u).filter((c) => c.dmg.tags?.includes('funnel'));
assert.ok(before.length >= 1, `${id}: a pre-skill drone hit`);
const preScale = before.at(-1).amount / u.s.atk;
u.skill.gainSp(999);
assert.ok(h.runUntil(() => u.skill.active, 5));
const t0 = h.b.time;
h.run(2);
const full = u.s.atk * u.s.atkScaleMul;
const later = mine(h, u).filter((c) => c.t + 1e-9 >= t0 - h.b.dt);
const body = later.filter((c) => c.dmg.isAttack && !c.dmg.isSkill && !(c.dmg.tags || []).includes('funnel'));
const drones = later.filter((c) => (c.dmg.tags || []).includes(DRONE_TAG));
assert.ok(body.length > 0, `${id}: the operator's own hit`);
assert.ok(drones.length >= 2, `${id}: both released drones`);
for (const c of body) {
near(c.amount, full, `${id} body is 100% ATK`);
assert.ok(!(c.dmg.tags || []).includes('addition'));
}
for (const c of drones) {
assert.ok(c.dmg.isSkill && !c.dmg.isAttack && c.type === 'arts', `${id}: drone skill hit`);
assert.ok(!(c.dmg.tags || []).includes('addition') && !(c.dmg.tags || []).includes('funnel'));
const r = c.amount / full;
assert.ok(r + 1e-6 >= u.profile.funnel.init && r <= u.profile.funnel.max + 1e-6, `${id} drone scale ${r}`);
}
const first = drones[0].amount / full;
if (id.startsWith('chess_char_4_03')) near(first, u.profile.funnel.init, `${id} restarts at the initial scale`);
else assert.ok(first > u.profile.funnel.init + 1e-6 && first + 1e-6 >= Math.min(u.profile.funnel.max, preScale + u.profile.funnel.delta) - 1e-6,
`${id} continues the pre-skill ramp (${first} after ${preScale})`);
done(h);
}
});
test('Whitw2 S1 passive and head-wolf stage 3: only the drone count grows', () => {
for (const id of ['chess_char_6_18_a', 'chess_char_6_18_b']) {
const { h, u } = field({ chessId: id, skillIndex: 0 });
h.run(0.7);
assert.equal(volleys(h, u)[0].filter((c) => c.dmg.isAttack).length, 1);
assert.equal(volleys(h, u)[0].filter((c) => c.dmg.tags.includes('funnel')).length, 2);
// Controlled input keeps S1 off while its deployment-time talent progresses.
h.b.addBuff(u, { key: 'test:no-skill', flags: { silence: true } });
h.run(65);
assert.equal(u.mem.wolfStage, 3);
const last = volleys(h, u).at(-1);
assert.equal(last.filter((c) => c.dmg.isAttack).length, 1);
assert.equal(last.filter((c) => c.dmg.tags.includes('funnel')).length, 3);
done(h);
}
});
test('Minimalist charged S2: two body hits and two drone additions share one talent roll and one attack action', () => {
for (const id of ['chess_char_3_13_a', 'chess_char_3_13_b']) {
const { h, u } = field({ chessId: id });
u.skill.gainSp(999);
h.run(2);
const vs = volleys(h, u).filter((v) => v[0].dmg.isSkill);
assert.ok(vs.length > 0);
for (const v of vs) {
assert.equal(v.length, 4);
const body = v.filter((c) => c.dmg.isAttack), drone = v.filter((c) => c.dmg.tags.includes('funnel'));
assert.equal(body.length, 2); assert.equal(drone.length, 2);
near(body[0].amount, body[1].amount, 'same talent roll on both body hits');
near(drone[0].amount, drone[1].amount, 'same ramp and talent roll on both drone hits');
assert.ok(drone[0].amount / body[0].amount <= u.profile.funnel.max + 1e-6);
}
done(h);
}
});
test('Whitw2 S1 on: the toggle keeps one body hit and both unreleased additions', () => {
for (const id of ['chess_char_6_18_a', 'chess_char_6_18_b']) {
const { h, u } = field({ chessId: id, skillIndex: 0 });
assert.ok(u.skill.activate('test', { free: true }));
const t0 = h.b.time;
h.run(2);
const vs = volleys(h, u).filter((v) => v[0].t + 1e-9 >= t0);
assert.ok(vs.length >= 1, `${id}: attacks while S1 is on`);
for (const v of vs) {
const body = v.filter((c) => c.dmg.isAttack && !(c.dmg.tags || []).includes('addition'));
const drone = v.filter((c) => (c.dmg.tags || []).includes('funnel'));
assert.equal(body.length, 1, `${id}: the 100% body is not dropped`);
assert.equal(drone.length, 2, `${id}: both unreleased drones`);
near(body[0].amount, u.s.atk * u.s.atkScaleMul, `${id} body`);
for (const c of drone) {
assert.ok(!c.dmg.isAttack);
const r = c.amount / body[0].amount;
assert.ok(r + 1e-6 >= u.profile.funnel.init && r <= u.profile.funnel.max + 1e-6, `${id} ramp ${r}`);
}
}
done(h);
}
});
test('Whitw2 S2 stays drone-only: no full-ATK body beside the ramp', () => {
for (const id of ['chess_char_6_18_a', 'chess_char_6_18_b']) {
const { h, u } = field({ chessId: id, skillIndex: 1 });
u.skill.gainSp(999);
assert.ok(h.runUntil(() => u.skill.active, 8));
const t0 = h.b.time;
h.run(2);
const full = u.s.atk * u.s.atkScaleMul;
const active = mine(h, u).filter((c) => c.t + 1e-9 >= t0 - h.b.dt && c.dmg.isSkill);
assert.ok(active.length > 0, `${id}: skill hits`);
assert.ok(active.every((c) => c.dmg.isAttack && !(c.dmg.tags || []).includes('funnel')), `${id}: ramp stays on the attack`);
assert.equal(active.filter((c) => Math.abs(c.amount - full) < 1e-4).length, 0, `${id}: no 100% body`);
done(h);
}
});
test('Kjera S2: a lock that leaves her range still takes drone hits, and the body does not follow it', () => {
const route = {
motion: 'FLY', start: [10, 6], end: [9, 2],
steps: [{ t: 'wait', s: 1.2 }, { t: 'move', p: [12, 6] }, { t: 'wait', s: 20 }, { t: 'move', p: [9, 2] }],
};
for (const id of ['chess_char_3_20_a', 'chess_char_4_03_a']) {
const h = makeBattle({
seed: 4, autoFinish: false, timeLimit: 40, captureNoisy: true, hooks: ['damaged', 'attack'],
defs: { enemies: { enemy_lock: enemyRec({ key: 'enemy_lock', hp: 1e8, speed: 1, motion: 'FLY' }) } },
units: [{ uid: 1, row: 10, col: 4, chessId: id, carryState: { sp: 999 } }],
enemies: [{ key: 'enemy_lock', route }],
});
h.step();
const u = h.unit(1), e = h.enemies()[0];
assert.ok(u.skill.active, `${id} opens on the carried SP`);
assert.ok(h.runUntil(() => e.alive && !bodyInKeys(e, u.rangeKeySet), 8), `${id}: the lock leaves range`);
h.run(1.5);
const t = h.b.time, attacks = u.stats.attacks;
h.run(3);
assert.ok(e.alive && u.skill.active && !bodyInKeys(e, u.rangeKeySet));
const out = mine(h, u).filter((c) => c.target === e && c.t + 1e-9 >= t);
assert.ok(out.length > 0, `${id}: damage outside range`);
assert.ok(out.every((c) => (c.dmg.tags || []).includes(DRONE_TAG) && c.dmg.isSkill && !c.dmg.isAttack), `${id}: drone only`);
assert.equal(u.stats.attacks, attacks, `${id}: the body does not attack with nobody in range`);
done(h);
}
});
test('one attached volley: attack-SP, attack equipment and afterHit fire once while two damage instances share attackId', () => {
const h = makeBattle({
content: 'full', autoFinish: false, captureNoisy: true, hooks: ['damaged', 'attack'],
defs: {
chess: { test_funnel: chessRec({ id: 'test_funnel', profession: 'CASTER', subProf: 'funnel',
rangeGrid: [[0, 0], [0, 1], [0, 2]], stats: { atk: 100, bat: 2 },
skill: { spType: 'INCREASE_WHEN_ATTACK', spCost: 100, initSp: 0 } }) },
enemies: { enemy_dummy: enemyRec({ key: 'enemy_dummy', hp: 10000, speed: 0, mass: 0 }) },
},
units: [{ uid: 1, chessId: 'test_funnel', row: 10, col: 4, items: ['chess_item_4_03_e_a'] }],
});
h.step();
const u = h.unit(1), e = h.spawn('enemy_dummy', { pos: [10, 6] });
const callbacks = [];
// Read-only callback observer on the controlled profile; no damage or attack is added by it.
u.profile.afterHit = (b, source, target, ctx) => callbacks.push({ source, target, dealt: ctx.dealt });
h.run(0.7);
const hits = mine(h, u);
assert.equal(hits.length, 2);
assert.equal(hits[0].dmg.attackId, hits[1].dmg.attackId);
assert.equal(h.hooksOf('attack').length, 1);
assert.equal(u.stats.attacks, 1);
assert.equal(u.skill.spType, 'attack');
near(u.skill.spTotal, 1, 'one attack-SP gain');
assert.equal(u.s.aspd, u.base.aspd + 1, 'one accelerator stack');
assert.equal(callbacks.length, 1);
near(callbacks[0].dealt, 120, 'afterHit receives the combined actual HP damage');
near(10000 - e.hp, 120, 'body and addition HP damage');
done(h);
});
test('damage equipment: Pegasus riders stay bounded and burn sees both arts components without recursive attack events', () => {
for (const items of [['chess_item_6_01_e_a', 'chess_item_5_09_e_a'], ['chess_item_4_09_e_a']]) {
const { h, u, e } = field({ chessId: 'chess_char_2_10_a', items });
h.run(0.7);
const main = mine(h, u).filter((c) => c.dmg.attackId > 0);
assert.equal(main.length, 2, 'body plus drone');
assert.equal(main[0].type, 'arts'); assert.equal(main[1].type, 'arts');
assert.equal(h.hooksOf('attack').length, 1, 'riders are not extra attack actions');
if (items.length === 2) {
const riders = mine(h, u).filter((c) => c.dmg.tags.includes('item:pegasus'));
assert.equal(riders.length, 2, 'one rider per component; no recursion');
assert.ok(riders.every((c) => c.type === 'true' && !c.dmg.isAttack));
near(1e8 - e.hp, mine(h, u).reduce((sum, c) => sum + c.amount, 0), 'all bounded damage agrees with HP');
} else {
near(e.elem.burn, 0.1 * main.reduce((sum, c) => sum + c.amount, 0), 'burn from body and drone arts damage');
}
done(h);
}
});
test('lethal body or addition: one death and no remaining instances redirected to another target', () => {
for (const hp of [200, 320]) {
const { h, u, e } = field({ chessId: 'chess_char_2_10_a' }, { hp }, { hooks: ['damaged', 'attack', 'death', 'kill'] });
const other = h.spawn('enemy_dummy', { pos: [11, 6] });
h.run(0.7);
assert.equal(e.alive, false);
const hits = mine(h, u);
assert.equal(hits.length, hp === 200 ? 1 : 2);
assert.ok(hits.every((c) => c.target === e));
near(hits.reduce((sum, c) => sum + c.amount, 0), hp === 200 ? 283 : 339.6, 'mitigated amounts before HP clamping');
near(u.stats.dmg, hp, 'damage statistics count only HP actually removed');
near(other.hp, hp, 'no transfer to a spare target');
assert.equal(h.hooksOf('death').filter((c) => c.unit === e).length, 1);
assert.equal(h.hooksOf('kill').filter((c) => c.victim === e && c.killer === u).length, 1);
done(h);
}
});
test('a target killed during projectile flight receives neither the body nor drone on impact', () => {
const { h, u, e } = field({ chessId: 'chess_char_2_10_a' });
assert.ok(h.runUntil(() => h.hooksOf('attack').length === 1, 1));
assert.equal(mine(h, u).length, 0, 'projectile is still flying');
h.b.kill(e, null);
h.run(0.7);
assert.equal(mine(h, u).length, 0);
done(h);
});
test('Minimalist S2: one charge and one talent roll for all four arts instances', () => {
for (const id of ['chess_char_3_13_a', 'chess_char_3_13_b']) {
const { h, u } = field({ chessId: id });
const original = h.b.rng.chance;
let talentRolls = 0;
h.b.rng.chance = (p) => { talentRolls++; return original(p); };
u.skill.gainSp(999);
h.run(0.7);
const hits = mine(h, u);
assert.equal(hits.length, 4);
assert.ok(hits.every((c) => c.type === 'arts' && c.dmg.isSkill));
assert.equal(new Set(hits.map((c) => c.dmg.attackId)).size, 1);
assert.equal(u.skill.activations, 1);
assert.equal(u.skill.charges, u.skill.maxCharges - 1);
assert.equal(talentRolls, 1);
assert.equal(h.hooksOf('attack').length, 1);
done(h);
}
});
test('Siracusa rolls once for each body, while two attached additions and its own riders do not roll again', () => {
const { h, u } = field({ chessId: 'chess_char_6_18_a', skillIndex: 0 }, {}, {
bonds: { siracusaShip: { count: 6, active: true, tier: 2, layers: 0 } },
});
const original = h.b.rng;
let rolls = 0;
h.b.rng = Object.assign(() => { rolls++; return original(); }, original);
h.run(0.7);
const attacks = h.hooksOf('attack').filter((c) => c.attacker === u).length;
assert.ok(attacks > 0);
assert.equal(mine(h, u).filter((c) => c.dmg.tags.includes('funnel')).length, attacks * 2);
assert.equal(rolls, attacks, 'one ordinary-damage roll, no additional/rider recursion');
done(h);
});
+158
View File
@@ -0,0 +1,158 @@
// PRTS 分支特性信息 驭械术师: changing targets or redeploying resets the drone ramp.
// Controlled battle inputs here; the real Match route is covered in test/match/funnel-redeploy.test.js.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
const make = (id = 'chess_char_2_10_a', extra = []) => makeBattle({
units: [{ chessId: id, row: 10, col: 4 }, ...extra],
defs: { enemies: { dummy: enemyRec({ key: 'dummy', hp: 1e7, speed: 0 }) } },
enemies: [{ key: 'dummy', pos: [10, 6] }], timeLimit: 300, autoFinish: false,
hooks: ['damaged'], captureNoisy: true,
});
const hits = (h, u) => h.hooksOf('damaged').filter((c) => c.source === u && c.target.side === 'enemy');
const steps = (h, u) => hits(h, u).filter((c) => c.dmg?.tags?.includes('funnel'));
const near = (a, b) => assert.ok(Math.abs(a - b) < 1e-8, `${a} != ${b}`);
const ramp = (h, u) => {
h.runUntil(() => steps(h, u).length >= 8, 30);
assert.ok(steps(h, u).length >= 8);
};
for (const id of ['chess_char_2_10_a', 'chess_char_2_10_b', 'chess_char_4_03_a', 'chess_char_4_03_b']) {
test(`${id}: same living target starts at the configured initial scale after automatic redeployment`, () => {
const h = make(id), u = h.unit(id);
ramp(h, u);
const e = h.enemies()[0];
assert.ok(u.trait.funnelScale > u.profile.funnel.init);
const before = hits(h, u).length;
h.b.dealDamage(e, u, { amount: 1e7, type: 'true' });
assert.equal(u.alive, false);
h.runUntil(() => u.alive, 100);
assert.equal(u.alive, true);
assert.equal(e.alive, true);
assert.equal(u.trait.funnelTarget, null);
near(u.trait.funnelScale, u.profile.funnel.init);
assert.equal(h.runUntil(() => hits(h, u).length > before, 5), true);
assert.ok(hits(h, u).length > before);
assert.equal(hits(h, u).at(-1).target, e);
near(u.trait.funnelScale, u.profile.funnel.init);
checkInvariants(h.b);
assert.deepEqual(h.b.errors, []);
});
}
for (const id of ['chess_char_3_13_a', 'chess_char_3_13_b', 'chess_char_3_20_a', 'chess_char_3_20_b']) {
test(`${id}: per-target funnel map restarts on redeployment`, () => {
const h = make(id), u = h.unit(id);
ramp(h, u);
const e = h.enemies()[0];
assert.ok(u.trait.funnelMap.get(e.id).s > u.profile.funnel.init);
h.b.retreat(u);
assert.equal(h.b.redeploy(u), true);
assert.equal(u.trait.funnelMap.size, 0);
const before = hits(h, u).length;
assert.equal(h.runUntil(() => hits(h, u).length > before, 5), true);
assert.ok(hits(h, u).length > before);
near(u.trait.funnelMap.get(e.id).s, u.profile.funnel.init);
checkInvariants(h.b);
});
}
test('continuous attacks ramp and cap; changing the living target resets normally', () => {
const h = make(), u = h.unit('chess_char_2_10_a');
ramp(h, u);
near(u.trait.funnelScale, u.profile.funnel.max);
const replacement = h.spawn('dummy', { pos: [10, 5] });
const before = hits(h, u).length;
assert.equal(h.runUntil(() => hits(h, u).length > before, 5), true);
assert.ok(hits(h, u).length > before);
assert.equal(hits(h, u).at(-1).target, replacement);
near(u.trait.funnelScale, u.profile.funnel.init);
});
test('another unit deployment and a free move keep this ramp; unrelated trait state survives redeployment', () => {
const h = make('chess_char_2_10_a', [{ chessId: 'chess_char_1_02_a', row: 12, col: 3 }]);
const u = h.unit('chess_char_2_10_a'), other = h.unit('chess_char_1_02_a');
ramp(h, u);
const scale = u.trait.funnelScale, target = u.trait.funnelTarget;
u.trait.testUnrelated = { value: 7 }; // controlled sentinel: no production trait object may be replaced
const sentinel = u.trait.testUnrelated;
h.b.retreat(other);
assert.equal(h.b.redeploy(other), true);
assert.equal(u.trait.funnelTarget, target);
near(u.trait.funnelScale, scale);
assert.equal(h.b.moveRedeploy(u, 10, 3), true);
assert.equal(u.trait.funnelTarget, target);
near(u.trait.funnelScale, scale);
h.b.retreat(u);
assert.equal(h.b.redeploy(u), true);
assert.equal(u.trait.testUnrelated, sentinel);
near(u.trait.funnelScale, u.profile.funnel.init);
});
test('an old in-flight drone can advance the reset ramp before the first fresh drone lands', (t) => {
for (const drainOld of [false, true]) {
const h = make(), u = h.unit('chess_char_2_10_a');
ramp(h, u);
const e = h.enemies()[0], launches = new Map(), impacts = [], events = [];
const state = () => ({ at: h.b.time, currentSeq: u.deploySeq, scale: u.trait.funnelScale, hp: e.hp });
h.b.on('attack', (c) => {
if (c.attacker !== u) return;
const shot = { kind: 'launch', attackId: h.b._attackSeq, ...state() };
launches.set(shot.attackId, shot);
events.push(shot);
});
h.b.on('deploy', (c) => {
if (c.unit === u) events.push({ kind: 'deploy', target: u.trait.funnelTarget, ...state() });
}, { priority: -1000 });
h.b.on('damaged', (c) => {
if (c.source !== u || c.target !== e || !(c.dmg?.attackId > 0)) return;
const launch = launches.get(c.dmg.attackId);
const hit = { kind: 'impact', attackId: c.dmg.attackId, launchAt: launch?.at,
launchSeq: launch?.currentSeq, ...state(), amount: c.amount, hpBefore: e.hp + c.amount,
addition: !!c.dmg.tags?.includes('funnel'), isAttack: !!c.dmg.isAttack };
impacts.push(hit);
events.push(hit);
});
const volleysLanded = () => new Set(impacts.map((i) => i.attackId)).size;
assert.equal(h.runUntil(() => launches.size === 1, 3), true);
const oldShot = [...launches.values()][0];
assert.equal(impacts.length, 0);
assert.ok(h.b.projectiles.list.some((p) => p.source === u && p.target === e));
if (drainOld) assert.equal(h.runUntil(() => volleysLanded() >= 1, 1), true);
h.b.retreat(u);
assert.equal(h.b.redeploy(u), true);
const seq = u.deploySeq;
assert.equal(h.runUntil(() => impacts.some((i) => i.launchSeq === seq), 2), true);
t.diagnostic(JSON.stringify({ drainOld, events }));
const deployment = events.find((i) => i.kind === 'deploy');
assert.equal(deployment.target, null);
near(deployment.scale, u.profile.funnel.init);
const of = (id) => impacts.filter((i) => i.attackId === id);
const oldParts = of(oldShot.attackId);
const fresh = impacts.find((i) => i.launchSeq === seq);
const freshParts = of(fresh.attackId);
assert.equal(oldParts[0].launchSeq, oldShot.currentSeq);
assert.notEqual(oldParts[0].launchSeq, fresh.launchSeq);
assert.ok(oldParts.at(-1).at <= fresh.at);
assert.equal(oldParts[0].currentSeq, drainOld ? oldShot.currentSeq : seq);
near(oldParts[0].scale, drainOld ? u.profile.funnel.max : u.profile.funnel.init);
near(fresh.scale, u.profile.funnel.init + (drainOld ? 0 : u.profile.funnel.delta));
for (const parts of [oldParts, freshParts]) {
assert.equal(parts.filter((p) => p.isAttack).length, 1);
assert.equal(parts.filter((p) => p.addition).length, 1);
const body = parts.find((p) => p.isAttack);
const add = parts.find((p) => p.addition);
near(body.amount, u.s.atk * u.s.atkScaleMul);
near(add.amount, body.amount * body.scale);
}
const oldSum = oldParts.reduce((s, p) => s + p.amount, 0);
const freshSum = freshParts.reduce((s, p) => s + p.amount, 0);
near(oldShot.hp - oldParts.at(-1).hp, oldSum);
near(oldParts.at(-1).hp, freshParts[0].hpBefore);
near(freshParts[0].hpBefore - freshParts.at(-1).hp, freshSum);
assert.ok(freshParts.at(-1).hp > 0);
checkInvariants(h.b);
assert.deepEqual(h.b.errors, []);
}
});
+53
View File
@@ -0,0 +1,53 @@
// The tile of a target is its position rounded half to even — PRTS 作战机制 「受击方坐标经round函数取整(四舍六入五成双)
// 得到其所属格坐标,按是否属于该格判定」 — not Math.round, which rounds every tie up: an enemy exactly halfway between
// columns 10 and 11 (x = 10.5) is on column 10, one at x = 11.5 on column 12.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, chessRec, enemyRec } from '../helpers/battleHarness.js';
import { roundHalfEven } from '../../server/sim/detmath.js';
import { bodyKeys, bodyOnTile, bodyTileReach } from '../../server/sim/body.js';
import { tileKeyOf } from '../../server/sim/targeting.js';
import { COLS } from '../../server/sim/constants.js';
test('roundHalfEven: ties to the even integer, the rest to the nearest; never −0', () => {
const cases = [[0.5, 0], [1.5, 2], [2.5, 2], [3.5, 4], [10.5, 10], [11.5, 12], [-0.5, 0], [-1.5, -2], [-2.5, -2],
[2.4999999999999996, 2], [2.5000000000000004, 3], [-0.4, 0], [-0, 0], [7, 7], [4503599627370495.5, 4503599627370496]];
for (const [x, want] of cases) assert.ok(Object.is(roundHalfEven(x), want), `${x} → ${roundHalfEven(x)}, want ${want}`);
for (let i = -2000; i <= 2000; i++) {
const x = i / 8, v = roundHalfEven(x), d = Math.abs(x - v);
assert.ok(Number.isInteger(v) && (d < 0.5 || (d === 0.5 && v % 2 === 0)), `${x} → ${v}`);
if (d !== 0.5) assert.equal(v, Math.round(x) + 0, `${x}: away from a tie it is Math.round`);
}
});
test('a point target exactly halfway is on the even tile: bodyKeys, bodyOnTile, bodyTileReach, tileKeyOf', () => {
const e = { x: 10.5, y: 3.5 };
assert.deepEqual(bodyKeys(e), [4 * COLS + 10]);
assert.ok(bodyOnTile(e, 4, 10) && !bodyOnTile(e, 4, 11) && !bodyOnTile(e, 3, 10));
assert.equal(bodyTileReach(e, 4, 10), 0);
assert.equal(bodyTileReach(e, 4, 12), 2);
assert.equal(tileKeyOf(e), 4 * COLS + 10);
assert.equal(tileKeyOf({ x: 11.5, y: 2.5 }), 2 * COLS + 12);
});
test('the battle\'s enemy index puts an enemy at x = 10.5 on column 10, not 11', () => {
const h = makeBattle({
kind: 'boss', content: 'none', autoFinish: false, timeLimit: 60,
defs: {
chess: { t_one: chessRec({ id: 't_one', stats: { atk: 100, blockCnt: 0, maxHp: 1e7 }, rangeGrid: [[0, 0]], skill: null }) },
enemies: { enemy_still: enemyRec({ key: 'enemy_still', hp: 1e8, speed: 0 }) },
},
players: [{ playerId: 'p1', seat: 0, side: 'L', coords: 'field', units: [{ uid: 1, kind: 'chess', chessId: 't_one', row: 1, col: 1 }], bonds: {} }],
});
h.step();
const e = h.spawn('enemy_still', { pos: [3, 10], routeIndex: 0 });
e.x = 10.5;
e.y = 3;
h.step();
e.x = 10.5;
e.y = 3;
const u = h.unit('t_one');
assert.deepEqual(h.b.enemiesInKeys([3 * COLS + 10], u, { canHitFly: true }).map((x) => x.id), [e.id]);
assert.deepEqual(h.b.enemiesInKeys([3 * COLS + 11], u, { canHitFly: true }).map((x) => x.id), []);
});