feedback7: merge fb7-unbalance — the official 失衡 (UNBALANCE) after a push / pull (the idea of PR #392 by @xcdoge, re-implemented from PRTS): no walking, attacking or skills while it lasts; pushes by the 推力-位移 time table, pulls by the force window (0.5 / 1 s), static bodies 0.1 s pushed / the window pulled; 弧光锋卫 bleeds 400 / 0.066 s while unbalanced; the client slide uses the same time
- The owner asked to verify the official rule before deciding (research: PRTS 失衡位移机制 / 推与拉 / 游戏数据基础 / 特殊机制,
the client's Rigidbody2D data); the PR's 0.6387·√tiles formula and fear exemption were not taken.
- Grok review: MERGE AFTER FIXES — two HIGH (static pulls, 弧光锋卫's bleed), skills during the hold, husk 重生, exact
frames — fixed on the branch (1db84d79).
- Golden union: bond-miraShip-low differs from HEAD (fewer enemy attacks: 169 → 166 events, same kills) though the
branch alone left it — HEAD's ×1.1 练度 path now displaces an enemy there. Broad node --test 5681 (5679 pass, 0 fail,
2 skipped); lint 0 errors.
This commit is contained in:
commit
0ae2fac2b1
27 files changed
+1452
-1058
No files matched your search
@@ -1453,7 +1453,7 @@ export async function createFieldView(host, options = {}) {
|
||||
if (e[1] === 'displace') {
|
||||
const d = e[4] && typeof e[4] === 'object' ? e[4] : null;
|
||||
const v = d && d.id != null ? views.get(d.id) : null;
|
||||
if (v && v.slideTo) v.slideTo(Number(e[2]), Number(e[3]));
|
||||
if (v && v.slideTo) v.slideTo(Number(e[2]), Number(e[3]), Number(d.dur) > 0 ? { dur: Number(d.dur) } : {});
|
||||
}
|
||||
// an enemy's mode change — the `form` of a sim setForm fx (shared/protocol.js fxForm: 掠海漂移体 → 爬行模式, user
|
||||
// playtest #5 item 1; 转译基底's forms, a 逐火 ember and its revival, the leaders' 重生, 守墓石像 — user report after
|
||||
@@ -1513,7 +1513,8 @@ export async function createFieldView(host, options = {}) {
|
||||
if (!Array.isArray(e) || e[0] !== 'fx' || e[1] !== 'displace') return;
|
||||
const extra = e[4] && typeof e[4] === 'object' ? e[4] : null;
|
||||
const v = extra && extra.id != null ? views.get(extra.id) : null;
|
||||
if (v && v.slideTo) v.slideTo(Number(e[2]), Number(e[3]), { at: slideAt });
|
||||
// `dur`: the push / pull's 失衡 time in game seconds (battle/displacement.js) — the slide's length
|
||||
if (v && v.slideTo) v.slideTo(Number(e[2]), Number(e[3]), Number(extra.dur) > 0 ? { at: slideAt, dur: Number(extra.dur) } : { at: slideAt });
|
||||
}
|
||||
let renderT0Battle = null; // game time of the first rendered battle frame (spawn puffs skip the initial wave)
|
||||
let downSeq = 0; // syncBattle pass counter: a view still marked down after a pass left the `down` list
|
||||
|
||||
+13
-13
@@ -178,16 +178,14 @@ const RAISED_Z = 0.12;
|
||||
*/
|
||||
export const FLY_HOVER = 1.3;
|
||||
/**
|
||||
* A push / pull slide (推拉, PR #380 by @xcdoge): real seconds per √tile of travel. The sim displaces at once —
|
||||
* server/sim/battle/displacement.js walks its 0.1-tile steps inside one call — so the snapshots only ever show the
|
||||
* destination, and a pushed / pulled enemy appeared at the end of its path (a ≤ 2.5-tile push in one snapshot interval,
|
||||
* a longer pull snapped). The view now slides there under a constant deceleration (UnitView.slideTo): the official
|
||||
* knockback abilities (`Knockback`, `KnockBackWithDirection`, `DragTowardSource` in the client's metadata) carry an
|
||||
* impulse (`m_force`) and a velocity decaying under friction (`m_friction`, the tile's `additionalFriction`), and the data
|
||||
* has no per-skill duration (docs/research/13-knockback-official.md). The duration T = DISPLACE_SLIDE·√D, kept in
|
||||
* 0.12–0.45 s, is ours [ASSUMED: a fit so the view arrives where the sim put it — no source gives the official
|
||||
* timing]; v0 = 2D/T, a = v0/T then run the distance in exactly T. Purely visual: the sim's timing, damage, blocking and
|
||||
* the golden digests are untouched.
|
||||
* A push / pull slide (推拉, PR #380 by @xcdoge). The sim displaces at once — server/sim/battle/displacement.js walks its
|
||||
* 0.1-tile steps inside one call — and then holds the enemy in its 失衡 (UNBALANCE) state (PR #392's idea): a push for the
|
||||
* 位移时间 of its 受力等级 (PRTS 游戏数据基础 推力-位移近似对应表: 0.2 … 35/30 game s), a pull for its force window (推与拉:
|
||||
* 0.5 / 1 s). The snapshots only ever show the destination, so the view slides there under a constant deceleration
|
||||
* (UnitView.slideTo) for that same span: the `displace` fx carries it (`dur`, game seconds) and the view divides it by the
|
||||
* playback rate (ctx.animRate — 2 game s per real second by default: a 0.8 s push slides 0.4 real s) — it lands as the
|
||||
* sim's state ends. v0 = 2D/T, a = v0/T then run the distance in exactly T. DISPLACE_SLIDE (real s per √tile, kept in
|
||||
* 0.12–0.45 s) is only the fallback for an fx without `dur` (a recording made before 0.2.2) [ASSUMED].
|
||||
*/
|
||||
export const DISPLACE_SLIDE = 0.14;
|
||||
/**
|
||||
@@ -860,7 +858,8 @@ export class UnitView {
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide to a displacement's destination (推拉, the `displace` fx at (x, y)) instead of appearing there (DISPLACE_SLIDE).
|
||||
* Slide to a displacement's destination (推拉, the `displace` fx at (x, y)) instead of appearing there: `opts.dur` = the
|
||||
* fx's 失衡 time in game seconds (real seconds = dur / ctx.animRate), else the DISPLACE_SLIDE·√D fallback.
|
||||
* `at` (game s): the time of the snapshot that carries the destination — render/app.js starts the slide as soon as the
|
||||
* interpolator shows the interval before it, and until the render clock reaches `at` the view holds where it stood
|
||||
* (the sample in between is a lerp or a snap towards the destination). From then on it eases from there into the
|
||||
@@ -877,8 +876,9 @@ export class UnitView {
|
||||
const D = Math.hypot(dx, dy);
|
||||
if (!this.alive || !(D > 0.05)) { this.x = x; this.y = y; this.slide = null; return; }
|
||||
const f = Number.isFinite(opts.friction) && opts.friction > 0 ? opts.friction : SLIDE_FRICTION;
|
||||
// a slippery tile (f < 1) slides longer; the duration still follows √D (constant deceleration)
|
||||
const T = Math.max(0.05, (opts.dur > 0 ? opts.dur : clamp(DISPLACE_SLIDE * Math.sqrt(D), 0.12, 0.45)) / f);
|
||||
// the sim's 失衡 time (game s) at the playback rate; a slippery tile (f < 1) slides longer
|
||||
const rate = this.ctx.animRate?.() || 1;
|
||||
const T = Math.max(0.05, (opts.dur > 0 ? opts.dur / rate : clamp(DISPLACE_SLIDE * Math.sqrt(D), 0.12, 0.45)) / f);
|
||||
// v0 = 2D/T and a = v0/T run the distance in exactly T with the velocity reaching 0 there, integrated in update().
|
||||
// The official turns a displaced unit towards the force (its _dontChangeFaceByDirection is an opt-in flag), while
|
||||
// our facing comes from the snapshot's vx — which points back down the route the enemy resumes after the
|
||||
|
||||
Reference in new issue
Block a user