feedback5: 宴 stands during 落地斩·破门 — her one unnumbered skill set (Skill_Start / Loop / End) is S1 分神's sit-down rest, and the by-name resolver gave it to S2 too, so she knelt through the opening seconds of every battle (the owner's playtest of 2026-10-07); tools/assets/spine.mjs PREFAB_SPINE_ROLES now also fixes operator models by character id (front and back): 宴's S2 plays her ordinary clips (via 'attack'), S1 keeps the rest; data/assets.json rebuilt offline (only her entries changed); test/feedback5-utage-anims.test.js; CHANGELOG 界面, §25.22.9; golden unchanged (client art only)
This commit is contained in:
1 parent
f24d2a9016
commit
caee1dbed9
5 files changed
+71
-5
No files matched your search
@@ -90,6 +90,8 @@
|
||||
- 游戏数据没能下载时,「干员调配」不再显示空的干员列表,导入也不再提示「这份数据在当前版本没有可用的调配」:现在会直接写明游戏数据没有载入、缺的是哪个文件,并提示刷新页面、检查广告拦截插件和网络。这时三个标签页都不执行导入,已保存的干员持有和自选编队也不会再被清空(GitHub #173,感谢 @sarilendorf)。
|
||||
- 每回合结算时跳出官方的「作战结束」框,只写自己这一回合被扣的目标生命值:没扣是「全员无伤!」,扣了是「生命值减少 −N」,并播放官方的三种战斗结束音效之一。联防回合的数字按服务器实际扣的点数;联防有敌人漏过去时不显示「全员无伤!」,没被扣的人只看到标题。最终攻势、隐秘核心,以及已淘汰的玩家和观战者不弹框(GitHub #235,PR #112,感谢 @Convey123)。
|
||||
|
||||
- 宴开局时不再跪在地上:她的模型只有一套技能动作,是一技能「分神」坐下休息的姿势,之前二技能(卫戍里的「落地斩·破门」,每次部署后的头几秒)也套用了它,所以每场开局都跪着;现在二技能期间正常站立和攻击,一技能仍是坐下休息(维护者试玩反馈)。
|
||||
|
||||
### 联机与大厅
|
||||
|
||||
- 干员持有和自选编队按座位保存,开局时固定;对局进行中修改的设置留到下一局生效。
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":1,"hash":"c79a28fbd507","generator":"tools/fetch-assets.mjs","stats":{"files":7969,"bytes":485061859,"chars":209,"charsWithBack":206,"enemies":252,"enemiesWithSpine":251,"tokens":58,"tokensWithSpine":13,"spineModels":671,"bonds":23,"items":59,"bands":40,"skills":522,"modules":131,"ui":602,"sfxUnits":483,"voiceChars":191},"chars":{"char_003_kalts":{"avatar":"/assets/char/avatar/char_003_kalts.png","avatarE2":"/assets/char/avatar/char_003_kalts_2.png","portrait":"/assets/char/portrait/char_003_kalts_1.png","portraitE2":"/assets/char/portrait/char_003_kalts_2.png","spine":{"front":{"skel":"/assets/spine/op/char_003_kalts/front/char_003_kalts.skel","atlas":"/assets/spine/op/char_003_kalts/front/char_003_kalts.atlas","textures":["/assets/spine/op/char_003_kalts/front/char_003_kalts.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"die":"Die","move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"1":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":1,"idle":null},"2":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":2,"idle":null}}},"animations":{"Attack":1,"Default":0,"Die":1,"Idle":9,"Start":1},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433]},"bounds":{"x":-227.579,"y":-138.244,"width":532.04,"height":551.479}},"back":{"skel":"/assets/spine/op/char_003_kalts/back/char_003_kalts.skel","atlas":"/assets/spine/op/char_003_kalts/back/char_003_kalts.atlas","textures":["/assets/spine/op/char_003_kalts/back/char_003_kalts.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"die":null,"move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"1":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":1,"idle":null},"2":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":2,"idle":null}}},"animations":{"Attack":1,"Default":0,"Idle":9,"Start":1},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433]},"bounds":{"x":410.785,"y":-2.26,"width":531.785,"height":416.492}}}},"char_010_chen":{"avatar":"/assets/char/avatar/char_010_chen.png","avatarE2":"/assets/char/avatar/char_010_chen_2.png","portrait":"/assets/char/portrait/char_010_chen_1.png","portraitE2":"/assets/char/portrait/char_010_chen_2.png","spine":{"front":{"skel":"/assets/spine/op/char_010_chen/front/char_010_chen.skel","atlas":"/assets/spine/op/char_010_chen/front/char_010_chen.atlas","textures":["/assets/spine/op/char_010_chen/front/char_010_chen.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"die":"Die","move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"1":{"begin":null,"loop":"Skill_2","end":null,"index":1,"idle":null},"2":{"begin":null,"loop":"Skill_3","end":null,"index":2,"idle":null}}},"animations":{"Attack":1.5,"Attack_End":0.6,"Attack_Pre":0.6,"Default":0,"Die":1,"Idle":2,"Skill":1,"Skill_2":1.167,"Skill_3":2.933,"Skill_End":0.6,"Skill_End_2":0.6,"Skill_End_3":0.3,"Start":0.833},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433,1],"Skill":[0.467],"Skill_2":[0.467],"Skill_3":[0.6,0.8,1,1.2,1.4,1.6,1.8,2,2.2,2.833,2.933]},"bounds":{"x":-322.335,"y":-109.274,"width":663.549,"height":524.806}},"back":{"skel":"/assets/spine/op/char_010_chen/back/char_010_chen.skel","atlas":"/assets/spine/op/char_010_chen/back/char_010_chen.atlas","textures":["/assets/spine/op/char_010_chen/back/char_010_chen.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"die":null,"move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"1":{"begin":null,"loop":"Skill","end":"Skill_End","index":1,"idle":null},"2":{"begin":null,"loop":"Skill","end":"Skill_End","index":2,"idle":null}}},"animations":{"Attack":1.5,"Attack_End":0.6,"Attack_Pre":0.6,"Default":0,"Idle":2,"Skill":1,"Skill_End":0.6,"Start":0.833},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433,1],"Skill":[0.467]},"bounds":{"x":-173.082,"y":-13.829,"width":315.887,"height":404.623}}}},"char_017_huang":{"avatar":"/assets/char/avatar/char_017_huang.png","avatarE2":"/assets/char/avatar/char_017_huang_2.png","portrait":"/assets/char/portrait/char_017_huang_1.png","portraitE2":"/assets/char/portrait/char_017_huang_2.png","spine":{"front":{"skel":"/assets/spine/op/char_017_huang/front/char_017_huang.skelLine truncated
|
||||
{"version":1,"hash":"b699458e3e10","generator":"tools/fetch-assets.mjs","stats":{"files":7969,"bytes":485061859,"chars":209,"charsWithBack":206,"enemies":252,"enemiesWithSpine":251,"tokens":58,"tokensWithSpine":13,"spineModels":671,"bonds":23,"items":59,"bands":40,"skills":522,"modules":131,"ui":602,"sfxUnits":483,"voiceChars":191},"chars":{"char_003_kalts":{"avatar":"/assets/char/avatar/char_003_kalts.png","avatarE2":"/assets/char/avatar/char_003_kalts_2.png","portrait":"/assets/char/portrait/char_003_kalts_1.png","portraitE2":"/assets/char/portrait/char_003_kalts_2.png","spine":{"front":{"skel":"/assets/spine/op/char_003_kalts/front/char_003_kalts.skel","atlas":"/assets/spine/op/char_003_kalts/front/char_003_kalts.atlas","textures":["/assets/spine/op/char_003_kalts/front/char_003_kalts.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"die":"Die","move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"1":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":1,"idle":null},"2":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":2,"idle":null}}},"animations":{"Attack":1,"Default":0,"Die":1,"Idle":9,"Start":1},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433]},"bounds":{"x":-227.579,"y":-138.244,"width":532.04,"height":551.479}},"back":{"skel":"/assets/spine/op/char_003_kalts/back/char_003_kalts.skel","atlas":"/assets/spine/op/char_003_kalts/back/char_003_kalts.atlas","textures":["/assets/spine/op/char_003_kalts/back/char_003_kalts.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"die":null,"move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":0,"idle":null},"1":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":1,"idle":null},"2":{"begin":null,"loop":"Attack","end":null,"via":"attack","index":2,"idle":null}}},"animations":{"Attack":1,"Default":0,"Idle":9,"Start":1},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433]},"bounds":{"x":410.785,"y":-2.26,"width":531.785,"height":416.492}}}},"char_010_chen":{"avatar":"/assets/char/avatar/char_010_chen.png","avatarE2":"/assets/char/avatar/char_010_chen_2.png","portrait":"/assets/char/portrait/char_010_chen_1.png","portraitE2":"/assets/char/portrait/char_010_chen_2.png","spine":{"front":{"skel":"/assets/spine/op/char_010_chen/front/char_010_chen.skel","atlas":"/assets/spine/op/char_010_chen/front/char_010_chen.atlas","textures":["/assets/spine/op/char_010_chen/front/char_010_chen.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"die":"Die","move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"1":{"begin":null,"loop":"Skill_2","end":null,"index":1,"idle":null},"2":{"begin":null,"loop":"Skill_3","end":null,"index":2,"idle":null}}},"animations":{"Attack":1.5,"Attack_End":0.6,"Attack_Pre":0.6,"Default":0,"Die":1,"Idle":2,"Skill":1,"Skill_2":1.167,"Skill_3":2.933,"Skill_End":0.6,"Skill_End_2":0.6,"Skill_End_3":0.3,"Start":0.833},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433,1],"Skill":[0.467],"Skill_2":[0.467],"Skill_3":[0.6,0.8,1,1.2,1.4,1.6,1.8,2,2.2,2.833,2.933]},"bounds":{"x":-322.335,"y":-109.274,"width":663.549,"height":524.806}},"back":{"skel":"/assets/spine/op/char_010_chen/back/char_010_chen.skel","atlas":"/assets/spine/op/char_010_chen/back/char_010_chen.atlas","textures":["/assets/spine/op/char_010_chen/back/char_010_chen.png"],"pma":false,"anims":{"idle":"Idle","deploy":"Start","attack":{"begin":null,"loop":"Attack","end":null},"attackDown":null,"skill":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"die":null,"move":null,"stun":null,"skills":{"0":{"begin":null,"loop":"Skill","end":"Skill_End","index":0,"idle":null},"1":{"begin":null,"loop":"Skill","end":"Skill_End","index":1,"idle":null},"2":{"begin":null,"loop":"Skill","end":"Skill_End","index":2,"idle":null}}},"animations":{"Attack":1.5,"Attack_End":0.6,"Attack_Pre":0.6,"Default":0,"Idle":2,"Skill":1,"Skill_End":0.6,"Start":0.833},"events":["OnAttack","OnStart"],"hits":{"Attack":[0.433,1],"Skill":[0.467]},"bounds":{"x":-173.082,"y":-13.829,"width":315.887,"height":404.623}}}},"char_017_huang":{"avatar":"/assets/char/avatar/char_017_huang.png","avatarE2":"/assets/char/avatar/char_017_huang_2.png","portrait":"/assets/char/portrait/char_017_huang_1.png","portraitE2":"/assets/char/portrait/char_017_huang_2.png","spine":{"front":{"skel":"/assets/spine/op/char_017_huang/front/char_017_huang.skelLine truncated
|
||||
+17
-1
@@ -1872,7 +1872,8 @@ contact (#232, §25.22.1), the round-start banner of an eliminated player or a s
|
||||
without its game data (#173, §25.22.3), the official result box and battle-over sounds of the approved PR #112 (#235,
|
||||
§25.22.4), the 5-阿戈尔 batch revive by board position (§25.22.5), an enemy finishing its attack clip after a strike
|
||||
(§25.22.6, with the owner's 1 s re-stealth for the 鸭爵 swap's 流泪小子, a deliberate deviation), and 蕾缪安's S3 that
|
||||
waits for targets (§25.22.8). Official as it was: 拉普兰德's and 赫默's layers from the 整备区 (§25.22.7). The rest of
|
||||
waits for targets (§25.22.8); from the owner's own playtest, 宴's model no longer kneels while her deployment skill
|
||||
runs (§25.22.9). Official as it was: 拉普兰德's and 赫默's layers from the 整备区 (§25.22.7). The rest of
|
||||
round 19 was answered (not a bug, already fixed in 0.2.0, or left for 0.2.1).
|
||||
|
||||
#### 25.22.1 GitHub #232 「再部署之后的干员无法阻挡破隐被冰冻的隐身怪」 (@ccyl; the repro and the cause by @kukiC): a stunned or frozen enemy is blocked by contact — `sim/ai.js updateEnemy`
|
||||
@@ -2204,6 +2205,21 @@ round 19 was answered (not a bug, already fixed in 0.2.0, or left for 0.2.1).
|
||||
stays while the shooter's skill bit is on, then LOCK_T after; an unheld one times out — fails on the parent's
|
||||
renderer); `test/content/kits_t6.test.js`, `kits_alt_t6.test.js`, `test/sim/feedback3-ammo-bar.test.js` pass unchanged.
|
||||
|
||||
#### 25.22.9 宴 knelt through the opening seconds of every battle (the owner's playtest of 2026-10-07: 「干员宴的模型开局时是跪地的状态,不是正常的站立」) — `tools/assets/spine.mjs PREFAB_SPINE_ROLES`, `data/assets.json`
|
||||
|
||||
- **Seen**: 宴 on the board knelt as the battle opened and stood up a few seconds later. **Cause**: her skeleton has one
|
||||
unnumbered skill set (Skill_Start / Skill_Loop / Skill_End) — she sits down and rests, S1 分神's pose (停止攻击,防御力
|
||||
提升,每秒恢复生命); tools/assets/anim-roles.mjs resolves clips by name, so both skill indices got it, and S2 — the 卫戍
|
||||
default 落地斩·破门, on for its duration from every deployment — played the rest pose. **Now**: PREFAB_SPINE_ROLES also
|
||||
fixes operator models (by character id, front and back): 宴's index 1 plays her ordinary clips (`via: 'attack'`, which
|
||||
render/spine.js treats as no skill clip), index 0 keeps the rest; `fetch-assets --offline` rebuilt data/assets.json
|
||||
(only her entries changed). [ASSUMED]: by the clips' pose and S1's text (the prefab's skill table was not read).
|
||||
- Open: 29 more operators in the mode share one unnumbered skill set across their skills (e.g. 德克萨斯, 雷蛇, 拉普兰德,
|
||||
银灰, 煌); for most it is an attack-like skill pose, so a skill that officially has none shows it while it runs — to be
|
||||
checked against the prefabs' skill tables for 0.2.1.
|
||||
- Tests: `test/feedback5-utage-anims.test.js` (the resolver alone kneels in S2; the fix; the shipped manifest, both models).
|
||||
Checked in a real match (the fast server's starter kit on round 2): both copies stand at 0.7 s with 落地斩·破门 on.
|
||||
|
||||
### 25.23 The Japanese, Korean and Traditional Chinese interfaces (UI-JA, UI-KO, UI-TW; the owner's decision of 2026-10-07) — `public/i18n/ja.json`, `ko.json`, `zh-TW.json`, `shared/packs.js`, `shared/i18nPacks.js`, `shared/i18n.js`, `public/js/ui/lang.js machineTranslationNote`, `public/js/ui/settings.js`, `tools/build-i18n.mjs` (`untranslated: 'native'`, `nativeCharset`), `data/i18n/*.json`, `public/css/theme.css` (`--cjk-faces`, `:lang()`), `public/js/screens/lobby.js`, docs/I18N.md, docs/PACKS.md
|
||||
|
||||
- **Seen**: the owner tested 0.2.0 — 「新版本日语韩语繁体中文实测切换没有生效,只有中文英文生效」. The switch worked (the game texts
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// 宴's skill clips (the owner's playtest of 2026-10-07: 「干员宴的模型开局时是跪地的状态」): her one unnumbered skill set
|
||||
// (Skill_Start / Skill_Loop / Skill_End, a sit-down rest) belongs to S1 分神 only; S2 — the 卫戍 default 落地斩·破门, on
|
||||
// from every deployment for its duration — attacks with her ordinary clips (tools/assets/spine.js PREFAB_SPINE_ROLES).
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { resolveRoles } from '../tools/assets/anim-roles.mjs';
|
||||
import { applyRoleFix, PREFAB_SPINE_ROLES } from '../tools/assets/spine.mjs';
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const CLIPS = ['Attack', 'Die', 'Idle', 'Skill_End', 'Skill_Loop', 'Skill_Start', 'Start'];
|
||||
const durations = Object.fromEntries(CLIPS.map((n) => [n, 1]));
|
||||
|
||||
test('宴: the resolver alone gives both skill indices the sit-down set; the role fix keeps it for S1 and attacks normally in S2', () => {
|
||||
const resolved = resolveRoles(CLIPS, { skillIndices: [1, 0], durations });
|
||||
assert.equal(resolved.skills['1'].loop, 'Skill_Loop', 'by name alone, S2 would kneel (the reported bug)');
|
||||
const { roles, missing } = applyRoleFix(resolved, PREFAB_SPINE_ROLES.char_337_utage, durations);
|
||||
assert.deepEqual(missing, []);
|
||||
assert.equal(roles.skills['0'].loop, 'Skill_Loop', 'S1 分神 keeps her rest');
|
||||
assert.equal(roles.skills['1'].loop, 'Attack');
|
||||
assert.equal(roles.skills['1'].via, 'attack', "via 'attack': the renderer plays no skill clip (render/spine.js)");
|
||||
assert.equal(roles.skill.index, 1, 'the primary (equipped by default) skill is S2');
|
||||
assert.equal(roles.skill.via, 'attack');
|
||||
});
|
||||
|
||||
test('宴: the shipped manifest carries the fix on both models', () => {
|
||||
const a = JSON.parse(readFileSync(path.join(ROOT, 'data/assets.json'), 'utf8'));
|
||||
for (const side of ['front', 'back']) {
|
||||
const an = a.chars.char_337_utage.spine[side].anims;
|
||||
assert.equal(an.skill.via, 'attack', `${side}: no kneeling during 落地斩·破门`);
|
||||
assert.equal(an.skills['1'].via, 'attack', side);
|
||||
assert.equal(an.skills['0'].loop, 'Skill_Loop', `${side}: S1 分神 sits down`);
|
||||
}
|
||||
});
|
||||
+15
-3
@@ -113,8 +113,8 @@ const PRISONER_GREY_3 = Object.freeze({
|
||||
die: 'Die3', move: clipOf('Move3'),
|
||||
});
|
||||
/**
|
||||
* Role fixes of web enemy models from their official battle prefabs, for skeletons whose clip names mislead the resolver
|
||||
* (by name): model id → roles replacing the resolved ones (the others are kept); processModels applies them, so
|
||||
* Role fixes of web models (enemies from their official battle prefabs; operators by character id) for skeletons whose clip
|
||||
* names mislead the resolver (by name): model id → roles replacing the resolved ones (the others are kept); processModels applies them, so
|
||||
* data/assets.json carries them. A fix naming a clip the skeleton lacks is dropped and reported. Source: the prefab's
|
||||
* animation table (its Graphic component: anim key → clip) and the clip its Spine starts on, read from the local client's
|
||||
* battle/enm_pfb_*.ab (tools/local-extract, UnityPy).
|
||||
@@ -126,9 +126,20 @@ const PRISONER_GREY_3 = Object.freeze({
|
||||
* set (强壮囚犯's Idle is its grey one; 拳师囚犯 / 重犯 / 传奇重犯 *_grey); every prisoner's later sets are the render/units.js
|
||||
* FORMS 'warning' / 'liberty' the sim switches to (content/enemies/archetypes.js prisoner).
|
||||
*/
|
||||
/**
|
||||
* 宴 (char_337_utage): her skeleton has one unnumbered skill set, Skill_Start / Skill_Loop / Skill_End — she sits down and
|
||||
* rests: S1 分神's pose (停止攻击,防御力提升,每秒恢复生命). Her other skill, index 1 (S2, the 卫戍 default 落地斩·破门, an ATK
|
||||
* buff for its first seconds after every deployment), attacks with her ordinary clips. The resolver (by name) gave both
|
||||
* indices the unnumbered set, so she knelt through the opening seconds of every battle (the owner's playtest of
|
||||
* 2026-10-07). [ASSUMED: by the clips' pose and S1's text; the prefab's skill table was not read]
|
||||
*/
|
||||
const UTAGE_S1 = Object.freeze({ begin: 'Skill_Start', loop: 'Skill_Loop', end: 'Skill_End', index: 0, idle: null });
|
||||
const UTAGE_S2 = Object.freeze({ ...clipOf('Attack', 'attack'), index: 1, idle: null });
|
||||
export const PREFAB_SPINE_ROLES = Object.freeze({
|
||||
enemy_1116_liprr: PRISONER_GREY_3,
|
||||
enemy_1116_liprr_2: PRISONER_GREY_3,
|
||||
// operators by character id: both the front and the back model
|
||||
char_337_utage: { skill: UTAGE_S2, skills: { 0: UTAGE_S1, 1: UTAGE_S2 } },
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -317,7 +328,8 @@ export async function processModels(models, { root, dl, cachePath, download = tr
|
||||
nextCache[m.skel.rel] = { key: ck, info: sk };
|
||||
if (sk.missingRegions?.length) problems.push(`${m.key}: ${sk.missingRegions.length} attachment(s) not in atlas (e.g. ${sk.missingRegions[0]})`);
|
||||
if (!sk.animations.length) { problems.push(`${m.key}: skeleton has no animations`); continue; }
|
||||
const id = String(m.key).startsWith('enemy:') ? String(m.key).slice('enemy:'.length) : null;
|
||||
const key = String(m.key);
|
||||
const id = key.startsWith('enemy:') ? key.slice('enemy:'.length) : key.startsWith('op:') ? key.split(':')[1] : null; // op:<char>:front|back
|
||||
const fixed = applyRoleFix(resolveRoles(sk.animations, { skillIndices: m.skillIndices, durations: sk.durations }), id ? PREFAB_SPINE_ROLES[id] : undefined, sk.durations);
|
||||
if (fixed.missing.length) problems.push(`${m.key}: role fix not applied (clip missing) for ${fixed.missing.join(', ')}`);
|
||||
const anims = fixed.roles;
|
||||
|
||||
Reference in new issue
Block a user