feedback5 WE1: enemy attacks strike at their damage frame; a short stun before it cuts the swing (GitHub #187 point 1, #170)
PRTS 状态机: ATTACK / COMBAT "每帧检查异常状态,若有则切换到异常状态的状态"; PRTS 异常效果 STUNNED (the state machine leaves the attack), DISARMED "正在进行的普通攻击将被中断". The strike frame is data/enemies.json attackAnim.hit. - ai.js: attackWindup = the clip's strike frame (half the clip when none is named), shortened with the clip like the stand; the cooldown counts down to the strike and the swing (enemy.swing) starts when it reaches the wind-up with a target in reach (attackTargets, shared with the frame) — steady-state strikes stay one interval apart. An enemy whose cooldown ran out before it had a target (walking, just blocked, a cut swing) swings from the start: the whole wind-up. - A stun / freeze / sleep / 浮空 / hiding, 缴械, 恐惧, 战栗 while blocked or losing every target cuts a swing short of its frame: no strike, the next swing starts from its wind-up. A stun in the cooldown only pauses it; a strike already made stays made. No clip known (36 of 249 kinds): no wind-up, the old rule. [ASSUMED] targets re-taken at the frame, a cut swing does not spend the cooldown, enemy heals keep no wind-up. Golden: 275 of 283 scenarios moved — roster all 49; bonds 41 of 46 (unchanged: bond-arcaneShip-high, bond-kjeragShip-low, bond-maniShip-low, bond-skillfulShip-high, bond-swiftShip-low); fields all 22; matches all 18; standins all 10; diy 135 of 138 (unchanged: diy-027, diy-029, diy-087) — every battle where a clip-carrying enemy meets an operator: the first strike of a contact waits its wind-up, stuns cut swings (the cut alone moves 55). With every attackAnim stripped from the data the corpus is byte-identical to the previous commit (nothing else moved). Bot matches: solo-HARD-2 now wins, coop2-NORMAL-8-serverrun now loses; the other 16 keep their result. Tests: test/sim/feedback5-enemy-swing.test.js (new, 6). Updated on purpose: feedback2-enemy-attack-stand.test.js (it locked the instant first strike), enemies_bosses.test.js (沉沙 / 新硎's cleared interval, 帝国的甲胄, 斩胄之剑 / 破胄之锤 wait for the frame). test/sim, test/content, test/match pass. Docs: SIM.md, DATA.md (attackAnim), ASSETS.md.
This commit is contained in:
1 parent
8f62f3e360
commit
89f730d05c
14 files changed
+5975
-5833
No files matched your search
+1
-1
@@ -219,7 +219,7 @@ All paths are URL paths relative to the site root, for example `/assets/char/ava
|
|||||||
|
|
||||||
The enemies' attack clip lengths are also a data input: `tools/build-data.mjs` copies each enemy model's
|
The enemies' attack clip lengths are also a data input: `tools/build-data.mjs` copies each enemy model's
|
||||||
`anims.attack.loop` length and first `hits` time into data/enemies.json `attackAnim` (the sim stands an unblocked
|
`anims.attack.loop` length and first `hits` time into data/enemies.json `attackAnim` (the sim stands an unblocked
|
||||||
ranged enemy for that clip, GitHub #58; docs/DATA.md §9) — rebuild the data after a manifest change that touches them.
|
ranged enemy for that clip, GitHub #58, and strikes every enemy attack at that frame, 0.2.0; docs/DATA.md §9) — rebuild the data after a manifest change that touches them.
|
||||||
|
|
||||||
### The `Roles` object
|
### The `Roles` object
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -368,7 +368,7 @@ blackboards (transitively). Level = `randomEnemyAttributeDict[key].level` (0 for
|
|||||||
| `hitArea` | `{"w":4.95,"h":2.95,"dx":0,"dy":1}` (`enemy_9013_acstmk`) | **huge units only** (巨型单位, 7 keys: 假想敌:胄 ×2, 假想敌:管 ×2 — the 隐秘核心 one `dx` 1 —, 盐风主教昆图斯, 阿利斯泰尔,帝国余晖, “萨米的意志”): the hit rectangle, `w` tiles along the columns × `h` along the rows, centred on the unit's position moved `dx` columns right / `dy` rows up (sim/body.js; user playtest #5). Not in the game tables (the collider lives in the prefab): `tools/build-data.mjs HIT_AREAS` by `prefabKey`, from PRTS "巨型单位:受击判定区域为长4.95、宽2.95的长方形,向上偏移1.0" and PRTS盟约记录 (the season's 阿利斯泰尔 / “萨米的意志” versions); absent = a point. All 7 are also 自缚 + 无法被阻挡 (PRTS 天赋 — not a data field either: content/bosses.js `SELF_BOUND`) |
|
| `hitArea` | `{"w":4.95,"h":2.95,"dx":0,"dy":1}` (`enemy_9013_acstmk`) | **huge units only** (巨型单位, 7 keys: 假想敌:胄 ×2, 假想敌:管 ×2 — the 隐秘核心 one `dx` 1 —, 盐风主教昆图斯, 阿利斯泰尔,帝国余晖, “萨米的意志”): the hit rectangle, `w` tiles along the columns × `h` along the rows, centred on the unit's position moved `dx` columns right / `dy` rows up (sim/body.js; user playtest #5). Not in the game tables (the collider lives in the prefab): `tools/build-data.mjs HIT_AREAS` by `prefabKey`, from PRTS "巨型单位:受击判定区域为长4.95、宽2.95的长方形,向上偏移1.0" and PRTS盟约记录 (the season's 阿利斯泰尔 / “萨米的意志” versions); absent = a point. All 7 are also 自缚 + 无法被阻挡 (PRTS 天赋 — not a data field either: content/bosses.js `SELF_BOUND`) |
|
||||||
| `staticBody` | `true` (`enemy_1005_yokai` 妖怪) | **静态刚体 only** (28 keys: every air unit of the mode except “炎佑” — 妖怪 ×3, 御4, 暴鸰, 法术大师 ×2, 寒霜, 帝国炮火先兆者 ×2, 枯朽之种, 枯朽萃聚使徒, 护障 ×2, 远眺, 愧悔魂灵圣杯, 假想敌:黑云, “斩胄之剑”, “破胄之锤”, 刺胄之弹, 未装配刀片, 防护背心, 冲击式施术单元, 节日气球, “萨科塔之翼 / 之眼 / 昂首” — plus the ground boss 盐风主教昆图斯): pushes and pulls never move it, the skills still hit it (sim `Battle._displaceable`; player report after 0.1.0). PRTS 特殊机制 静态刚体: "该单位的Unity刚体的刚体类型为部分静态(Kinematic)或静态(Static)…无法产生任何速度或移动…※是否为静态刚体与单位的行动方式无关". Not in the game tables (the rigidbody lives in the prefab): `tools/build-data.mjs STATIC_BODIES` by key, from the 天赋 "{{特殊机制|静态刚体}}" of each enemy's PRTS page (every enemy of the file, read 2026-10-03); absent = a dynamic body |
|
| `staticBody` | `true` (`enemy_1005_yokai` 妖怪) | **静态刚体 only** (28 keys: every air unit of the mode except “炎佑” — 妖怪 ×3, 御4, 暴鸰, 法术大师 ×2, 寒霜, 帝国炮火先兆者 ×2, 枯朽之种, 枯朽萃聚使徒, 护障 ×2, 远眺, 愧悔魂灵圣杯, 假想敌:黑云, “斩胄之剑”, “破胄之锤”, 刺胄之弹, 未装配刀片, 防护背心, 冲击式施术单元, 节日气球, “萨科塔之翼 / 之眼 / 昂首” — plus the ground boss 盐风主教昆图斯): pushes and pulls never move it, the skills still hit it (sim `Battle._displaceable`; player report after 0.1.0). PRTS 特殊机制 静态刚体: "该单位的Unity刚体的刚体类型为部分静态(Kinematic)或静态(Static)…无法产生任何速度或移动…※是否为静态刚体与单位的行动方式无关". Not in the game tables (the rigidbody lives in the prefab): `tools/build-data.mjs STATIC_BODIES` by key, from the 天赋 "{{特殊机制|静态刚体}}" of each enemy's PRTS page (every enemy of the file, read 2026-10-03); absent = a dynamic body |
|
||||||
| `modelScale` | `0.5926` (`enemy_1005_yokai_3` 威龙) | official drawn size of the enemy's Spine model relative to the standard (user playtest #6): the battle prefab's transform scale down to its Spine renderer (Graphic × FaceSwitcher × Spine; SkeletonDataAsset.scale is 0.01 for every enemy skeleton) ÷ 0.27, the standard of 1454 of the client's 2147 enemy prefabs (2080 have exactly one Spine renderer) and of the operators' battle skins. The renderer multiplies `UNIT.modelScale` by it (render/units.js `enemyModelScale`). 125 keys (122 prefabs) carry one, from 0.5926 (威龙 0.16; 妖怪 0.7407, 寒霜 0.6667) to 2.2222 (青铜镜 / 青瓷茶器 0.6); absent = 1. Not in the game tables: `tools/build-data.mjs MODEL_SCALES` by `prefabKey`, read from the local client by `tools/local-extract/enemy_scales.py` |
|
| `modelScale` | `0.5926` (`enemy_1005_yokai_3` 威龙) | official drawn size of the enemy's Spine model relative to the standard (user playtest #6): the battle prefab's transform scale down to its Spine renderer (Graphic × FaceSwitcher × Spine; SkeletonDataAsset.scale is 0.01 for every enemy skeleton) ÷ 0.27, the standard of 1454 of the client's 2147 enemy prefabs (2080 have exactly one Spine renderer) and of the operators' battle skins. The renderer multiplies `UNIT.modelScale` by it (render/units.js `enemyModelScale`). 125 keys (122 prefabs) carry one, from 0.5926 (威龙 0.16; 妖怪 0.7407, 寒霜 0.6667) to 2.2222 (青铜镜 / 青瓷茶器 0.6); absent = 1. Not in the game tables: `tools/build-data.mjs MODEL_SCALES` by `prefabKey`, read from the local client by `tools/local-extract/enemy_scales.py` |
|
||||||
| `attackAnim` | `{"clip":"Attack","dur":1,"hit":0.533}` (`enemy_1019_jshoot` 隐形弩手) | the enemy's attack clip — the one the client plays for its attacks (data/assets.json `anims.attack.loop` of its model, not an Idle stand-in) —, its length (s) and first strike frame (`hits`, the OnAttack event; absent when the clip has none). An unblocked ranged enemy stands for this clip at each attack (sim/ai.js `attackStand`, GitHub #58). 213 keys; absent = no attack clip known (御4, 寒霜, the 岁 relics …: the sim keeps `ATTACK_PAUSE`). Not in the game tables: `tools/build-data.mjs enemyAttackAnim` reads the committed asset manifest (tools/fetch-assets.mjs, from the Spine skeletons) |
|
| `attackAnim` | `{"clip":"Attack","dur":1,"hit":0.533}` (`enemy_1019_jshoot` 隐形弩手) | the enemy's attack clip — the one the client plays for its attacks (data/assets.json `anims.attack.loop` of its model, not an Idle stand-in) —, its length (s) and first strike frame (`hits`, the OnAttack event; absent when the clip has none). An unblocked ranged enemy stands for this clip at each attack (sim/ai.js `attackStand`, GitHub #58), and every enemy attack strikes at `hit` after its swing starts — a stun before it cuts the swing (sim/ai.js `attackWindup`, 0.2.0). 213 keys; absent = no attack clip known (御4, 寒霜, the 岁 relics …: the sim keeps `ATTACK_PAUSE`). Not in the game tables: `tools/build-data.mjs enemyAttackAnim` reads the committed asset manifest (tools/fetch-assets.mjs, from the Spine skeletons) |
|
||||||
| `attackMoves` | `true` | **「不停止移动」 attackers only**: the handbook ability text says it attacks on the move (“十字路口”量产型's 四向攻击) — it never stops to attack (sim/ai.js `attackStand`). No enemy of the mode has it (build-data `attacksOnTheMove`) |
|
| `attackMoves` | `true` | **「不停止移动」 attackers only**: the handbook ability text says it attacks on the move (“十字路口”量产型's 四向攻击) — it never stops to attack (sim/ai.js `attackStand`). No enemy of the mode has it (build-data `attacksOnTheMove`) |
|
||||||
|
|
||||||
## 10. `factions.json` — special enemies (特训敌人)
|
## 10. `factions.json` — special enemies (特训敌人)
|
||||||
|
|||||||
+1
-1
@@ -301,7 +301,7 @@ and, unblocked, stand for each attack's clip — `attackStand`: data/enemies.jso
|
|||||||
(cooldown ≤ the strike frame, a target in range) and the rest of the clip after the strike, shortened when the attacks
|
(cooldown ≤ the strike frame, a target in range) and the rest of the clip after the strike, shortened when the attacks
|
||||||
come quicker than the clip; `ATTACK_PAUSE` (0.35 s) after the strike when no clip is known; an `attackMoves`
|
come quicker than the clip; `ATTACK_PAUSE` (0.35 s) after the strike when no clip is known; an `attackMoves`
|
||||||
(「不停止移动」) enemy never stops; a stun ends the stand; only the walking waits — a route WAIT keeps running and
|
(「不停止移动」) enemy never stops; a stun ends the stand; only the walking waits — a route WAIT keeps running and
|
||||||
DISAPPEAR / APPEAR legs still happen, hiding ends the stand; GitHub #58 — then walk on; `fear`/`disarm` stop attacks; `dmgType 'none'` enemies
|
DISAPPEAR / APPEAR legs still happen, hiding ends the stand; GitHub #58 — then walk on. Every normal attack strikes at its clip's damage frame (`attackWindup`: `attackAnim.hit`, shortened like the clip; 0 with no clip known — the strike as the swing starts): the cooldown runs down to the frame and the swing (`enemy.swing`) starts when it reaches the wind-up with a target in reach — the whole wind-up from that tick when the cooldown ran out before (it walked ready, its swing was cut); a stun / freeze / sleep / 浮空, hiding, 缴械, 恐惧, 战栗 while blocked or losing every target before the frame cuts the swing — no strike, the next one starts from its wind-up (PRTS 状态机 ATTACK / COMBAT "每帧检查异常状态", 异常效果 STUNNED / DISARMED "正在进行的普通攻击将被中断"; GitHub #187 / #170, 0.2.0) —, a strike already made stays made (its shot lands); the targets are taken at the frame [ASSUMED]; `fear`/`disarm` stop attacks; `dmgType 'none'` enemies
|
||||||
never attack — unless content arms them through `enemy.profile` (`noAttack: false`, `melee`, `dmgType`, `maxTargets`:
|
never attack — unless content arms them through `enemy.profile` (`noAttack: false`, `melee`, `dmgType`, `maxTargets`:
|
||||||
转译基底·α's 寻仇者 / 特战术师 forms, which then attack like any enemy); `dmgType 'heal'` enemies heal the lowest-HP% enemy in their radius instead. A `noMove` enemy stands (not `moving`, drawn idle). Content can take over an
|
转译基底·α's 寻仇者 / 特战术师 forms, which then attack like any enemy); `dmgType 'heal'` enemies heal the lowest-HP% enemy in their radius instead. A `noMove` enemy stands (not `moving`, drawn idle). Content can take over an
|
||||||
enemy's attack: `enemy.profile.deferHit` = the engine makes the attack (target, timing, the `'atk'` event) but deals no
|
enemy's attack: `enemy.profile.deferHit` = the engine makes the attack (target, timing, the `'atk'` event) but deals no
|
||||||
|
|||||||
+75
-34
@@ -18,9 +18,11 @@
|
|||||||
// its unit blocks (PRTS 卫戍协议/帮助 "对于医疗干员(咒愈师分支除外),攻击目标为需要治疗的单位"). An ally target
|
// its unit blocks (PRTS 卫戍协议/帮助 "对于医疗干员(咒愈师分支除外),攻击目标为需要治疗的单位"). An ally target
|
||||||
// (Battle.setAllyTarget: 白铁's 铁钳号·原型机, an enemy-camp summon our operators attack, 嘲讽等级 −2) on the range comes after
|
// (Battle.setAllyTarget: 白铁's 铁钳号·原型机, an enemy-camp summon our operators attack, 嘲讽等级 −2) on the range comes after
|
||||||
// every enemy (acquireTargets) and a ranged attack flies to it like to an enemy.
|
// every enemy (acquireTargets) and a ranged attack flies to it like to an enemy.
|
||||||
// Unblocked ranged enemies attack allies within their radius and stand for each attack's clip — through its wind-up
|
// Every enemy attack strikes at its clip's damage frame after its swing starts (attackWindup; a stun before the frame
|
||||||
// and until the clip ends — then walk on (attackStand, GitHub #58; ATTACK_PAUSE after the strike when no clip is known;
|
// cuts the swing — enemyAttack, GitHub #187). Unblocked ranged enemies attack allies within their radius and stand for
|
||||||
// 「不停止移动」 attackers never stop); the candidates pass the enemy's own rule (`e.profile.canTarget`) and are ordered
|
// each attack's clip — through its wind-up and until the clip ends — then walk on (attackStand, GitHub #58;
|
||||||
|
// ATTACK_PAUSE after the strike when no clip is known; 「不停止移动」 attackers never stop); the candidates pass the
|
||||||
|
// enemy's own rule (`e.profile.canTarget`) and are ordered
|
||||||
// blocker → taunt → latest deployed (targeting.js sortAllyTargets). An enemy's damage type is its data's unless content
|
// blocker → taunt → latest deployed (targeting.js sortAllyTargets). An enemy's damage type is its data's unless content
|
||||||
// arms it (`e.profile.dmgType`: 转译基底's forms, whose data never attacks). Reaching the final leg's end = leak. A `fear` (恐惧) status suspends the route: the
|
// arms it (`e.profile.dmgType`: 转译基底's forms, whose data never attacks). Reaching the final leg's end = leak. A `fear` (恐惧) status suspends the route: the
|
||||||
// enemy runs between random checkpoints away from the fear's source (fear.js moveFeared; a self-inflicted fear
|
// enemy runs between random checkpoints away from the fear's source (fear.js moveFeared; a self-inflicted fear
|
||||||
@@ -499,9 +501,13 @@ export function updateEnemy(b, e, dt) {
|
|||||||
if (!e.alive) return;
|
if (!e.alive) return;
|
||||||
// hidden (teleporting) enemies only advance wait legs
|
// hidden (teleporting) enemies only advance wait legs
|
||||||
const stunned = e.s.flags.stun;
|
const stunned = e.s.flags.stun;
|
||||||
|
const prevCd = e.atkCd;
|
||||||
if (e.atkCd > 0 && !stunned && !e.hidden) e.atkCd = Math.max(0, e.atkCd - dt);
|
if (e.atkCd > 0 && !stunned && !e.hidden) e.atkCd = Math.max(0, e.atkCd - dt);
|
||||||
|
// a stun / freeze / sleep / 浮空 — or leaving the field — takes the enemy out of its attack: a swing short of its damage
|
||||||
|
// frame does not land, and the attack starts again from its wind-up afterwards (enemyAttack)
|
||||||
|
if (e.swing && (stunned || e.hidden)) e.swing = false;
|
||||||
// true: an unblocked ranged enemy in the wind-up of its next attack with a target in range (it stands)
|
// true: an unblocked ranged enemy in the wind-up of its next attack with a target in range (it stands)
|
||||||
const winding = !e.hidden && !stunned && enemyAttack(b, e);
|
const winding = !e.hidden && !stunned && enemyAttack(b, e, prevCd);
|
||||||
if (!e.alive) return;
|
if (!e.alive) return;
|
||||||
// a stun / freeze / sleep cuts the attack clip short: no stand left once it ends [ASSUMED]
|
// a stun / freeze / sleep cuts the attack clip short: no stand left once it ends [ASSUMED]
|
||||||
if (stunned && !e.hidden) { e.atkStandUntil = -Infinity; return; }
|
if (stunned && !e.hidden) { e.atkStandUntil = -Infinity; return; }
|
||||||
@@ -656,43 +662,31 @@ export function attackStand(e, out = { wind: 0, rest: 0 }) {
|
|||||||
if (e.profile?.attackMoves ?? e.def?.attackMoves) return out;
|
if (e.profile?.attackMoves ?? e.def?.attackMoves) return out;
|
||||||
const a = e.def?.attackAnim;
|
const a = e.def?.attackAnim;
|
||||||
if (!a || !(a.dur > 0)) { out.rest = ATTACK_PAUSE; return out; }
|
if (!a || !(a.dur > 0)) { out.rest = ATTACK_PAUSE; return out; }
|
||||||
const iv = e.s.interval;
|
const speed = clipSpeed(e, a);
|
||||||
const speed = iv > 0 && iv < a.dur ? a.dur / iv : 1;
|
const hit = clipHit(a);
|
||||||
const hit = Number.isFinite(a.hit) ? Math.min(a.dur, Math.max(0, a.hit)) : a.dur / 2;
|
|
||||||
out.wind = hit / speed;
|
out.wind = hit / speed;
|
||||||
out.rest = (a.dur - hit) / speed;
|
out.rest = (a.dur - hit) / speed;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
const STAND = { wind: 0, rest: 0 };
|
const STAND = { wind: 0, rest: 0 };
|
||||||
|
/** The attack clip's strike frame (s into the clip); half the clip when the manifest names none. */
|
||||||
|
const clipHit = (a) => (Number.isFinite(a.hit) ? Math.min(a.dur, Math.max(0, a.hit)) : a.dur / 2);
|
||||||
|
/** The clip plays faster when the attacks come quicker than it. */
|
||||||
|
const clipSpeed = (e, a) => { const iv = e.s.interval; return iv > 0 && iv < a.dur ? a.dur / iv : 1; };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One tick of an enemy's attack: attacks when its cooldown is over and a target is in reach. Returns true while an
|
* The damage frame of an enemy's normal attack: seconds from the start of its swing to the strike — its attack clip's
|
||||||
* unblocked ranged enemy is in the wind-up of its next attack (cooldown ≤ its clip's wind-up, attackStand) with a
|
* strike frame (data/enemies.json `attackAnim.hit`, half the clip when the manifest names none), shortened with the clip
|
||||||
* target in range: it stands (updateEnemy).
|
* when the attacks come quicker than it (as attackStand; a 「不停止移动」 attacker swings on the move); 0 with no clip known
|
||||||
|
* (the strike as the swing starts — the rule before 0.2.0).
|
||||||
*/
|
*/
|
||||||
function enemyAttack(b, e) {
|
export function attackWindup(e) {
|
||||||
const def = e.def;
|
const a = e.def?.attackAnim;
|
||||||
if (e.profile && e.profile.noAttack) return false;
|
return a && a.dur > 0 ? clipHit(a) / clipSpeed(e, a) : 0;
|
||||||
const dmgType = (e.profile && e.profile.dmgType) || def.dmgType;
|
}
|
||||||
if (dmgType === 'none' || e.s.atk <= 0) return false;
|
|
||||||
if (e.s.flags.fear || e.s.flags.disarm) return false;
|
/** The allies `e` could hit now: its blocker (and, with a range, the others in reach), passing its own target rule. */
|
||||||
if (e.s.flags.tremble && e.blockedBy) return false; // 战栗: 被阻挡后无法进行普通攻击
|
function attackTargets(b, e, radius, reach, own) {
|
||||||
if (dmgType === 'heal') { if (e.atkCd <= 0) enemyHeal(b, e, e.base.rangeRadius); return false; }
|
|
||||||
// applyWay MELEE enemies only ever hit their blocker, even when their data carries a rangeRadius (粉碎攻坚手 2.5,
|
|
||||||
// 宿主士兵 2.5, 深池伙友卫队 1.4 … — that radius belongs to their abilities/splash, handled by content).
|
|
||||||
// Content may flip it with `e.profile.melee = false`.
|
|
||||||
const melee = e.profile?.melee ?? def.applyWay === 'MELEE';
|
|
||||||
const radius = melee ? 0 : e.base.rangeRadius;
|
|
||||||
// the range circle takes an ally whose 0.25 collider touches it (PRTS 作战机制 §碰撞体积: 索敌 uses the colliders)
|
|
||||||
const reach = radius > 0 ? radius + ALLY_COLLIDER_RADIUS : 0;
|
|
||||||
// `e.profile.canTarget(ally)`: the enemy's own target rule (只攻击地面单位, 不会攻击飞行单位 …; content/enemies/*.js),
|
|
||||||
// applied to the candidates before the priority sort and the target count
|
|
||||||
const own = e.profile && typeof e.profile.canTarget === 'function' ? e.profile.canTarget : null;
|
|
||||||
if (e.atkCd > 0) {
|
|
||||||
// the wind-up of the next attack (GitHub #58): an unblocked ranged enemy stands once a target is in range
|
|
||||||
if (e.blockedBy || radius <= 0 || !(e.atkCd <= attackStand(e, STAND).wind + 1e-9)) return false;
|
|
||||||
return b.alliesInRadius(e.x, e.y, reach, null).some((a) => canTargetAlly(e, a, true) && (!own || own(a)));
|
|
||||||
}
|
|
||||||
let targets = [];
|
let targets = [];
|
||||||
if (e.blockedBy) {
|
if (e.blockedBy) {
|
||||||
const bl = e.blockedBy;
|
const bl = e.blockedBy;
|
||||||
@@ -704,8 +698,55 @@ function enemyAttack(b, e) {
|
|||||||
targets = b.alliesInRadius(e.x, e.y, reach, null).filter((a) => canTargetAlly(e, a, true));
|
targets = b.alliesInRadius(e.x, e.y, reach, null).filter((a) => canTargetAlly(e, a, true));
|
||||||
}
|
}
|
||||||
if (own && targets.length) targets = targets.filter((a) => own(a));
|
if (own && targets.length) targets = targets.filter((a) => own(a));
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One tick of an enemy's attack. Its cooldown (`atkCd`) counts down to the damage frame of its next attack: the swing
|
||||||
|
* starts `attackWindup` before it — the cooldown down to the wind-up with a target in reach (attackTargets) — and lasts
|
||||||
|
* while a target stays in reach; at the frame the attack is made on the targets in reach then. An enemy whose cooldown
|
||||||
|
* ran out before it had a target (walking, a swing cut short) swings from the start: the whole wind-up from that tick.
|
||||||
|
* A swing short of its frame is cut by a stun / freeze / sleep / 浮空 / leaving the field (updateEnemy), 缴械, 恐惧, 战栗
|
||||||
|
* while blocked, or losing every target: no damage, and the next swing starts from its wind-up again — PRTS 状态机
|
||||||
|
* (ATTACK / COMBAT "每帧检查异常状态,若有则切换到异常状态的状态") and 异常效果 (STUNNED, DISARMED "正在进行的普通攻击将被
|
||||||
|
* 中断"); GitHub #187 / #170 (a 0.1 s 卡西米尔 pulse, 忍冬 S3's 0.2 s stun). A strike already made stays made (a shot in
|
||||||
|
* flight lands). An enemy with no attack clip known has no wind-up: it strikes as the swing starts (the old rule).
|
||||||
|
* [ASSUMED] the targets are taken at the frame (the swing needs one in reach every tick; the official selection happens
|
||||||
|
* as the swing starts); an enemy healer's heal has no wind-up.
|
||||||
|
* Returns true while an unblocked ranged enemy swings (its wind-up): it stands (updateEnemy). `prevCd`: the cooldown
|
||||||
|
* before this tick's countdown.
|
||||||
|
*/
|
||||||
|
function enemyAttack(b, e, prevCd) {
|
||||||
|
const def = e.def;
|
||||||
|
if (e.profile && e.profile.noAttack) { e.swing = false; return false; }
|
||||||
|
const dmgType = (e.profile && e.profile.dmgType) || def.dmgType;
|
||||||
|
if (dmgType === 'none' || e.s.atk <= 0) { e.swing = false; return false; }
|
||||||
|
// 恐惧 / 缴械 / 战栗 (被阻挡后无法进行普通攻击): no normal attack, and the one swung is interrupted
|
||||||
|
if (e.s.flags.fear || e.s.flags.disarm || (e.s.flags.tremble && e.blockedBy)) { e.swing = false; return false; }
|
||||||
|
if (dmgType === 'heal') { if (e.atkCd <= 0) enemyHeal(b, e, e.base.rangeRadius); return false; }
|
||||||
|
// applyWay MELEE enemies only ever hit their blocker, even when their data carries a rangeRadius (粉碎攻坚手 2.5,
|
||||||
|
// 宿主士兵 2.5, 深池伙友卫队 1.4 … — that radius belongs to their abilities/splash, handled by content).
|
||||||
|
// Content may flip it with `e.profile.melee = false`.
|
||||||
|
const melee = e.profile?.melee ?? def.applyWay === 'MELEE';
|
||||||
|
const radius = melee ? 0 : e.base.rangeRadius;
|
||||||
|
// the range circle takes an ally whose 0.25 collider touches it (PRTS 作战机制 §碰撞体积: 索敌 uses the colliders)
|
||||||
|
const reach = radius > 0 ? radius + ALLY_COLLIDER_RADIUS : 0;
|
||||||
|
// `e.profile.canTarget(ally)`: the enemy's own target rule (只攻击地面单位, 不会攻击飞行单位 …; content/enemies/*.js),
|
||||||
|
// applied to the candidates before the priority sort and the target count
|
||||||
|
const own = e.profile && typeof e.profile.canTarget === 'function' ? e.profile.canTarget : null;
|
||||||
|
const wind = attackWindup(e);
|
||||||
|
if (e.atkCd > wind + 1e-9) { e.swing = false; return false; } // the cooldown runs
|
||||||
|
let targets = attackTargets(b, e, radius, reach, own);
|
||||||
|
if (!targets.length) { e.swing = false; return false; } // ready, nobody in reach: no swing (or it is cut)
|
||||||
|
if (!e.swing) {
|
||||||
|
e.swing = true;
|
||||||
|
// ready before this tick (it walked with its cooldown over, or its swing was cut): the whole wind-up from now
|
||||||
|
if (prevCd < wind) e.atkCd = wind;
|
||||||
|
}
|
||||||
|
// the wind-up (GitHub #58): an unblocked ranged enemy stands through it (a 「不停止移动」 one walks on)
|
||||||
|
if (e.atkCd > 0) return !e.blockedBy && radius > 0 && !(e.profile?.attackMoves ?? def.attackMoves);
|
||||||
|
e.swing = false;
|
||||||
if (targets.length > 1) sortAllyTargets(e, targets);
|
if (targets.length > 1) sortAllyTargets(e, targets);
|
||||||
if (!targets.length) return false;
|
|
||||||
// `enemyAttackStart` { enemy, targets }: the enemy starts a normal attack, before 麻痹 may interrupt it (the client's
|
// `enemyAttackStart` { enemy, targets }: the enemy starts a normal attack, before 麻痹 may interrupt it (the client's
|
||||||
// ON_BEFORE_ABILITY_SPELL_ON of an attack that 麻痹 can interrupt — 酒神 堕梦 "攻击范围内的敌人普通攻击时受到70点神经损伤",
|
// ON_BEFORE_ABILITY_SPELL_ON of an attack that 麻痹 can interrupt — 酒神 堕梦 "攻击范围内的敌人普通攻击时受到70点神经损伤",
|
||||||
// PRTS 备注 "于敌人成功普通攻击前之前触发(意味着触发的元素爆发可打断当次普攻…)": a burst it causes interrupts this attack)
|
// PRTS 备注 "于敌人成功普通攻击前之前触发(意味着触发的元素爆发可打断当次普攻…)": a burst it causes interrupts this attack)
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ export class BattleSpawns {
|
|||||||
e.atkCd = 0;
|
e.atkCd = 0;
|
||||||
e.pauseUntil = -Infinity; // content holds (暴鸰's drop)
|
e.pauseUntil = -Infinity; // content holds (暴鸰's drop)
|
||||||
e.atkStandUntil = -Infinity; // standing for its attack clip (ai.js attackStand)
|
e.atkStandUntil = -Infinity; // standing for its attack clip (ai.js attackStand)
|
||||||
|
e.swing = false; // a normal attack swung, its damage frame not reached yet (ai.js enemyAttack)
|
||||||
// every enemy profile starts with the same fields (stable object shapes keep the hot loop's property reads fast);
|
// every enemy profile starts with the same fields (stable object shapes keep the hot loop's property reads fast);
|
||||||
// `dmgType` null = the data's (content may arm a data-unarmed enemy: ai.js enemyAttack)
|
// `dmgType` null = the data's (content may arm a data-unarmed enemy: ai.js enemyAttack)
|
||||||
e.profile = { noAttack: def.dmgType === 'none', maxTargets: 1, atkScale: 1, dmgType: null };
|
e.profile = { noAttack: def.dmgType === 'none', maxTargets: 1, atkScale: 1, dmgType: null };
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { makeBattle, chessRec, checkInvariants } from '../helpers/battleHarness.
|
|||||||
import * as enemiesMod from '../../server/sim/content/enemies.js';
|
import * as enemiesMod from '../../server/sim/content/enemies.js';
|
||||||
import * as bossesMod from '../../server/sim/content/bosses.js';
|
import * as bossesMod from '../../server/sim/content/bosses.js';
|
||||||
import { spawnYanyou } from '../../server/sim/content/tokens.js';
|
import { spawnYanyou } from '../../server/sim/content/tokens.js';
|
||||||
|
import { attackWindup } from '../../server/sim/ai.js';
|
||||||
|
|
||||||
const E = JSON.parse(fs.readFileSync(new URL('../../data/enemies.json', import.meta.url), 'utf8'));
|
const E = JSON.parse(fs.readFileSync(new URL('../../data/enemies.json', import.meta.url), 'utf8'));
|
||||||
const W = JSON.parse(fs.readFileSync(new URL('../../data/waves.json', import.meta.url), 'utf8'));
|
const W = JSON.parse(fs.readFileSync(new URL('../../data/waves.json', import.meta.url), 'utf8'));
|
||||||
@@ -291,8 +292,9 @@ for (const [key, n] of Object.entries(DEATH_SPAWN)) {
|
|||||||
|
|
||||||
for (const key of ['enemy_1207_sfji', 'enemy_1207_sfji_2']) {
|
for (const key of ['enemy_1207_sfji', 'enemy_1207_sfji_2']) {
|
||||||
// PRTS 天赋 "攻击力+X%,持有4个【断刃】 / 每次成功攻击后消耗1个【断刃】,攻击结束时若已耗尽【断刃】,则立刻切换为无断刃模式并失去攻击力
|
// PRTS 天赋 "攻击力+X%,持有4个【断刃】 / 每次成功攻击后消耗1个【断刃】,攻击结束时若已耗尽【断刃】,则立刻切换为无断刃模式并失去攻击力
|
||||||
// 加成" (popup: "清空当次攻击间隔" — it attacks again at once); GitHub #107: until 0.2.0 each attack stacked another layer
|
// 加成" (popup: "清空当次攻击间隔" — it attacks again at once: since 0.2.0 its next swing starts at once and strikes at the
|
||||||
test(`${nm(key)}: one ATK layer while it holds a blade, gone with the 4th attack (which is followed at once by the next); unspent blades become 矛头 on death (at least 1)`, () => {
|
// clip's damage frame, ai.js attackWindup); GitHub #107: until 0.2.0 each attack stacked another layer
|
||||||
|
test(`${nm(key)}: one ATK layer while it holds a blade, gone with the 4th attack (which is followed at once by the next swing); unspent blades become 矛头 on death (at least 1)`, () => {
|
||||||
const per = tb(key, 'Atkup.atk') ?? tb(key, 'AtkUp.atk'), cnt = tb(key, 'DeadSpawn.cnt');
|
const per = tb(key, 'Atkup.atk') ?? tb(key, 'AtkUp.atk'), cnt = tb(key, 'DeadSpawn.cnt');
|
||||||
const h = arena({ units: [{ chessId: 't_wall', row: 9, col: 5 }] });
|
const h = arena({ units: [{ chessId: 't_wall', row: 9, col: 5 }] });
|
||||||
h.step();
|
h.step();
|
||||||
@@ -304,8 +306,10 @@ for (const key of ['enemy_1207_sfji', 'enemy_1207_sfji_2']) {
|
|||||||
h.runUntil(() => e.stats.attacks >= cnt, 20);
|
h.runUntil(() => e.stats.attacks >= cnt, 20);
|
||||||
approx(e.s.atk, base, 1e-6, 'the last blade spent: 无断刃模式, no bonus');
|
approx(e.s.atk, base, 1e-6, 'the last blade spent: 无断刃模式, no bonus');
|
||||||
const tLast = h.b.time;
|
const tLast = h.b.time;
|
||||||
assert.ok(h.runUntil(() => e.stats.attacks >= cnt + 1, 0.2), 'the mode switch clears the attack interval: the next attack at once');
|
const wind = attackWindup(e);
|
||||||
assert.ok(h.b.time - tLast < e.s.interval / 2, `${h.b.time - tLast} s after the 4th attack`);
|
assert.ok(wind > 0 && h.runUntil(() => e.stats.attacks >= cnt + 1, wind + 0.2), 'the mode switch clears the attack interval: the next swing at once');
|
||||||
|
assert.ok(Math.abs(h.b.time - tLast - wind) <= 3 * h.TICK, `${h.b.time - tLast} s after the 4th attack: its wind-up (${wind} s)`);
|
||||||
|
assert.ok(h.b.time - tLast < e.s.interval / 2);
|
||||||
const child = E[key].talents.bbStr['DeadSpawn.enemy_key'];
|
const child = E[key].talents.bbStr['DeadSpawn.enemy_key'];
|
||||||
killed(h, e, null);
|
killed(h, e, null);
|
||||||
assert.equal(alive(h, child).length, 1, 'no blade left: still one 矛头');
|
assert.equal(alive(h, child).length, 1, 'no blade left: still one 矛头');
|
||||||
@@ -1289,6 +1293,7 @@ test(`${nm('enemy_10027_vtsk')}: entrance barrage (${skb('enemy_10027_vtsk', 'Ap
|
|||||||
assert.ok(barrage.every((c) => c.target === h.unit('t_wall')), 'the highest-HP unit');
|
assert.ok(barrage.every((c) => c.target === h.unit('t_wall')), 'the highest-HP unit');
|
||||||
approx(barrage[0].amount, e.s.atk);
|
approx(barrage[0].amount, e.s.atk);
|
||||||
h.runUntil(() => e.stats.attacks >= 1, 10);
|
h.runUntil(() => e.stats.attacks >= 1, 10);
|
||||||
|
h.run(1); // (its shot lands: since 0.2.0 the first strike comes at the clip's damage frame, after the barrage window)
|
||||||
const d = h.hooksOf('damaged').find((c) => c.source === e && c.dmg.isAttack);
|
const d = h.hooksOf('damaged').find((c) => c.source === e && c.dmg.isAttack);
|
||||||
approx(d.amount, e.s.atk * tb('enemy_10027_vtsk', 'range.attack@atk_scale_range'));
|
approx(d.amount, e.s.atk * tb('enemy_10027_vtsk', 'range.attack@atk_scale_range'));
|
||||||
h.run(skb('enemy_10027_vtsk', 'MultiCombat').initCooldown + 6);
|
h.run(skb('enemy_10027_vtsk', 'MultiCombat').initCooldown + 6);
|
||||||
@@ -2412,7 +2417,8 @@ test('“斩胄之剑” / “破胄之锤” 初始模式 attack: every ally in
|
|||||||
const h = bossArena({ units: [{ chessId: 't_wall', row: 10, col: 9 }, { chessId: 't_wall2', row: 10, col: 7 }] });
|
const h = bossArena({ units: [{ chessId: 't_wall', row: 10, col: 9 }, { chessId: 't_wall2', row: 10, col: 7 }] });
|
||||||
h.step();
|
h.step();
|
||||||
put(h, key, [3, 8], { tag: 'part' });
|
put(h, key, [3, 8], { tag: 'part' });
|
||||||
h.run(1);
|
// (the first attack: its 0.8 / 0.867 s wind-up, then the shots — since 0.2.0 an attack strikes at its damage frame)
|
||||||
|
h.runUntil(() => h.unit('t_wall').stats.taken > 0 && h.unit('t_wall2').stats.taken > 0, 3);
|
||||||
approx(h.unit('t_wall').stats.taken, E[key].stats.atk * scale, 1e-6, key);
|
approx(h.unit('t_wall').stats.taken, E[key].stats.atk * scale, 1e-6, key);
|
||||||
approx(h.unit('t_wall2').stats.taken, E[key].stats.atk * scale, 1e-6, key);
|
approx(h.unit('t_wall2').stats.taken, E[key].stats.atk * scale, 1e-6, key);
|
||||||
}
|
}
|
||||||
|
|||||||
+486
-486
File diff suppressed because it is too large.
Load diff
+2624
-2627
File diff suppressed because it is too large.
Load diff
+614
-657
File diff suppressed because it is too large.
Load diff
+323
-322
File diff suppressed because it is too large.
Load diff
+1433
-1421
File diff suppressed because it is too large.
Load diff
+271
-271
@@ -20,58 +20,58 @@
|
|||||||
"time": 170,
|
"time": 170,
|
||||||
"ticks": 5100,
|
"ticks": 5100,
|
||||||
"reason": "timeout",
|
"reason": "timeout",
|
||||||
"killed": 17,
|
"killed": 22,
|
||||||
"total": 50,
|
"total": 50,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 620,
|
"rngDraws": 595,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {
|
"p1": {
|
||||||
"killed": 17,
|
"killed": 22,
|
||||||
"total": 50,
|
"total": 50,
|
||||||
"perfect": false,
|
"perfect": false,
|
||||||
"leaks": 33,
|
"leaks": 28,
|
||||||
"leaksUncounted": 0,
|
"leaksUncounted": 0,
|
||||||
"coins": 4,
|
"coins": 4,
|
||||||
"dmg": 240621,
|
"dmg": 280742,
|
||||||
"bossDmg": 0,
|
"bossDmg": 0,
|
||||||
"heal": 17519,
|
"heal": 26765,
|
||||||
"deaths": 24,
|
"deaths": 19,
|
||||||
"layerGains": {"raidShip":13,"visiShip":2}
|
"layerGains": {"raidShip":13,"visiShip":2}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_3_12_a",2,null,0,0,72,3,40439,3657,0,19,2],
|
["p1",1,"op","chess_char_3_12_a",2,null,0,0,73,3,40405,3648,0,20,2],
|
||||||
["p1",2,"op","chess_char_4_09_a",0,null,0,0,1,2,32698,2984,0,17,1],
|
["p1",2,"op","chess_char_4_09_a",0,null,458.8,1,83,5,55322,5509,0,34,2],
|
||||||
["p1",3,"op","chess_char_3_05_a",2,null,2505,1,74,2,29899,11886,0,45,2],
|
["p1",3,"op","chess_char_3_05_a",2,null,1865.8,1,77,3,29828,11858,0,46,2],
|
||||||
["p1",4,"op","chess_char_3_18_a",2,null,0,0,7,1,14915,3668,0,36,1],
|
["p1",4,"op","chess_char_3_18_a",2,null,2638,1,7,2,32526,8770,0,75,2],
|
||||||
["p1",5,"op","chess_char_4_04_a",1,null,497.45,1,91,2,12814,6576,0,82,10],
|
["p1",5,"op","chess_char_4_04_a",1,null,1264.1,1,91,2,17806,8706,0,100,9],
|
||||||
["p1",6,"op","chess_char_4_07_a",1,null,0,0,75,1,18472,13600,0,43,1],
|
["p1",6,"op","chess_char_4_07_a",1,null,0,0,74,1,16008,10455,0,37,1],
|
||||||
["p1",7,"op","chess_char_4_16_a",1,null,0,0,88,0,3482,9543,0,103,0],
|
["p1",7,"op","chess_char_4_16_a",1,null,807.8,1,92,1,9136,11490,0,98,0],
|
||||||
["p1",8,"op","chess_char_3_01_a",2,null,1271,1,5,0,19777,0,0,141,2],
|
["p1",8,"op","chess_char_3_01_a",2,null,1271,1,5,0,15937,0,0,131,2],
|
||||||
["p1",9,"op","chess_char_3_04_a",2,null,1218,1,84,0,0,1599,17519,35,2],
|
["p1",9,"op","chess_char_3_04_a",2,null,1218,1,8,0,0,0,26765,59,3],
|
||||||
["p1",10,"op","chess_char_3_21_a",2,null,716.85,1,6,4,45212,555,0,138,2],
|
["p1",10,"op","chess_char_3_21_a",2,null,161.7,1,6,1,42388,1110,0,121,2],
|
||||||
["p1",11,"op","chess_char_4_02_a",1,null,1272,1,90,2,12787,1653,0,68,1],
|
["p1",11,"op","chess_char_4_02_a",1,null,1272,1,93,3,11537,1724,0,61,1],
|
||||||
["p1",12,"op","chess_char_4_13_a",1,null,0,0,86,0,10126,1624,0,26,1]
|
["p1",12,"op","chess_char_4_13_a",1,null,812,1,84,1,9849,812,0,27,1]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_10001_trslim": [1,1,0,17,4860],
|
"enemy_10001_trslim": [1,1,0,8,4860],
|
||||||
"enemy_1000_gopro_2": [1,1,0,0,1836],
|
"enemy_1000_gopro_2": [1,1,0,0,1836],
|
||||||
"enemy_10018_sgrobh": [1,1,0,2810,8100],
|
"enemy_10018_sgrobh": [1,1,0,2811,8100],
|
||||||
"enemy_1001_bigbo": [1,0,1,1235,2581],
|
"enemy_1001_bigbo": [1,0,1,1301,3217],
|
||||||
"enemy_10027_vtsk": [1,0,1,15097,2542],
|
"enemy_10027_vtsk": [1,0,1,16122,2471],
|
||||||
"enemy_10031_cnvsld": [1,0,1,0,0],
|
"enemy_10031_cnvsld": [1,0,1,0,0],
|
||||||
"enemy_10034_cnvsax": [1,0,1,364,2496],
|
"enemy_10034_cnvsax": [1,0,1,0,0],
|
||||||
"enemy_10042_prtrop": [1,0,1,0,0],
|
"enemy_10042_prtrop": [1,0,1,0,0],
|
||||||
"enemy_1116_liprr_2": [21,11,10,5655,116700],
|
"enemy_1116_liprr_2": [21,12,9,5347,131366],
|
||||||
"enemy_1119_vofsd": [12,2,8,13284,62929],
|
"enemy_1119_vofsd": [12,6,6,19166,93491],
|
||||||
"enemy_1121_lifbos_2": [9,1,7,11244,38577]
|
"enemy_1121_lifbos_2": [9,1,7,9882,35401]
|
||||||
},
|
},
|
||||||
"hooks": [1,91,5100,870,870,1441,1438,3866,41,82,25,33,0,18850,26,37,50,30,1,42,5,0,6],
|
"hooks": [1,93,5100,939,939,1515,1509,3842,41,82,27,38,0,22264,26,41,50,27,1,41,5,0,6],
|
||||||
"events": {"atk":1013,"bounty":2,"deploy":41,"die":52,"dmg":1438,"engage":11,"fx":62,"heal":35,"layer":5,"leak":30,"skill":47,"spawn":62,"status":126},
|
"events": {"atk":1088,"bounty":2,"deploy":43,"die":55,"dmg":1509,"engage":11,"fx":61,"heal":59,"layer":5,"leak":27,"skill":52,"spawn":62,"status":123},
|
||||||
"fx": {"beam":4,"blink":11,"dodge":6,"dp":5,"garrison":5,"liberate":14,"slash":16,"telegraph":1},
|
"fx": {"blink":14,"dodge":7,"dp":5,"garrison":5,"liberate":13,"slash":16,"telegraph":1},
|
||||||
"snaps": "dec536bc cbfb0e19 608df77d 4bc1be00 31528b18 50c15974 172a64b1 80ed52af 452e6c6e 2cbbaf73 d2893b65 71598545 0ff0a232 8497b8ca 56857b5a 512860f1 25c11ae9"
|
"snaps": "f6b212e6 305ae509 ec53440d 68686487 36b691ce 6a3a0f75 3bf73b20 56836b06 21e8ab42 092dab80 ab8cb21f 0d51c9c6 b1e5b425 ac801d55 57850eec ee889f70 5b8b495b"
|
||||||
},
|
},
|
||||||
"standin-02": {
|
"standin-02": {
|
||||||
"about": "normal band 5 as stand-ins: chess_char_4_17_a→char_610_acfend chess_char_4_18_a→char_602_cdfend chess_char_5_05_a→char_602_cdfend chess_char_4_19_a→char_608_acpion chess_char_5_01_a→char_600_cpione chess_char_4_22_a→char_609_acguad chess_char_4_23_a→char_609_acguad chess_char_5_06_a→char_609_acguad chess_char_4_20_a→char_603_csnipe chess_char_4_24_a→char_604_ccast chess_char_5_02_a→char_604_ccast chess_char_5_03_a→char_612_accast",
|
"about": "normal band 5 as stand-ins: chess_char_4_17_a→char_610_acfend chess_char_4_18_a→char_602_cdfend chess_char_5_05_a→char_602_cdfend chess_char_4_19_a→char_608_acpion chess_char_5_01_a→char_600_cpione chess_char_4_22_a→char_609_acguad chess_char_4_23_a→char_609_acguad chess_char_5_06_a→char_609_acguad chess_char_4_20_a→char_603_csnipe chess_char_4_24_a→char_604_ccast chess_char_5_02_a→char_604_ccast chess_char_5_03_a→char_612_accast",
|
||||||
@@ -89,42 +89,42 @@
|
|||||||
"total": 68,
|
"total": 68,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 113,
|
"rngDraws": 108,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {"killed":9,"total":68,"perfect":false,"leaks":59,"leaksUncounted":0,"coins":0,"dmg":98109,"bossDmg":0,"heal":0,"deaths":23,"layerGains":{"preciShip":12}}
|
"p1": {"killed":9,"total":68,"perfect":false,"leaks":59,"leaksUncounted":0,"coins":0,"dmg":102545,"bossDmg":0,"heal":0,"deaths":22,"layerGains":{"preciShip":12}}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_4_17_a",1,null,0,0,3,0,57,2604,0,4,1],
|
["p1",1,"op","chess_char_4_17_a",1,null,0,0,3,1,294,2604,0,4,1],
|
||||||
["p1",2,"op","chess_char_4_18_a",1,null,0,0,78,0,2350,6810,0,6,1],
|
["p1",2,"op","chess_char_4_18_a",1,null,0,0,78,0,2350,6810,0,6,1],
|
||||||
["p1",3,"op","chess_char_5_05_a",2,null,0,0,70,0,14,4256,0,1,0],
|
["p1",3,"op","chess_char_5_05_a",2,null,0,0,72,0,41,4256,0,3,1],
|
||||||
["p1",4,"op","chess_char_4_19_a",1,null,0,0,66,0,316,3058,0,13,1],
|
["p1",4,"op","chess_char_4_19_a",1,null,0,0,66,0,632,3058,0,12,1],
|
||||||
["p1",5,"op","chess_char_5_01_a",2,null,0,0,91,0,35,3675,0,2,0],
|
["p1",5,"op","chess_char_5_01_a",2,null,154.94,1,91,0,52,3520,0,3,0],
|
||||||
["p1",6,"op","chess_char_4_22_a",1,null,0,0,71,0,5165,5276,0,9,0],
|
["p1",6,"op","chess_char_4_22_a",1,null,0,0,74,0,6886,5276,0,11,0],
|
||||||
["p1",7,"op","chess_char_4_23_a",1,null,0,0,64,0,5497,5276,0,9,0],
|
["p1",7,"op","chess_char_4_23_a",1,null,0,0,65,0,5497,5276,0,9,0],
|
||||||
["p1",8,"op","chess_char_5_06_a",2,null,0,0,1,0,0,2638,0,0,0],
|
["p1",8,"op","chess_char_5_06_a",2,null,0,0,1,0,0,2638,0,0,0],
|
||||||
["p1",9,"op","chess_char_4_20_a",1,null,1271,1,92,1,11656,2542,0,25,0],
|
["p1",9,"op","chess_char_4_20_a",1,null,1271,1,92,1,11656,2542,0,25,0],
|
||||||
["p1",10,"op","chess_char_4_24_a",1,null,0,0,90,0,3736,3399,0,8,0],
|
["p1",10,"op","chess_char_4_24_a",1,null,0,0,90,0,4203,3399,0,9,0],
|
||||||
["p1",11,"op","chess_char_5_02_a",2,null,0,0,84,3,13253,2266,0,25,1],
|
["p1",11,"op","chess_char_5_02_a",2,null,0,0,84,2,14070,2266,0,26,1],
|
||||||
["p1",12,"op","chess_char_5_03_a",2,null,0,0,4,5,56032,1372,0,10,1]
|
["p1",12,"op","chess_char_5_03_a",2,null,0,0,4,5,56863,1372,0,10,1]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_10042_prtrop_2": [1,0,1,4567,14393],
|
"enemy_10042_prtrop_2": [1,0,1,4429,14122],
|
||||||
"enemy_10043_sailor": [1,1,0,1137,23649],
|
"enemy_10043_sailor": [1,1,0,1024,23649],
|
||||||
"enemy_10044_wintun": [1,0,1,4374,12094],
|
"enemy_10044_wintun": [1,0,1,3812,11990],
|
||||||
"enemy_10045_parrot": [1,0,1,0,4099],
|
"enemy_10045_parrot": [1,0,1,0,4099],
|
||||||
"enemy_10054_cjhot": [1,0,1,1676,1665],
|
"enemy_10054_cjhot": [1,0,1,2686,1997],
|
||||||
"enemy_1005_yokai": [27,8,19,0,29182],
|
"enemy_1005_yokai": [27,8,19,0,29752],
|
||||||
"enemy_1005_yokai_2": [27,0,24,11401,2816],
|
"enemy_1005_yokai_2": [27,0,24,10786,3283],
|
||||||
"enemy_1005_yokai_3": [6,0,6,20017,14371],
|
"enemy_1005_yokai_3": [6,0,6,20260,18054],
|
||||||
"enemy_10065_ftzlc": [1,0,1,0,560],
|
"enemy_10065_ftzlc": [1,0,1,19,640],
|
||||||
"enemy_10067_ftsjc": [1,0,1,0,680],
|
"enemy_10067_ftsjc": [1,0,1,0,680],
|
||||||
"enemy_1006_shield": [1,0,1,0,760]
|
"enemy_1006_shield": [1,0,1,0,760]
|
||||||
},
|
},
|
||||||
"hooks": [1,92,5700,337,337,558,523,0,32,88,5,5,0,12532,1,13,68,56,1,32,3,0,41],
|
"hooks": [1,92,5700,335,335,575,545,0,31,87,6,6,0,13069,1,13,68,56,1,31,3,0,41],
|
||||||
"events": {"atk":345,"deploy":24,"die":32,"dmg":523,"engage":11,"fx":81,"layer":3,"leak":56,"skill":10,"spawn":80,"status":2},
|
"events": {"atk":343,"deploy":24,"die":31,"dmg":545,"engage":11,"fx":83,"layer":3,"leak":56,"skill":12,"spawn":80,"status":2},
|
||||||
"fx": {"aoe":4,"dodge":41,"dp":4,"explode":27,"garrison":3,"garrisonGrant":1,"zone":1},
|
"fx": {"aoe":4,"dodge":41,"dp":4,"explode":29,"garrison":3,"garrisonGrant":1,"zone":1},
|
||||||
"snaps": "9d2468c6 9a32f006 99b2aa33 a01ecc39 97bb00b0 2fcede4b fe594f15 377f7691 e87b0fd3 af44759d 7b13ea89 61cd9b40 4f9d1182 5905fb57 d697ca06 c37e9513 3102b854 296cdd49 4d5efa28"
|
"snaps": "bb11ef91 3dacfd27 a1a9e1ba 0c1cbf13 1a25c591 303d857a 3dc0bf41 8f47df11 f254e91e 21b1a437 0bef3640 47e52a7a d371b6b0 8a488ba7 9a40aca9 786c46b4 ca780f2a f8b06cfe 10e274ca"
|
||||||
},
|
},
|
||||||
"standin-03": {
|
"standin-03": {
|
||||||
"about": "normal band 5 as stand-ins: chess_char_5_08_a→char_610_acfend chess_char_5_14_a→char_608_acpion chess_char_5_19_a→char_617_sharp2 chess_char_5_07_a→char_601_cguard chess_char_5_13_a→char_609_acguad chess_char_5_17_a→char_615_acspec chess_char_5_10_a→char_606_csuppo chess_char_5_11_a→char_613_acmedc chess_char_5_12_a→char_614_acsupo chess_char_5_15_a→char_603_csnipe chess_char_5_18_a→char_611_acnipe chess_char_5_20_a→char_614_acsupo",
|
"about": "normal band 5 as stand-ins: chess_char_5_08_a→char_610_acfend chess_char_5_14_a→char_608_acpion chess_char_5_19_a→char_617_sharp2 chess_char_5_07_a→char_601_cguard chess_char_5_13_a→char_609_acguad chess_char_5_17_a→char_615_acspec chess_char_5_10_a→char_606_csuppo chess_char_5_11_a→char_613_acmedc chess_char_5_12_a→char_614_acsupo chess_char_5_15_a→char_603_csnipe chess_char_5_18_a→char_611_acnipe chess_char_5_20_a→char_614_acsupo",
|
||||||
@@ -138,44 +138,44 @@
|
|||||||
"time": 190,
|
"time": 190,
|
||||||
"ticks": 5700,
|
"ticks": 5700,
|
||||||
"reason": "timeout",
|
"reason": "timeout",
|
||||||
"killed": 46,
|
"killed": 44,
|
||||||
"total": 74,
|
"total": 74,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 247,
|
"rngDraws": 317,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {"p1":{"killed":46,"total":74,"perfect":false,"leaks":28,"leaksUncounted":0,"coins":8,"dmg":342938,"bossDmg":0,"heal":45325,"deaths":12,"layerGains":{}}},
|
"players": {"p1":{"killed":44,"total":74,"perfect":false,"leaks":30,"leaksUncounted":0,"coins":8,"dmg":357249,"bossDmg":0,"heal":48257,"deaths":10,"layerGains":{}}},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_5_08_a",2,null,515.8,1,6,0,11779,9335,0,131,2],
|
["p1",1,"op","chess_char_5_08_a",2,null,2206.8,1,91,0,5923,3841,0,59,1],
|
||||||
["p1",2,"op","chess_char_5_14_a",2,null,0,0,89,24,159150,7595,0,61,6],
|
["p1",2,"op","chess_char_5_14_a",2,null,0,0,90,23,142481,7595,0,63,6],
|
||||||
["p1",3,"op","chess_char_5_19_a",0,null,0,0,90,6,38255,15228,0,94,2],
|
["p1",3,"op","chess_char_5_19_a",0,null,349.6,1,89,6,47622,15311,0,100,3],
|
||||||
["p1",4,"op","chess_char_5_07_a",2,null,2564,1,91,2,10656,2984,0,18,1],
|
["p1",4,"op","chess_char_5_07_a",2,null,843.2,1,7,1,29523,11092,0,77,3],
|
||||||
["p1",5,"op","chess_char_5_13_a",2,null,0,0,11,7,58468,14481,0,126,4],
|
["p1",5,"op","chess_char_5_13_a",2,null,822,1,11,7,56384,11384,0,123,4],
|
||||||
["p1",6,"op","chess_char_5_17_a",2,null,1154,1,93,3,11205,3361,0,59,0],
|
["p1",6,"op","chess_char_5_17_a",2,null,1154,1,92,0,4254,4200,0,59,0],
|
||||||
["p1",7,"op","chess_char_5_10_a",2,null,932,1,2,0,8982,0,0,77,2],
|
["p1",7,"op","chess_char_5_10_a",2,null,932,1,2,1,8953,0,0,74,2],
|
||||||
["p1",8,"op","chess_char_5_11_a",2,null,1224,1,3,0,0,0,45325,72,2],
|
["p1",8,"op","chess_char_5_11_a",2,null,1224,1,3,0,0,0,48257,71,2],
|
||||||
["p1",9,"op","chess_char_5_12_a",2,null,1160,1,4,1,22227,0,0,86,2],
|
["p1",9,"op","chess_char_5_12_a",2,null,1160,1,4,0,19483,0,0,77,2],
|
||||||
["p1",10,"op","chess_char_5_15_a",2,null,0,0,84,2,8190,12762,0,91,2],
|
["p1",10,"op","chess_char_5_15_a",2,null,0,0,84,2,8336,14152,0,96,2],
|
||||||
["p1",11,"op","chess_char_5_18_a",2,null,0,0,1,0,5656,1272,0,20,1],
|
["p1",11,"op","chess_char_5_18_a",2,null,0,0,1,4,27171,1272,0,32,1],
|
||||||
["p1",12,"op","chess_char_5_20_a",2,null,1972,1,92,1,8370,1972,0,35,1]
|
["p1",12,"op","chess_char_5_20_a",2,null,0,0,5,0,7118,1972,0,39,2]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_1006_shield_2": [1,1,0,679,8000],
|
"enemy_1006_shield_2": [1,1,0,582,8000],
|
||||||
"enemy_1006_shield_3": [1,0,1,12959,19581],
|
"enemy_1006_shield_3": [1,0,1,10399,13075],
|
||||||
"enemy_10073_mpcar": [1,1,0,12,1600],
|
"enemy_10073_mpcar": [1,1,0,12,1600],
|
||||||
"enemy_1007_slime": [1,1,0,0,440],
|
"enemy_1007_slime": [1,1,0,0,440],
|
||||||
"enemy_10081_mpplai": [1,1,0,0,2000],
|
"enemy_10081_mpplai": [1,1,0,0,2000],
|
||||||
"enemy_10087_hlchgr": [1,1,0,58,4800],
|
"enemy_10087_hlchgr": [1,1,0,38,4800],
|
||||||
"enemy_10094_crstf": [1,1,0,28,3200],
|
"enemy_10094_crstf": [1,1,0,28,3200],
|
||||||
"enemy_10097_crshd": [1,1,0,0,8000],
|
"enemy_10097_crshd": [1,1,0,0,8000],
|
||||||
"enemy_1166_dusbr_2": [42,31,11,3354,115737],
|
"enemy_1166_dusbr_2": [42,30,12,2728,121684],
|
||||||
"enemy_1170_dushld_2": [12,6,4,28840,54328],
|
"enemy_1170_dushld_2": [12,5,6,28117,47066],
|
||||||
"enemy_9011_acrefr": [12,2,3,23060,125251]
|
"enemy_9011_acrefr": [12,2,6,28914,147383]
|
||||||
},
|
},
|
||||||
"hooks": [1,93,5700,1154,1154,1775,1770,135,58,77,25,27,0,28761,3090,58,74,19,1,58,0,0,8],
|
"hooks": [1,92,5700,1098,1098,1657,1660,130,54,79,28,28,0,28379,3587,52,74,25,1,56,0,0,8],
|
||||||
"events": {"atk":1247,"bounty":4,"deploy":19,"die":58,"dmg":1767,"engage":11,"fx":170,"heal":124,"leak":19,"skill":56,"spawn":86,"status":614},
|
"events": {"atk":1229,"bounty":4,"deploy":18,"die":54,"dmg":1659,"engage":11,"fx":131,"heal":126,"leak":25,"skill":60,"spawn":86,"status":621},
|
||||||
"fx": {"aoe":60,"displace":1,"dodge":18,"dp":30,"phase":1,"slash":48,"sp":2,"spGain":10},
|
"fx": {"aoe":30,"displace":1,"dodge":13,"dp":29,"phase":1,"slash":48,"sp":1,"spGain":8},
|
||||||
"snaps": "dbcb5cec 56a8a8f6 e8d97a5d d2594a66 b6f753a4 78a2f35e 80349f15 2cd292dd d7240cae 4f120b33 69d90058 45d5da9a ae0b244b 17b17251 4df0cf30 f2c7c569 baa94919 07ba89e9 e4a68e4d"
|
"snaps": "530ce9ab 3259d8c0 918a3cff a85e2d90 3b23751a 8f259c98 ac7cc207 e97f970a 310fc8e2 3ccf05ce 133339f2 3ce55224 a14db521 246e0ee0 c7100c7e 91ae8513 4b6a214c 8c1f8a7b 41afe990"
|
||||||
},
|
},
|
||||||
"standin-04": {
|
"standin-04": {
|
||||||
"about": "normal band 6 as stand-ins: chess_char_6_03_a→char_610_acfend chess_char_6_02_a→char_608_acpion chess_char_6_07_a→char_617_sharp2 chess_char_6_10_a→char_617_sharp2 chess_char_6_11_a→char_608_acpion chess_char_6_06_a→char_609_acguad chess_char_5_22_a→char_611_acnipe chess_char_6_01_a→char_611_acnipe chess_char_6_04_a→char_614_acsupo chess_char_6_05_a→char_611_acnipe chess_char_6_08_a→char_612_accast chess_char_6_09_a→char_613_acmedc",
|
"about": "normal band 6 as stand-ins: chess_char_6_03_a→char_610_acfend chess_char_6_02_a→char_608_acpion chess_char_6_07_a→char_617_sharp2 chess_char_6_10_a→char_617_sharp2 chess_char_6_11_a→char_608_acpion chess_char_6_06_a→char_609_acguad chess_char_5_22_a→char_611_acnipe chess_char_6_01_a→char_611_acnipe chess_char_6_04_a→char_614_acsupo chess_char_6_05_a→char_611_acnipe chess_char_6_08_a→char_612_accast chess_char_6_09_a→char_613_acmedc",
|
||||||
@@ -186,62 +186,62 @@
|
|||||||
"round": 12,
|
"round": 12,
|
||||||
"seed": 428893583,
|
"seed": 428893583,
|
||||||
"waveId": "act1autochess_h05",
|
"waveId": "act1autochess_h05",
|
||||||
"time": 201.7,
|
"time": 196.37,
|
||||||
"ticks": 6051,
|
"ticks": 5891,
|
||||||
"reason": "cleared",
|
"reason": "cleared",
|
||||||
"killed": 136,
|
"killed": 127,
|
||||||
"total": 158,
|
"total": 158,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 644,
|
"rngDraws": 656,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {
|
"p1": {
|
||||||
"killed": 136,
|
"killed": 127,
|
||||||
"total": 158,
|
"total": 158,
|
||||||
"perfect": false,
|
"perfect": false,
|
||||||
"leaks": 22,
|
"leaks": 31,
|
||||||
"leaksUncounted": 0,
|
"leaksUncounted": 0,
|
||||||
"coins": 8,
|
"coins": 8,
|
||||||
"dmg": 1309822,
|
"dmg": 1279084,
|
||||||
"bossDmg": 0,
|
"bossDmg": 0,
|
||||||
"heal": 23527,
|
"heal": 23617,
|
||||||
"deaths": 12,
|
"deaths": 13,
|
||||||
"layerGains": {"sargonShip":5}
|
"layerGains": {"sargonShip":5}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_6_03_a",2,null,0,0,174,0,698,7812,0,6,0],
|
["p1",1,"op","chess_char_6_03_a",2,null,0,0,173,0,379,7812,0,3,0],
|
||||||
["p1",2,"op","chess_char_6_02_a",2,null,1529,1,179,1,2975,3058,0,7,2],
|
["p1",2,"op","chess_char_6_02_a",2,null,0,0,175,2,4099,4587,0,9,1],
|
||||||
["p1",3,"op","chess_char_6_07_a",0,null,0,0,172,9,135322,3730,0,74,1],
|
["p1",3,"op","chess_char_6_07_a",0,null,0,0,169,9,146057,3730,0,77,1],
|
||||||
["p1",4,"op","chess_char_6_10_a",0,null,0,0,166,5,94409,3730,0,75,2],
|
["p1",4,"op","chess_char_6_10_a",0,null,1865,1,182,0,26824,3730,0,28,1],
|
||||||
["p1",5,"op","chess_char_6_11_a",2,null,1026.4,1,178,11,100320,8547,0,40,4],
|
["p1",5,"op","chess_char_6_11_a",2,null,1529,1,179,11,105846,7699,0,33,4],
|
||||||
["p1",6,"op","chess_char_6_06_a",2,null,2080.4,1,156,9,111400,19283,0,111,4],
|
["p1",6,"op","chess_char_6_06_a",2,null,2080.4,1,157,13,102010,19207,0,105,3],
|
||||||
["p1",7,"op","chess_char_5_22_a",2,null,1272,1,3,2,25528,0,0,19,2],
|
["p1",7,"op","chess_char_5_22_a",2,null,1272,1,3,2,36737,0,0,27,2],
|
||||||
["p1",8,"op","chess_char_6_01_a",2,null,1272,1,4,34,325813,0,0,164,2],
|
["p1",8,"op","chess_char_6_01_a",2,null,1272,1,4,41,375365,0,0,160,3],
|
||||||
["p1",9,"op","chess_char_6_04_a",2,null,1160,1,13,7,65845,0,0,121,2],
|
["p1",9,"op","chess_char_6_04_a",2,null,1160,1,13,5,66082,0,0,118,2],
|
||||||
["p1",10,"op","chess_char_6_05_a",2,null,1272,1,14,18,234561,2453,0,122,2],
|
["p1",10,"op","chess_char_6_05_a",2,null,1272,1,14,16,199814,2964,0,123,2],
|
||||||
["p1",11,"op","chess_char_6_08_a",2,null,1372,1,5,39,212952,0,0,57,2],
|
["p1",11,"op","chess_char_6_08_a",2,null,1372,1,5,28,215871,0,0,59,2],
|
||||||
["p1",12,"op","chess_char_6_09_a",2,null,1224,1,11,0,0,0,23527,37,2],
|
["p1",12,"op","chess_char_6_09_a",2,null,1224,1,11,0,0,0,23617,34,2],
|
||||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,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]
|
["-","~2","device","trap_1105_accrate",null,null,100,1,2,0,0,0,0,0,null]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_10098_crhro": [1,1,0,3450,41472],
|
"enemy_10098_crhro": [1,1,0,1577,41472],
|
||||||
"enemy_10099_crvln": [1,1,0,2453,20736],
|
"enemy_10099_crvln": [1,1,0,2964,20736],
|
||||||
"enemy_1009_lurker": [1,1,0,16,3041],
|
"enemy_1009_lurker": [1,1,0,16,3041],
|
||||||
"enemy_1010_demon": [1,1,0,0,10368],
|
"enemy_1010_demon": [1,1,0,0,10368],
|
||||||
"enemy_1010_demon_2": [28,22,6,15447,543909],
|
"enemy_1010_demon_2": [28,20,8,11373,543506],
|
||||||
"enemy_10112_ymgds": [1,1,0,0,6912],
|
"enemy_10112_ymgds": [1,1,0,0,6912],
|
||||||
"enemy_10116_ymgtop": [1,1,0,2924,13824],
|
"enemy_10116_ymgtop": [1,1,0,3450,13824],
|
||||||
"enemy_10118_ymgprc": [1,0,1,3965,18459],
|
"enemy_10118_ymgprc": [1,0,1,5235,10561],
|
||||||
"enemy_1071_dftman": [63,63,0,447,243855],
|
"enemy_1071_dftman": [63,60,3,290,241610],
|
||||||
"enemy_1072_dlancer": [60,45,15,19911,429319]
|
"enemy_1072_dlancer": [60,41,19,24824,407969]
|
||||||
},
|
},
|
||||||
"hooks": [1,181,6051,918,918,1945,1944,62,148,170,25,24,0,31170,4160,44,158,22,1,149,2,0,13],
|
"hooks": [1,182,5891,853,853,1865,1862,60,140,171,23,22,0,28489,4121,43,158,31,1,141,2,0,12],
|
||||||
"events": {"atk":1080,"bounty":4,"deploy":21,"die":148,"dmg":1944,"engage":11,"fx":87,"heal":45,"layer":2,"leak":22,"skill":49,"spawn":172,"status":440},
|
"events": {"atk":998,"bounty":4,"deploy":22,"die":140,"dmg":1862,"engage":11,"fx":77,"heal":44,"layer":2,"leak":31,"skill":45,"spawn":172,"status":464},
|
||||||
"fx": {"aoe":7,"dodge":13,"dp":18,"garrison":2,"revive":1,"slash":29,"sp":12,"spGain":3,"telegraph":2},
|
"fx": {"aoe":4,"dodge":15,"dp":18,"garrison":2,"revive":1,"slash":24,"sp":8,"spGain":3,"telegraph":2},
|
||||||
"snaps": "29a29463 6fc96b2d 184b448a fce3c126 45d67357 4c47175a 1292297b 3e42d44e b7bf91a6 dd4e2386 0b4615ac 81792172 a056e50b 7e87af96 dd9818ad 8c9001ef b2db6556 9bf17d05 66cf3ead 709fbe1f c88b2f46"
|
"snaps": "1184691a ac872d2c 04c21bcf 302d411f 5ea6c6b7 1d6c2c6a d1adbc33 d86e6315 835cf160 a3576945 32ffef8a f9d81c1e 035b4b09 12f6f260 41a84026 a6a6ba61 9dd38c5e dcbccdf8 93092800 8b97b584"
|
||||||
},
|
},
|
||||||
"standin-05": {
|
"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",
|
"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",
|
||||||
@@ -252,47 +252,47 @@
|
|||||||
"round": 12,
|
"round": 12,
|
||||||
"seed": 4096833445,
|
"seed": 4096833445,
|
||||||
"waveId": "act1autochess_h05",
|
"waveId": "act1autochess_h05",
|
||||||
"time": 214.33,
|
"time": 215.57,
|
||||||
"ticks": 6430,
|
"ticks": 6467,
|
||||||
"reason": "cleared",
|
"reason": "cleared",
|
||||||
"killed": 7,
|
"killed": 5,
|
||||||
"total": 104,
|
"total": 104,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 246,
|
"rngDraws": 215,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {"killed":7,"total":104,"perfect":false,"leaks":97,"leaksUncounted":0,"coins":0,"dmg":426178,"bossDmg":0,"heal":1353,"deaths":22,"layerGains":{"raidShip":3}}
|
"p1": {"killed":5,"total":104,"perfect":false,"leaks":99,"leaksUncounted":0,"coins":0,"dmg":414926,"bossDmg":0,"heal":451,"deaths":22,"layerGains":{"raidShip":3}}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_6_17_a",2,null,0,0,128,1,103267,9556,0,43,1],
|
["p1",1,"op","chess_char_6_17_a",2,null,0,0,130,1,102521,9556,0,46,1],
|
||||||
["p1",2,"op","chess_char_6_13_a",2,null,0,0,132,1,25092,9232,0,87,0],
|
["p1",2,"op","chess_char_6_13_a",2,null,1154,1,135,0,23355,9232,0,75,0],
|
||||||
["p1",3,"op","chess_char_6_19_a",2,null,0,0,134,2,29265,9232,0,141,0],
|
["p1",3,"op","chess_char_6_19_a",2,null,0,0,133,3,24753,9232,0,127,0],
|
||||||
["p1",4,"op","chess_char_6_12_a",2,null,671.78,1,7,1,143681,975,0,85,2],
|
["p1",4,"op","chess_char_6_12_a",2,null,671.78,1,7,0,141278,975,0,83,2],
|
||||||
["p1",5,"op","chess_char_6_15_a",2,null,0,0,133,2,54479,4965,0,113,2],
|
["p1",5,"op","chess_char_6_15_a",2,null,0,0,134,1,52715,4965,0,109,2],
|
||||||
["p1",6,"op","chess_char_6_18_a",2,null,1372,1,85,0,70393,1372,0,42,2],
|
["p1",6,"op","chess_char_6_18_a",2,null,1372,1,85,0,70303,1372,0,42,2],
|
||||||
["p1",7,"op","chess_char_6_20_a",2,null,1224,1,4,0,0,1353,1353,3,1],
|
["p1",7,"op","chess_char_6_20_a",2,null,1224,1,4,0,0,451,451,1,1],
|
||||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,0,0,0,0,0,null],
|
["-","~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],
|
["-","~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]
|
["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_10122_uacann_2": [1,0,1,6380,12182],
|
"enemy_10122_uacann_2": [1,0,1,7356,12074],
|
||||||
"enemy_10124_uashld_2": [1,0,1,0,5764],
|
"enemy_10124_uashld_2": [1,0,1,0,5764],
|
||||||
"enemy_10127_rkmbst_2": [1,0,1,834,0],
|
"enemy_10127_rkmbst_2": [1,0,1,1154,0],
|
||||||
"enemy_10138_xdsnow": [1,0,1,0,1276],
|
"enemy_10138_xdsnow": [1,0,1,0,1276],
|
||||||
"enemy_10141_xdpeng_2": [1,0,1,4211,14094],
|
"enemy_10141_xdpeng_2": [1,0,1,771,638],
|
||||||
"enemy_10144_xdelk_2": [1,0,1,0,42],
|
"enemy_10144_xdelk_2": [1,0,1,0,0],
|
||||||
"enemy_10156_mncrer": [1,0,1,0,738],
|
"enemy_10156_mncrer": [1,0,1,0,1476],
|
||||||
"enemy_10159_mntrjn": [1,0,1,0,0],
|
"enemy_10159_mntrjn": [1,0,1,0,0],
|
||||||
"enemy_1381_winman": [27,5,22,3499,98764],
|
"enemy_1381_winman": [27,4,23,2007,92343],
|
||||||
"enemy_1381_winman_2": [39,1,38,5799,153206],
|
"enemy_1381_winman_2": [39,0,39,7769,165158],
|
||||||
"enemy_1387_winshd": [30,1,29,15960,140112]
|
"enemy_1387_winshd": [30,1,29,16725,136197]
|
||||||
},
|
},
|
||||||
"hooks": [1,134,6430,620,620,988,988,6,29,128,8,24,0,14868,2437,28,104,97,1,29,1,0,0],
|
"hooks": [1,135,6467,577,577,964,964,2,27,128,8,24,0,14795,2484,27,104,99,1,27,1,0,0],
|
||||||
"events": {"atk":651,"deploy":27,"die":31,"dmg":901,"engage":6,"fx":58,"heal":3,"layer":1,"leak":97,"skill":47,"spawn":114,"status":514},
|
"events": {"atk":608,"deploy":28,"die":29,"dmg":872,"engage":6,"fx":65,"heal":1,"layer":1,"leak":99,"skill":50,"spawn":114,"status":505},
|
||||||
"fx": {"aoe":5,"blink":2,"camouflage":1,"displace":22,"dodge":3,"dp":2,"explode":6,"garrison":1,"garrisonGrant":2,"slash":8,"zone":6},
|
"fx": {"aoe":5,"blink":2,"camouflage":1,"displace":29,"dodge":1,"dp":2,"explode":7,"garrison":1,"garrisonGrant":2,"slash":8,"zone":7},
|
||||||
"snaps": "8d7b3223 b6dafa64 3940bc8e fd79b9e2 e5e85618 6fcfc479 90958489 71bfbb91 d12c224c cd2c9c7f 4a9fff33 68e48a86 4b97e027 5f8e8dad da62239a 8601c0dc 73717b6d 9e4f784f 818e7ed1 c1f2a855 33118eab 9bafc0bc"
|
"snaps": "7d1098cf eed27d14 68262b97 c6f234c7 8b38f4e3 21342a44 02b1ea83 cb4a0d82 ab536b9b 983e88e0 79e6d79f 29c12df3 10ec6f87 f8880188 2817d38e c8292cb4 c36fbc55 11c36bec 13e7ad67 fa20b3bf b4378733 2c35030e"
|
||||||
},
|
},
|
||||||
"standin-06": {
|
"standin-06": {
|
||||||
"about": "elite band 5 as stand-ins: chess_char_3_12_b→char_608_acpion chess_char_4_09_b→char_617_sharp2 chess_char_3_05_b→char_601_cguard chess_char_3_18_b→char_609_acguad chess_char_4_04_b→char_607_cspec chess_char_4_07_b→char_601_cguard chess_char_4_16_b→char_615_acspec chess_char_3_01_b→char_603_csnipe chess_char_3_04_b→char_605_cmedic chess_char_3_21_b→char_611_acnipe chess_char_4_02_b→char_611_acnipe chess_char_4_13_b→char_614_acsupo",
|
"about": "elite band 5 as stand-ins: chess_char_3_12_b→char_608_acpion chess_char_4_09_b→char_617_sharp2 chess_char_3_05_b→char_601_cguard chess_char_3_18_b→char_609_acguad chess_char_4_04_b→char_607_cspec chess_char_4_07_b→char_601_cguard chess_char_4_16_b→char_615_acspec chess_char_3_01_b→char_603_csnipe chess_char_3_04_b→char_605_cmedic chess_char_3_21_b→char_611_acnipe chess_char_4_02_b→char_611_acnipe chess_char_4_13_b→char_614_acsupo",
|
||||||
@@ -303,61 +303,61 @@
|
|||||||
"round": 10,
|
"round": 10,
|
||||||
"seed": 1442657168,
|
"seed": 1442657168,
|
||||||
"waveId": "act1autochess_h03",
|
"waveId": "act1autochess_h03",
|
||||||
"time": 182.73,
|
"time": 183.7,
|
||||||
"ticks": 5482,
|
"ticks": 5511,
|
||||||
"reason": "cleared",
|
"reason": "cleared",
|
||||||
"killed": 46,
|
"killed": 50,
|
||||||
"total": 98,
|
"total": 98,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 295,
|
"rngDraws": 345,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {
|
"p1": {
|
||||||
"killed": 46,
|
"killed": 50,
|
||||||
"total": 98,
|
"total": 98,
|
||||||
"perfect": false,
|
"perfect": false,
|
||||||
"leaks": 52,
|
"leaks": 48,
|
||||||
"leaksUncounted": 0,
|
"leaksUncounted": 0,
|
||||||
"coins": 8,
|
"coins": 8,
|
||||||
"dmg": 621924,
|
"dmg": 676478,
|
||||||
"bossDmg": 0,
|
"bossDmg": 0,
|
||||||
"heal": 27685,
|
"heal": 30426,
|
||||||
"deaths": 32,
|
"deaths": 31,
|
||||||
"layerGains": {"raidShip":26,"visiShip":4}
|
"layerGains": {"raidShip":26,"visiShip":12}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_3_12_b",2,"none",1904,1,138,10,143498,5544,956,21,3],
|
["p1",1,"op","chess_char_3_12_b",2,"none",1904,1,140,10,155395,5504,915,21,3],
|
||||||
["p1",2,"op","chess_char_4_09_b",0,"none",0,0,6,9,109862,3510,0,21,1],
|
["p1",2,"op","chess_char_4_09_b",0,"none",0,0,6,10,119787,3510,0,39,1],
|
||||||
["p1",3,"op","chess_char_3_05_b",2,"none",0,0,93,2,26416,9128,0,18,2],
|
["p1",3,"op","chess_char_3_05_b",2,"none",0,0,90,2,23950,8566,0,18,2],
|
||||||
["p1",4,"op","chess_char_3_18_b",2,"none",0,0,92,3,33920,9190,2808,27,2],
|
["p1",4,"op","chess_char_3_18_b",2,"none",0,0,93,3,28745,9190,2808,27,2],
|
||||||
["p1",5,"op","chess_char_4_04_b",1,"none",0,0,137,0,13321,10188,0,31,8],
|
["p1",5,"op","chess_char_4_04_b",1,"none",0,0,137,0,25476,10224,0,40,9],
|
||||||
["p1",6,"op","chess_char_4_07_b",1,"none",0,0,96,1,23318,10676,0,23,1],
|
["p1",6,"op","chess_char_4_07_b",1,"none",0,0,101,3,28031,10981,0,27,1],
|
||||||
["p1",7,"op","chess_char_4_16_b",1,"none",0,0,136,3,27487,13878,0,36,0],
|
["p1",7,"op","chess_char_4_16_b",1,"none",0,0,139,7,42175,16104,0,70,0],
|
||||||
["p1",8,"op","chess_char_3_01_b",2,"none",0,0,132,2,23235,3020,0,28,1],
|
["p1",8,"op","chess_char_3_01_b",2,"none",0,0,122,1,16716,3020,0,24,1],
|
||||||
["p1",9,"op","chess_char_3_04_b",2,"none",0,0,4,0,0,13615,23921,23,2],
|
["p1",9,"op","chess_char_3_04_b",2,"none",0,0,4,0,0,15932,26703,25,2],
|
||||||
["p1",10,"op","chess_char_3_21_b",2,"none",0,0,117,11,155638,7911,0,47,1],
|
["p1",10,"op","chess_char_3_21_b",2,"none",0,0,118,12,175716,7911,0,55,1],
|
||||||
["p1",11,"op","chess_char_4_02_b",1,"none",0,0,2,5,48494,1483,0,31,1],
|
["p1",11,"op","chess_char_4_02_b",1,"none",0,0,124,2,41362,2966,0,27,1],
|
||||||
["p1",12,"op","chess_char_4_13_b",1,"none",0,0,99,0,16734,3262,0,23,2]
|
["p1",12,"op","chess_char_4_13_b",1,"none",0,0,103,0,19124,2704,0,26,2]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_10162_mnctpt": [1,1,0,7990,39813],
|
"enemy_10162_mnctpt": [1,1,0,7378,39813],
|
||||||
"enemy_1019_jshoot": [1,1,0,423,4479],
|
"enemy_1019_jshoot": [1,1,0,295,4479],
|
||||||
"enemy_1019_jshoot_2": [1,1,0,1526,6718],
|
"enemy_1019_jshoot_2": [1,1,0,837,6718],
|
||||||
"enemy_1021_bslime": [1,1,0,3434,6121],
|
"enemy_1021_bslime": [1,1,0,1648,6121],
|
||||||
"enemy_1023_jmage": [1,1,0,2086,5474],
|
"enemy_1023_jmage": [1,1,0,2497,5474],
|
||||||
"enemy_1025_reveng": [1,1,0,0,12442],
|
"enemy_1025_reveng": [1,1,0,0,12442],
|
||||||
"enemy_1026_aghost": [1,1,0,0,9456],
|
"enemy_1026_aghost": [1,1,0,0,9456],
|
||||||
"enemy_1043_zomsbr": [1,1,0,0,6287],
|
"enemy_1043_zomsbr": [1,1,0,0,6285],
|
||||||
"enemy_1251_lysyta_2": [57,29,28,15958,256380],
|
"enemy_1251_lysyta_2": [57,33,24,13447,289829],
|
||||||
"enemy_1252_lysytb_2": [21,8,13,24284,223998],
|
"enemy_1252_lysytb_2": [21,8,13,29953,226804],
|
||||||
"enemy_1329_cbshld_2": [12,1,11,35708,50755]
|
"enemy_1329_cbshld_2": [12,1,11,40556,69057]
|
||||||
},
|
},
|
||||||
"hooks": [1,138,5482,523,523,776,802,93,78,137,24,36,0,6341,31,56,98,52,1,86,5,0,4],
|
"hooks": [1,140,5511,596,596,875,906,94,81,139,25,37,0,7322,36,60,98,48,1,89,7,0,4],
|
||||||
"events": {"atk":611,"bounty":4,"deploy":40,"die":85,"dmg":802,"engage":11,"fx":59,"heal":66,"layer":5,"leak":52,"skill":48,"spawn":110,"status":107},
|
"events": {"atk":684,"bounty":4,"deploy":42,"die":91,"dmg":906,"engage":11,"fx":62,"heal":67,"layer":7,"leak":48,"skill":50,"spawn":110,"status":117},
|
||||||
"fx": {"blink":7,"camouflage":1,"dodge":8,"dp":13,"explode":1,"garrison":5,"slash":24},
|
"fx": {"blink":10,"camouflage":1,"dodge":6,"dp":13,"explode":1,"garrison":7,"slash":24},
|
||||||
"snaps": "32c77df2 e0a686fc 511e3625 2a2c9595 4d454cd6 ba68fe2a 509a2a40 0f18d74e 26c72bef 4d6d5cce 834f8ce9 462b0854 0fec1e43 fd1bd922 ab1c6896 53173cd5 dbdfb42d 6f942256 4207d16e"
|
"snaps": "accd1698 74126f20 63d105c2 6f46af20 41b2aaf8 62757331 5ee97ef6 6331a731 2b18e7ef 8540aa5c 5e961254 ad125465 3ac7012a 04cc07f3 968df17c 2499c755 43a6f5dc 312679f4 5b9c22ce"
|
||||||
},
|
},
|
||||||
"standin-07": {
|
"standin-07": {
|
||||||
"about": "elite band 6 as stand-ins: chess_char_4_17_b→char_610_acfend chess_char_4_18_b→char_602_cdfend chess_char_5_05_b→char_602_cdfend chess_char_4_19_b→char_608_acpion chess_char_5_01_b→char_600_cpione chess_char_4_22_b→char_609_acguad chess_char_4_23_b→char_609_acguad chess_char_5_06_b→char_609_acguad chess_char_4_20_b→char_603_csnipe chess_char_4_24_b→char_604_ccast chess_char_5_02_b→char_604_ccast chess_char_5_03_b→char_612_accast",
|
"about": "elite band 6 as stand-ins: chess_char_4_17_b→char_610_acfend chess_char_4_18_b→char_602_cdfend chess_char_5_05_b→char_602_cdfend chess_char_4_19_b→char_608_acpion chess_char_5_01_b→char_600_cpione chess_char_4_22_b→char_609_acguad chess_char_4_23_b→char_609_acguad chess_char_5_06_b→char_609_acguad chess_char_4_20_b→char_603_csnipe chess_char_4_24_b→char_604_ccast chess_char_5_02_b→char_604_ccast chess_char_5_03_b→char_612_accast",
|
||||||
@@ -368,24 +368,24 @@
|
|||||||
"round": 12,
|
"round": 12,
|
||||||
"seed": 816286799,
|
"seed": 816286799,
|
||||||
"waveId": "act1autochess_h05",
|
"waveId": "act1autochess_h05",
|
||||||
"time": 222.97,
|
"time": 223.57,
|
||||||
"ticks": 6689,
|
"ticks": 6707,
|
||||||
"reason": "cleared",
|
"reason": "cleared",
|
||||||
"killed": 8,
|
"killed": 9,
|
||||||
"total": 80,
|
"total": 80,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 80,
|
"rngDraws": 86,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {
|
"p1": {
|
||||||
"killed": 8,
|
"killed": 9,
|
||||||
"total": 80,
|
"total": 80,
|
||||||
"perfect": false,
|
"perfect": false,
|
||||||
"leaks": 72,
|
"leaks": 71,
|
||||||
"leaksUncounted": 0,
|
"leaksUncounted": 0,
|
||||||
"coins": 4,
|
"coins": 4,
|
||||||
"dmg": 126420,
|
"dmg": 124008,
|
||||||
"bossDmg": 0,
|
"bossDmg": 0,
|
||||||
"heal": 0,
|
"heal": 0,
|
||||||
"deaths": 22,
|
"deaths": 22,
|
||||||
@@ -393,38 +393,38 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_4_17_b",1,"none",0,0,3,0,42,3211,0,2,1],
|
["p1",1,"op","chess_char_4_17_b",1,"none",0,0,3,0,210,3211,0,2,1],
|
||||||
["p1",2,"op","chess_char_4_18_b",1,"none",0,0,83,0,30,9306,0,1,1],
|
["p1",2,"op","chess_char_4_18_b",1,"none",0,0,83,0,30,9306,0,1,1],
|
||||||
["p1",3,"op","chess_char_5_05_b",2,"none",0,0,97,0,572,5816,0,1,1],
|
["p1",3,"op","chess_char_5_05_b",2,"none",0,0,97,0,1145,5816,0,2,1],
|
||||||
["p1",4,"op","chess_char_4_19_b",1,"none",1847.63,1,107,1,367,3864,0,5,1],
|
["p1",4,"op","chess_char_4_19_b",1,"none",1847.63,1,107,0,230,3864,0,7,1],
|
||||||
["p1",5,"op","chess_char_5_01_b",2,"none",1036.53,1,105,0,2197,3985,0,5,3],
|
["p1",5,"op","chess_char_5_01_b",2,"none",1036.53,1,105,0,2197,3985,0,5,3],
|
||||||
["p1",6,"op","chess_char_4_22_b",1,"none",3191,1,109,0,1178,14884,0,5,1],
|
["p1",6,"op","chess_char_4_22_b",1,"none",3191,1,109,0,1178,15724,0,5,1],
|
||||||
["p1",7,"op","chess_char_4_23_b",1,"none",0,0,67,0,3484,6610,0,8,1],
|
["p1",7,"op","chess_char_4_23_b",1,"none",0,0,68,0,3484,6865,0,8,1],
|
||||||
["p1",8,"op","chess_char_5_06_b",2,"uniequip_002_acguad",0,0,10,0,0,3820,0,0,0],
|
["p1",8,"op","chess_char_5_06_b",2,"uniequip_002_acguad",0,0,10,0,0,3820,0,0,0],
|
||||||
["p1",9,"op","chess_char_4_20_b",1,"none",1255.06,1,106,2,16976,4326,0,31,1],
|
["p1",9,"op","chess_char_4_20_b",1,"none",1255.06,1,106,2,14281,4581,0,27,1],
|
||||||
["p1",10,"op","chess_char_4_24_b",1,"none",1007.59,1,108,0,5460,3072,0,18,1],
|
["p1",10,"op","chess_char_4_24_b",1,"none",1007.59,1,108,0,5710,3072,0,19,1],
|
||||||
["p1",11,"op","chess_char_5_02_b",2,"none",0,0,102,1,8032,4080,0,19,1],
|
["p1",11,"op","chess_char_5_02_b",2,"none",0,0,102,1,8684,4080,0,19,1],
|
||||||
["p1",12,"op","chess_char_5_03_b",2,"uniequip_002_accast",0,0,4,4,88082,1749,0,10,1],
|
["p1",12,"op","chess_char_5_03_b",2,"uniequip_002_accast",0,0,4,6,86859,1749,0,10,1],
|
||||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,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]
|
["-","~2","device","trap_1105_accrate",null,null,100,1,2,0,0,0,0,0,null]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_1005_yokai_2": [18,2,16,3894,7075],
|
"enemy_1005_yokai_2": [18,3,15,3871,7232],
|
||||||
"enemy_1041_lazerd_2": [24,3,21,41810,33530],
|
"enemy_1041_lazerd_2": [24,3,21,43406,32062],
|
||||||
"enemy_1042_frostd": [30,1,29,0,24206],
|
"enemy_1042_frostd": [30,1,29,0,25469],
|
||||||
"enemy_1045_hammer": [1,1,0,1914,15552],
|
"enemy_1045_hammer": [1,1,0,2117,15552],
|
||||||
"enemy_1045_hammer_2": [1,0,1,6132,25057],
|
"enemy_1045_hammer_2": [1,0,1,5327,20514],
|
||||||
"enemy_1046_agent": [1,1,0,57,3888],
|
"enemy_1046_agent": [1,1,0,72,3888],
|
||||||
"enemy_1050_lslime": [1,0,1,9425,1320],
|
"enemy_1050_lslime": [1,0,1,9701,0],
|
||||||
"enemy_1061_zomshd": [1,0,1,31,9241],
|
"enemy_1061_zomshd": [1,0,1,61,13862],
|
||||||
"enemy_1062_rager_2": [1,0,1,1459,14551],
|
"enemy_1062_rager_2": [1,0,1,1519,13929],
|
||||||
"enemy_1067_snslime": [1,0,1,0,0],
|
"enemy_1067_snslime": [1,0,1,0,0],
|
||||||
"enemy_1071_dftman": [1,0,1,0,0]
|
"enemy_1071_dftman": [1,0,1,0,0]
|
||||||
},
|
},
|
||||||
"hooks": [1,109,6689,304,304,581,573,378,30,102,13,13,0,8920,9,11,80,72,1,33,2,0,8],
|
"hooks": [1,109,6707,301,301,585,576,545,31,102,13,13,0,8990,10,14,80,71,1,34,2,0,9],
|
||||||
"events": {"atk":330,"bounty":2,"deploy":27,"die":30,"dmg":573,"engage":11,"fx":22,"layer":2,"leak":72,"skill":26,"spawn":94,"status":103},
|
"events": {"atk":327,"bounty":2,"deploy":27,"die":31,"dmg":576,"engage":11,"fx":23,"layer":2,"leak":71,"skill":26,"spawn":94,"status":111},
|
||||||
"fx": {"aoe":1,"dodge":8,"dp":6,"garrison":2,"garrisonGrant":1,"palsy":1,"revive":3},
|
"fx": {"aoe":1,"dodge":9,"dp":5,"garrison":2,"garrisonGrant":1,"palsy":2,"revive":3},
|
||||||
"snaps": "ef9ff66a 4f4ac6fc 133f7f1c a187a8c8 46d89701 4bb496a8 0dfccf57 81173658 8c42876d 4718c77c d3b80c8e df3c692d 0576a74b 7684de92 e59b0c43 849795d5 e99812de 3f883cd6 6bb9cdf6 b246f597 289cd790 2f34e6ff 997f51f3"
|
"snaps": "801e90ec 5f30137a 56120166 3365328a cd10076b ddf2ae60 00e0a9a1 f0fbc83c 9a8e0ded c4876430 15bb6d00 e61302d2 75a24a51 0b7275b4 f728ca3f 437d1568 ed5e8b79 5a14602a ac144838 2dcf417a 7b12357a 77ef33ec ff8819ba"
|
||||||
},
|
},
|
||||||
"standin-08": {
|
"standin-08": {
|
||||||
"about": "elite band 6 as stand-ins: chess_char_5_08_b→char_610_acfend chess_char_5_14_b→char_608_acpion chess_char_5_19_b→char_617_sharp2 chess_char_5_07_b→char_601_cguard chess_char_5_13_b→char_609_acguad chess_char_5_17_b→char_615_acspec chess_char_5_10_b→char_606_csuppo chess_char_5_11_b→char_613_acmedc chess_char_5_12_b→char_614_acsupo chess_char_5_15_b→char_603_csnipe chess_char_5_18_b→char_611_acnipe chess_char_5_20_b→char_614_acsupo",
|
"about": "elite band 6 as stand-ins: chess_char_5_08_b→char_610_acfend chess_char_5_14_b→char_608_acpion chess_char_5_19_b→char_617_sharp2 chess_char_5_07_b→char_601_cguard chess_char_5_13_b→char_609_acguad chess_char_5_17_b→char_615_acspec chess_char_5_10_b→char_606_csuppo chess_char_5_11_b→char_613_acmedc chess_char_5_12_b→char_614_acsupo chess_char_5_15_b→char_603_csnipe chess_char_5_18_b→char_611_acnipe chess_char_5_20_b→char_614_acsupo",
|
||||||
@@ -438,47 +438,47 @@
|
|||||||
"time": 230,
|
"time": 230,
|
||||||
"ticks": 6900,
|
"ticks": 6900,
|
||||||
"reason": "timeout",
|
"reason": "timeout",
|
||||||
"killed": 43,
|
"killed": 36,
|
||||||
"total": 179,
|
"total": 179,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 1025,
|
"rngDraws": 1087,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {"p1":{"killed":43,"total":179,"perfect":false,"leaks":136,"leaksUncounted":0,"coins":2,"dmg":2172511,"bossDmg":0,"heal":95038,"deaths":13,"layerGains":{}}},
|
"players": {"p1":{"killed":36,"total":179,"perfect":false,"leaks":143,"leaksUncounted":0,"coins":2,"dmg":1859123,"bossDmg":0,"heal":138461,"deaths":10,"layerGains":{}}},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_5_08_b",2,"uniequip_002_acfend",3371,1,203,4,94861,14912,0,116,3],
|
["p1",1,"op","chess_char_5_08_b",2,"uniequip_002_acfend",3167.17,1,165,4,83889,36030,0,116,3],
|
||||||
["p1",2,"op","chess_char_5_14_b",2,"uniequip_002_acpion",0,0,124,14,988772,21777,0,61,10],
|
["p1",2,"op","chess_char_5_14_b",2,"uniequip_002_acpion",1904,1,194,7,473061,9225,0,48,8],
|
||||||
["p1",3,"op","chess_char_5_19_b",0,"uniequip_002_sharp2",4154.5,1,205,8,235963,23398,0,64,2],
|
["p1",3,"op","chess_char_5_19_b",0,"uniequip_002_sharp2",0,0,156,7,350021,33747,0,99,3],
|
||||||
["p1",4,"op","chess_char_5_07_b",2,"none",3334,1,204,2,34977,19978,0,29,2],
|
["p1",4,"op","chess_char_5_07_b",2,"none",3334,1,203,1,30240,30649,0,29,2],
|
||||||
["p1",5,"op","chess_char_5_13_b",2,"uniequip_002_acguad",0,0,161,5,103856,25240,0,51,3],
|
["p1",5,"op","chess_char_5_13_b",2,"uniequip_002_acguad",2176.17,1,129,7,177239,32096,0,89,4],
|
||||||
["p1",6,"op","chess_char_5_17_b",2,"uniequip_002_acspec",1448,1,200,4,83107,24504,0,112,0],
|
["p1",6,"op","chess_char_5_17_b",2,"uniequip_002_acspec",1448,1,188,5,87979,26616,0,142,0],
|
||||||
["p1",7,"op","chess_char_5_10_b",2,"none",1131,1,4,2,79514,0,0,153,4],
|
["p1",7,"op","chess_char_5_10_b",2,"none",1131,1,4,0,74712,0,0,155,4],
|
||||||
["p1",8,"op","chess_char_5_11_b",2,"uniequip_002_acmedc",2262.4,1,5,0,0,0,95038,74,3],
|
["p1",8,"op","chess_char_5_11_b",2,"uniequip_002_acmedc",2262.4,1,5,0,0,0,138461,78,3],
|
||||||
["p1",9,"op","chess_char_5_12_b",2,"uniequip_002_acsupo",1430,1,11,0,112393,0,0,146,3],
|
["p1",9,"op","chess_char_5_12_b",2,"uniequip_002_acsupo",1430,1,11,2,99017,0,0,136,3],
|
||||||
["p1",10,"op","chess_char_5_15_b",2,"none",1510,1,13,0,77843,0,0,215,4],
|
["p1",10,"op","chess_char_5_15_b",2,"none",1510,1,13,0,76181,0,0,234,4],
|
||||||
["p1",11,"op","chess_char_5_18_b",2,"uniequip_002_acnipe",2380.5,1,6,4,262886,0,0,169,3],
|
["p1",11,"op","chess_char_5_18_b",2,"uniequip_002_acnipe",2380.5,1,6,3,299976,0,0,164,3],
|
||||||
["p1",12,"op","chess_char_5_20_b",2,"uniequip_002_acsupo",1430,1,14,0,98338,0,0,125,3],
|
["p1",12,"op","chess_char_5_20_b",2,"uniequip_002_acsupo",1430,1,14,0,106807,0,0,136,3],
|
||||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,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],
|
["-","~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]
|
["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_1072_dlancer": [1,1,0,3008,37150],
|
"enemy_1072_dlancer": [1,1,0,3008,37150],
|
||||||
"enemy_1081_sotisd": [1,0,1,0,27122],
|
"enemy_1081_sotisd": [1,0,1,0,27095],
|
||||||
"enemy_1092_mdgint": [1,0,1,1448,67],
|
"enemy_1092_mdgint": [1,0,1,0,33],
|
||||||
"enemy_1116_liprr": [1,0,1,0,7702],
|
"enemy_1116_liprr": [1,0,1,0,6095],
|
||||||
"enemy_1116_liprr_2": [1,0,1,0,1829],
|
"enemy_1116_liprr_2": [1,0,1,0,2364],
|
||||||
"enemy_1118_lidbox_2": [1,0,1,0,1344],
|
"enemy_1118_lidbox_2": [1,0,1,0,1344],
|
||||||
"enemy_1119_vofsd": [1,0,1,0,889],
|
"enemy_1119_vofsd": [1,0,1,0,889],
|
||||||
"enemy_1121_lifbos": [1,0,1,0,1525],
|
"enemy_1121_lifbos": [1,0,1,0,1997],
|
||||||
"enemy_1249_lysdb_2": [60,13,44,41971,986578],
|
"enemy_1249_lysdb_2": [60,16,44,44297,925272],
|
||||||
"enemy_1251_lysyta": [63,28,35,8822,665956],
|
"enemy_1251_lysyta": [63,18,45,8302,477784],
|
||||||
"enemy_1254_lypa_2": [48,1,47,74560,442348]
|
"enemy_1254_lypa_2": [48,1,46,112756,379100]
|
||||||
},
|
},
|
||||||
"hooks": [1,205,6900,1764,1764,3493,3533,147,56,189,40,44,0,26478,16569,72,179,133,1,59,0,0,10],
|
"hooks": [1,203,6900,1914,1914,3154,3238,154,46,188,40,41,0,27753,17018,59,179,142,1,51,0,0,24],
|
||||||
"events": {"atk":2013,"bounty":1,"deploy":23,"die":56,"dmg":3508,"engage":11,"fx":308,"heal":130,"leak":133,"skill":90,"spawn":194,"status":1297},
|
"events": {"atk":2198,"bounty":1,"deploy":21,"die":46,"dmg":3227,"engage":11,"fx":296,"heal":145,"leak":142,"skill":85,"spawn":194,"status":1301},
|
||||||
"fx": {"aoe":90,"displace":12,"dodge":31,"dp":24,"shieldBreak":59,"slash":80,"sp":1,"spGain":11},
|
"fx": {"aoe":89,"displace":4,"dodge":50,"dp":15,"shieldBreak":60,"slash":64,"sp":4,"spGain":10},
|
||||||
"snaps": "4d4dc5ab 00efc642 4dc3aa32 13e9533b a3617bdf 587927d0 9fe3b7b8 0b39dceb 2981edf9 2ba1ce8c ef825d5b 85fd9608 a83f0a12 9e6b1271 7c5bf7ee f6ad8d8e c76286f6 037365de bf979497 771a38f7 b74aaf11 518326a3 19e5e338"
|
"snaps": "c4ba1bfb 2dfd8eae 9edfcbdb 398871eb 8ec5c018 bdeb7f73 3a80c711 b3542ba8 7c2bcdeb 332b7d77 cfba3c82 e42b9504 e04cec26 299bbeab 55c539ae fb163352 d1b5dcef e0628f10 16c64f3c f935f6ce dfa3bfea 0a6ae300 8f573ae7"
|
||||||
},
|
},
|
||||||
"standin-09": {
|
"standin-09": {
|
||||||
"about": "elite band 7 as stand-ins: chess_char_6_03_b→char_610_acfend chess_char_6_02_b→char_608_acpion chess_char_6_07_b→char_617_sharp2 chess_char_6_10_b→char_617_sharp2 chess_char_6_11_b→char_608_acpion chess_char_6_06_b→char_609_acguad chess_char_5_22_b→char_611_acnipe chess_char_6_01_b→char_611_acnipe chess_char_6_04_b→char_614_acsupo chess_char_6_05_b→char_611_acnipe chess_char_6_08_b→char_612_accast chess_char_6_09_b→char_613_acmedc",
|
"about": "elite band 7 as stand-ins: chess_char_6_03_b→char_610_acfend chess_char_6_02_b→char_608_acpion chess_char_6_07_b→char_617_sharp2 chess_char_6_10_b→char_617_sharp2 chess_char_6_11_b→char_608_acpion chess_char_6_06_b→char_609_acguad chess_char_5_22_b→char_611_acnipe chess_char_6_01_b→char_611_acnipe chess_char_6_04_b→char_614_acsupo chess_char_6_05_b→char_611_acnipe chess_char_6_08_b→char_612_accast chess_char_6_09_b→char_613_acmedc",
|
||||||
@@ -489,31 +489,31 @@
|
|||||||
"round": 13,
|
"round": 13,
|
||||||
"seed": 2308517178,
|
"seed": 2308517178,
|
||||||
"waveId": "act1autochess_h06",
|
"waveId": "act1autochess_h06",
|
||||||
"time": 198.9,
|
"time": 198.43,
|
||||||
"ticks": 5967,
|
"ticks": 5953,
|
||||||
"reason": "cleared",
|
"reason": "cleared",
|
||||||
"killed": 158,
|
"killed": 158,
|
||||||
"total": 158,
|
"total": 158,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 257,
|
"rngDraws": 232,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {"killed":158,"total":158,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":924432,"bossDmg":0,"heal":30129,"deaths":1,"layerGains":{"sargonShip":20}}
|
"p1": {"killed":158,"total":158,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":924222,"bossDmg":0,"heal":29638,"deaths":1,"layerGains":{"sargonShip":20}}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_acfend",4974.95,1,8,0,0,0,0,0,0],
|
["p1",1,"op","chess_char_6_03_b",2,"uniequip_002_acfend",4974.95,1,8,0,0,0,0,0,0],
|
||||||
["p1",2,"op","chess_char_6_02_b",2,"uniequip_002_acpion",1904,1,6,0,0,0,0,0,0],
|
["p1",2,"op","chess_char_6_02_b",2,"uniequip_002_acpion",1904,1,6,0,0,0,0,0,0],
|
||||||
["p1",3,"op","chess_char_6_07_b",0,"uniequip_002_sharp2",2494,1,9,0,0,0,0,0,0],
|
["p1",3,"op","chess_char_6_07_b",0,"uniequip_002_sharp2",2494,1,9,0,0,0,0,0,0],
|
||||||
["p1",4,"op","chess_char_6_10_b",0,"uniequip_002_sharp2",2494,1,11,20,146204,0,0,174,4],
|
["p1",4,"op","chess_char_6_10_b",0,"uniequip_002_sharp2",2494,1,11,27,129672,0,0,173,3],
|
||||||
["p1",5,"op","chess_char_6_11_b",2,"uniequip_002_acpion",1834,1,13,45,168227,12564,0,58,23],
|
["p1",5,"op","chess_char_6_11_b",2,"uniequip_002_acpion",1904,1,13,35,186014,11957,0,60,20],
|
||||||
["p1",6,"op","chess_char_6_06_b",2,"uniequip_002_acguad",3531,1,14,10,62057,943,0,157,4],
|
["p1",6,"op","chess_char_6_06_b",2,"uniequip_002_acguad",3531,1,14,18,61248,763,0,155,4],
|
||||||
["p1",7,"op","chess_char_5_22_b",2,"uniequip_002_acnipe",1587,1,4,0,0,0,0,0,0],
|
["p1",7,"op","chess_char_5_22_b",2,"uniequip_002_acnipe",1587,1,4,0,0,0,0,0,0],
|
||||||
["p1",8,"op","chess_char_6_01_b",2,"uniequip_002_acnipe",1643,1,5,0,0,0,0,0,0],
|
["p1",8,"op","chess_char_6_01_b",2,"uniequip_002_acnipe",1643,1,5,0,948,0,0,4,1],
|
||||||
["p1",9,"op","chess_char_6_04_b",2,"uniequip_002_acsupo",2465,1,137,8,65378,2465,0,91,2],
|
["p1",9,"op","chess_char_6_04_b",2,"uniequip_002_acsupo",2465,1,141,7,73191,2465,0,92,2],
|
||||||
["p1",10,"op","chess_char_6_05_b",2,"uniequip_002_acnipe",1643,1,7,22,90616,0,0,96,2],
|
["p1",10,"op","chess_char_6_05_b",2,"uniequip_002_acnipe",1643,1,7,20,89868,0,0,93,2],
|
||||||
["p1",11,"op","chess_char_6_08_b",2,"uniequip_002_accast",1819,1,10,53,391951,0,0,83,2],
|
["p1",11,"op","chess_char_6_08_b",2,"uniequip_002_accast",1819,1,10,51,383282,0,0,78,2],
|
||||||
["p1",12,"op","chess_char_6_09_b",2,"uniequip_002_acmedc",1394,1,12,0,0,16762,30129,83,3],
|
["p1",12,"op","chess_char_6_09_b",2,"uniequip_002_acmedc",1394,1,12,0,0,16988,29638,83,3],
|
||||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,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],
|
["-","~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]
|
["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null]
|
||||||
@@ -522,19 +522,19 @@
|
|||||||
"enemy_1121_lifbos_2": [1,1,0,0,24000],
|
"enemy_1121_lifbos_2": [1,1,0,0,24000],
|
||||||
"enemy_1148_dssbr": [1,1,0,0,2688],
|
"enemy_1148_dssbr": [1,1,0,0,2688],
|
||||||
"enemy_1148_dssbr_2": [1,1,0,0,3456],
|
"enemy_1148_dssbr_2": [1,1,0,0,3456],
|
||||||
"enemy_1158_divman": [1,1,0,195,3168],
|
"enemy_1158_divman": [1,1,0,153,3168],
|
||||||
"enemy_1160_hvyslr": [1,1,0,0,9600],
|
"enemy_1160_hvyslr": [1,1,0,0,9600],
|
||||||
"enemy_1160_hvyslr_2": [1,1,0,133,13440],
|
"enemy_1160_hvyslr_2": [1,1,0,133,13440],
|
||||||
"enemy_1161_tidmag": [1,1,0,1336,5760],
|
"enemy_1161_tidmag": [1,1,0,554,5760],
|
||||||
"enemy_1161_tidmag_2": [1,1,0,1391,7680],
|
"enemy_1161_tidmag_2": [1,1,0,1758,7680],
|
||||||
"enemy_1249_lysdb_2": [60,60,0,1459,345600],
|
"enemy_1249_lysdb_2": [60,60,0,2085,345600],
|
||||||
"enemy_1251_lysyta": [51,51,0,0,134640],
|
"enemy_1251_lysyta": [51,51,0,0,134640],
|
||||||
"enemy_1329_cbshld": [39,39,0,3019,374400]
|
"enemy_1329_cbshld": [39,39,0,2290,374400]
|
||||||
},
|
},
|
||||||
"hooks": [1,174,5967,836,836,1660,1803,179,159,159,40,38,0,28209,2688,60,158,0,1,159,3,1,23],
|
"hooks": [1,174,5953,812,812,1599,1718,168,159,159,37,36,0,29335,2593,62,158,0,1,159,3,1,17],
|
||||||
"events": {"atk":974,"bounty":4,"deploy":13,"die":159,"dmg":1782,"engage":6,"fx":330,"heal":135,"layer":3,"skill":78,"spawn":173,"status":334},
|
"events": {"atk":917,"bounty":4,"deploy":13,"die":159,"dmg":1707,"engage":7,"fx":298,"heal":127,"layer":3,"skill":73,"spawn":173,"status":324},
|
||||||
"fx": {"aoe":2,"burst":1,"dodge":28,"dp":68,"garrison":3,"shieldBreak":60,"slash":152,"sp":16},
|
"fx": {"aoe":2,"burst":1,"dodge":19,"dp":55,"garrison":3,"shieldBreak":60,"slash":144,"sp":12,"strike":2},
|
||||||
"snaps": "526d4c63 f04a2d68 53d511ef 5f8b4334 d796abdd 122e9876 81bad943 4c6a838a eb463850 1e1d2025 875b599b 2d763f55 51548a07 73b07326 88a8ea6f ec211cd8 e329b226 03d1aa7b 63fd2bb2 afee939a"
|
"snaps": "526d4c63 f61576c6 e1be6631 53288d14 7de80a4f 26575d3b 14b2dc7b 09bff769 03f7af9b 81a2c2a0 80d45921 19ddd297 25520dc8 270c7d09 288a246a 05a0a7ec ed5b2582 a7da7717 af272d65 435b22b3"
|
||||||
},
|
},
|
||||||
"standin-10": {
|
"standin-10": {
|
||||||
"about": "elite band 7 as stand-ins: chess_char_6_17_b→char_608_acpion chess_char_6_13_b→char_615_acspec chess_char_6_19_b→char_615_acspec chess_char_6_12_b→char_612_accast chess_char_6_15_b→char_614_acsupo chess_char_6_18_b→char_612_accast chess_char_6_20_b→char_613_acmedc",
|
"about": "elite band 7 as stand-ins: chess_char_6_17_b→char_608_acpion chess_char_6_13_b→char_615_acspec chess_char_6_19_b→char_615_acspec chess_char_6_12_b→char_612_accast chess_char_6_15_b→char_614_acsupo chess_char_6_18_b→char_612_accast chess_char_6_20_b→char_613_acmedc",
|
||||||
@@ -545,46 +545,46 @@
|
|||||||
"round": 13,
|
"round": 13,
|
||||||
"seed": 3949114127,
|
"seed": 3949114127,
|
||||||
"waveId": "act1autochess_h06",
|
"waveId": "act1autochess_h06",
|
||||||
"time": 216.2,
|
"time": 230,
|
||||||
"ticks": 6486,
|
"ticks": 6900,
|
||||||
"reason": "cleared",
|
"reason": "timeout",
|
||||||
"killed": 25,
|
"killed": 28,
|
||||||
"total": 131,
|
"total": 131,
|
||||||
"unspawned": 0,
|
"unspawned": 0,
|
||||||
"bossHpLeft": null,
|
"bossHpLeft": null,
|
||||||
"rngDraws": 245,
|
"rngDraws": 262,
|
||||||
"errors": {"count":0,"kinds":[]},
|
"errors": {"count":0,"kinds":[]},
|
||||||
"players": {
|
"players": {
|
||||||
"p1": {"killed":25,"total":131,"perfect":false,"leaks":106,"leaksUncounted":0,"coins":0,"dmg":508719,"bossDmg":0,"heal":10260,"deaths":25,"layerGains":{"raidShip":6}}
|
"p1": {"killed":28,"total":131,"perfect":false,"leaks":103,"leaksUncounted":0,"coins":2,"dmg":537630,"bossDmg":0,"heal":10974,"deaths":25,"layerGains":{"raidShip":6}}
|
||||||
},
|
},
|
||||||
"units": [
|
"units": [
|
||||||
["p1",1,"op","chess_char_6_17_b",2,"uniequip_002_acpion",0,0,164,8,199340,14855,0,64,9],
|
["p1",1,"op","chess_char_6_17_b",2,"uniequip_002_acpion",480.36,1,164,9,211459,13918,0,77,10],
|
||||||
["p1",2,"op","chess_char_6_13_b",2,"uniequip_002_acspec",0,0,163,6,43893,11872,0,99,0],
|
["p1",2,"op","chess_char_6_13_b",2,"uniequip_002_acspec",0,0,165,5,46951,13356,0,105,0],
|
||||||
["p1",3,"op","chess_char_6_19_b",2,"uniequip_002_acspec",1484,1,165,3,65411,16324,0,126,0],
|
["p1",3,"op","chess_char_6_19_b",2,"uniequip_002_acspec",1484,1,166,4,74447,16324,0,138,0],
|
||||||
["p1",4,"op","chess_char_6_12_b",2,"uniequip_002_accast",2265.49,1,4,4,78264,281,0,32,2],
|
["p1",4,"op","chess_char_6_12_b",2,"uniequip_002_accast",2265.49,1,4,4,78264,281,0,32,2],
|
||||||
["p1",5,"op","chess_char_6_15_b",2,"uniequip_002_acsupo",0,0,147,2,52466,6493,0,38,3],
|
["p1",5,"op","chess_char_6_15_b",2,"uniequip_002_acsupo",0,0,147,2,54506,6494,0,39,3],
|
||||||
["p1",6,"op","chess_char_6_18_b",2,"uniequip_002_accast",1819,1,8,2,69344,618,0,44,2],
|
["p1",6,"op","chess_char_6_18_b",2,"uniequip_002_accast",1819,1,8,4,72003,900,0,43,2],
|
||||||
["p1",7,"op","chess_char_6_20_b",2,"uniequip_002_acmedc",1464,1,9,0,0,3373,10260,17,1],
|
["p1",7,"op","chess_char_6_20_b",2,"uniequip_002_acmedc",1464,1,9,0,0,4263,10974,19,1],
|
||||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,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]
|
["-","~2","device","trap_1105_accrate",null,null,100,1,2,0,0,0,0,0,null]
|
||||||
],
|
],
|
||||||
"enemies": {
|
"enemies": {
|
||||||
"enemy_1006_shield_3": [21,1,20,14948,163592],
|
"enemy_1006_shield_3": [21,1,20,16907,164045],
|
||||||
"enemy_1043_zomsbr": [66,20,46,789,124139],
|
"enemy_1043_zomsbr": [66,22,44,926,136167],
|
||||||
"enemy_1162_magmot": [1,0,1,4063,11534],
|
"enemy_1162_magmot": [1,0,1,4704,11483],
|
||||||
"enemy_1165_duhond": [1,1,0,139,4645],
|
"enemy_1165_duhond": [1,1,0,93,4645],
|
||||||
"enemy_1165_duhond_2": [1,0,1,0,0],
|
"enemy_1165_duhond_2": [1,0,1,0,0],
|
||||||
"enemy_1166_dusbr": [1,0,1,0,0],
|
"enemy_1166_dusbr": [1,0,1,0,0],
|
||||||
"enemy_1166_dusbr_2": [1,0,1,0,0],
|
"enemy_1166_dusbr_2": [1,0,1,0,0],
|
||||||
"enemy_1168_dumage": [1,1,0,1476,7465],
|
"enemy_1168_dumage": [1,1,0,1897,7465],
|
||||||
"enemy_1168_dumage_2": [1,0,1,3178,0],
|
"enemy_1168_dumage_2": [1,1,0,4932,10783],
|
||||||
"enemy_1169_duphlx": [1,0,1,0,0],
|
"enemy_1169_duphlx": [1,0,1,0,1489],
|
||||||
"enemy_1402_tgshd_2": [36,2,34,29224,197345]
|
"enemy_1402_tgshd_2": [36,2,33,26077,201554]
|
||||||
},
|
},
|
||||||
"hooks": [1,165,6486,549,549,865,877,6809,50,159,17,36,0,8308,1125,49,131,106,1,50,1,1,0],
|
"hooks": [1,166,6900,579,579,900,914,7045,53,158,18,38,0,8737,1167,49,131,102,1,53,1,1,0],
|
||||||
"events": {"atk":554,"deploy":32,"die":53,"dmg":802,"engage":6,"fx":530,"heal":21,"layer":1,"leak":106,"skill":74,"spawn":140,"status":378},
|
"events": {"atk":586,"bounty":1,"deploy":33,"die":56,"dmg":848,"engage":6,"fx":538,"heal":25,"layer":1,"leak":102,"skill":78,"spawn":140,"status":384},
|
||||||
"fx": {"aoe":4,"blink":3,"burst":1,"displace":17,"dodge":3,"dp":17,"expose":414,"garrison":1,"garrisonGrant":3,"slash":67},
|
"fx": {"aoe":5,"blink":3,"burst":1,"displace":18,"dodge":1,"dp":19,"expose":413,"garrison":1,"garrisonGrant":3,"slash":74},
|
||||||
"snaps": "80709a69 1b180600 2040e410 16970933 7ec28fab 061d6583 09f2da3e 98333fee 741e4051 c5f8165a 55db9474 b9b2bf46 d72aea5d 20d591d8 3077f062 ab32900d eb4540a2 37c492a6 3e3cd8f7 20a4cb8e 22ada53e b9ce62f2"
|
"snaps": "fba27448 de0d1730 e90ea321 52a21ef0 85a0833c 2a8e4ffa 3b4a24e3 f3d67a0b 9f0134f0 9cb0d19a e7da4c3d 843017d8 4557a167 130155ab 0afb1b21 d4aa9c6c c0ffca41 9e9e17c9 975fc2dd 20398d66 00b5e499 52760797 5a270974"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
// `attackAnim`, tools/build-data.mjs from the asset manifest; server/sim/ai.js attackStand). It used to stop only
|
// `attackAnim`, tools/build-data.mjs from the asset manifest; server/sim/ai.js attackStand). It used to stop only
|
||||||
// ATTACK_PAUSE (0.35 s) after each strike while the client played the attack clip over the whole walk. An enemy with no
|
// ATTACK_PAUSE (0.35 s) after each strike while the client played the attack clip over the whole walk. An enemy with no
|
||||||
// clip known keeps the old 0.35 s (test/sim/combat.test.js); a 「不停止移动」 attacker never stops; a stun cuts the stand.
|
// clip known keeps the old 0.35 s (test/sim/combat.test.js); a 「不停止移动」 attacker never stops; a stun cuts the stand.
|
||||||
|
// Since 0.2.0 (GitHub #187 / #170) every attack has its wind-up — the strike comes at the clip's damage frame after the
|
||||||
|
// swing starts, also the first one of an enemy whose cooldown ran out before it had a target (it used to strike at once)
|
||||||
|
// — and a stun before the frame cuts the swing (test/sim/feedback5-enemy-swing.test.js).
|
||||||
|
|
||||||
import { test } from 'node:test';
|
import { test } from 'node:test';
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
@@ -101,9 +104,10 @@ test('a 「不停止移动」 attacker (attackMoves) keeps walking through its a
|
|||||||
};
|
};
|
||||||
const moving = run(true), standing = run(false);
|
const moving = run(true), standing = run(false);
|
||||||
assert.ok(moving.atks.length >= 3 && standing.atks.length >= 3);
|
assert.ok(moving.atks.length >= 3 && standing.atks.length >= 3);
|
||||||
for (const t of moving.atks.slice(1, 3)) assert.ok(walked(moving.log, t - 0.5, t + 1) > 0.6, `walks through the attack at ${t.toFixed(2)}`);
|
for (const t of moving.atks.slice(0, 3)) assert.ok(walked(moving.log, t - 0.5, t + 1) > 0.6, `walks through the attack at ${t.toFixed(2)}`);
|
||||||
// (the first attack lands as the target comes into range, its cooldown long over: no wind-up to stand through)
|
// (since 0.2.0 the first attack too: its cooldown long over as the target comes into range, it swings from the start —
|
||||||
for (const t of standing.atks.slice(1, 3)) assert.equal(walked(standing.log, t - 0.5 + 2 * TICK, t + 1 - TICK), 0, 'the same enemy without it stands');
|
// the whole 0.5 s wind-up stood before the strike)
|
||||||
|
for (const t of standing.atks.slice(0, 3)) assert.equal(walked(standing.log, t - 0.5 + 2 * TICK, t + 1 - TICK), 0, 'the same enemy without it stands');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('no attack clip known: ATTACK_PAUSE after the strike and no wind-up stand; a stun cuts a stand short', () => {
|
test('no attack clip known: ATTACK_PAUSE after the strike and no wind-up stand; a stun cuts a stand short', () => {
|
||||||
@@ -116,8 +120,13 @@ test('no attack clip known: ATTACK_PAUSE after the strike and no wind-up stand;
|
|||||||
});
|
});
|
||||||
h.step();
|
h.step();
|
||||||
const e = h.enemy('enemy_slow');
|
const e = h.enemy('enemy_slow');
|
||||||
assert.ok(e.lastAttackAt >= 0, 'attacked at once');
|
// (0.2.0: a target in range at once, its cooldown over — it swings at once and strikes at the 0.5 s damage frame; it
|
||||||
assert.ok(Math.abs(e.atkStandUntil - (h.b.time - TICK + 2.5)) < 1e-6, 'stands the 2.5 s after the strike');
|
// used to strike in the first tick)
|
||||||
|
assert.equal(e.lastAttackAt, -Infinity, 'swinging, not struck yet');
|
||||||
|
h.runUntil(() => e.lastAttackAt >= 0, 2);
|
||||||
|
assert.ok(Math.abs(e.lastAttackAt - (TICK + 0.5)) < TICK + 1e-6, `struck at the damage frame (${e.lastAttackAt.toFixed(3)})`);
|
||||||
|
h.step();
|
||||||
|
assert.ok(Math.abs(e.atkStandUntil - (e.lastAttackAt + 2.5)) < 1e-6, 'stands the 2.5 s after the strike');
|
||||||
h.run(0.5);
|
h.run(0.5);
|
||||||
const x0 = e.x;
|
const x0 = e.x;
|
||||||
h.b.applyStatus(e, 'stun', { duration: 0.5 });
|
h.b.applyStatus(e, 'stun', { duration: 0.5 });
|
||||||
@@ -156,8 +165,9 @@ test('a ranged enemy with a target in range on a WAIT checkpoint leaves when the
|
|||||||
assert.equal(free.attacks, 0);
|
assert.equal(free.attacks, 0);
|
||||||
assert.ok(sniper.attacks >= 2 && quick.attacks >= 5);
|
assert.ok(sniper.attacks >= 2 && quick.attacks >= 5);
|
||||||
assert.ok(Math.abs(sniper.waited - free.waited) < 1e-9 && Math.abs(quick.waited - free.waited) < 1e-9, `the wait ends at ${free.waited.toFixed(2)} s for all three`);
|
assert.ok(Math.abs(sniper.waited - free.waited) < 1e-9 && Math.abs(quick.waited - free.waited) < 1e-9, `the wait ends at ${free.waited.toFixed(2)} s for all three`);
|
||||||
// it walks on once the attack clip running at the end of the wait is over (the attack at 2.7 s: until 3.2 s)
|
// it walks on once the attack clip running at the end of the wait is over (since 0.2.0 the first strike at its 0.5 s
|
||||||
assert.ok(sniper.moved > free.moved && sniper.moved <= 3.2 + 2 * TICK, `leaves at ${sniper.moved?.toFixed(2)} s (no target: ${free.moved.toFixed(2)} s)`);
|
// damage frame, the next one 2.7 s later at 3.2 s: its clip until 3.7 s; it used to strike at once — until 3.2 s)
|
||||||
|
assert.ok(sniper.moved > free.moved && sniper.moved <= 3.7 + 2 * TICK, `leaves at ${sniper.moved?.toFixed(2)} s (no target: ${free.moved.toFixed(2)} s)`);
|
||||||
assert.equal(quick.moved, null, 'an enemy attacking quicker than its clip stands while the target stays in range');
|
assert.equal(quick.moved, null, 'an enemy attacking quicker than its clip stands while the target stays in range');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// test/sim/feedback5-enemy-swing.test.js — an enemy's normal attack strikes at its clip's damage frame, and a stun before the
|
||||||
|
// frame cuts the swing (GitHub #187 point 1 「短轴眩晕无法打断敌人攻击,比如:六卡西米尔、异德三、忍冬三」, #170; PRTS 状态机
|
||||||
|
// ATTACK / COMBAT "每帧检查异常状态,若有则切换到异常状态的状态", PRTS 异常效果 STUNNED / DISARMED "正在进行的普通攻击将被中断") —
|
||||||
|
// server/sim/ai.js updateEnemy / enemyAttack / attackWindup. The damage frame is data/enemies.json `attackAnim.hit` (the
|
||||||
|
// clip's strike frame), shortened with the clip when the attacks come quicker than it; no clip known ⇒ no wind-up.
|
||||||
|
// Run: node --test test/sim/feedback5-enemy-swing.test.js
|
||||||
|
|
||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { makeBattle, enemyRec, chessRec, checkInvariants } from '../helpers/battleHarness.js';
|
||||||
|
import { TICK } from '../../server/sim/constants.js';
|
||||||
|
import { attackWindup } from '../../server/sim/ai.js';
|
||||||
|
|
||||||
|
const HIT = 0.4; // the clip's strike frame
|
||||||
|
const BAT = 2; // attack interval
|
||||||
|
const near = (a, b, msg, ticks = 2) => assert.ok(Math.abs(a - b) <= ticks * TICK + 1e-9, `${msg}: ${a.toFixed(3)} vs ${b.toFixed(3)}`);
|
||||||
|
|
||||||
|
/** A wall operator and one enemy (melee on the wall's tile — blocked at once —, or ranged 3 tiles away). */
|
||||||
|
function field({ ranged = false, clip = true } = {}) {
|
||||||
|
const rec = {
|
||||||
|
...enemyRec({ key: 'enemy_sw', hp: 1e9, atk: 100, bat: BAT, speed: 0, ...(ranged ? { range: 3 } : null) }),
|
||||||
|
...(clip ? { attackAnim: { clip: 'Attack', dur: 1, hit: HIT } } : null),
|
||||||
|
};
|
||||||
|
const h = makeBattle({
|
||||||
|
defs: { chess: { t_wall: chessRec({ id: 't_wall', stats: { maxHp: 1e9, atk: 0, def: 0 }, skill: null }) }, enemies: { enemy_sw: rec } },
|
||||||
|
units: [{ chessId: 't_wall', row: 10, col: 6 }], enemies: [{ key: 'enemy_sw', pos: ranged ? [10, 9] : [10, 6] }],
|
||||||
|
content: 'none', autoFinish: false, timeLimit: 60, hooks: ['attack', 'damaged'], captureNoisy: true,
|
||||||
|
});
|
||||||
|
h.step();
|
||||||
|
return { h, e: h.enemy('enemy_sw'), wall: h.unit('t_wall') };
|
||||||
|
}
|
||||||
|
const strikes = (h, e) => h.hooksOf('attack').filter((c) => c.attacker === e).map((c) => c.t);
|
||||||
|
const hits = (h, e) => h.hooksOf('damaged').filter((c) => c.source === e && c.dmg.isAttack).map((c) => c.t);
|
||||||
|
const done = (h) => { checkInvariants(h.b); assert.equal(h.b.errors.length, 0, JSON.stringify(h.b.errors[0])); };
|
||||||
|
|
||||||
|
test('attackWindup: the clip\'s strike frame, shortened with the clip when the attacks come quicker than it; 0 with no clip', () => {
|
||||||
|
const w = (anim, interval) => attackWindup({ def: { attackAnim: anim }, s: { interval } });
|
||||||
|
assert.equal(w({ dur: 1, hit: 0.4 }, 2), 0.4);
|
||||||
|
assert.equal(w({ dur: 2, hit: 1 }, 1), 0.5);
|
||||||
|
assert.equal(w({ dur: 1 }, 2), 0.5, 'no strike frame named: half the clip');
|
||||||
|
assert.equal(w(undefined, 2), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a blocked enemy swings when its cooldown is over and strikes at the damage frame: the first strike one wind-up after the block (its cooldown long over), then one per attack interval', () => {
|
||||||
|
const { h, e } = field();
|
||||||
|
const t0 = h.b.time; // blocked in the first tick
|
||||||
|
h.run(4.6);
|
||||||
|
const s = strikes(h, e);
|
||||||
|
assert.ok(s.length >= 3, `${s.length} strikes`);
|
||||||
|
near(s[0], t0 + HIT, 'the first strike: the whole wind-up from the block (it used to land at once)');
|
||||||
|
near(s[1] - s[0], BAT, 'then one per interval', 1);
|
||||||
|
near(s[2] - s[1], BAT, 'then one per interval', 1);
|
||||||
|
assert.deepEqual(hits(h, e), s, 'melee: the damage at the strike');
|
||||||
|
done(h);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const dur of [0.1, 0.2]) {
|
||||||
|
test(`a ${dur} s stun before the damage frame cuts the swing: no strike at that frame, the attack starts again from its wind-up after the stun (卡西米尔 6's pulse, 忍冬 S3)`, () => {
|
||||||
|
const { h, e } = field();
|
||||||
|
assert.ok(h.runUntil(() => strikes(h, e).length === 1, 2));
|
||||||
|
const t1 = strikes(h, e)[0];
|
||||||
|
// its next swing starts at t1 + BAT − HIT; the stun lands 0.2 s into it
|
||||||
|
h.runUntil(() => h.b.time >= t1 + BAT - HIT + 0.2 - 1e-9, 3);
|
||||||
|
assert.ok(e.swing, 'swinging');
|
||||||
|
const tStun = h.b.time;
|
||||||
|
h.b.applyStatus(e, 'stun', { duration: dur });
|
||||||
|
h.run(dur + HIT + 0.3);
|
||||||
|
const s = strikes(h, e);
|
||||||
|
assert.equal(s.filter((t) => t > t1 && t < tStun + dur).length, 0, 'the cut swing never struck');
|
||||||
|
near(s[1], tStun + dur + HIT, 'the next strike: the stun, then the whole wind-up again', 3);
|
||||||
|
assert.ok(s[1] > t1 + BAT + dur + 0.1, `later than a mere pause of the countdown (${(t1 + BAT + dur).toFixed(2)})`);
|
||||||
|
done(h);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test('a stun during the cooldown (before the swing) only pauses it; 缴械 cuts a swing like a stun; a strike already made stays made (a ranged shot in flight lands)', () => {
|
||||||
|
// the cooldown: a 0.5 s stun 0.5 s after a strike delays the next one by 0.5 s
|
||||||
|
const a = field();
|
||||||
|
assert.ok(a.h.runUntil(() => strikes(a.h, a.e).length === 1, 2));
|
||||||
|
const t1 = strikes(a.h, a.e)[0];
|
||||||
|
a.h.run(0.5);
|
||||||
|
a.h.b.applyStatus(a.e, 'stun', { duration: 0.5 });
|
||||||
|
a.h.run(BAT + 0.3);
|
||||||
|
near(strikes(a.h, a.e)[1], t1 + BAT + 0.5, 'paused by the stun, no new wind-up', 3);
|
||||||
|
done(a.h);
|
||||||
|
// 缴械 mid-swing: the swing is cut, a new one starts once it ends
|
||||||
|
const b = field();
|
||||||
|
assert.ok(b.h.runUntil(() => strikes(b.h, b.e).length === 1, 2));
|
||||||
|
const u1 = strikes(b.h, b.e)[0];
|
||||||
|
b.h.runUntil(() => b.h.b.time >= u1 + BAT - HIT + 0.2 - 1e-9, 3);
|
||||||
|
const tD = b.h.b.time;
|
||||||
|
b.h.b.addBuff(b.e, { key: 'test:disarm', duration: 0.1, flags: { disarm: true } });
|
||||||
|
b.h.run(HIT + 0.5);
|
||||||
|
near(strikes(b.h, b.e)[1], tD + 0.1 + HIT, '缴械 "正在进行的普通攻击将被中断": the whole wind-up after it', 3);
|
||||||
|
done(b.h);
|
||||||
|
// ranged: stunned just after the strike — the shot flies on and lands
|
||||||
|
const c = field({ ranged: true });
|
||||||
|
assert.ok(c.h.runUntil(() => strikes(c.h, c.e).length === 1, 3));
|
||||||
|
assert.equal(hits(c.h, c.e).length, 0, 'the shot is in flight');
|
||||||
|
c.h.b.applyStatus(c.e, 'stun', { duration: 1 });
|
||||||
|
c.h.run(0.6);
|
||||||
|
assert.equal(hits(c.h, c.e).length, 1, 'a strike already made is not undone');
|
||||||
|
done(c.h);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no attack clip known: no wind-up — it strikes as its swing starts, so a stun only pauses its cooldown (the rule before 0.2.0)', () => {
|
||||||
|
const { h, e } = field({ clip: false });
|
||||||
|
assert.equal(attackWindup(e), 0);
|
||||||
|
h.step();
|
||||||
|
assert.equal(strikes(h, e).length, 1, 'struck in its first tick blocked');
|
||||||
|
const t1 = strikes(h, e)[0];
|
||||||
|
h.runUntil(() => h.b.time >= t1 + BAT - 0.1 - 1e-9, 3);
|
||||||
|
h.b.applyStatus(e, 'stun', { duration: 0.1 });
|
||||||
|
h.run(0.5);
|
||||||
|
near(strikes(h, e)[1], t1 + BAT + 0.1, 'paused by the stun', 3);
|
||||||
|
done(h);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user