diff --git a/server/sim/content/kits/ops/chess_char_4_18-mudrok.js b/server/sim/content/kits/ops/chess_char_4_18-mudrok.js index 385fdd38..5d4c543e 100644 --- a/server/sim/content/kits/ops/chess_char_4_18-mudrok.js +++ b/server/sim/content/kits/ops/chess_char_4_18-mudrok.js @@ -8,10 +8,12 @@ import { export default withDefaults({ // ===== 泥岩 (unyield) S2 岩崩锤 — next attack: heal 4 %, 190 % phys to all ground enemies around, 30 % stun; talents - // S1 防御力强化·γ型 (TAKE_DAMAGE); S3 秽壤的血脉 (10 s dormant — cannot act, takes no damage, keeps blocking — - // with enemies around −60 % speed; then ground enemies around stunned 3 s/3.5 s and for the rest of the skill - // BAT −0.3 s, ATK/DEF up, attacks every blocked enemy); module UNY-Y (沃土的愿景): ATK/DEF +8 % with no ally - // on the 8 tiles around + // S1 防御力强化·γ型 (TAKE_DAMAGE); S3 秽壤的血脉 (10 s dormant — PRTS 备注 "实际将会进入闭锁状态": 闭锁 = 强制缴械 + + // 无敌 + 不可阻挡 (PRTS 异常效果: SHELTERING; 不可阻挡 BLOCK_FREE "无法阻挡/被阻挡,自动解除阻挡") — she makes no attack, + // takes no damage and blocks nobody: the enemies she held walk on (flag noBlock — "keeps blocking" until 0.2.0 + // WV); the 备注's 眩晕 / 冻结 / 沉默 反制 are not modelled — with enemies around −60 % speed; then ground + // enemies around stunned 3 s/3.5 s and for the rest of the skill BAT −0.3 s, ATK/DEF up, attacks every blocked + // enemy); module UNY-Y (沃土的愿景): ATK/DEF +8 % with no ally on the 8 tiles around chess_char_4_18_a: (bb, chess, def) => { const t0 = tbb(def, 0), t1 = tbb(def, 1); const tb = def.traitBb || {}; @@ -25,7 +27,8 @@ export default withDefaults({ attack: { hitAllBlocked: true }, onStart({ battle, unit }) { unit.mem.mudS3 = { awake: false, t: 0 }; - battle.addBuff(unit, { key: 'mudrok:dormant', duration: sleep + 1, flags: { invulnerable: true, disarm: true }, visible: true }); + // 闭锁: 强制缴械 + 无敌 + 不可阻挡 (her blocked enemies are released: ai.js lets go of a noBlock blocker) + battle.addBuff(unit, { key: 'mudrok:dormant', duration: sleep + 1, flags: { invulnerable: true, disarm: true, noBlock: true }, visible: true }); battle.fx('stone', { x: unit.x, y: unit.y, id: unit.id }); }, onTick({ battle, unit, dt }) { diff --git a/test/content/kits_alt_t4.test.js b/test/content/kits_alt_t4.test.js index cefe7062..a9cb69d7 100644 --- a/test/content/kits_alt_t4.test.js +++ b/test/content/kits_alt_t4.test.js @@ -797,7 +797,7 @@ test('星熊 module PRO-X 护身符: DEF +20 % while blocking', () => { approx(def(null, true), def(null, false), 1e-9); }); -test('泥岩 S1 防御力强化·γ型 (TAKE_DAMAGE) and S3 秽壤的血脉 (dormant & invulnerable & blocking, slow; then stun, buffs, hits all blocked)', () => { +test('泥岩 S1 防御力强化·γ型 (TAKE_DAMAGE) and S3 秽壤的血脉 (闭锁: invulnerable, no attack, blocks nobody — the enemies she held walk on —, slow; then stun, buffs, hits all blocked)', () => { for (const id of pair('chess_char_4_18_a')) { const b1 = D(id, 0).skill.bb, sk = D(id, 2).skill, b3 = sk.bb; let h = battle([U(id, 10, 4, 0)], { enemies: { enemy_hitter: dummy({ key: 'enemy_hitter', atk: 300, bat: 1 }) } }); @@ -812,21 +812,32 @@ test('泥岩 S1 防御力强化·γ型 (TAKE_DAMAGE) and S3 秽壤的血脉 (dor for (let i = 0; i < 3; i++) h.spawn('e_walk', { routeIndex: 0 }); u = h.unit(id); assert.ok(h.runUntil(() => u.blocking.length === 3, 30), 'blocks three walkers'); + const walkers = u.blocking.slice(); const hp0 = u.hp; assert.ok(u.skill.activate('test', { free: true })); const t0 = h.b.time; - h.run(b3.sleep - 1); + h.step(); + // 闭锁 (PRTS 备注 "实际将会进入闭锁状态"; PRTS 异常效果 闭锁 = 强制缴械 + 无敌 + 不可阻挡, 不可阻挡 "无法阻挡/被阻挡,自动解除阻挡") + assert.ok(u.blocking.length === 0 && walkers.every((e) => e.blockedBy !== u), `${id}: 闭锁 lets go of the enemies she held`); + assert.ok(walkers.every((e) => e.findBuff(`mudrok:slow:${u.id}`)), 'enemies around slowed'); + const x0 = walkers.map((e) => e.x); + h.run(1); + assert.ok(walkers.every((e, i) => e.removed || e.x < x0[i] - 0.05), `${id}: they walk on`); + h.run(b3.sleep - 2.5); assert.equal(u.hp >= hp0 - 1e-6, true, `${id}: no damage while dormant`); - assert.equal(u.blocking.length, 3, 'keeps blocking'); + assert.equal(u.blocking.length, 0, `${id}: blocks nobody while dormant`); assert.equal(h.hooksOf('attack').filter((c) => c.attacker === u && c.t > t0).length, 0, 'cannot act'); - assert.ok(u.blocking.every((e) => e.findBuff(`mudrok:slow:${u.id}`)), 'enemies around slowed'); - h.run(1.2); - assert.ok(u.findBuff('mudrok:awake'), 'awake'); - for (const e of u.blocking) assert.ok(e.s.flags.stun, 'ground enemies around stunned'); + const near = [0, 1, 2].map(() => h.spawn('enemy_dummy', { pos: [9, 5] })); // on her tile before she wakes + h.step(); + assert.equal(u.blocking.length, 0, `${id}: not blocked before she wakes`); + assert.ok(h.runUntil(() => !!u.findBuff('mudrok:awake'), 2), 'awake'); + h.run(0.2); + for (const e of near) assert.ok(e.s.flags.stun, 'ground enemies around stunned'); approx(u.s.atk, u.base.atk * (1 + b3.atk) * (u.findBuff('mudrok:module') ? 1 + (u.def.traitBb.atk ?? 0) : 1), 1e-6, 'ATK'); approx(u.s.interval, (u.base.bat + b3.base_attack_time) * 100 / u.s.aspd, 1e-6, 'BAT −0.3 s'); assert.ok(h.runUntil(() => h.hooksOf('attack').some((c) => c.attacker === u && c.t > t0), 5)); assert.equal(h.hooksOf('attack').find((c) => c.attacker === u && c.t > t0).targets.length, 3, 'attacks every blocked enemy'); + assert.ok(h.runUntil(() => u.blocking.length === 3, 4), `${id}: she blocks again once awake (their stun over)`); h.runUntil(() => !u.skill.active, sk.duration); assert.ok(!u.findBuff('mudrok:awake')); checkInvariants(h.b); diff --git a/test/golden/roster.json b/test/golden/roster.json index a27a137f..b2366366 100644 --- a/test/golden/roster.json +++ b/test/golden/roster.json @@ -2460,18 +2460,18 @@ "total": 65, "unspawned": 0, "bossHpLeft": null, - "rngDraws": 299, + "rngDraws": 300, "errors": {"count":0,"kinds":[]}, - "players": {"p1":{"killed":27,"total":65,"perfect":false,"leaks":38,"leaksUncounted":0,"coins":4,"dmg":520678,"bossDmg":0,"heal":2131,"deaths":24,"layerGains":{}}}, + "players": {"p1":{"killed":27,"total":65,"perfect":false,"leaks":38,"leaksUncounted":0,"coins":4,"dmg":532691,"bossDmg":0,"heal":2131,"deaths":24,"layerGains":{}}}, "units": [ - ["p1",1,"op","chess_char_4_01_a",1,null,0,0,3,0,1745,2638,0,25,1], - ["p1",2,"op","chess_char_4_17_a",2,null,0,0,6,0,3603,2849,0,5,1], - ["p1",3,"op","chess_char_4_18_a",2,null,0,0,8,1,13840,3440,573,16,1], + ["p1",1,"op","chess_char_4_01_a",1,null,0,0,3,0,2694,2638,0,47,1], + ["p1",2,"op","chess_char_4_17_a",2,null,0,0,6,0,10584,2849,0,16,1], + ["p1",3,"op","chess_char_4_18_a",2,null,0,0,8,1,15145,3440,573,17,1], ["p1",4,"op","chess_char_4_04_a",2,null,0,0,94,2,31268,7040,0,24,4], ["p1",5,"op","chess_char_4_07_a",2,null,0,0,83,0,6702,7655,0,9,1], ["p1",6,"op","chess_char_4_16_a",1,null,857.6,1,96,3,66532,8961,1097,21,9], ["p1",7,"op","chess_char_4_09_a",2,null,969.81,1,87,0,19950,1702,0,21,1], - ["p1",8,"op","chess_char_3_19_b",1,"none",0,0,4,7,58645,1648,0,68,1], + ["p1",8,"op","chess_char_3_19_b",1,"none",0,0,4,7,61423,1648,0,72,1], ["p1",9,"op","chess_char_3_21_b",1,"uniequip_004_archet",0,0,95,6,166061,3180,0,86,9], ["p1",10,"op","chess_char_4_02_a",1,null,0,0,86,2,57313,2856,0,16,1], ["p1",11,"op","chess_char_4_12_a",1,null,0,0,11,4,37850,2214,460,36,1], @@ -2482,21 +2482,21 @@ ], "enemies": { "enemy_1005_yokai": [24,12,12,0,46985], - "enemy_1005_yokai_2": [27,10,13,8055,87836], - "enemy_1005_yokai_3": [6,1,4,19583,242123], + "enemy_1005_yokai_2": [27,10,13,8037,87836], + "enemy_1005_yokai_3": [6,1,4,18726,244901], "enemy_10065_ftzlc": [1,1,0,0,16339], - "enemy_10162_mnctpt": [1,0,1,7074,47489], + "enemy_10162_mnctpt": [1,0,1,6996,48110], "enemy_1119_vofsd": [1,1,0,170,47298], "enemy_1196_msfyin_2": [1,1,0,0,3], - "enemy_1254_lypa_2": [1,0,1,8330,24869], - "enemy_1367_dseed": [1,0,1,0,1582], + "enemy_1254_lypa_2": [1,0,1,9283,32765], + "enemy_1367_dseed": [1,0,1,0,2300], "enemy_1517_xi": [1,0,1,6203,6145], "enemy_9016_acstmr": [1,1,0,0,8] }, - "hooks": [1,95,5100,608,608,959,992,323,53,86,31,31,15,9466,320,13,65,33,1,63,0,2,21], - "events": {"atk":684,"bounty":2,"deploy":28,"die":53,"dmg":984,"engage":12,"fx":104,"heal":2,"leak":33,"skill":62,"spawn":80,"status":184}, - "fx": {"beam":4,"buff":2,"burst":2,"coldWind":1,"dodge":21,"dp":1,"explode":1,"iceSpike":1,"overclock":1,"overload":1,"palsy":1,"revive":3,"ripple":1,"rockfall":1,"sentry":6,"shadowWeave":14,"shield":7,"shieldBreak":7,"stone":1,"swordStorm":9,"telegraph":3,"volley":9,"wake":1,"wolfShadow":2,"wolfShadowLost":3,"zone":1}, - "snaps": "b82d753d 9cf4ba99 fcad021b 654db731 d77e82d7 9f8f33f9 017d7bbc 96acf49e 6fb2359b 1c86069b 9ddc6975 6ce15810 e8f0b7f7 11dd93da a2b48e05 18e63893 1e4df384" + "hooks": [1,95,5100,640,640,1007,1043,323,53,86,31,31,21,9432,318,15,65,33,1,63,0,2,21], + "events": {"atk":725,"bounty":2,"deploy":28,"die":53,"dmg":1036,"engage":12,"fx":105,"heal":2,"leak":33,"skill":62,"spawn":80,"status":184}, + "fx": {"beam":4,"block":1,"buff":2,"burst":2,"coldWind":1,"dodge":21,"dp":1,"explode":1,"iceSpike":1,"overclock":1,"overload":1,"palsy":1,"revive":3,"ripple":1,"rockfall":1,"sentry":6,"shadowWeave":14,"shield":7,"shieldBreak":7,"stone":1,"swordStorm":9,"telegraph":3,"volley":9,"wake":1,"wolfShadow":2,"wolfShadowLost":3,"zone":1}, + "snaps": "b82d753d 9cf4ba99 fcad021b 654db731 bb6a3dff 378d28e1 47603a0d 144d6b03 599f2544 522197cf 268e0f04 30a6df9f d0f8683b 3c7d6f84 a71a9576 12b08084 610181fa" }, "roster-041": { "about": "pass 2 band 5: chess_char_4_23_a chess_char_4_01_b chess_char_4_19_a chess_char_4_22_a chess_char_4_04_b chess_char_4_07_b chess_char_4_09_b chess_char_4_20_a chess_char_4_24_a chess_char_4_25_a chess_char_4_02_b chess_char_4_12_b",