feedback5 WE1: 武者 trait heal on every damage instance, through 禁疗 (follow-up 1)
PRTS 分支特性信息 武者: "特性治疗于干员每次输出伤害时触发(不局限于攻击)", "通过自身特性/天赋/技能产生的作用于自身的治疗效果会无视 自身的禁疗" (utage_trait / helage_trait / zuole_trait: ON_OUTPUT_DAMAGE); PRTS 异常效果: an abnormal flag is one switch. - professions.js installMushaHeal: one heal of the trait value per damage instance dealt to an enemy, at that instance (every hit of an attack, skill / item / bond damage); a dodged hit, a 流失, an element 损伤 or a talent / DoT damage heals nothing; ignoreHealFree. 收割者 keeps its rule (installReaperHeal) and ignores 禁疗 too (the same PRTS sentence). - 赫拉格's kit: its second-hit heal patch is gone (redundant). 左乐's S1 reads his HP when it fires, before its strike's own heal [ASSUMED]. Golden (diy only): diy-007, diy-008, diy-009 (赫拉格: a multi-target attack heals 70 per target in separate heals instead of one 70 × n heal — HP identical, heal hook / event counts move); diy-033, diy-034, diy-035 (左乐: heals land between his S1 / S2 hits, so his HP-dependent T2 roll, 坚忍 and 庇护 read the healed HP from the second instance on). roster, bonds, fields, matches, standins unchanged (宴 hits once per attack). Tests: test/sim/feedback5-musha-heal.test.js (new, 4); op_helage, op_zuole, kits_t1t2, kits_t5, kits_alt_t5 pass. Docs: SIM.md §Professions.
This commit is contained in:
1 parent
89f730d05c
commit
a7d62b5fc1
6 files changed
+192
-97
No files matched your search
@@ -10,9 +10,8 @@
|
||||
// 属性加成,损失一定比例时达最大加成(同类属性取最高)") and ba.protect 庇护 ("受到的物理和法术伤害降低相应比例(同名效果取最高)"), his
|
||||
// battle skeleton char_188_helage.skel (Skill: two OnAttack, Skill_2: two, Skill_3_Loop: one).
|
||||
// - Trait (武者) "不成为其他角色的治疗目标,每次攻击到敌人后回复自身70生命": the profession default (professions.js `musha`: no
|
||||
// heal from others, value HP per enemy an attack hits), ground-only melee on his 1-1, block 1. The branch heals on every
|
||||
// damage instance he deals: the engine heals once per enemy an attack strikes, so the second hit of S1 / S2's 二连击 on
|
||||
// an enemy heals once more here (the trait's `value`, a self heal).
|
||||
// heal from others, `value` HP on every damage instance he deals — PRTS 分支特性信息 武者 — so the second hit of S1 / S2's
|
||||
// 二连击 heals too), ground-only melee on his 1-1, block 1.
|
||||
// - T1 月盈星亏 "在场时,自身获得最高+100攻击速度的坚忍(损失70%生命值时达到最大加成)": ASPD + min_attack_speed × the share of
|
||||
// the HP lost up to 1 − min_hp_ratio (linear, 坚忍), refreshed every tick. SBL-X stage 3: +130 at 50 % lost (the module
|
||||
// talent change).
|
||||
@@ -90,16 +89,6 @@ export default {
|
||||
} },
|
||||
],
|
||||
install(battle, unit) {
|
||||
// 武者: the trait heal on every damage instance — the engine heals once per enemy an attack strikes, so each further
|
||||
// hit of the same attack on that enemy (S1, S2's 二连击) heals once more
|
||||
battle.on('damaged', (c) => {
|
||||
const d = c.dmg;
|
||||
if (c.source !== unit || !unit.alive || !d || !d.isAttack || !d.attackId || !c.target || c.target.side !== 'enemy') return;
|
||||
const m = unit.mem;
|
||||
if (m.helageAttackId !== d.attackId) { m.helageAttackId = d.attackId; m.helageStruck = new Set(); }
|
||||
if (!m.helageStruck.has(c.target.id)) { m.helageStruck.add(c.target.id); return; }
|
||||
battle.heal(unit, unit, num(unit.profile?.selfHeal, num(tb.value, 70)), { self: true });
|
||||
}, { owner: unit, priority: -10 });
|
||||
// SBL-X “藏锋”: 生命值低于50%时,获得25%的庇护 (physical and arts damage taken)
|
||||
const dr = num(t0.damage_resistance), drBelow = num(t0.hp_ratio);
|
||||
if (dr > 0 && drBelow > 0) {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// `[shield_core]`, `zuole_s_3` / `[shield]`, `zuole_e_002[resistance]`, `zuole_e_003_talent`, `zuole_e_003_trait`);
|
||||
// Arknights Terra Wiki "Zuo Le" (the barrier caps count each skill's own barrier only).
|
||||
// - Trait (武者) "不成为其他角色的治疗目标,每次攻击到敌人后回复自身70生命": the profession default (musha: no heal from
|
||||
// others, `value` per enemy hit; zuole_trait heals on every damage he outputs — the profession heals a normal attack
|
||||
// per target and any other damage per instance, so S1's extra strikes are separate damage instances).
|
||||
// others; zuole_trait heals on every damage he outputs — the profession heals `value` per damage instance, PRTS 分支特性信息
|
||||
// 武者, so S1's extra strikes heal too).
|
||||
// - T1 秉烛照影 "在场时,自身获得最高+50攻击速度和技力自然回复速度+2/秒的坚忍(损失70%生命值时达到最大加成)" (bb
|
||||
// min_attack_speed / min_sp_recovery_per_sec / min_hp_ratio): 坚忍 (ba.berserk "根据已损失的生命值获得相应比例的属性
|
||||
// 加成") — ASPD and SP recovery × min(1, lost HP ÷ (1 − min_hp_ratio)) while he is deployed. SBL-X stage 3: +70 /
|
||||
@@ -29,7 +29,8 @@
|
||||
// not while a 不死 already holds him ("_dontConsumeWhenUndeadable": 坚固维式重锤's window, items/battle.js holdsUndying).
|
||||
// - S1 破虏 (AUTO, 可充能 2 次): the next attack at atk_scale × ATK; "自身生命低于80%时额外攻击1次,低于50%时额外攻击2次"
|
||||
// (hp_ratio_double / hp_ratio_tripple): one / two more strikes on that target at the same scale, separate damage
|
||||
// instances [ASSUMED: the same target — nothing when it fell]. The data's DEFAULT trigger (an AUTO "next attack").
|
||||
// instances [ASSUMED: the same target — nothing when it fell; the HP read when the skill fires, before the strike's
|
||||
// own trait heal]. The data's DEFAULT trigger (an AUTO "next attack").
|
||||
// - S2 行险 (MANUAL, 12 s): "立即流失50%当前生命" (zuole_s_2[shield] DamageViaCurHpRatio, undeadable: never below 1 HP;
|
||||
// a 流失), then a barrier of scale × max HP (ba.barrier "可以吸收一定数值的伤害") added to the one he still has, capped at
|
||||
// max_scale × max HP at each gain (PRTS "上限于每次获取屏障时实时发生变化"; Terra: the cap counts this skill's barrier
|
||||
@@ -96,10 +97,14 @@ export default {
|
||||
skills: {
|
||||
[S1]: {
|
||||
kind: num(s1?.maxChargeTime, 1) > 1 ? 'charges' : 'instant',
|
||||
// the HP that decides the extra strikes: when the skill fires, before its strike lands (the trait heals at each
|
||||
// damage instance — professions.js musha — so after the first strike he would read healed) [ASSUMED]
|
||||
onStart({ unit }) { unit.mem.zuoleS1Hp = unit.hpRatio; },
|
||||
attack: {
|
||||
atkScale: num(b1.atk_scale, 1),
|
||||
onHit({ battle, unit, target }) {
|
||||
const r = unit.hpRatio;
|
||||
const r = unit.mem.zuoleS1Hp ?? unit.hpRatio;
|
||||
unit.mem.zuoleS1Hp = null;
|
||||
const extra = (r < num(b1.hp_ratio_double, 0.8) ? 1 : 0) + (r < num(b1.hp_ratio_tripple, 0.5) ? 1 : 0);
|
||||
for (let i = 0; i < extra && target && target.alive; i++) {
|
||||
battle.dealDamage(unit, target, { amount: unit.s.atk * num(b1.atk_scale, 1), type: 'phys', isSkill: true, tags: ['skill'] });
|
||||
|
||||
+38
-18
@@ -58,26 +58,46 @@ export const PROFESSION_DEFAULTS = Object.freeze({
|
||||
// install helpers (per-unit hooks). All use engine helpers only; tunables come from unit.profile.
|
||||
|
||||
/**
|
||||
* 武者 / 收割者 self-heal ("每次攻击到敌人回复自身50生命"; 收割者 adds "最大生效数等于阻挡数"). Normal attacks arrive as one
|
||||
* 'attack' event whose `targets` are every enemy hit.
|
||||
* 武者 (musha) trait "每次攻击到敌人后回复自身N生命" (bb value) with the branch rules of PRTS 分支特性信息 武者: "特性治疗于干员每次
|
||||
* 输出伤害时触发(不局限于攻击)" and "常态持有禁疗;通过自身特性/天赋/技能产生的作用于自身的治疗效果会无视自身的禁疗". The official
|
||||
* trait buffs (buff_template_data `utage_trait`, `helage_trait`, `zuole_trait`) fire on ON_OUTPUT_DAMAGE: one heal per damage
|
||||
* instance the unit deals to an enemy — every hit of a normal attack (the second hit of a double strike, a splash or
|
||||
* chain victim) and every skill / item / bond damage instance credited to it; a dodged hit deals none (no `damaged`).
|
||||
* Not a 流失 (no damage dealt), not an element 损伤 (a gauge fill, no HP damage — as 咒愈师), not a buff-made damage
|
||||
* (talent / DoT tags: attackType BUFF — [ASSUMED] as before; only 隐德来希's template filters it and no 武者 kit deals such
|
||||
* damage). The heal ignores 禁疗 (`ignoreHealFree`: an abnormal flag is one switch whoever set it — PRTS 异常效果).
|
||||
*/
|
||||
const installMushaHeal = (battle, unit) => {
|
||||
battle.on('damaged', (c) => {
|
||||
if (c.source !== unit || !unit.alive || !c.target || c.target.side !== 'enemy') return;
|
||||
const dmg = c.dmg;
|
||||
if (!dmg || isHpLoss(dmg) || c.type === 'element') return;
|
||||
const tags = dmg.tags || [];
|
||||
if (tags.includes('talent') || tags.includes('dot') || tags.includes('periodic')) return;
|
||||
battle.heal(unit, unit, unit.profile.selfHeal ?? 50, { self: true, ignoreHealFree: true });
|
||||
}, { owner: unit, priority: -10 });
|
||||
};
|
||||
|
||||
/**
|
||||
* 收割者 (reaper) self-heal ("每次攻击到敌人回复自身50生命,最大生效数等于阻挡数"). Normal attacks arrive as one 'attack' event
|
||||
* whose `targets` are every enemy hit.
|
||||
*
|
||||
* The official trait is a buff ON the operator that fires on ON_OUTPUT_DAMAGE — buff_template_data `etlchi_trait`,
|
||||
* `excu2_trait`, `utage_trait`, `helage_trait`, `zuole_trait` all react to any damage the unit outputs, and 隐德来希's
|
||||
* filters the attackType BUFF out (damage produced by a buff/talent — e.g. her own 萃血 DoT). So skill damage heals too:
|
||||
* 隐德来希's S2 blood sickles restore her life although the skill stops her attacks (`attack: { noAttack: true }`) — the
|
||||
* sickle's AOEDamage nodes are attackType NORMAL and PRTS 备注 says "伤害来源始终视为隐德来希". Every such hit arrives as
|
||||
* one 'damaged' event per enemy, so the reaper cap ("最大生效数") is applied per instant here: the official `[heal_fake]`
|
||||
* window is 0.05 s and its stack count is the block number (`SetStackCountViaBlockNum`). [ASSUMED] the sim uses the same
|
||||
* `battle.time` as its window, so simultaneous hits (both 血镰, an AoE) share the block-count cap; a normal attack has its
|
||||
* own event and its own cap, as before.
|
||||
* `excu2_trait` react to any damage the unit outputs, and 隐德来希's filters the attackType BUFF out (damage produced by a
|
||||
* buff/talent — e.g. her own 萃血 DoT). So skill damage heals too: 隐德来希's S2 blood sickles restore her life although the
|
||||
* skill stops her attacks (`attack: { noAttack: true }`) — the sickle's AOEDamage nodes are attackType NORMAL and PRTS 备注
|
||||
* says "伤害来源始终视为隐德来希". Every such hit arrives as one 'damaged' event per enemy, so the reaper cap ("最大生效数") is
|
||||
* applied per instant here: the official `[heal_fake]` window is 0.05 s and its stack count is the block number
|
||||
* (`SetStackCountViaBlockNum`; PRTS 分支特性信息 收割者 "触发后的0.05s内最多只能累加等于自身阻挡数的治疗次数"). [ASSUMED] the sim uses
|
||||
* the same `battle.time` as its window, so simultaneous hits (both 血镰, an AoE) share the block-count cap; a normal attack
|
||||
* has its own event and its own cap, as before. Like the 武者's, the heal ignores 禁疗 (PRTS 分支特性信息 收割者 "通过自身特性/
|
||||
* 天赋/技能产生的作用于自身的治疗效果会无视自身的禁疗").
|
||||
*/
|
||||
const installSelfHealOnHit = (capByBlock) => (battle, unit) => {
|
||||
const heal = (n) => { if (n > 0 && unit.alive) battle.heal(unit, unit, (unit.profile.selfHeal ?? 50) * n, { self: true }); };
|
||||
const installReaperHeal = (battle, unit) => {
|
||||
const heal = (n) => { if (n > 0 && unit.alive) battle.heal(unit, unit, (unit.profile.selfHeal ?? 50) * n, { self: true, ignoreHealFree: true }); };
|
||||
battle.on('attack', (ctx) => {
|
||||
if (ctx.attacker !== unit || !unit.alive) return;
|
||||
let n = ctx.targets.length;
|
||||
if (capByBlock) n = Math.min(n, Math.max(1, unit.s.blockCnt));
|
||||
heal(n);
|
||||
heal(Math.min(ctx.targets.length, Math.max(1, unit.s.blockCnt)));
|
||||
}, { owner: unit, priority: -10 });
|
||||
battle.on('damaged', (c) => {
|
||||
if (c.source !== unit || !unit.alive || !c.target || c.target.side !== 'enemy') return;
|
||||
@@ -87,7 +107,7 @@ const installSelfHealOnHit = (capByBlock) => (battle, unit) => {
|
||||
if (tags.includes('talent') || tags.includes('dot') || tags.includes('periodic')) return; // attackType BUFF
|
||||
const mem = unit.mem;
|
||||
if (mem.selfHealAt !== battle.time) { mem.selfHealAt = battle.time; mem.selfHealN = 0; }
|
||||
if (capByBlock && mem.selfHealN >= Math.max(1, unit.s.blockCnt)) return;
|
||||
if (mem.selfHealN >= Math.max(1, unit.s.blockCnt)) return;
|
||||
mem.selfHealN++;
|
||||
heal(1);
|
||||
}, { owner: unit, priority: -10 });
|
||||
@@ -537,8 +557,8 @@ export const SUB = Object.freeze({
|
||||
const [fr, fc] = frontOf(unit.tileR, unit.tileC, unit.dir);
|
||||
return bodyOnTile(target, unit.tileR, unit.tileC) || bodyOnTile(target, fr, fc) ? 1 : (unit.profile.rangedScale ?? 0.8);
|
||||
} }),
|
||||
musha: P({ noHeal: true, install: installSelfHealOnHit(false) }),
|
||||
reaper: P({ noHeal: true, allInRange: true, install: installSelfHealOnHit(true) }),
|
||||
musha: P({ noHeal: true, install: installMushaHeal }),
|
||||
reaper: P({ noHeal: true, allInRange: true, install: installReaperHeal }),
|
||||
sword: P({ hits: 2 }),
|
||||
artsfghter: P({ dmgType: 'arts' }),
|
||||
swordmaster: P({ hits: 2 }),
|
||||
|
||||
Reference in new issue
Block a user