feedback1f WT: 蒂比's 起飞 is 对地规避 — ground enemies no longer target or hit her while airborne
Official: ba.liftoff 起飞 "不阻挡地面敌人且不会被地面敌人攻击,可以阻挡飞行敌人"; PRTS 术语释义 起飞 "包含对地规避(无法被不同 阵营行动方式为地面的单位选中)… 起飞后单位的行动方式依旧是地面"; PRTS 异常效果 MOTION_TARGET_FREE; PRTS 行动方式 "起飞的干员仍然 是地面单位". Cause: 起飞 was `unit.ground = false` (an operator on a high tile). Melee enemies were released, but every ranged ground enemy kept shooting her and the AoE / skills of ground enemies hit her (控潮术师 6 hits in one S2 window). Now 起飞 is the skill buff flag `liftoff`: - targeting.js evadesGround: no ground enemy (not Unit.isFlying) selects her (canTargetAlly; the content picks that bypass it: 周围四格 additions, chain / bounce jumps, the 自行炮 shells); flyers, 近地悬浮 and 浮空 enemies still do. - damage.js / Battle.applyStatus: a ground enemy's damage, element fill and statuses never land on her (area damage, shots under way); sourceless damage and `ignoreSelect` zones (【污染秽蚀】 "可对空,无视无法选择") still do. - Battle._blockerFor: she blocks no ground enemy; flyers at the air radius as before. - She stays a ground unit on her low tile: 污染秽蚀 at the low rate, 隐德来希 S2 can put a 血镰 on her (可对空).
This commit is contained in:
1 parent
a7ec6a1438
commit
80f5bf1930
12 files changed
+363
-46
No files matched your search
+18
-2
@@ -1,6 +1,7 @@
|
||||
// server/sim/damage.js — damage & heal pipeline, shields, dodge, element gauges (DESIGN §5.5).
|
||||
//
|
||||
// dealDamage order: (element → gauge path) | invulnerable? → 'hit' hook (mutable DamageInfo, may set cancel)
|
||||
// dealDamage order: (element → gauge path) | invulnerable? / 对地规避 (a ground enemy's damage to an airborne 起飞 ally —
|
||||
// targeting.js evadesGround; not `ignoreSelect` damage) → 'hit' hook (mutable DamageInfo, may set cancel)
|
||||
// → dodge (phys/arts, canDodge) → mitigation (phys: DEF, arts: RES, true: none)
|
||||
// → × source dmgDealtMul (× phys/artsDealtMul) × target dmgTakenMul (not for 元素伤害) × type-taken mul × dmg.mul
|
||||
// → 限伤 (leaders in boss / hidden battles: a hit of ceil(final) ≥ BOSS_HIT_LIMIT is cancelled, see leaderHitCancelled)
|
||||
@@ -47,6 +48,7 @@
|
||||
|
||||
import { MIN_DAMAGE_RATIO, ELEMENT, ELEMENT_ORDER, PALSY_MAX } from './constants.js';
|
||||
import { BOSS_HIT_LIMIT } from '../../shared/constants.js';
|
||||
import { evadesGround } from './targeting.js';
|
||||
|
||||
const clamp01 = (v) => (v < 0 ? 0 : v > 1 ? 1 : v);
|
||||
|
||||
@@ -82,6 +84,8 @@ export function makeDamageInfo(d = {}) {
|
||||
cancel: false,
|
||||
noSp: !!d.noSp,
|
||||
ignoreSleep: !!d.ignoreSleep,
|
||||
// 无视无法选择 (PRTS: 【污染秽蚀】 "可对空,无视无法选择"): reaches an airborne 起飞 ally whatever the source's 行动方式
|
||||
ignoreSelect: !!d.ignoreSelect,
|
||||
sourceless: !!d.sourceless,
|
||||
attackId: d.attackId ?? 0,
|
||||
};
|
||||
@@ -92,6 +96,17 @@ function sleepBlocks(target, source, dmg) {
|
||||
return !!target.s.flags.sleep && !dmg.ignoreSleep && !(source && source.profile && source.profile.hitSleep);
|
||||
}
|
||||
|
||||
/**
|
||||
* 起飞 (flag `liftoff`): a ground enemy's damage never reaches the airborne ally — it cannot select it (对地规避, PRTS 作战机制
|
||||
* "AOE的判定是对攻击范围内的每个可以被选中的敌人进行判定"), so its splash, area abilities and element fills skip it, and a shot
|
||||
* already in flight or a DoT ticking when it took off lands on nothing [ASSUMED: PRTS 伤害流程 7 "取消掉隐匿/无敌状态下的攻击"
|
||||
* read for 对地规避]. Checked before the `hit` hook only: 蒂比 S2 takes off inside the hook of the hit that set it off, which
|
||||
* then resolves as usual (dodged if physical / arts — PRTS 备注). Sourceless damage and `ignoreSelect` damage still land.
|
||||
*/
|
||||
function liftoffEvades(target, source, dmg) {
|
||||
return !!target.s.flags.liftoff && !dmg.ignoreSelect && evadesGround(source, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure mitigation formula (exported for tests). `target` = the target's stats; `ign.elementalRes` = its 元素抗性
|
||||
* (epDamageResistance) for 'elemental' damage.
|
||||
@@ -178,7 +193,7 @@ export function dealDamage(battle, source, target, dmgIn) {
|
||||
// gets the stats and the kill (PRTS 伤害分类 无来源 ③)
|
||||
const hs = dmg.sourceless ? null : source;
|
||||
let ts = target.s;
|
||||
if (ts.flags.invulnerable || sleepBlocks(target, hs, dmg)) return 0;
|
||||
if (ts.flags.invulnerable || sleepBlocks(target, hs, dmg) || liftoffEvades(target, hs, dmg)) return 0;
|
||||
if (battle._hooks.hit) {
|
||||
battle.emit('hit', { source: hs, target, dmg, credit: source });
|
||||
if (dmg.cancel || !target.alive || !target.deployed) return 0;
|
||||
@@ -335,6 +350,7 @@ export function applyElement(battle, source, target, dmg) {
|
||||
if (!el || !(el in target.elem)) return 0;
|
||||
if (!hasHp(target)) return 0; // a killing blow's rider: the target is dead, nothing fills or bursts (header)
|
||||
if (target.s.flags.invulnerable || sleepBlocks(target, source, dmg)) return 0;
|
||||
if (liftoffEvades(target, dmg.sourceless ? null : source, dmg)) return 0;
|
||||
if (burstLocked(target, el)) return 0;
|
||||
if (battle._hooks.elementHit) {
|
||||
battle.emit('elementHit', { source, target, dmg });
|
||||
|
||||
Reference in new issue
Block a user