feedback7 R22-UNBAL: a pushed / pulled enemy is held in the official 失衡 (UNBALANCE) state — no walking, no normal attack — for the push's 位移时间 of its 受力等级 or the pull's force window; a 静态刚体 hit by a force gets the 0.1 s floor; the client's slide takes the same game time (idea from PR #392 by @xcdoge, re-implemented from the sources); golden: 69 scenarios move, 35 with kills / leaks / deaths / boss HP (below)
Seen: the sim moved a displaced enemy at once and it walked / swung again on the next tick; players compared with the official game (PR #392: 「被推/拉完的敌人会先站住一小会儿再走」). Research (scratchpad report r3): PRTS 失衡位移机制 — a force > 0 puts an enemy in the UNBALANCE state machine with a 0.1 s 失衡硬直 floor, ending when its speed is ≤ 0.1 m/s, on 浮空 or a forced state change; 异常效果图鉴/失衡免疫 「失衡期间无法自主移动、发动攻击、使用技能」; 异常效果 — not an abnormal status (水遁忍者's check still runs); 游戏数据基础 推力-位移近似对应表 位移时间 (whole frames at 30 fps); 推与拉 拉力 「作用时间默认为 1 s;若本次受力 等级 < −1,作用时间改为 0.5 s」, 急停 keeps the state to the window's end; 特殊机制 静态刚体 (0.1 s 保底); 术语释义 浮空. Now: constants.js PUSH_UNBALANCE {−2: 0.2, −1: 0.4, 0: 0.8, 1: 0.9, 2: 32/30, 3: 35/30}, PULL_UNBALANCE 1 / PULL_UNBALANCE_WEAK 0.5, UNBALANCE_MIN 0.1. battle/displacement.js: push() holds for its level's row (the −2 correction included), kept when the 特效 column or a wall shortens the slide [ASSUMED for the wall], the 0.1 s floor when a wall stops it at the first step [ASSUMED]; pull() holds for its window whatever the travel (≤ −3: none; an enemy the puller blocks: still no pull [ASSUMED, unchanged]); a 静态刚体 (data staticBody, not 失衡免疫 noDisplace) hit by force level ≥ −2 gets 0.1 s and no movement (_staticForce); _unbalance sets enemy.unbalanceUntil (a longer running one kept) and ends the attack clip's stand. ai.js updateEnemy: no walking (恐惧 / 诱导 too — PR #392's fear exemption is not taken), no new normal attack, a swing short of its frame cut, 浮空 clears it; a 重生 clears it (archetypes.js reborn). Not a stun: no status, no immunity, SP and the attack cooldown run. No global skill lock: enemy abilities keep ticking ([ASSUMED] scope). The move stays instant (the unbalanced() talents keyed off the jump unchanged). The displace fx carries `dur` (game s); render/units.js slideTo divides it by ctx.animRate (2× default: a 0.8 s push slides 0.4 real s); DISPLACE_SLIDE·√D is only the fallback for an fx without it. Not taken from #392: UNBALANCE_TRAVEL 0.6387·√tiles / the client's 0.3194 (derived from the page's μ = 0.5 单位假设, one frame high on every push row, the wrong shape for pulls) and the fear exemption. Tests: test/sim/unbalance.test.js (8: the push rows and walking after them; no attack in the hold, a feared enemy held; the −2 correction's 0.2 s; 特效 / wall-shortened rows and the first-step floor; pull windows incl. the 急停 and ≤ −3; 静态刚体 0.1 s without movement, 失衡免疫 never; 浮空 clears; the fx `dur` — the file fails on the parent); test/render/unitview.test.js (+1: the slide at 2× for a push and a pull, the fallback — fails on the parent); feedback1b-displacement B5 (the drone is now held 0.1 s per force, never moved). test/sim + test/content + test/render: 3433 pass. Docs: SIM.md (push / pull, displace, assumptions), PLAYING.md 推开 / 拉拽, research 13 §0 / §5. Golden — every moved battle has pushes / pulls (probe of the callers) and its enemies are now held; outcome moves: roster-002 (野鬃: killed 29→33, leaks 15→11), roster-003 (野鬃: deaths 3→7), roster-007 (薄绿: killed 110→118, leaks 53→47), roster-008 (薄绿: 45→47 / 42→40), roster-010 (歌蕾蒂娅: killed 45→44, leaks 57→58), roster-011 (莫斯提马: 78→79 / 4→3), roster-031 (钩索师 pulls, tier4: killed 64→72, leaks 12→4, deaths 6→5), roster-041 (钩索师: deaths 5→4), roster-043 (山: deaths 15→14), roster-044 (山: killed 107→103, leaks 12→16, deaths 15→14); bond-deputShip-low (薄绿: 18→21 killed, leaks 3→0, deaths 1→0), bond-kazimierzShip-high (野鬃: deaths 3→2); boss-boss_3-pair (锏: p2 deaths 3→2), boss-boss_4-pair (莫斯提马 / 歌蕾蒂娅: killed 11→12, boss HP 7442429→7375628, p2 leaks 2→1, deaths 19→18), boss-boss_6-pair (boss HP 6932482→6865243, p2 deaths 19→17), hidden-boss_8-pair (boss HP 12585770→12585798), hidden-boss_9-pair (锏: boss HP 3630612→3636991); standin-05 / 08 / 10 (预备干员-特种 pulls: killed 5→8 / 42→44 / 28→29, leaks down by 3 / 2 / 1); diy-101 (傀影: killed 22→21, leaks 92→93), diy-114 / 115 / 116 (黑键: 106→99 & 83→90 / 154→156 & 78→70 / 3→2 & 120→121), diy-137 (预备干员-特种: 68→79 / 79→68); matches through those battles — coop2-HARD-4, coop2-NORMAL-14-standins, coop2-NORMAL-3, coop2-NORMAL-70-diy, coop3-ABYSS-5, coop4-ABYSS-7, solo-ABYSS-2 (LP 2→4 at round 10), solo-HARD-2 (ai_0 now survives round 13: eliminated 13 → alive), solo-HARD-9-boosted (LP 399→398), solo-NORMAL-1. Other moves (damage, heals, snapshots only): roster-009/012/017/019/032/039/040/042/046, 13 bonds, boss-boss_2-pair, hidden-boss_10-pair, standin-03, diy-053/084/085/102/103/108/109, coop2-ABYSS-10-boosted, solo-ABYSS-1.
This commit is contained in:
1 parent
3969e4b012
commit
cdf2bd5c88
19 files changed
+1295
-1085
No files matched your search
+12
-7
@@ -537,13 +537,17 @@ export function updateEnemy(b, e, dt) {
|
||||
// hidden (teleporting) enemies only advance wait legs
|
||||
const stunned = e.s.flags.stun;
|
||||
if (stunned || e.hidden || e.s.flags.fear) b._cutAttackStand(e);
|
||||
// 失衡 (UNBALANCE, battle/displacement.js _unbalance): a state machine, not a status — 浮空 ends it (PRTS 术语释义 浮空
|
||||
// 「触发浮空时清除受到的推/拉力…无法陷入失衡」); while it lasts the enemy neither walks nor starts a normal attack
|
||||
if (e.s.flags.levitate && e.unbalanceUntil > b.time) e.unbalanceUntil = -Infinity;
|
||||
const unbalanced = b.time < e.unbalanceUntil;
|
||||
const prevCd = e.atkCd;
|
||||
if (e.atkCd > 0 && !stunned && !e.hidden) e.atkCd = Math.max(0, e.atkCd - dt);
|
||||
// a stun / freeze / sleep / 浮空 — or leaving the field — takes the enemy out of its attack: a swing short of its damage
|
||||
// frame does not land, and the attack starts again from its wind-up afterwards (enemyAttack)
|
||||
if (e.swing && (stunned || e.hidden)) e.swing = false;
|
||||
// a stun / freeze / sleep / 浮空 / 失衡 — or leaving the field — takes the enemy out of its attack: a swing short of its
|
||||
// damage frame does not land, and the attack starts again from its wind-up afterwards (enemyAttack)
|
||||
if (e.swing && (stunned || e.hidden || unbalanced)) e.swing = false;
|
||||
// true: an unblocked ranged enemy in the wind-up of its next attack with a target in range (it stands)
|
||||
const winding = !e.hidden && !stunned && enemyAttack(b, e, prevCd);
|
||||
const winding = !e.hidden && !stunned && !unbalanced && enemyAttack(b, e, prevCd);
|
||||
if (!e.alive) return;
|
||||
// a stun / freeze / sleep cuts the attack clip short: no stand left once it ends [ASSUMED]. 沉睡 also holds 不可阻挡
|
||||
// (PRTS 异常效果 SLEEPING = 无法行动+无敌+不可阻挡): a sleeper's blocker lets go — its swing was cut above; Battle.applyStatus
|
||||
@@ -572,12 +576,13 @@ export function updateEnemy(b, e, dt) {
|
||||
if (b.time < e.pauseUntil) return;
|
||||
// standing for an attack clip (attackStand, GitHub #58): only the walking waits — a checkpoint's WAIT keeps running
|
||||
// and DISAPPEAR / APPEAR legs still happen (advanceRoute); drawn idle (the client plays the clip, then Move again);
|
||||
// a 恐惧 runs at once (it cannot attack)
|
||||
const standing = winding || (b.time < e.atkStandUntil && !e.s.flags.fear);
|
||||
// a 恐惧 runs at once (it cannot attack). 失衡 holds the walking too — under 恐惧 / 诱导 as well (失衡免疫 says 「失衡期间
|
||||
// 无法自主移动」; no source exempts a fear)
|
||||
const standing = winding || unbalanced || (b.time < e.atkStandUntil && !e.s.flags.fear);
|
||||
if (e.s.flags.noMove) { e.moving = false; return; } // standing (a 重生, a form change): drawn idle, not walking
|
||||
// 恐惧 (ba.fear "无法被阻挡并四散逃跑"; PRTS 诱发移动: 恐惧 outranks 诱导): runs to random tiles of the fan away from
|
||||
// its source — a self-inflicted fear flutters inside its own tile (fear.js); the route re-plans once it ends
|
||||
if (e.s.flags.fear && !e.hidden) { moveFeared(b, e, dt); return; }
|
||||
if (e.s.flags.fear && !e.hidden) { if (unbalanced) e.moving = false; else moveFeared(b, e, dt); return; }
|
||||
if (e.mem.fearMove) endFear(e);
|
||||
// 诱导 (ba.attract "无法被阻挡并向目标位置移动"): walks to the attract point instead of following its route
|
||||
if (e.s.flags.attract) { if (standing) e.moving = false; else moveAttracted(b, e, dt); return; }
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
// directional), pull, the raw mover displace and who can be moved at all.
|
||||
// Installed on Battle.prototype by server/sim/Battle.js (a method container: never instantiated; `this` is the battle).
|
||||
|
||||
import { COLS, PUSH_TILES, PUSH_TILES_EFFECT, PULL_WEAK_SHARE, PULL_CRAWL, PULL_ORIGIN, PULL_STOP_RADIUS, PUSH_DIRECTIONAL_MIN_DIST } from '../constants.js';
|
||||
import {
|
||||
COLS, PUSH_TILES, PUSH_TILES_EFFECT, PULL_WEAK_SHARE, PULL_CRAWL, PULL_ORIGIN, PULL_STOP_RADIUS, PUSH_DIRECTIONAL_MIN_DIST,
|
||||
PUSH_UNBALANCE, PULL_UNBALANCE, PULL_UNBALANCE_WEAK, UNBALANCE_MIN,
|
||||
} from '../constants.js';
|
||||
import { fin } from './util.js';
|
||||
import { hypot } from '../detmath.js';
|
||||
|
||||
@@ -16,6 +19,18 @@ export function pushTiles(level, effect = false) {
|
||||
return (effect ? PUSH_TILES_EFFECT : PUSH_TILES)[Math.min(3, l)];
|
||||
}
|
||||
|
||||
/** 失衡 (UNBALANCE) of a push of 受力等级 `level`, game seconds (constants.js PUSH_UNBALANCE: ≤ −3 → 0, ≥ 3 → the 3 value). */
|
||||
export function pushUnbalance(level) {
|
||||
const l = Math.round(fin(level, -99));
|
||||
return l <= -3 ? 0 : PUSH_UNBALANCE[Math.min(3, l)];
|
||||
}
|
||||
|
||||
/** 失衡 of a pull of 受力等级 `level`: its force window (PULL_UNBALANCE, 0.5 s below −1), none at ≤ −3 (force 0). */
|
||||
export function pullUnbalance(level) {
|
||||
const l = Math.round(fin(level, -99));
|
||||
return l <= -3 ? 0 : l < -1 ? PULL_UNBALANCE_WEAK : PULL_UNBALANCE;
|
||||
}
|
||||
|
||||
export class BattleDisplacement {
|
||||
/**
|
||||
* 受力等级 of enemy `e` under a push / pull of 力度 `force` (微小力 −1, 小力 0, 中力 1, 较大力 2, 大力 3, 大力+1 4, 特大力 5):
|
||||
@@ -40,7 +55,7 @@ export class BattleDisplacement {
|
||||
* Returns the tiles moved.
|
||||
*/
|
||||
push(e, force, { from = null, dir = null, fixed = false, fixedAngle = false, inward = false, effect = false } = {}) {
|
||||
if (!this._displaceable(e)) return 0;
|
||||
if (!this._displaceable(e)) { this._staticForce(e, force); return 0; }
|
||||
let level = this.forceLevel(e, force);
|
||||
const fx0 = fin(from?.x, e.x), fy0 = fin(from?.y, e.y);
|
||||
const vx = e.x - fx0, vy = e.y - fy0, d = hypot(vx, vy);
|
||||
@@ -58,7 +73,12 @@ export class BattleDisplacement {
|
||||
else return 0;
|
||||
let dist = pushTiles(level, effect);
|
||||
if (inward && !(dl > 0)) { ux = -ux; uy = -uy; dist = Math.min(dist, Math.max(0, d - PULL_STOP_RADIUS)); }
|
||||
return this.displace(e, { x: ux, y: uy }, dist);
|
||||
// 失衡 for the row's 位移时间 — also when the 特效 column or a wall shortens the slide [ASSUMED for the wall]; a slide a
|
||||
// wall stops at the first step gets the 0.1 s floor, like a body that cannot move [ASSUMED: 碰撞、停止 is 待补充]
|
||||
const hold = pushUnbalance(level);
|
||||
const moved = this.displace(e, { x: ux, y: uy }, dist, { dur: hold });
|
||||
if (hold > 0) this._unbalance(e, moved > 0 ? hold : UNBALANCE_MIN);
|
||||
return moved;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,12 +88,17 @@ export class BattleDisplacement {
|
||||
* the official 拉力起点 in front of an operator. Returns the tiles moved.
|
||||
*/
|
||||
pull(e, force, { to, center = null, stop = PULL_STOP_RADIUS } = {}) {
|
||||
if (!this._displaceable(e) || !to) return 0;
|
||||
if (!to) return 0;
|
||||
if (!this._displaceable(e)) { this._staticForce(e, force); return 0; }
|
||||
// an enemy the puller itself blocks already stands in front of it (at contact) [ASSUMED: no pull, no unblocking]
|
||||
if (center && center.side === 'ally' && e.blockedBy === center) return 0;
|
||||
const level = this.forceLevel(e, force);
|
||||
// 失衡 for the force window, whatever the travel: the 急停 zeroes the movement, the state lasts to the window's end
|
||||
const hold = pullUnbalance(level);
|
||||
if (!(hold > 0)) return 0;
|
||||
const tx = fin(to.x, e.x), ty = fin(to.y, e.y);
|
||||
const dx = tx - e.x, dy = ty - e.y, d0 = hypot(dx, dy);
|
||||
if (!(d0 > 1e-6)) return 0;
|
||||
if (!(d0 > 1e-6)) { this._unbalance(e, hold); return 0; }
|
||||
const ux = dx / d0, uy = dy / d0;
|
||||
// travel until inside the stop circle around `center` (smaller root of |e + t·u − c| = stop), else up to `to`
|
||||
let full = d0;
|
||||
@@ -84,9 +109,10 @@ export class BattleDisplacement {
|
||||
const disc = wu * wu - w2 + r * r;
|
||||
if (disc >= 0) { const t = -wu - Math.sqrt(disc); if (t >= 0) full = Math.min(full, t); }
|
||||
}
|
||||
const level = this.forceLevel(e, force);
|
||||
const dist = level >= 0 ? full : level === -1 ? Math.min(full, PULL_WEAK_SHARE * d0) : level === -2 ? Math.min(full, PULL_CRAWL) : 0;
|
||||
return dist > 1e-6 ? this.displace(e, { x: ux, y: uy }, dist) : 0;
|
||||
const dist = level >= 0 ? full : level === -1 ? Math.min(full, PULL_WEAK_SHARE * d0) : Math.min(full, PULL_CRAWL);
|
||||
const moved = dist > 1e-6 ? this.displace(e, { x: ux, y: uy }, dist, { dur: hold }) : 0;
|
||||
this._unbalance(e, hold);
|
||||
return moved;
|
||||
}
|
||||
|
||||
/** Official distance (tiles) a push of 力度 `force` would move `e` on open ground (0 when it cannot be displaced). */
|
||||
@@ -107,12 +133,39 @@ export class BattleDisplacement {
|
||||
* 失衡状态 … 但物理层面上无法产生任何速度或移动" — every air unit of the mode except “炎佑”, plus the boss 昆图斯 (build-data
|
||||
* STATIC_BODIES; player report after 0.1.0, "飞机可以被薄绿的技能拉走"). A skill that reaches it still hits it (its targeting
|
||||
* is the skill's own: 锏 S3, 薄绿, the 钩索师 …); only the movement is 0, so distance-based effects (drag damage, 见行者 S2's
|
||||
* wall stun) come to nothing. [ASSUMED] the 0.1 s 失衡硬直 a 静态刚体 still gets is not modelled (no displacement models it).
|
||||
* wall stun) come to nothing — but a force > 0 still puts it in the 失衡 state for its 0.1 s floor (_staticForce).
|
||||
*/
|
||||
_displaceable(e) {
|
||||
return !!(e && e.alive && e.side === 'enemy' && !e.isBoss && !e.s.flags.noDisplace && !(e.def && e.def.staticBody));
|
||||
}
|
||||
|
||||
/**
|
||||
* A push / pull of 力度 `force` on a 静态刚体 (data `staticBody`; not 失衡免疫 `noDisplace` — PRTS 特殊机制 静态刚体: unlike
|
||||
* 失衡免疫 it "可以进入失衡状态并启用物理,但物理层面上无法产生任何速度或移动", leaving it 「在失去施力后立刻」 with 「0.1 秒保底持续
|
||||
* 时间」): a force > 0 (受力等级 ≥ −2) gives the UNBALANCE_MIN state, no movement. Leaders (the boss pool) stay out.
|
||||
*/
|
||||
_staticForce(e, force) {
|
||||
if (!(e && e.alive && e.side === 'enemy' && !e.isBoss && !e.s.flags.noDisplace && e.def && e.def.staticBody)) return;
|
||||
if (this.forceLevel(e, force) >= -2) this._unbalance(e, UNBALANCE_MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put enemy `e` in the 失衡 (UNBALANCE) state for `dur` game seconds from now (a running one is kept when it lasts longer):
|
||||
* a state machine, not a status (PRTS 异常效果: no 阻止攻击 status — no stun, no immunity, SP untouched) — ai.js
|
||||
* updateEnemy reads `unbalanceUntil`: the enemy neither walks (恐惧 / 诱导 included) nor starts a normal attack, a swing
|
||||
* short of its frame is cut; checks that ignore the state (水遁忍者's damage, content abilities) go on. The state machine
|
||||
* switch ends the attack clip it stood for (PRTS 状态机: the states are exclusive — UNBALANCE, then DEFAULT → MOVE). It
|
||||
* ends with its time, or at once with 浮空 (术语释义 浮空 「触发浮空时清除受到的推/拉力…无法陷入失衡」, ai.js) or a 重生.
|
||||
* No global skill lock: enemy abilities keep ticking (the 「使用技能」 part is not modelled — docs/SIM.md).
|
||||
*/
|
||||
_unbalance(e, dur) {
|
||||
if (!(dur > 0) || !e || !e.alive) return;
|
||||
const until = this.time + dur;
|
||||
if (!(e.unbalanceUntil >= until)) e.unbalanceUntil = until;
|
||||
this._cutAttackStand(e);
|
||||
e.atkStandUntil = -Infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an enemy `distance` tiles along `dir` = {x, y} (normalised internally) over passable tiles — the raw mover of
|
||||
* push() / pull(), which apply the official 力度 − 重量 rules (content uses those; the old `force` option is gone).
|
||||
@@ -120,7 +173,7 @@ export class BattleDisplacement {
|
||||
* ⇒ no movement (_displaceable). The tiles it may cross follow its movement (`motion`): a hovering enemy walks the
|
||||
* ground, so it stays on ground-passable tiles.
|
||||
*/
|
||||
displace(e, dir, distance) {
|
||||
displace(e, dir, distance, { dur = 0 } = {}) {
|
||||
if (!this._displaceable(e) || !dir) return 0;
|
||||
const dxv = fin(dir.x, 0), dyv = fin(dir.y, 0);
|
||||
const len = hypot(dxv, dyv);
|
||||
@@ -144,7 +197,8 @@ export class BattleDisplacement {
|
||||
this._cutAttackStand(e);
|
||||
e.atkStandUntil = -Infinity;
|
||||
if (e.route) e.route.pts = null;
|
||||
this.fx('displace', { x: e.x, y: e.y, id: e.id });
|
||||
// `dur` (game s): the 失衡 the push / pull gives — the client's slide takes that long (render/units.js slideTo)
|
||||
this.fx('displace', dur > 0 ? { x: e.x, y: e.y, id: e.id, dur } : { x: e.x, y: e.y, id: e.id });
|
||||
}
|
||||
return moved;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ export class BattleSpawns {
|
||||
e.atkCd = 0;
|
||||
e.pauseUntil = -Infinity; // content holds (暴鸰's drop)
|
||||
e.atkStandUntil = -Infinity; // standing for its attack clip (ai.js attackStand)
|
||||
e.unbalanceUntil = -Infinity; // 失衡 (UNBALANCE) after a push / pull (battle/displacement.js _unbalance, ai.js)
|
||||
e.atkStandCutAt = -Infinity; // display metadata: when its stand was last cut or ignored (snapshot standCut)
|
||||
e.swing = false; // a normal attack swung, its damage frame not reached yet (ai.js enemyAttack)
|
||||
// every enemy profile starts with the same fields (stable object shapes keep the hot loop's property reads fast);
|
||||
|
||||
@@ -128,6 +128,21 @@ export const PULL_CRAWL = 0.03;
|
||||
export const PULL_ORIGIN = 0.5;
|
||||
export const PULL_STOP_RADIUS = 0.6708;
|
||||
export const PUSH_DIRECTIONAL_MIN_DIST = 0.25;
|
||||
/**
|
||||
* 失衡 (UNBALANCE) — the state machine a force > 0 puts an enemy in (PRTS 失衡位移机制 「当一名敌方单位受到一个任意来源的力,
|
||||
* 并且受力大小 > 0 时,该敌方单位将进入失衡(UNBALANCE)状态机」; 异常效果图鉴/失衡免疫 「失衡期间无法自主移动、发动攻击、使用技能」 —
|
||||
* not an abnormal status: 异常效果 「失衡…不属于异常效果,它是一种状态机」, so it is no stun). Its length in game seconds:
|
||||
* PUSH_UNBALANCE = a push by 受力等级 — PRTS 游戏数据基础 推力-位移近似对应表 「位移时间」 (whole frames at 30 fps: 6, 12, 24,
|
||||
* 27, 32, 35; the 0.1 s floor is inside them); PULL_UNBALANCE / PULL_UNBALANCE_WEAK = a pull's force window — 推与拉 §拉力
|
||||
* 「作用时间默认为 1 s;若本次受力等级 < −1,作用时间改为 0.5 s」, the state lasting to its end after the 急停 too (「目标将仍保持
|
||||
* 失衡状态至拉力作用时间结束为止」); UNBALANCE_MIN = the 失衡硬直 floor (「立刻拥有 0.1 s 的“失衡硬直”。此期间无法解除失衡状态机
|
||||
* ——哪怕已经没有被移动或者受力」) — what a 静态刚体 hit by a force gets (特殊机制 静态刚体 「失衡状态拥有 0.1 秒保底持续时间」).
|
||||
* PR #392 by @xcdoge brought the state; its 0.6387·√tiles was derived from the page's μ = 0.5 单位假设, not printed.
|
||||
*/
|
||||
export const PUSH_UNBALANCE = Object.freeze({ '-2': 0.2, '-1': 0.4, 0: 0.8, 1: 0.9, 2: 32 / 30, 3: 35 / 30 });
|
||||
export const PULL_UNBALANCE = 1;
|
||||
export const PULL_UNBALANCE_WEAK = 0.5;
|
||||
export const UNBALANCE_MIN = 0.1;
|
||||
|
||||
/**
|
||||
* Fallback freeze when a second 寒冷 lands and neither the remaining cold nor the incoming one has a duration
|
||||
|
||||
@@ -356,6 +356,7 @@ function reborn({ dur = 0, hpRatio = 1, invincible = 0, onKo = null, during = nu
|
||||
a.state = 'reborn';
|
||||
a.t0 = b.time;
|
||||
a.noAtk = e.profile.noAttack;
|
||||
e.unbalanceUntil = -Infinity; // a 重生 is a forced state change: it ends a 失衡 (PRTS 失衡位移机制 「例如复活」)
|
||||
rebirthCleanse(b, e);
|
||||
e.hp = Math.min(1, e.s.maxHp);
|
||||
if (onKo) safe(b, e, () => onKo(b, e, a));
|
||||
|
||||
Reference in new issue
Block a user