feedback1 integrate: follow-ups from the workstream notes (official rules)

- an operator's radius area damage skips unblocked 隐匿 and untargetable enemies (Battle.foesInRadius;
  PRTS 作战机制 AOE伤害判定), the 逐火 embers included
- PRTS 溅射半径一览: 投掷手 0.9, 链术师 1.7, 格雷伊 1.0; 迷迭香 S2 radius 1.5
- 阿罗玛's first-attack mark is shared between 阿罗玛 and leaves with its setter (PRTS 备注)
- 奥术法阵 on the field: 炎佑's damage silences its target (PRTS 盟约记录 备注)
- skills restart from their initial cooldown when a 重生 ends (PRTS 特殊机制)
- 高准度伦蒂尼姆城防自行炮: lock in range, 3x3 area, every 0.5 s up to 10 shots, 失衡/控制免疫 meanwhile
- 琳琅诗怀雅 S3 coins go to range 2-4 in front and the units she blocks
- 阿戈尔 devour is a 物理流失 reduced by the target's DEF
This commit is contained in:
sganggs committed 2026-10-03 07:57:28 +08:00
1 parent 4e68100065
commit 75e2f02590
21 files changed
+346 -112

No files matched your search

+19 -5
View File
@@ -43,6 +43,8 @@ const LINE = Object.freeze(Array.from({ length: COLS }, (_, i) => Object.freeze(
const BILLRO_S3_RAMP = 20;
/** 卡涅利安 S3 charged mark: one buff per enemy, shared by every 卡涅利安 (PRTS 备注), ≤ 5 stacks (skill text). */
const BILLRO_MARK = 'billro:mark';
/** 阿罗玛's 非首次标记 (talent 起泡性能测试): one per enemy, shared by every 阿罗玛 (PRTS 备注). */
const AROMA_MARK = 'aroma:bubbled';
const BILLRO_MARK_MAX = 5;
// ---------------------------------------------------------------------------------------------------------------
@@ -863,14 +865,26 @@ const kits = {
}),
skill: { kind: 'duration', mods: { atkPct: num(bb.atk) }, onStart({ battle, unit }) { battle.fx('slippery', { x: unit.x, y: unit.y, id: unit.id }); } },
talents: [{ install(battle, unit) { // first attack on each enemy: ×1.1 and levitate 2.5 s
unit.mem.bubbled = new Set();
// PRTS 阿罗玛 备注: "天赋采用施加非首次标记的方式判断是否为'首次进行攻击',自身离场时移除自身已施加的标记,不同阿罗玛之间的
// 非首次标记通用" — one mark per enemy (AROMA_MARK, the setter as source) for every 阿罗玛; hers go when she leaves
// the field (until 0.1.1 each 阿罗玛 kept her own list, so two of them both triggered on one enemy)
unit.mem.bubbled = new Set(); // the enemies she marked
battle.on('hit', (c) => {
const e = c.target;
if (c.source !== unit || !c.dmg.isAttack || e.side !== 'enemy' || unit.mem.bubbled.has(e.id)) return;
if (c.source !== unit || !c.dmg.isAttack || e.side !== 'enemy' || e.findBuff(AROMA_MARK)) return;
battle.addBuff(e, { key: AROMA_MARK, source: unit });
unit.mem.bubbled.add(e.id);
c.dmg.mul *= num(t0.damage_scale, 1.1);
if (battle.applyStatus(e, 'levitate', { duration: num(t0.levitate_duration, 2.5), source: unit })) battle.fx('levitate', { x: e.x, y: e.y, id: e.id });
}, { owner: unit });
battle.on('death', (c) => {
if (c.unit !== unit) return;
for (const id of unit.mem.bubbled) {
const e = battle.unitById(id);
if (e && e.findBuff(AROMA_MARK)?.source === unit) battle.removeBuff(e, AROMA_MARK);
}
unit.mem.bubbled.clear();
}, { owner: unit });
} }],
install(battle, unit) {
// S2: landing damage for every levitated enemy (any source) that lands inside her range while the skill runs
@@ -979,7 +993,7 @@ const kits = {
onTick({ battle, unit, dt }) {
const T = unit.mem.tornado;
if (!T) return;
const inside = battle.enemiesInRadius(T.x, T.y, R);
const inside = battle.foesInRadius(T.x, T.y, R);
for (const e of inside) pulse(battle, e, `glady:slow:${unit.id}`, { moveMul: Math.max(0, 1 + num(bb.move_speed, -0.5)) });
T.acc += dt;
if (T.acc + 1e-9 < iv) return;
@@ -996,7 +1010,7 @@ const kits = {
const T = unit.mem.tornado;
unit.mem.tornado = null;
if (!T || reason === 'death' || !unit.alive) return;
for (const e of battle.enemiesInRadius(T.x, T.y, R)) pullSelf(battle, unit, e, force);
for (const e of battle.foesInRadius(T.x, T.y, R)) pullSelf(battle, unit, e, force);
battle.fx('pull', { x: T.x, y: T.y, id: unit.id });
},
},
@@ -1946,7 +1960,7 @@ const kits = {
if (S2 && skillActive(unit)) {
// S2: motes orbit wider and hit enemies instead of operators
const hitAt = unit.mem.moteHit || (unit.mem.moteHit = new Map());
const foes = battle.enemiesInRadius(unit.x, unit.y, num(bb.outside_radius, 2)).filter((e) => canTargetEnemy(unit, e, { canHitFly: true }))
const foes = battle.foesInRadius(unit.x, unit.y, num(bb.outside_radius, 2)).filter((e) => canTargetEnemy(unit, e, { canHitFly: true }))
.sort((a, b) => a.id - b.id);
for (const e of foes) {
if ((hitAt.get(e.id) ?? -Infinity) > battle.time + 1e-9) continue;