0.2.3: prepare follow-up fixes and client features (#407, #408, #410, #413, #431, #435, #436, #440, #444)
Add special-target activation without bypassing attack cadence, cooperative card preferences and emotes, skill sound banks, per-operator voice choices, text sizing, install prompts, closed-tab recovery and unanimous setup rerolls. Retain late deployment elapsed time and resolve echo/counter pulses without recursive hook overflow. Independent final review remains pending. Golden: roster-016, roster-035, roster-036, roster-045; boss-boss_1-pair, boss-boss_3-pair, boss-boss_5-pair, boss-boss_7-pair, hidden-boss_9-pair; solo-HARD-9-boosted: Lemuen attack cadence. diy-132: Necras extra activation targets. coop2-NORMAL-14-standins: cooperative purchase preference and simulation fixes. hidden-boss_10-solo: echo pulse FIFO resolution. See DESIGN 28.13-28.24 for assumptions, sources and contributor credit.
This commit is contained in:
1 parent
314564c139
commit
f3658a0dd4
104 files changed
+3674
-741
No files matched your search
+30
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
import { RAW, joinUrl, safeName, urlBase, urlDir } from './sources.mjs';
|
||||
import { kindOf } from './formats.mjs';
|
||||
import { pickUnitSfx, UI_SFX, BATTLE_SFX, resolveSpec, indexVoice, VOICE_DIRS, VOICE_BATTLE_SLOTS } from './audio.mjs';
|
||||
import { pickUnitSfx, pickModeAttacks, pickModeHits, skillModeLetter, SLOT_MODE_LETTER, UI_SFX, BATTLE_SFX, resolveSpec, indexVoice, VOICE_DIRS, VOICE_BATTLE_SLOTS } from './audio.mjs';
|
||||
import { literal } from './manifest.mjs';
|
||||
import { EMOTE_CATALOG } from '../../shared/constants.js';
|
||||
|
||||
@@ -387,6 +387,19 @@ export function buildPlan({ assets07, ops03, enemies05, maps05, audio, modelsDat
|
||||
born: audio.bank(`battle.ON_PROJECTILE_BORN.projectile_chr_${short}`), hit: audio.bank(`battle.ON_PROJECTILE_HIT.projectile_chr_${short}`) } });
|
||||
const { roles: u, mix } = unitSounds(audio, sfx);
|
||||
const skillSfx = {};
|
||||
// Per-skill ATTACK / IMPACT sound (audio.mjs pickModeAttacks / pickModeHits): a skill mode has its own swing and its
|
||||
// own hit sound, and neither may play as the unit's normal attack / impact (银灰, 纯烬艾雅法拉). An operator whose
|
||||
// every attack belongs to a skill mode has no normal bank at all (司霆惊蛰 — 解放者, she only attacks while a skill
|
||||
// runs — the report 「三技能攻击没有音效」); 赤刃明霄陈's S3 slashes swing `p_atk_hljdswd_s` and land `p_imp_hljdswd_s`
|
||||
// where her normal attack uses the `_n` files (the report 「斩击音效应该和普通攻击不一样」). The mode letter of a skill
|
||||
// index is read from that skill's own activation sound (`p_skill_lzxqlkl_s` → s = 技能3); without one (most operators
|
||||
// carry no activation sound) we infer 技能1 / 2 / 3 = d / h / s ([ASSUMED], below). The client plays
|
||||
// them while that skill is active (public/js/audio.js unit()).
|
||||
const modeAttacks = pickModeAttacks(audio.unitBanks.get(id));
|
||||
const modeHits = pickModeHits(audio.unitBanks.get(id));
|
||||
const attacks = {};
|
||||
const hits = {};
|
||||
const attackMix = {}, hitMix = {};
|
||||
for (const i of idx) {
|
||||
const s = (o.skills || []).find((k) => k.index === i);
|
||||
if (!s) { notes.push(`${id}: skill index ${i} missing in research data`); continue; }
|
||||
@@ -395,10 +408,26 @@ export function buildPlan({ assets07, ops03, enemies05, maps05, audio, modelsDat
|
||||
if (s.skillId) skillsById[s.skillId] = iconId;
|
||||
const ss = audio.skillBanks.get(s.skillId)?.get('ON_SKILL_START');
|
||||
if (ss?.length) skillSfx[String(i)] = soundLeaf(ss);
|
||||
// [ASSUMED] Without a named activation mode, infer d/h/s from slot 1/2/3; see DESIGN §28.17.
|
||||
const letter = skillModeLetter(ss?.[0]) ?? SLOT_MODE_LETTER[i];
|
||||
if (letter && modeAttacks[letter]) {
|
||||
attacks[String(i)] = soundLeaf(modeAttacks[letter]);
|
||||
const m = audio.mixOf?.(modeAttacks[letter]);
|
||||
if (m) attackMix[String(i)] = m;
|
||||
}
|
||||
if (letter && modeHits[letter]) {
|
||||
hits[String(i)] = soundLeaf(modeHits[letter]);
|
||||
const m = audio.mixOf?.(modeHits[letter]);
|
||||
if (m) hitMix[String(i)] = m;
|
||||
}
|
||||
}
|
||||
const primarySkill = skillSfx[String(idx[0])];
|
||||
if (primarySkill) u.skill = primarySkill;
|
||||
if (Object.keys(skillSfx).length > 1) u.skills = skillSfx;
|
||||
if (Object.keys(attacks).length) u.attacks = attacks;
|
||||
if (Object.keys(hits).length) u.hits = hits;
|
||||
if (Object.keys(attackMix).length) u.attackMix = attackMix;
|
||||
if (Object.keys(hitMix).length) u.hitMix = hitMix;
|
||||
if (mix) u.mix = mix;
|
||||
if (Object.keys(u).length) unitsSfx[id] = u;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user