183 lines
11 KiB
Markdown
183 lines
11 KiB
Markdown
# Original WoW spell visuals
|
|
|
|
The runtime packages every WoW 3.3.5 visual model referenced by the current
|
|
ability manifest, across all ten WoW classes. There is no class filter in
|
|
`package-wow-original.mjs`. Ascension and RuneWaker entries retain their existing
|
|
source mappings and sound behavior.
|
|
|
|
Current coverage: 483 packaged models; 5,066 of 5,066 source phase assets; 311
|
|
mesh models, 1,711 particle emitters, 249 ribbon emitters, and 479 unique source
|
|
textures. The generated
|
|
manifest includes per-class coverage. A spell rank without a source visual
|
|
phase (for example, a passive or totem-management action) is not counted as a
|
|
missing model. This does not invent original visuals for spells with no source
|
|
mapping; the runtime still supplies its generated school fallback.
|
|
|
|
## Generate and verify
|
|
|
|
```sh
|
|
npm run effects:wow
|
|
npm run effects:audit
|
|
npm run effects:test
|
|
```
|
|
|
|
`npm run effects:meteor` packages the Ascension Mage Meteor release and impact
|
|
models used by Falling Stars. It reads the additional Ascension models from the
|
|
extracted `patch-N` directory and attaches browser-ready graphs to spell
|
|
`ascension:500135`. The full `effects:generate` command runs this step after
|
|
the WoW package step so a regenerated manifest keeps the affix visuals.
|
|
|
|
`effects:generate` rebuilds the DBC/audio mappings before packaging all WoW
|
|
visuals. `effects:priest` remains a compatibility alias for `effects:wow` so it
|
|
cannot accidentally revert the main manifest to Priest-only coverage. The old
|
|
Priest decoder and fixtures remain for compatibility tests.
|
|
|
|
The manifest collector also reads effectful boss spell IDs from
|
|
`dungeonCampaignCatalog.json`. Regenerate the dungeon catalog first whenever
|
|
boss spell semantics change. Missing or undecodable source audio falls back to
|
|
the runtime's short spatial school cue; enabled combat audio is never silently
|
|
dropped merely because a source file is absent.
|
|
|
|
Source assets resolve from the extracted sibling `LadiksMPQEditor` base-client
|
|
directories, with the sibling `wow335a/Data` archive stack recovering missing
|
|
files. Locale archives supply shared interface textures used by spell models.
|
|
Recovered files go into `.tools/wow-effects-source`; source installations are
|
|
read-only. BLPConverter8 converts the original BLPs to PNG. Model and texture
|
|
paths are checked before resolution. An incomplete run reports failures and
|
|
does not replace the active manifest.
|
|
|
|
Graph filenames hash the complete runtime payload, including source model,
|
|
skin, textures and nested model dependencies. Changes therefore get new URLs
|
|
instead of reusing an incompatible cached graph. The normal content publisher
|
|
assigns the entire `assets/game/combat-effects` tree to `core:combat-media`.
|
|
Publishing a new app/content release remains the normal deployment step.
|
|
Development gameplay uses Vite's local source media directly; release builds
|
|
retain the verified media-pack download requirement.
|
|
|
|
## RuneWaker spell media mapping
|
|
|
|
`npm run effects:rom` refreshes only RuneWaker manifest entries and packages
|
|
their sound cues without rebuilding WoW effects. It reads spell-to-image links
|
|
from `romPlayerCatalog.generated.json` and `magiccollectobject.db`. It follows
|
|
each direct MagicCollect component through `magicobject.db` to ImageObject
|
|
`ExtendACT` target models, alongside the spell's own ImageObject paths. Exact
|
|
same-name cues under the client's parallel `sound/fx` tree and zero-offset
|
|
direct ROS audio events supply phase-tagged cues. Delayed and fade-out events
|
|
stay in the batch report until their timeline has a matching runtime event.
|
|
The combat audio player layers distinct RuneWaker cues on the same phase,
|
|
including separate ROS appear and idle sounds; WoW sources retain weighted
|
|
single-cue selection.
|
|
|
|
`npm run effects:rom:particles` packages a decoded ROS particle archive for the
|
|
five primary classes and their accepted elite pairs. Build the native exporter
|
|
with `scripts/runewaker-pipeline/native/build-exporter.ps1` first. The exporter
|
|
reads ACT motion controllers, where the texture names and particle keys live;
|
|
the static entity tree alone contains default values. Set `RUNEWAKER_RESOURCE_ROOT`,
|
|
`RUNEWAKER_EXPORTER`, or `TEXCONV_BIN` to override the default source and tool
|
|
locations. The archive index at
|
|
`public/assets/game/combat-effects/original/runewaker/manifest.json` records
|
|
decoded and unsupported controller families per model. Its graphs contain the
|
|
source shader identity, blend mode, billboard settings, particle tracks, and
|
|
PNG versions of referenced DDS textures. The archive also extracts the SMUNI
|
|
vertex and pixel HLSL from the Rune engine source with a source hash. Texture
|
|
tile sizes are pixels, not atlas row and column counts.
|
|
|
|
`npm run effects:rom:audit` writes the first-five class and accepted-pair map
|
|
to `docs/ROM_SPELL_MEDIA_MAPPING.md`. It distinguishes source ROS references,
|
|
packaged audio, and browser-playable original visual graphs. The packager
|
|
enables any graph whose sprite, emitter, texture, subtree alpha, and nonvisual
|
|
event callback data meet the browser renderer's validated schema. Event IDs that spawn an
|
|
effect or control projectile flight remain blocked. Urgent Heal's target rune
|
|
and decal are an explicit partial-original exception; `rom-particle-readiness.mjs`
|
|
holds hand-reviewed scale and fidelity overrides. Other ROS phases retain
|
|
generated visual fallbacks until their controller families are implemented.
|
|
Open `scripts/combat-effects/rom-preview.html`
|
|
with the Vite dev server to inspect the decoded sprite models. The emitter
|
|
integrates source rate keys over each rendered frame so short bursts survive
|
|
slower frames. Whirlwind Shield uses a 2.5 presentation scale after live
|
|
dungeon review.
|
|
|
|
`npm run effects:rom:plan` creates `docs/ROM_MEDIA_BATCH_PLAN.md` and its
|
|
machine-readable JSON companion from the current primary-five manifest and ROS
|
|
archive. It groups models by unsupported controller family, lists fully decoded
|
|
graphs awaiting visual review, and flags embedded one-shot audio paths absent
|
|
from the manifest as candidates for timeline support. Run it after the audio
|
|
and particle package steps. The generator attaches source direct audio events
|
|
at the matching phase boundary when their motion and zero-offset timing are
|
|
known; remaining candidates require a different timeline or phase mapping.
|
|
`npm run effects:rom:batch` runs the manifest/audio pass, particle package,
|
|
manifest attachment pass, media audit, and batch plan in that order. Build the
|
|
native exporter before running it when its C++ source changes.
|
|
|
|
The Priest's holy `act_casting_c_hand.ros` has three renderable sprite layers
|
|
and one `CRuController_EventTrigger` in its `appear` motion. The RuneWaker
|
|
source identifies event 43 as looping direct 3D audio for
|
|
`sound/fx/skill/holy/act_casting_c_hand.wav`, not another visual layer. The
|
|
packager marks the model renderer-ready after validating the event's
|
|
parameters. Its packaged WAV loops only during the matching Priest cast and
|
|
stops on release or cancellation. The same source event rule applies to the
|
|
five class cohort when IDs 1, 41, 43, 44, 50, or 61 carry valid data.
|
|
|
|
Urgent Heal's target effect is linked through MagicCollect spell `491147` to
|
|
MagicObject component `501543`, whose ImageObject `573048` supplies
|
|
`ExtendACT=model/fx/skill/holy/act_benedictory_heal_t_down.ros` at `p_down`.
|
|
The client creates the component's `ExtendACT` on the target after the heal
|
|
resolves. Its `explode` motion contains two original sprite layers (holy line
|
|
and gold stars), a nested `rune_cylinder.ros` particle entity with source rune
|
|
texture, a `kan_rune_circle.dds` ground decal, and a one-shot direct 3D audio
|
|
event for `sound/fx/skill/holy/act_benedictory_heal_t_down.mp3`. The browser
|
|
plays the two sprite layers and source rune mesh emission, and animates the
|
|
decal radius, rotation, color, and alpha. The decal lies on a level plane;
|
|
the RuneWaker client projects it onto collision triangles. The graph remains
|
|
`partial-original` for that terrain projection difference while replacing
|
|
the generated target filler.
|
|
|
|
Rising Tide spell `490256` uses ImageObject `572061` for
|
|
`act_icecone01_c_hand.ros` at cast start and `act_icecone01_f.ros` on release.
|
|
MagicObject component `620408` links ImageObject `572062`, whose target
|
|
`ExtendACT` is `act_riptide_t_freeze_hit.ros` at `freeze_hit`. The source
|
|
audio events name the projectile cue
|
|
`sound/fx/skill/ice/icenew/act_icecone01_f.ros.mp3` and target cue
|
|
`sound/fx/skill/ice/act_riptide_t_freeze_hit.mp3`; the cast hand has its
|
|
mirrored WAV. The verified models are attached to their respective combat
|
|
presentation phases after their controller support and source motion checks.
|
|
|
|
## Rendering
|
|
|
|
The `wow-m2-model` format composes source particles, animated/skinned geometry,
|
|
material alpha and colors, UV transforms, and bone-driven ribbon trails. The
|
|
renderer resolves full and upright billboards, texture layers, source-space
|
|
pivots, global animation sequences, and Stand/Hold/Decay timelines. Original
|
|
geometry particles use instance pools; secondary particle emitters are bounded
|
|
to prevent recursive effects multiplying the scene budget.
|
|
|
|
The live combat path uses the same cast, projectile, impact and aura events as
|
|
before. In original mode, an instant release also renders any source-side
|
|
`cast-start` layers without publishing another gameplay or audio event. Instant
|
|
terminal events prefer their exact phase, then use the source `impact` or
|
|
`aura-start` counterpart when that is the only mapping. The source phase stays
|
|
on the render event so attachment and aura lifetime rules remain correct. This
|
|
covers all 1,106 castable instant rank records that have a packaged source
|
|
visual, including all 287 latest-rank instant abilities with source visuals.
|
|
The source catalog also contains three passive instant records with visuals;
|
|
passives do not publish combat events. Abilities without a source mapping, or
|
|
with no usable asset load, retain generated fallback. Particle budgets,
|
|
placement anchors, and travel timing remain the game's presentation rules;
|
|
this is not a claim of pixel-identical client simulation or exhaustive
|
|
spell-by-spell gameplay QA.
|
|
|
|
Decoder reference for compressed bone quaternions, float UV quaternions, and
|
|
source record layouts: [wowlib M2 records](https://skarndev.github.io/wowlib/python/m2/records/).
|
|
|
|
## Local visual inspection
|
|
|
|
Run `npm run dev` and open `/scripts/combat-effects/preview.html`. The
|
|
development-only preview lists every directly referenced model and uses the
|
|
same mesh, ribbon and particle renderer as live combat. Drag to orbit, scroll
|
|
to zoom, replay an effect, or freeze its opening frame. The preview is not
|
|
included in the production app entry point.
|
|
|
|
Runtime tests parse all shipped graphs, sample bone transforms, and verify
|
|
geometry bounds, dependency textures and billboard behavior. Browser evidence
|
|
and observed limitations are recorded in `PLAYTEST_NOTES.md`.
|