Official: S2 「该角色受到攻击时刺玫对目标造成攻击力20%的法术伤害并仅对该角色触发刺玫特性」 (en "...and activates her Trait on the ally"); the client buff vendla_tr heals through the S2TraitHealRange selector (the vendla_s_2 holder) only for a damage whose modifier carries vendla_s_2 (the counter, vendla_s_2[extra_damage]), else through TraitHealRange (_excludeOwner 0). Cause: kits/ops/chess_char_1_06-vendla.js sent EVERY trait heal to the protégé while the skill ran (usually at full HP), so a 源石溶剂 carrier healed nobody for 15 s. Golden: roster-001 / roster-002 (刺玫 S2 in band 1), bond-deputShip-low / -high, bond-suntShip-high, bond-victoriaShip-low / -high (刺玫 on those teams), matches solo-FUNNY-2, coop2-NORMAL-3, coop3-ABYSS-5, coop4-FUNNY-6, coop4-ABYSS-7 (bots field 刺玫: her heals land on injured allies during S2, fights change). Tests: test/content/feedback5-vendla-heal.test.js (2, fail on the parent); kits_t1t2's 刺玫 assertion message reworded.
80 lines
5.1 KiB
JavaScript
80 lines
5.1 KiB
JavaScript
// server/sim/content/kits/ops/chess_char_1_06-vendla.js — 刺玫 (char_494_vendla) kit, tier 1.
|
||
// Conventions of the tier-1 kits: ../shared/tier1.js; kit contract and rules: ../README.md.
|
||
|
||
import { num, talentBb, up, byEnemyAttack, alliesInGridOf, skillBbOf } from '../shared/tier1.js';
|
||
|
||
export default {
|
||
// ---------------------------------------------------------------------------------------------------------------
|
||
// 1_06 刺玫 荆藤庇荫: ATK +atk; the ally with the highest max HP in range gets taunt +taunt_level; whenever that ally is
|
||
// attacked, 刺玫 deals atk_scale × ATK arts to the attacker, and the trait heal of THAT damage (scale × damage) goes to
|
||
// that ally ("并仅对该角色触发刺玫特性"; en "…and activates her Trait on the ally"). Her own attacks keep healing the
|
||
// lowest-HP ally in range — herself included — while the skill runs: client buff vendla_tr heals through the
|
||
// S2TraitHealRange selector (the vendla_s_2 holder) only for a damage whose modifier carries the key vendla_s_2 (the
|
||
// counter, vendla_s_2[extra_damage]), else through TraitHealRange (_excludeOwner 0, 禁疗 excluded). Until 0.2.0 every
|
||
// damage she dealt during the skill healed the protégé, usually at full HP, so she healed nobody (community report of
|
||
// 2026-10-06 「刺玫开技能(装备源石药剂)之后不能治疗」 — her 源石溶剂 drain went unhealed).
|
||
// 土壤基肥改良: the highest-max-HP ally in range receives heal_scale × healing ("受到的治疗效果提升") — never its natural /
|
||
// skill HP regeneration (the 生命回复速度 attribute is "不受治疗加成影响": 宴 分神, 角峰 体能强化; PRTS).
|
||
// Alternate S1 战术咏唱·γ型: ASPD +attack_speed (the trait heal keeps going to the most injured ally in range).
|
||
// Elite module INC-X (heal 60 % of the damage) is the incantation profile of the module trait (TUNE.incantationmedic).
|
||
chess_char_1_06_a: (bb, chess) => {
|
||
const hs = num(talentBb(chess, 0).heal_scale, 1);
|
||
const tauntKey = 'vendla:taunt';
|
||
// the protégé only exists while 荆藤庇荫 runs (mem.protege is set by its onStart only)
|
||
const protege = (u) => (u.skill?.active && up(u.mem.protege) ? u.mem.protege : null);
|
||
return {
|
||
skills: { 'skcom_magic_rage[3]': { kind: 'duration', mods: { aspd: num(skillBbOf(chess, 'skcom_magic_rage[3]').attack_speed) } } },
|
||
trait: {
|
||
// 咒愈师 trait: EVERY damage she deals heals an ally for 50 % of it (professions.js `installIncantation`,
|
||
// buff_template_data `vendla_tr` = ON_AFTER_OUTPUT_DAMAGE): the lowest-HP ally in range (herself included) — the
|
||
// S2 counter's damage names her protégé instead (`traitAlly`, talent install below), skill running or not
|
||
install(battle, u) {
|
||
battle.on('damaged', (c) => {
|
||
const t = c.target;
|
||
if (c.source !== u || !u.alive || !t || t.side !== 'enemy' || !(c.amount > 0)) return;
|
||
if (c.type === 'element' || c.type === 'elemental') return;
|
||
const ally = (c.dmg && c.dmg.traitAlly) || battle.lowestHpAllyInRange(u);
|
||
if (ally) battle.heal(u, ally, c.amount * (u.profile.healRatio ?? 0.5), { tags: ['incantation'] });
|
||
}, { owner: u });
|
||
},
|
||
},
|
||
skill: {
|
||
kind: 'duration', mods: { atkPct: num(bb.atk) },
|
||
onStart({ battle, unit, skill }) {
|
||
const cands = alliesInGridOf(battle, unit).sort((a, b) => b.s.maxHp - a.s.maxHp || a.deploySeq - b.deploySeq);
|
||
const p = cands[0] ?? null;
|
||
unit.mem.protege = p;
|
||
if (!p) return;
|
||
battle.addBuff(p, { key: tauntKey, duration: skill.duration + 0.1, mods: { taunt: num(bb.taunt_level, 1) }, visible: true, source: unit });
|
||
battle.fx('taunt', { x: p.x, y: p.y, id: p.id });
|
||
},
|
||
onEnd({ battle, unit }) {
|
||
if (unit.mem.protege) battle.removeBuff(unit.mem.protege, tauntKey);
|
||
unit.mem.protege = null;
|
||
},
|
||
},
|
||
talents: [{ install(battle, unit) {
|
||
battle.on('damaged', (ctx) => {
|
||
const p = protege(unit);
|
||
if (!p || ctx.target !== p || !byEnemyAttack(ctx) || !ctx.source.alive || !unit.canAct) return;
|
||
// "并仅对该角色触发刺玫特性": this counter damage is healed by the trait (install above) for the protégé — the
|
||
// damage instance names her, so no separate heal here (it would double)
|
||
battle.dealDamage(unit, ctx.source, { amount: unit.s.atk * num(bb.atk_scale), type: 'arts', isSkill: true, canDodge: false, tags: ['counter'], traitAlly: p });
|
||
battle.fx('counter', { x: ctx.source.x, y: ctx.source.y, id: unit.id });
|
||
}, { owner: unit });
|
||
if (hs !== 1) {
|
||
let cacheT = -1, top = null;
|
||
battle.on('heal', (ctx) => {
|
||
if (!up(unit) || ctx.opts?.regen) return;
|
||
if (cacheT !== battle.time) {
|
||
cacheT = battle.time;
|
||
top = alliesInGridOf(battle, unit).sort((a, b) => b.s.maxHp - a.s.maxHp || a.deploySeq - b.deploySeq)[0] ?? null;
|
||
}
|
||
if (ctx.target === top) ctx.amount *= hs;
|
||
}, { owner: unit });
|
||
}
|
||
} }],
|
||
};
|
||
},
|
||
};
|