0.2.3: add Clementia and Shu/Ulpianus modules (#437)
Regenerate roster-019, roster-038 and diy-059 through diy-140 for added and regrouped loadouts; other golden families unchanged.
This commit is contained in:
1 parent
62eb113419
commit
2e122873f0
21 files changed
+2940
-2312
No files matched your search
@@ -0,0 +1,114 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { KITS } from '../../server/sim/content/kits/index.js';
|
||||
import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
|
||||
|
||||
const GUAY = 'uniequip_003_shu', CRUY = 'uniequip_003_ulpia';
|
||||
const approx = (a, b) => assert.ok(Math.abs(a - b) < 1e-6, `${a} != ${b}`);
|
||||
const target = enemyRec({ key: 'dummy', hp: 1e8, speed: 0, def: 0, atk: 0 });
|
||||
const war = chessRec({ id: 'war', profession: 'WARRIOR', skill: null, stats: { atk: 100, blockCnt: 0 } });
|
||||
const med = chessRec({ id: 'med', profession: 'MEDIC', skill: null, stats: { atk: 100, blockCnt: 0 } });
|
||||
const helpers = [2, 3, 4].map((uid) => ({ uid, chessId: 'war', row: 10, col: uid }));
|
||||
function shu(tier, others = []) {
|
||||
const h = makeBattle({ defs: { enemies: { dummy: target }, chess: { war, med } }, autoFinish: false,
|
||||
units: [{ uid: 1, diy: { slot: tier, charId: 'char_2025_shu', skillIndex: 2, uniEquipId: GUAY }, elite: true, row: 11, col: 5 }, ...others] });
|
||||
h.step(); return { h, u: h.unit(1) };
|
||||
}
|
||||
|
||||
test('黍 GUA-Y stage 1/3 reduces incoming damage by 15%, independently of HP, after deployment', () => {
|
||||
for (const tier of [5, 6]) {
|
||||
const { h, u } = shu(tier);
|
||||
approx(u.s.dmgTakenMul, 0.85);
|
||||
const e = h.spawn('dummy', { pos: [10, 9] });
|
||||
const hp = u.hp;
|
||||
h.b.dealDamage(e, u, { amount: 100, type: 'true' });
|
||||
approx(hp - u.hp, 85);
|
||||
const hp2 = u.hp;
|
||||
h.b.dealDamage(e, u, { amount: 100, type: 'elemental' });
|
||||
approx(hp2 - u.hp, 100);
|
||||
checkInvariants(h.b); assert.equal(h.b.errors.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
test('黍 GUA-Y stage 3 requires two conditions, buffs each operator once, and drops the bonus when a condition ends', () => {
|
||||
for (const tier of [5, 6]) {
|
||||
const { h, u } = shu(tier, [...helpers, { uid: 5, chessId: 'med', row: 9, col: 3 }]);
|
||||
h.run(0.3);
|
||||
const a = h.unit(2);
|
||||
approx(a.s.atk / a.base.atk, tier === 6 ? 1.05 : 1);
|
||||
assert.equal(a.s.aspd, tier === 6 ? 116 : 112);
|
||||
h.b.retreat(h.unit(5), { permanent: true });
|
||||
h.run(0.7);
|
||||
approx(a.s.atk / a.base.atk, 1);
|
||||
assert.equal(u.s.aspd, tier === 6 ? 116 : 112);
|
||||
checkInvariants(h.b); assert.equal(h.b.errors.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
function ulpia({ moduleId = CRUY, potential = 6, stage3 = false } = {}) {
|
||||
// The mode's tier-5 elite only exposes module stage 1. Exercise its stage-3 talent separately using the
|
||||
// official CRU-Y blackboard (battle_equip_table, 2026-10-09); do not change the production slot's module level.
|
||||
const kits = stage3 ? { chess_char_5_05_a: (bb, raw, def) => {
|
||||
const rec = structuredClone(raw);
|
||||
rec.talents.find((t) => t.index === 1).bb = {
|
||||
max_stack_cnt: potential === 6 ? 10 : 9, max_hp: 150, atk: 38,
|
||||
'ulpia_t_1[abyssal].max_hp': 90, 'ulpia_t_1[abyssal].atk': 22.799999,
|
||||
'ulpia_t_1[abyssal].max_stack_cnt': potential === 6 ? 10 : 9,
|
||||
block_cnt: 1, add_block_cnt_stack_cnt: 9,
|
||||
};
|
||||
return KITS.chess_char_5_05_a(bb, rec, def);
|
||||
} } : undefined;
|
||||
const h = makeBattle({ autoFinish: false, kits, defs: { enemies: { dummy: target, victim: enemyRec({ key: 'victim', hp: 1, atk: 0, speed: 0 }) } },
|
||||
units: [{ uid: 1, chessId: 'chess_char_5_05_b', row: 10, col: 5, moduleId, skillIndex: 0, potential },
|
||||
{ uid: 2, chessId: 'chess_char_3_05_a', row: 11, col: 5 },
|
||||
{ uid: 3, chessId: 'chess_char_1_01_a', row: 9, col: 5 }] });
|
||||
h.step(); return { h, u: h.unit(1), hunter: h.unit(2), other: h.unit(3) };
|
||||
}
|
||||
|
||||
test('乌尔比安 CRU-Y scales damage against enemies blocked by any ally, including skill damage', () => {
|
||||
const { h, u, hunter } = ulpia();
|
||||
const e = h.spawn('dummy', { pos: [10, 7] });
|
||||
const amount = () => h.b.dealDamage(u, e, { amount: 100, type: 'phys', isSkill: true });
|
||||
approx(amount(), 100);
|
||||
e.blockedBy = hunter; hunter.blocking.push(e);
|
||||
approx(amount(), 110);
|
||||
e.blockedBy = null; hunter.blocking.length = 0;
|
||||
checkInvariants(h.b); assert.equal(h.b.errors.length, 0);
|
||||
});
|
||||
|
||||
test('乌尔比安 CRU-Y hunters share kill stacks; block +1 at nine, potential cap ten, other operators do not trigger it', () => {
|
||||
for (const potential of [1, 6]) {
|
||||
const { h, u, hunter, other } = ulpia({ potential, stage3: true });
|
||||
const kill = (killer) => h.b.dealDamage(killer, h.spawn('victim', { pos: [10, 8] }), { amount: 100, type: 'true' });
|
||||
kill(other); assert.equal(u.findBuff('ulpia:blood'), null);
|
||||
const block = u.s.blockCnt;
|
||||
for (let n = 1; n <= 12; n++) {
|
||||
kill(hunter);
|
||||
assert.equal(u.findBuff('ulpia:blood')?.stacks, Math.min(n, potential === 6 ? 10 : 9));
|
||||
assert.equal(u.s.blockCnt, block + (n >= 9 ? 1 : 0));
|
||||
}
|
||||
assert.ok(hunter.findBuff('ulpia:bloodShare'));
|
||||
checkInvariants(h.b); assert.equal(h.b.errors.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
test('乌尔比安 without the new module still only gains stacks from his own kills', () => {
|
||||
const { h, u, hunter } = ulpia({ moduleId: 'none' });
|
||||
h.b.dealDamage(hunter, h.spawn('victim', { pos: [10, 8] }), { amount: 100, type: 'true' });
|
||||
assert.equal(u.findBuff('ulpia:blood'), null);
|
||||
h.b.dealDamage(u, h.spawn('victim', { pos: [10, 8] }), { amount: 100, type: 'true' });
|
||||
assert.equal(u.findBuff('ulpia:blood').stacks, 1);
|
||||
checkInvariants(h.b); assert.equal(h.b.errors.length, 0);
|
||||
});
|
||||
|
||||
|
||||
test('乌尔比安 CRU-Y counts a withdrawn hunter’s delayed credited kill only while Ulpianus is deployed', () => {
|
||||
const { h, u, hunter } = ulpia({ stage3: true });
|
||||
h.b.retreat(hunter, { permanent: true });
|
||||
h.b.dealDamage(hunter, h.spawn('victim', { pos: [10, 8] }), { amount: 100, type: 'true' });
|
||||
assert.equal(u.findBuff('ulpia:blood')?.stacks, 1);
|
||||
h.b.retreat(u, { permanent: true });
|
||||
h.b.dealDamage(hunter, h.spawn('victim', { pos: [10, 8] }), { amount: 100, type: 'true' });
|
||||
assert.ok((u.findBuff('ulpia:blood')?.stacks ?? 0) <= 1);
|
||||
checkInvariants(h.b); assert.deepEqual(h.b.errors, []);
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
|
||||
import { KITTED_CHARS } from '../../server/sim/content/kits/index.js';
|
||||
import { diyPool } from '../../shared/diy.js';
|
||||
import { performAttack, effectiveProfile } from '../../server/sim/ai.js';
|
||||
const C = 'char_4231_clemnt';
|
||||
const data = Object.fromEntries(['chess', 'backups'].map((f) => [f, JSON.parse(readFileSync(new URL(`../../data/${f}.json`, import.meta.url)))]));
|
||||
const approx = (a, b, label = '') => assert.ok(Math.abs(a - b) < 1e-5 * Math.max(1, Math.abs(b)), `${label}: ${a} != ${b}`);
|
||||
const enemy = (key, opts = {}) => enemyRec({ key, hp: 1e8, atk: 0, speed: 0, ...opts });
|
||||
const defs = { enemies: { dummy: enemy('dummy'), light: enemy('light', { mass: 3 }), heavy: enemy('heavy', { mass: 9 }),
|
||||
fly: enemy('fly', { motion: 'FLY' }), zero: enemy('zero', { mass: 0 }), armored: enemy('armored', { def: 100 }) } };
|
||||
function field({ tier = 6, elite = true, skill = 0, potential = 6, dir = 'RIGHT', row = 10, col = 3 } = {}) {
|
||||
const h = makeBattle({ seed: 23, autoFinish: false, timeLimit: 180, defs,
|
||||
hooks: ['damaged', 'attack', 'elementBurst', 'ammoUsed'], captureNoisy: true,
|
||||
units: [{ uid: 1, diy: { slot: tier, charId: C, skillIndex: skill }, elite, potential, row, col, dir }] });
|
||||
h.step(); return { h, u: h.unit(1) };
|
||||
}
|
||||
function done(h) { checkInvariants(h.b); assert.deepEqual(h.b.errors, []); }
|
||||
function start(u) { u.skill.gainSp(999, 'init'); assert.equal(u.skill.activate('test'), true); }
|
||||
const hits = (h, tag) => h.hooksOf('damaged').filter((c) => c.dmg?.tags?.includes(tag));
|
||||
|
||||
test('克莱门莎 is selectable with authored skills in both slots, every form and potential', () => {
|
||||
assert.ok(KITTED_CHARS.includes(C));
|
||||
for (const tier of [5, 6]) {
|
||||
assert.ok(diyPool(tier, { data, kitted: KITTED_CHARS }).includes(C));
|
||||
for (const elite of [false, true]) for (const skill of [0, 1, 2]) for (const potential of [1, 6]) {
|
||||
const { h, u } = field({ tier, elite, skill, potential });
|
||||
assert.equal(u.def.charId, C); assert.equal(u.kit.skillSource, 'skills'); assert.ok(!u.kit.generic);
|
||||
assert.equal(u.skill.id, `skchr_clemnt_${skill + 1}`);
|
||||
assert.deepEqual([u.profile.dmgType, u.profile.canHitFly, u.s.blockCnt, u.base.bat], ['phys', false, 2, 1.2]);
|
||||
assert.ok(u.def.bonds.includes('egirShip'));
|
||||
assert.equal(u.skill.rule, skill ? 'ACTIVE_RANGE' : 'DEFAULT');
|
||||
done(h);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('生死定夺 checks current versus initial DEF for each physical hit; scales before DEF, never elemental damage', () => {
|
||||
for (const potential of [1, 3, 6]) {
|
||||
const { h, u } = field({ potential });
|
||||
const e = h.spawn('armored', { pos: [10, 6] }); h.b.rng = () => 0.3;
|
||||
approx(h.b.dealDamage(u, e, { amount: 1000, type: 'phys' }), 900);
|
||||
h.b.addBuff(e, { key: 'test:def', mods: { defFlat: -50 } });
|
||||
approx(h.b.dealDamage(u, e, { amount: 1000, type: 'phys' }), 1000 * (potential >= 3 ? 1.5 : 1.35) - 50);
|
||||
approx(h.b.dealDamage(u, e, { amount: 1000, type: 'elemental' }), 1000);
|
||||
const z = h.spawn('dummy', { pos: [10, 7] }); h.b.addBuff(z, { key: 'test:def', mods: { defFlat: -50 } });
|
||||
approx(h.b.dealDamage(u, z, { amount: 1000, type: 'phys' }), 1000);
|
||||
done(h);
|
||||
}
|
||||
});
|
||||
|
||||
test('习得性防御 handles all facings, boundary tiles, blocked enemies, seamonsters, and damage types', () => {
|
||||
for (const dir of ['RIGHT', 'LEFT', 'UP', 'DOWN']) {
|
||||
const { h, u } = field({ dir, col: 5 });
|
||||
const e = h.spawn('dummy', { pos: [10, 5] });
|
||||
const take = (type = 'arts') => { u.hp = u.s.maxHp; return h.b.dealDamage(e, u, { amount: 100, type }); };
|
||||
approx(take(), 100 * 0.9 * 0.65); // same tile/column belongs to the forward half-plane
|
||||
const [dr, dc] = { RIGHT: [0, 1], LEFT: [0, -1], UP: [1, 0], DOWN: [-1, 0] }[dir];
|
||||
e.x = 5 - dc; e.y = 10 - dr; approx(take(), 90);
|
||||
e.blockedBy = u; u.blocking.push(e); approx(take(), 90 * 0.65);
|
||||
e.def = { ...e.def, tags: ['seamonster'] }; approx(take(), 90 * 0.45);
|
||||
approx(take('true'), 100); approx(take('elemental'), 100);
|
||||
e.blockedBy = null; u.blocking.length = 0; done(h);
|
||||
}
|
||||
});
|
||||
|
||||
test('冲蚀 is every fourth attack and fills erosion from actual post-mitigation damage, with no air target', () => {
|
||||
for (const elite of [false, true]) {
|
||||
const { h, u } = field({ elite }); const e = h.spawn('dummy', { pos: [10, 4] }); h.b.rng = () => 0.99;
|
||||
h.run(5);
|
||||
const dealt = h.hooksOf('damaged').filter((c) => c.source === u && c.dmg.isAttack);
|
||||
assert.ok(dealt.length >= 4);
|
||||
dealt.forEach((c, i) => assert.equal(c.dmg.isSkill, i % 4 === 3));
|
||||
const r = hits(h, 'clemnt:rider'); assert.ok(r.length > 0);
|
||||
const first = dealt.find((c) => c.dmg.isSkill);
|
||||
approx(r[0].amount, first.amount * (elite ? 0.3 : 0.25));
|
||||
assert.ok(e.elem.erosion > 0); done(h);
|
||||
}
|
||||
});
|
||||
|
||||
test('风暴潮 carries at most eight total weight, excludes flyers/self-bound enemies and releases after three tiles', () => {
|
||||
const { h, u } = field({ skill: 1 });
|
||||
const es = [0, 1, 2].map(() => h.spawn('light', { pos: [10, 4] }));
|
||||
const heavy = h.spawn('heavy', { pos: [10, 4] }), fly = h.spawn('fly', { pos: [10, 4] });
|
||||
const bound = h.spawn('zero', { pos: [10, 4] }); h.b.addBuff(bound, { key: 'test:bound', flags: { selfBound: true, noMove: true } });
|
||||
start(u); assert.ok(u.s.flags.disarm); h.run(0.7);
|
||||
assert.equal(u.mem.clemntCabin.passengers.length, 2);
|
||||
assert.equal(u.mem.clemntCabin.mass, 2);
|
||||
assert.ok(es[0].s.flags.unblockable && es[0].s.flags.disarm);
|
||||
for (const e of [heavy, fly, bound]) assert.ok(!u.mem.clemntCabin.passengers.includes(e));
|
||||
h.run(0.9); assert.ok(u.mem.clemntCabin.stopped); approx(u.mem.clemntCabin.x, 6);
|
||||
assert.ok(!u.s.flags.disarm); assert.ok(!es[0].s.flags.unblockable);
|
||||
approx(es[0].x, 6); done(h);
|
||||
});
|
||||
|
||||
test('风暴潮 caps passengers at fifteen and cleans them on early skill end', () => {
|
||||
const { h, u } = field({ skill: 1 });
|
||||
for (let n = 0; n < 20; n++) h.spawn('zero', { pos: [10, 4] });
|
||||
start(u); h.run(0.4); assert.equal(u.mem.clemntCabin.passengers.length, 15);
|
||||
const es = [...u.mem.clemntCabin.passengers]; u.skill.stop();
|
||||
assert.ok(es.every((e) => !e.s.flags.disarm && !e.s.flags.unblockable && !e.s.flags.noMove));
|
||||
assert.equal(u.mem.clemntCabin, null); done(h);
|
||||
});
|
||||
|
||||
test('风暴潮 stops before a blocked tile; vortex keeps its continuous stop point, hits air and applies normal erosion resistance', () => {
|
||||
const { h, u } = field({ skill: 1 }); h.b.grid.setObstacle(10, 5, true);
|
||||
const fly = h.spawn('fly', { pos: [10, 5.55] });
|
||||
fly.def = { ...fly.def, epResistance: 99 };
|
||||
start(u); h.run(0.7); assert.ok(u.mem.clemntCabin.stopped);
|
||||
approx(u.mem.clemntCabin.x, 4.1); h.run(1.1);
|
||||
approx(fly.findBuff(`clemnt:vortex:${u.id}`).mods.moveMul, 0.3); approx(fly.elem.erosion, 10); // damage formula's 5% floor at 99 resistance
|
||||
assert.ok(hits(h, 'clemnt:vortex').some((c) => c.target === fly)); done(h);
|
||||
});
|
||||
|
||||
test('风暴潮 normal attack hits five ground enemies in total, never all neighbours or a flyer', () => {
|
||||
const { h, u } = field({ skill: 1 }); start(u); h.run(1.6);
|
||||
const es = Array.from({ length: 9 }, () => h.spawn('heavy', { pos: [10, 4] }));
|
||||
const fly = h.spawn('fly', { pos: [10, 4] });
|
||||
const before = h.hooksOf('damaged').length;
|
||||
performAttack(h.b, u, effectiveProfile(u), [es[0]]);
|
||||
const victims = new Set(h.hooksOf('damaged').slice(before).filter((c) => c.dmg.isAttack).map((c) => c.target));
|
||||
assert.equal(victims.size, 5); assert.ok(!victims.has(fly)); done(h);
|
||||
});
|
||||
|
||||
test('与海为敌 normal attacks hit three and spend no ammunition; remote erosion bursts fire three cross-shaped mixed hits', () => {
|
||||
const { h, u } = field({ skill: 2 }); start(u); h.b.rng = () => 0.99;
|
||||
const close = Array.from({ length: 3 }, () => h.spawn('dummy', { pos: [10, 4] }));
|
||||
performAttack(h.b, u, effectiveProfile(u), close);
|
||||
assert.equal(u.skill.ammoLeft, 10);
|
||||
const remote = h.spawn('dummy', { pos: [11, 9] }), near = h.spawn('dummy', { pos: [12, 9] });
|
||||
const diagonal = h.spawn('dummy', { pos: [12, 8] }), fly = h.spawn('fly', { pos: [11, 9] });
|
||||
h.b.dealDamage(u, remote, { amount: 1000, type: 'element', element: 'erosion' }); h.step();
|
||||
assert.equal(u.skill.ammoLeft, 9); u.skill.stop(); h.run(2.6);
|
||||
const bombs = hits(h, 'clemnt:bomb');
|
||||
for (const e of [remote, near]) {
|
||||
assert.equal(bombs.filter((c) => c.target === e && c.type === 'phys').length, 3);
|
||||
assert.equal(bombs.filter((c) => c.target === e && c.type === 'elemental').length, 3);
|
||||
}
|
||||
assert.ok(!bombs.some((c) => c.target === diagonal || c.target === fly)); done(h);
|
||||
});
|
||||
|
||||
test('与海为敌 selects nearest marked enemy, suppresses duplicate bombing tiles and does not mark air or sleeping units', () => {
|
||||
const { h, u } = field({ skill: 2 }); start(u);
|
||||
const far = h.spawn('dummy', { pos: [12, 9] }), near = h.spawn('dummy', { pos: [11, 7] });
|
||||
const same = h.spawn('dummy', { pos: [11, 7] }), fly = h.spawn('fly', { pos: [11, 8] });
|
||||
const asleep = h.spawn('dummy', { pos: [11, 6] }); h.b.applyStatus(asleep, 'sleep', { duration: 5 });
|
||||
for (const target of [far, near, same, fly, asleep]) h.b.emit('elementBurst', { source: null, target, element: 'erosion' });
|
||||
h.step(); assert.equal(u.skill.ammoLeft, 9); assert.ok(!u.mem.clemntBombs.marks.has(near));
|
||||
h.step(); assert.equal(u.skill.ammoLeft, 8); assert.ok(!u.mem.clemntBombs.marks.has(far));
|
||||
h.run(1.1); assert.equal(u.skill.ammoLeft, 8); assert.equal(u.mem.clemntBombs.marks.size, 0); done(h);
|
||||
});
|
||||
+2331
-2276
File diff suppressed because it is too large.
Load diff
+18
-18
@@ -1268,7 +1268,7 @@
|
||||
["p1",1,"op","chess_char_6_15_b",2,"uniequip_002_qiubai",5829.12,1,112,25,817580,42480,0,168,3],
|
||||
["p1",2,"op","chess_char_6_19_b",2,"uniequip_002_blkkgt",6696.14,1,9,5,198720,778,0,1,3],
|
||||
["p1",3,"op","chess_char_5_01_b",0,"uniequip_003_excu2",5521.67,1,10,0,11795,1147,300,4,0],
|
||||
["p1",4,"op","chess_char_5_05_b",0,"none",14096.5,1,7,0,0,0,0,0,0],
|
||||
["p1",4,"op","chess_char_5_05_b",0,"uniequip_003_ulpia",14967.7,1,7,0,0,0,0,0,0],
|
||||
["p1",5,"op","chess_char_6_17_b",2,"uniequip_002_nearl2",11659.29,1,24,21,474273,37335,0,107,3],
|
||||
["p1",6,"op","chess_char_6_13_b",1,"uniequip_002_angel2",5306.7,1,2,29,663495,11646,1190,58,2],
|
||||
["p1",7,"op","chess_char_6_14_b",2,"uniequip_002_lumen",4595.58,1,3,0,0,0,7779,76,1],
|
||||
@@ -1300,7 +1300,7 @@
|
||||
"hooks": [1,126,6021,786,786,2560,2883,573,109,114,28,25,56,20899,1618,75,108,0,1,109,2,0,0],
|
||||
"events": {"atk":1154,"bounty":6,"deploy":18,"die":114,"dmg":2673,"engage":10,"fx":534,"heal":437,"layer":2,"skill":53,"spawn":123,"status":429},
|
||||
"fx": {"airstrike":20,"aoe":9,"beam":26,"blink":2,"bombard":10,"bombardShell":10,"displace":5,"drone":347,"droneLock":57,"drones":3,"extraAttack":1,"finale":3,"garrison":2,"garrisonGrant":1,"link":10,"radiantSword":3,"slash":16,"steal":2,"summon":3,"sunBurst":1,"talent":3},
|
||||
"snaps": "f9e8faee dbe9b906 db6668e1 9b5d83f7 5ac11fea 257f514d 05c46f29 1991dd95 e806a918 38314f7b da515ea3 607236ee 6d03ef88 c5df95b9 3ac0270d 6bbc6ea8 183d1208 3638569e 0a132e83 38d98641"
|
||||
"snaps": "3bc002dc 99924baa b4e5485c 4572877f 2e5abf56 ab533660 d4f12dd4 7d0ce564 75b173a1 2daf77c4 765fb557 a2f4c5bd 0987ab99 45c06b00 2b52eba1 20bb7c71 b8fb29bd 6b0755df 1ac95c1e f2a7e61b"
|
||||
},
|
||||
"roster-020": {
|
||||
"about": "pass 1 band 1: chess_char_1_02_a chess_char_1_04_a chess_char_1_10_a chess_char_1_08_a chess_char_1_12_a chess_char_1_01_a chess_char_1_03_a chess_char_1_06_a chess_char_1_07_a chess_char_1_09_a chess_char_1_13_a chess_char_1_14_a",
|
||||
@@ -2358,41 +2358,41 @@
|
||||
"total": 157,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 49,
|
||||
"rngDraws": 45,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":157,"total":157,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":3467715,"bossDmg":0,"heal":72149,"deaths":2,"layerGains":{"raidShip":22}}
|
||||
"p1": {"killed":157,"total":157,"perfect":true,"leaks":0,"leaksUncounted":0,"coins":8,"dmg":3467641,"bossDmg":0,"heal":73044,"deaths":2,"layerGains":{"raidShip":22}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_5_08_b",1,"none",3052.5,1,2,18,392758,0,0,62,4],
|
||||
["p1",1,"op","chess_char_5_08_b",1,"none",3052.5,1,2,19,393842,0,0,62,4],
|
||||
["p1",2,"op","chess_char_6_19_b",0,"uniequip_003_blkkgt",5230.39,1,4,0,0,0,0,0,0],
|
||||
["p1",3,"op","chess_char_5_01_b",2,"none",2545.4,1,6,0,2613,0,0,2,0],
|
||||
["p1",4,"op","chess_char_5_05_b",1,"uniequip_002_ulpia",11326.7,1,7,11,138379,2934,360,24,1],
|
||||
["p1",5,"op","chess_char_5_06_b",1,"none",4121.7,1,8,110,2367402,24698,24698,110,8],
|
||||
["p1",4,"op","chess_char_5_05_b",1,"none",9477.62,1,7,9,113120,4230,480,20,1],
|
||||
["p1",5,"op","chess_char_5_06_b",1,"none",4121.7,1,8,107,2385886,24107,24107,110,8],
|
||||
["p1",6,"op","chess_char_6_17_b",0,"uniequip_003_nearl2",0,0,101,3,91899,9619,0,53,1],
|
||||
["p1",7,"op","chess_char_5_07_b",1,"none",3183.84,1,12,7,257729,44385,0,153,6],
|
||||
["p1",8,"op","chess_char_6_18_b",0,"none",1640.63,1,9,2,97475,0,0,149,1],
|
||||
["p1",9,"op","chess_char_6_20_b",0,"uniequip_003_agoat2",1628.75,1,10,0,0,0,44385,53,1],
|
||||
["p1",10,"op","chess_char_5_02_b",1,"uniequip_002_titi",1582.9,1,1,4,91179,0,2705,2,1],
|
||||
["p1",7,"op","chess_char_5_07_b",1,"none",3183.84,1,12,8,256736,45687,0,153,6],
|
||||
["p1",8,"op","chess_char_6_18_b",0,"none",1640.63,1,9,4,106163,0,0,149,1],
|
||||
["p1",9,"op","chess_char_6_20_b",0,"uniequip_003_agoat2",1628.75,1,10,0,0,0,45687,54,1],
|
||||
["p1",10,"op","chess_char_5_02_b",1,"uniequip_002_titi",1582.9,1,1,4,91738,0,2770,2,1],
|
||||
["p1",11,"op","chess_char_5_03_b",1,"none",1538.24,1,3,0,2310,162,0,2,1],
|
||||
["p1",12,"op","chess_char_5_10_b",1,"none",1518,1,5,1,25972,0,0,26,1]
|
||||
["p1",12,"op","chess_char_5_10_b",1,"none",1518,1,5,2,23335,0,0,23,1]
|
||||
],
|
||||
"enemies": {
|
||||
"enemy_1006_shield_3": [1,1,0,2931,143327],
|
||||
"enemy_1021_bslime": [1,1,0,3065,8815],
|
||||
"enemy_1148_dssbr_2": [1,1,0,0,12899],
|
||||
"enemy_1198_msfshu_2": [1,1,0,0,6],
|
||||
"enemy_1249_lysdb_2": [60,60,0,21415,1289945],
|
||||
"enemy_1251_lysyta": [51,51,0,2559,502541],
|
||||
"enemy_1249_lysdb_2": [60,60,0,20261,1289945],
|
||||
"enemy_1251_lysyta": [51,51,0,2355,502541],
|
||||
"enemy_1270_nhstlk": [1,1,0,2036,42998],
|
||||
"enemy_1329_cbshld": [39,39,0,46534,1397441],
|
||||
"enemy_1329_cbshld": [39,39,0,49898,1397441],
|
||||
"enemy_1389_winbab_2": [1,1,0,3097,25082],
|
||||
"enemy_2001_duckmi": [1,1,0,0,64497]
|
||||
},
|
||||
"hooks": [1,170,5944,770,768,3800,3743,575,159,159,25,20,40,15978,678,88,157,0,1,161,2,0,0],
|
||||
"events": {"atk":1152,"bounty":4,"deploy":13,"die":159,"dmg":3743,"engage":10,"fx":97,"heal":493,"layer":2,"skill":45,"spawn":169,"status":197},
|
||||
"hooks": [1,170,5944,764,762,3820,3763,578,159,159,25,20,40,15978,683,89,157,0,1,161,2,0,0],
|
||||
"events": {"atk":1149,"bounty":4,"deploy":13,"die":159,"dmg":3763,"engage":10,"fx":97,"heal":485,"layer":2,"skill":45,"spawn":169,"status":182},
|
||||
"fx": {"aoe":16,"explode":1,"garrison":2,"garrisonGrant":4,"overload":4,"reborn":1,"shieldBreak":60,"sleepGuard":1,"sunBurst":3,"talent":3,"undying":2},
|
||||
"snaps": "38ebdad4 4c56ab84 28991e1c d38e3ca9 a93fad01 78000e59 91035db7 97f82a70 314dbacf 171d41e5 77caf838 e9196e88 52b40b0e 302ec2b7 47b6a52c c639db96 51cb55bb 433ac4c3 d5827da5 868f9d65"
|
||||
"snaps": "2c013a42 e0a9d456 d93eb576 5f4d92f3 a5a0ebec 5214a5e1 27d57a43 91a4904c 9fca4890 d12b72df 7c44ce37 e62d1865 3d9a4fd9 350839a2 4e7c68e2 8dfe6cd9 9f96036b b28d664a 33c769dc 3d835553"
|
||||
},
|
||||
"roster-039": {
|
||||
"about": "pass 2 band 4: chess_char_3_12_a chess_char_3_12_b chess_char_3_18_a chess_char_3_18_b chess_char_3_04_a chess_char_3_05_a chess_char_3_04_b chess_char_3_05_b chess_char_3_01_a chess_char_3_19_a chess_char_3_21_a chess_char_3_01_b token_10028_vigil_wolf",
|
||||
|
||||
Reference in new issue
Block a user