feedback6 R21F: enemy animation states, the client part of PR #275 by @xcdoge re-implemented — the resolver gives an enemy every numbered skill clip (anims.skills; the caller's first index stays the primary, operators unchanged, 宴's PREFAB_SPINE_ROLES fix kept), the stun spellings Stun_1 and Dizzy_Begin/Loop/End, a separate run role (Run_Begin/Loop/End); the renderer walks an enemy faster than moveSpeed 1 on its Run cycle (猎狗pro, 深池侦察犬 ×2; [ASSUMED] threshold), swaps an enemy's skill clip on a cast event (UnitView.setSkillSlot; a form in force is kept), and plays the 重生 of 巨大的丑东西 (Revive, then the fleeing 大祭司 Idle_2 / Move_2 / Stun_2) and 自在 (Revive_01); data/assets.json regenerated offline: 18 enemies gain anims.skills, 6 anims.run, 3 a stun clip (巨大的丑东西, 斩胄之剑, 破胄之锤), nothing else; the sim's cast slot (a new event) is not part of it; golden: unchanged
This commit is contained in:
1 parent
14df10a5a3
commit
76a2db7dd0
11 files changed
+315
-19
No files matched your search
@@ -289,6 +289,18 @@ export const FORMS = Object.freeze({
|
||||
enemy_1525_blkswb: rebirth('Revive1', 'Revive2', 'Revive3', clipSet('B_Idle', 'B_Move', 'B_Die', 'B_Attack')),
|
||||
enemy_1535_wlfmster: rebirth('A_revive_1', 'A_revive_2', 'A_revive_3', clipSet('B_Idle', 'B_Move', 'B_Die', 'B_Attack')),
|
||||
enemy_1539_reid: rebirth('Revive_Begin', 'Revive_Loop', 'Revive_End'),
|
||||
// 重生 on the skeleton's own Revive clip (PR #275 by @xcdoge; content/enemies/leaders.js kitUglyThing / kitXi): 巨大的丑东西
|
||||
// — Revive 8.67 s of the 10 s 重生 (its self-destruct 2.17 s in), then the fleeing 大祭司 (Idle_2 / Move_2 / Stun_2;
|
||||
// 不进行攻击) holding its idle while the sim still holds the 重生 (reported as a stun); 自在 — Revive_01 5.33 s for the
|
||||
// 5 s 重生, then the same model, stronger (reborn.atk)
|
||||
enemy_1512_mcmstr: Object.freeze({
|
||||
reborn: Object.freeze({ change: 'Revive', next: 'form2', roles: Object.freeze({ idle: 'Idle_2', deploy: 'Idle_2', move: loop('Idle_2'), stun: loop('Idle_2'), attack: null, skill: null }) }),
|
||||
form2: Object.freeze({ change: null, roles: Object.freeze({ ...clipSet('Idle_2', 'Move_2', 'Die'), stun: loop('Stun_2') }) }),
|
||||
}),
|
||||
enemy_1517_xi: Object.freeze({
|
||||
reborn: Object.freeze({ change: 'Revive_01', next: 'form2', roles: Object.freeze({}) }),
|
||||
form2: Object.freeze({ change: null, roles: Object.freeze({}) }),
|
||||
}),
|
||||
enemy_1516_jakill: Object.freeze({
|
||||
reborn: Object.freeze({ change: 'C1_Die', roles: JAKILL2 }),
|
||||
form2: Object.freeze({ change: null, roles: JAKILL2 }),
|
||||
@@ -355,6 +367,9 @@ export class UnitView {
|
||||
this.info = { ...info };
|
||||
this.id = info.id;
|
||||
this.uid = info.uid ?? null;
|
||||
// the skill slot whose Spine clip the unit shows (DESIGN §16): an ally's equipped skill; an enemy's cast slot when the
|
||||
// sim reports one (`cast` event, setSkillSlot — a multi-skill boss's Skill_01..04, PR #275)
|
||||
this.skillIndex = Number.isInteger(info.skillIndex) ? info.skillIndex : null;
|
||||
this.prep = !!opts.prep;
|
||||
this.lodIdle = opts.lod === 'idle';
|
||||
this.culled = false; // outside the viewport this frame (not animated, not drawn)
|
||||
@@ -365,6 +380,9 @@ export class UnitView {
|
||||
// enemies: the official prefab's size factor (1 for operators, summons and enemies at the standard size)
|
||||
const def = this.isEnemy && ctx.lookupDef ? ctx.lookupDef(info) : null;
|
||||
this.modelK = this.isEnemy ? enemyModelScale(def) : 1;
|
||||
// a fast enemy walks on its model's own Run cycle when it has one (PR #275 by @xcdoge: 猎狗pro, moveSpeed 1.9, Run_Loop
|
||||
// 0.53 s next to Move_Loop 0.80 s; also 深池侦察犬 1.7). [ASSUMED] the threshold: faster than the standard 1
|
||||
this.moveFast = this.isEnemy && Number(def?.stats?.moveSpeed) > 1;
|
||||
// the official's own model quirks (enemies.json, read from its battle prefabs — tools/local-extract/enemy_model_offsets.py,
|
||||
// PR #211): a vertical stretch (its Graphic scale's sy / sx, the two 帝国炮火先兆者 at 1.263) and a mirrored X scale
|
||||
// (the Graphic's sx is negative, so the official draws the authored model flipped: 木制瑞印)
|
||||
@@ -546,7 +564,8 @@ export class UnitView {
|
||||
let actor = null;
|
||||
try {
|
||||
actor = new SpineActor(data, entry);
|
||||
actor.setSkillIndex(this.info.skillIndex);
|
||||
actor.setSkillIndex(this.skillIndex ?? undefined);
|
||||
actor.setRunMode(this.moveFast);
|
||||
// enemies play their attack clip once per attack, then walk on (GitHub #58: the sim stands them for that clip)
|
||||
actor.clipPerAttack = this.isEnemy;
|
||||
} catch (err) {
|
||||
@@ -849,6 +868,17 @@ export class UnitView {
|
||||
if (this.actor) this.actor.setSkill(on);
|
||||
}
|
||||
|
||||
/**
|
||||
* The skill slot an enemy casts (the sim's `cast` event; PR #275 by @xcdoge): its clip set swaps to that slot's skill
|
||||
* clip (`anims.skills`, a multi-skill boss's Skill_01..04), which the SKILL flag right after plays. The same slot again
|
||||
* or a non-slot changes nothing.
|
||||
*/
|
||||
setSkillSlot(index) {
|
||||
if (!Number.isInteger(index) || index < 0 || index === this.skillIndex) return;
|
||||
this.skillIndex = index;
|
||||
if (this.actor) this.actor.setSkillIndex(index);
|
||||
}
|
||||
|
||||
onDeploy() {
|
||||
this.fadeIn = 0;
|
||||
if (!this.alive) this.revive();
|
||||
|
||||
Reference in new issue
Block a user