feedback5 O20: the 缚地 status (groundbind) — an enemy air unit counts as a ground unit and cannot move
ba.groundbind "目标变为地面单位,无法移动;使部分近地悬浮敌人掉落;对重量大于3的单位持续时间减半" (予愿安洁莉娜 S2 needs it): - buffs.js: STATUS groundbind (flag groundbind + noMove, move x0), FLAG_KEYS, RESIST_STATUSES (as 束缚, [ASSUMED]); - units.js isFlying: an enemy under 缚地 is a ground unit unless a 浮空 lifts it (same result as before without the flag); - battle/status.js: 浮空 lands on a 缚地 data flyer (PRTS 异常效果 "…且不持有缚地异常…则Buff取消"), 缚地 halved on weight > 3; - content/enemies: 掠海漂移体 / 吉兆飞鳞 drop on 缚地 as their PRTS text says (吉兆飞鳞 stays down while it holds); - render/style.js: the 束缚 icon for it; docs/SIM.md (§2 isFlying, §3 flags / status table / 抵抗). Nothing applies it yet: every golden family is unchanged. Test: test/sim/feedback5-groundbind.test.js.
This commit is contained in:
1 parent
996f5d20fe
commit
83e879a335
8 files changed
+126
-25
No files matched your search
@@ -135,8 +135,8 @@ export class BattleStatus {
|
||||
* handlers may cancel it or change `duration` / `value`. Official rules (buffs.js STATUS): 抵抗 (the `resist` status)
|
||||
* shortens the RESIST_STATUSES by its value (default half; applied after `beforeStatus`; `resistApplied` skips that
|
||||
* pass — the cold-on-cold 冻结 below already used post-抵抗 lengths). A second 寒冷 while 寒冷 remains applies 冻结 for
|
||||
* max(remaining, this cold after 抵抗) (PRTS 术语释义 寒冷 「持续时间取双方之中最高」). 浮空 lasts half as long on units heavier
|
||||
* than LEVITATE_HALF_WEIGHT (current massLevel); 冻结's RES cut hits enemies only; 麻痹 adds stacks; "同名效果取最高"
|
||||
* max(remaining, this cold after 抵抗) (PRTS 术语释义 寒冷 「持续时间取双方之中最高」). 浮空 and 缚地 last half as long on units
|
||||
* heavier than LEVITATE_HALF_WEIGHT (current massLevel); 冻结's RES cut hits enemies only; 麻痹 adds stacks; "同名效果取最高"
|
||||
* statuses (`valued`) keep the strongest value — a weaker application only extends past the stronger one's end (it
|
||||
* then resumes); `stackAs` = the value such an application competes with instead of its own (its effect stays
|
||||
* `value`): an effect the game stacks as another strength — Raidian S3's 虚弱, PRTS 备注 "在叠加时视为90%(1级~6级)/80%
|
||||
@@ -162,9 +162,9 @@ export class BattleStatus {
|
||||
const immune = target.def && target.def.immune;
|
||||
if (!opts.force && tpl.immune && immune && immune.has(tpl.immune)) return false;
|
||||
// 浮空 Buff (PRTS 异常效果: "若单位数据上为飞行单位且不持有缚地异常或是持有浮空异常则Buff取消"; 行动方式 "行动类型(数据)为
|
||||
// 飞行的单位、以及已持有浮空异常的单位无法被施加浮空Buff"): refused on data flyers (`motion` FLY) and units already
|
||||
// levitated — a hovering 近地悬浮 enemy is WALK in its data, so it can be levitated (no 缚地 / 浮空强化 in this mode)
|
||||
if (key === 'levitate' && (target.motion === 'FLY' || target.s.flags.levitate)) return false;
|
||||
// 飞行的单位、以及已持有浮空异常的单位无法被施加浮空Buff"): refused on data flyers (`motion` FLY) that hold no 缚地 and on
|
||||
// units already levitated — a hovering 近地悬浮 enemy is WALK in its data, so it can be levitated (no 浮空强化 in this mode)
|
||||
if (key === 'levitate' && ((target.motion === 'FLY' && !target.s.flags.groundbind) || target.s.flags.levitate)) return false;
|
||||
if (this._hooks.beforeStatus) {
|
||||
const c = this.emit('beforeStatus', { source: opts.source ?? null, target, status: key, duration, value, cancel: false });
|
||||
if (c.cancel || !target.alive) return false;
|
||||
@@ -177,7 +177,8 @@ export class BattleStatus {
|
||||
const rv = this.resistOf(target);
|
||||
if (rv > 0) duration *= 1 - rv;
|
||||
}
|
||||
if (key === 'levitate' && target.s.massLevel > LEVITATE_HALF_WEIGHT) duration /= 2;
|
||||
// 浮空 / 缚地 (ba.levitate, ba.groundbind): "对重量大于3的单位持续时间减半"
|
||||
if ((key === 'levitate' || key === 'groundbind') && target.s.massLevel > LEVITATE_HALF_WEIGHT) duration /= 2;
|
||||
if (!(duration > 0)) return false;
|
||||
if (key === 'cold' && target.findBuff('cold') && !(immune && immune.has('frozen'))) {
|
||||
// PRTS 术语释义 寒冷: 友方寒冷 pairs into 冻结, 「持续时间取双方之中最高」. `duration` is this cold after 抵抗;
|
||||
|
||||
+9
-2
@@ -42,6 +42,8 @@ export const FLAG_KEYS = Object.freeze([
|
||||
// 自缚 (the unit's own immobility: 守墓石像's 转换模式, the 自缚 leaders) beside its `noMove` — 束缚 sets noMove too, and
|
||||
// only 自缚 makes a unit "不视为可达目标" for 余 S2's teleport (PRTS 余 S2 备注)
|
||||
'selfBound', 'healFree', 'stealthOff',
|
||||
// 缚地 (status `groundbind`): an enemy air unit counts as a ground unit meanwhile (Unit.isFlying)
|
||||
'groundbind',
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -90,6 +92,11 @@ export const STATUS = Object.freeze({
|
||||
// 浮空: 变为空中单位 (Unit.isFlying),无法移动、攻击及使用技能; 对重量大于3的单位持续时间减半; the state holds 不可阻挡 +
|
||||
// 失衡免疫 (noDisplace: "不会被位移影响", PRTS 异常效果)
|
||||
levitate: { flags: { levitate: true, stun: true, unblockable: true, noDisplace: true }, immune: 'levitate' },
|
||||
// 缚地 (gamedata_const ba.groundbind "目标变为地面单位,无法移动;使部分近地悬浮敌人掉落;对重量大于3的单位持续时间减半"):
|
||||
// an air unit (data flyer, 近地悬浮) counts as a ground unit (Unit.isFlying: melee operators hit it, ground blockers
|
||||
// block it) and cannot move; half duration on units with massLevel > 3 (Battle.applyStatus, as 浮空); a 浮空 still
|
||||
// lands on it (PRTS 异常效果 "若单位数据上为飞行单位且不持有缚地异常…则Buff取消"). 予愿安洁莉娜 S2 (kits/ops/op-aglna2.js)
|
||||
groundbind: { flags: { groundbind: true, noMove: true }, mods: { moveMul: 0 } },
|
||||
// 麻痹: value = stacks (default 1, max 3); each stack cancels one enemy normal attack; lasts until consumed; honours
|
||||
// 麻痹免疫 (enemy_database palsyImmune, e.g. 假想敌:铳 — PRTS 元素: a 神经 burst gives 麻痹 only "若单位不具有麻痹免疫")
|
||||
palsy: { palsy: true, immune: 'palsy' },
|
||||
@@ -120,12 +127,12 @@ export const STATUS = Object.freeze({
|
||||
});
|
||||
|
||||
/**
|
||||
* Control statuses (异常状态) shortened by 抵抗: 晕眩 冻结 寒冷 沉睡 恐惧 战栗 诱导 浮空 束缚 沉默 缴械 停顿 减速. The
|
||||
* Control statuses (异常状态) shortened by 抵抗: 晕眩 冻结 寒冷 沉睡 恐惧 战栗 诱导 浮空 束缚 沉默 缴械 停顿 减速 缚地. The
|
||||
* official term lists 晕眩/寒冷/冻结/恐惧/诱导…; the rest follow the operator kits that grant 抵抗 [ASSUMED]. 麻痹 is
|
||||
* stack-based: it decays instead (RESIST_PALSY_DECAY).
|
||||
*/
|
||||
export const RESIST_STATUSES = Object.freeze(new Set(['stun', 'freeze', 'cold', 'sleep', 'fear', 'tremble', 'attract', 'levitate',
|
||||
'bind', 'silence', 'disarm', 'sluggish', 'slow']));
|
||||
'bind', 'silence', 'disarm', 'sluggish', 'slow', 'groundbind']));
|
||||
|
||||
/** Statuses that should be reported to clients as `['status', id, key, on]`. */
|
||||
export const VISIBLE_STATUS = new Set(Object.keys(STATUS));
|
||||
|
||||
@@ -58,13 +58,13 @@ const SYUFO_CRAWL_STUN = 0.5;
|
||||
/**
|
||||
* 掠海漂移体 (PRTS): 初始模式 近地悬浮 + 失衡免疫, 不会攻击飞行单位; 受晕眩/无法行动/沉睡/冻结/缚地影响后进入爬行模式 for
|
||||
* good and is stunned 0.5 s — a ground unit (blockable, melee operators hit it) that "仅进行阻挡攻击" (only its blocker).
|
||||
* The engine has 晕眩 / 冻结 / 沉睡 (no operator here applies 无法行动 or 缚地). Erosion on every attack.
|
||||
* The engine has 晕眩 / 冻结 / 沉睡 / 缚地 (予愿安洁莉娜 S2; no operator here applies 无法行动). Erosion on every attack.
|
||||
*/
|
||||
function kitSyufo(ab) {
|
||||
return [float(), ep('erosion', T(ab, 'EpDamage.attack@ep_damage_ratio') ?? 0), {
|
||||
spawn(b, e) { e.profile.canTarget = (u) => !u.isFlying; },
|
||||
status(c, b, e, a) {
|
||||
if (a.crawl || !(c.status === 'stun' || c.status === 'freeze' || c.status === 'sleep')) return;
|
||||
if (a.crawl || !(c.status === 'stun' || c.status === 'freeze' || c.status === 'sleep' || c.status === 'groundbind')) return;
|
||||
a.crawl = true;
|
||||
setFloat(b, e, false);
|
||||
e.profile.melee = true;
|
||||
|
||||
@@ -103,7 +103,7 @@ function kitParrot(ab) {
|
||||
},
|
||||
status(c, b, e, a) {
|
||||
if (c.status === 'freeze') { a.chill = true; return; }
|
||||
if (a.down || !(c.status === 'stun' || c.status === 'sleep')) return;
|
||||
if (a.down || !(c.status === 'stun' || c.status === 'sleep' || c.status === 'groundbind')) return;
|
||||
a.down = true;
|
||||
setFloat(b, e, false);
|
||||
b.removeBuff(e, 'ab:parrotRun');
|
||||
@@ -114,8 +114,8 @@ function kitParrot(ab) {
|
||||
tick(b, e, a) {
|
||||
if (a.chill && !e.s.flags.freeze) { a.chill = false; b.applyStatus(e, 'stun', { duration: PARROT_CHILL_STUN, source: null }); }
|
||||
// "离开上述异常效果影响后进入初始模式": s.flags.stun also holds while asleep / frozen (units.js), so a sleep that
|
||||
// outlasts the mode stun keeps it down
|
||||
if (a.down && !e.s.flags.stun) {
|
||||
// outlasts the mode stun keeps it down; so does a 缚地 (flag `groundbind`)
|
||||
if (a.down && !e.s.flags.stun && !e.s.flags.groundbind) {
|
||||
a.down = false;
|
||||
b.removeBuff(e, 'ab:parrotDown');
|
||||
b.removeBuff(e, 'ab:parrotRun');
|
||||
|
||||
+10
-5
@@ -179,13 +179,18 @@ export class Unit {
|
||||
/**
|
||||
* Air unit (空中单位) for every targeting / ground-only rule: FLY movers, and enemies that hover (近地悬浮, buff flag
|
||||
* `float` — PRTS 术语释义 ba.float "算作空中单位"; they keep walking the ground path) or are levitated (浮空, gamedata_const
|
||||
* ba.levitate "变为空中单位"). Movement and pathing read `motion`, never this.
|
||||
* ba.levitate "变为空中单位"). A 缚地 enemy (status `groundbind`, ba.groundbind "目标变为地面单位") is a ground unit
|
||||
* meanwhile — unless a 浮空 lifts it again (浮空 lands on a 缚地 flyer: Battle.applyStatus). Movement and pathing read
|
||||
* `motion`, never this.
|
||||
*/
|
||||
get isFlying() {
|
||||
if (this.motion === 'FLY') return true;
|
||||
if (this.side !== 'enemy') return false;
|
||||
const f = this.s.flags;
|
||||
return !!(f.float || f.levitate);
|
||||
if (this.side === 'enemy') {
|
||||
const f = this.s.flags;
|
||||
if (f.levitate) return true;
|
||||
if (f.groundbind) return false;
|
||||
return this.motion === 'FLY' || !!f.float;
|
||||
}
|
||||
return this.motion === 'FLY';
|
||||
}
|
||||
|
||||
get hpRatio() { const mh = this.s.maxHp; return mh > 0 ? this.hp / mh : 0; }
|
||||
|
||||
Reference in new issue
Block a user