Add scripted lightning weapon mods with interpolated anchored effects

This commit is contained in:
raptorreplica committed 2026-10-11 16:45:22 +11:00
1 parent 98465133aa
commit c0a6fd3431
50 files changed
+3500 -65

No files matched your search

+25 -7
View File
@@ -1,8 +1,8 @@
# Optional HD artwork
The Rust Options screen includes **HD art**. It starts disabled. Enable it to use reviewed artwork from `../data/hd/hd.json`; each missing or rejected frame keeps the selected original / 2x / 3x / 4x crisp treatment. The scale setting still determines the indexed rendering resolution, and the HD toggle can be changed while paused. HD art is presentation only: simulation, collision sizes, banking positions and save content IDs stay unchanged.
The Rust Options screen includes **HD art**. It starts disabled. Enable it to use reviewed artwork from the selected data directory's `hd/hd.json`; each missing or rejected frame keeps the selected original / 2x / 3x / 4x crisp treatment. The bundled runtime uses `data/`, while development artwork and review jobs live under `../data/`. The scale setting still determines the indexed rendering resolution, and the HD toggle can be changed while paused. HD art is presentation only: simulation, collision sizes, banking positions and save content IDs stay unchanged.
The local base-game pack currently supplies **215 reviewed replacement frames**. Complete additions cover all twenty-one light, dark and firing-flash player poses, thirteen vehicle families, four industrial bosses, seven ground-defense targets, a bonus crate and complete five- and fifteen-frame opening bunkers, nineteen equipment/pickup families, seven complete projectile families, the twelve-frame energy ring, nine blue-spark phases, four death-ray hit phases, fourteen lightning phases, ten platoon fragment phases, sixteen air-blast phases, four pickup glow masks, nine pilot portraits, both original title logos and sixteen canonical terrain tiles. The complete catalog backlog and generation status are listed in [hd-backlog.md](hd-backlog.md).
The development base-game pack currently supplies **340 reviewed replacement frames in 122 complete sequences**. These include all twenty-one light, dark and firing-flash player poses, complete vehicle and boss families, ground defenses and opening bunkers, equipment and pickups, projectile and effect animations, nine pilot portraits, both title logos and sixty-four canonical terrain tiles. A bundled runtime snapshot may have an earlier count until the next packaging refresh; its manifest is the authoritative count for that build. The complete catalog backlog and generation status are listed in [hd-backlog.md](hd-backlog.md).
| Reviewed artwork | Original asset IDs | Supplied / complete frames |
| --- | --- | ---: |
@@ -16,9 +16,20 @@ The local base-game pack currently supplies **215 reviewed replacement frames**.
| `SHIP07` two-state craft | `0x102fe`–`0x102ff` | 2 / 2 |
| `SHIP08` moving tread phases | `0x10300`–`0x10303` | 4 / 4 |
| `SHIP09` hovercraft wake phases | `0x10304`–`0x10305` | 2 / 2 |
| `SHIP21` industrial platform wakes | `0x10317`–`0x10318` | 2 / 2 |
| `SHIP23` complete rotating craft | `0x1031f`–`0x10326` | 8 / 8 |
| `SHIP29`, `SHIP30`, `SHIP32`, `SHIP39` craft | `0x10332`, `0x10333`, `0x10335`, `0x10344` | 4 / 4 |
| `SHIP33` pod deployment | `0x10336`–`0x10339` | 4 / 4 |
| `SHIP34` orb light states | `0x1033a`–`0x1033b` | 2 / 2 |
| First-mission industrial boss `SHIP10G1_PIC` | `0x10306` | 1 / 1 |
| Industrial bosses `SHIP12G1_PIC`, `SHIP17G1_PIC` | `0x10308`, `0x1030f` | 2 / 2 |
| Industrial boss `SHIP11G1_PIC` | `0x10307` | 1 / 1 |
| Industrial boss `SHIP16G1_PIC` | `0x1030e` | 1 / 1 |
| `SHIP22` complete hatch phases | `0x10319`–`0x1031e` | 6 / 6 |
| Second-campaign static bosses | `0x200a1`, `0x200ac`, `0x200ad`, `0x200eb` | 4 / 4 |
| Second-campaign four-phase boss | `0x200a8`–`0x200ab` | 4 / 4 |
| Second-campaign six-phase boss | `0x200ce`–`0x200d3` | 6 / 6 |
| Duo emergence phases | `0x20104`–`0x2010b` | 8 / 8 |
| Ground-defense target `TARGT1G1_PIC` | `0x10138` | 1 / 1 |
| Ground-defense targets `TARGT2G1_PIC`, `TARGT3G1_PIC` | `0x10139`, `0x1013a` | 2 / 2 |
| Ground-defense target `TARGT5G1_PIC` | `0x1013c` | 1 / 1 |
@@ -37,6 +48,7 @@ The local base-game pack currently supplies **215 reviewed replacement frames**.
| Ground Missile equipment | `0x102c0` | 1 / 1 |
| Energy Grab equipment phases | `0x102c1`–`0x102c4` | 4 / 4 |
| Pulse Cannon equipment phases | `0x102c6`–`0x102c7` | 2 / 2 |
| Forward Laser equipment phases | `0x102c8`–`0x102cb` | 4 / 4 |
| Missile Pods equipment | `0x102be` | 1 / 1 |
| Mega Bomb equipment | `0x102c5` | 1 / 1 |
| Super Shield pickup | `0x102d0` | 1 / 1 |
@@ -48,6 +60,8 @@ The local base-game pack currently supplies **215 reviewed replacement frames**.
| Ground Missile 2 projectile | `0x101bf`–`0x101c0` | 2 / 2 |
| Forward Guns / MiniGun firing patterns | `0x101c3`–`0x101c6` | 4 / 4 |
| Mine pulse | `0x101d1`–`0x101d2` | 2 / 2 |
| Pulse Cannon projectile phases | `0x10223`–`0x10224` | 2 / 2 |
| Enemy coconut phases | `0x1024d`–`0x10250` | 4 / 4 |
| Energy ring | `0x101ae`–`0x101b9` | 12 / 12 |
| Blue sparks | `0x1019c`–`0x101a4` | 9 / 9 |
| Death-ray hits | `0x101f1`–`0x101f4` | 4 / 4 |
@@ -55,9 +69,13 @@ The local base-game pack currently supplies **215 reviewed replacement frames**.
| Platoon fragments | `0x10213`–`0x1021c` | 10 / 10 |
| Air blast | `0x102a0`–`0x102af` | 16 / 16 |
| Pickup glow light masks | `0x10225`–`0x10228` | 4 / 4 |
| Muzzle flash and casing phases | `0x101c7`–`0x101ca` | 4 / 4 |
| Small air explosion | `0x101fc`–`0x10209` | 14 / 14 |
| Pilot portraits, small and retained large variants | `0x10111`–`0x10119` | 9 / 9 |
| Original English and Chinese title logos | `0x10013`, `0x10014` | 2 / 2 |
| Canonical terrain set 1, first shard | `0x10360`–`0x1036f` | 16 / 16 |
| Canonical terrain set 2, corrected first shard | `0x2010d`–`0x2011c` | 16 / 16 |
| Canonical industrial terrain, first two shards | `0x300ed`–`0x3010c` | 32 / 32 |
Every registered frame passed the exact original source hash, logical canvas, aspect, visible alpha and path checks. Complete contact sheets were inspected at source size and the 4× presentation size; per-frame geometry metrics and review evidence remain with each family. Their logical collision sizes are unchanged. Small contours and interpreted metal detail differ. Missing artwork keeps the crisp original fallback. HD remains an opt-in preview while the remaining catalog and game screenshots are reviewed.
@@ -77,13 +95,13 @@ The additional fifteen-frame bunker preserves its door apertures, gun and blink
The two additional ground targets use subdued brown soil corrections; their machinery and original directions remain intact. The tiny gun sprites keep all four original gray/white patterns, and the mine keeps its pink then dark burgundy center with gold corners. These families have complete gallery review; it does not establish a placed gun or mine scene occurrence.
The first sixteen canonical terrain replacements passed independent review of every source/logical/4× frame, all 48 supplied mission contexts and all 755 declared cardinal neighbor pairs: 170 HD/HD and 585 HD/original. Actual native scene checks exercised all 32 cached scroll phases and content-hash/load-order invalidation. None of these sixteen IDs has a declared destroyed partner; the separate native destruction-cache proof therefore adds no HD debris coverage. Mixed detail contrast remains until neighboring tiles are remastered. The next terrain family has a corrected treeless `0x20111` and passed independent source and complete neighborhood review. It and the first thirty-two industrial terrain candidates remain held for recurring grain lines at some composed tile boundaries; they add no active coverage yet.
The first sixteen canonical terrain replacements passed independent review of every source/logical/4× frame, all 48 supplied mission contexts and all 755 declared cardinal neighbor pairs: 170 HD/HD and 585 HD/original. Actual native scene checks exercised all 32 cached scroll phases and content-hash/load-order invalidation. None of these sixteen IDs has a declared destroyed partner; the separate native destruction-cache proof therefore adds no HD debris coverage. The additional corrected terrain family preserves the treeless `0x20111`, and the thirty-two industrial tiles preserve source roof, wall and pipe geometry. Their final compositor review covers all 66 full pages and 1,706 cases: 1,379 neighbor pairs, 234 contexts and 93 state swaps. A texture-preserving edge/corner correction removes the earlier repeating grain ridges without moving source material boundaries. These forty-eight frames are now registered. Mixed HD/original detail contrast remains visible, and foreign destroyed partners still use original fallback; their appearances in state tests do not add HD debris coverage.
Four small pilot portraits (`0x10116`–`0x10119`) passed actual SDL main-menu SD/HD captures. Their faces, equipment and slanted ID-card backgrounds stay recognizable, and every surrounding UI pixel was identical. The five large portraits and both title logos have complete gallery review but no verified active UI route. The Chinese logo legitimately uses 478 original fire-class pixels; its HD output preserves that class and adds no water or blink labels.
Four small pilot portraits (`0x10116`–`0x10119`) passed actual SDL main-menu SD/HD captures in the new 400×225 layout at logical position `(30,45)`. All eight captures and the comparison board were reviewed; their faces, equipment and slanted ID-card backgrounds stay recognizable, and every surrounding UI pixel was identical. The five large portraits and both title logos have complete gallery review but no verified active UI route. The Chinese logo legitimately uses 478 original fire-class pixels; its HD output preserves that class and adds no water or blink labels.
The newly reviewed effect families retain their complete phase ordering. Lightning branches are thinner and slightly cooler blue; the late AirBlast rim is thinner; PickupGlow uses a rounded interpreted contour rather than identical alpha. Actual `Canvas::shade` checks over original terrain confirm that pickup-mask holes preserve the background and mask RGB never paints foreground pixels. Other effects remain held where generation filled transparent holes, removed final fragments or made subdued smoke/embers too bright. A successfully decoded draft does not establish artistic approval.
Original pixels and original-derived base-game artwork remain outside Git under `../data/hd/`. The separate authored mod packages include their generated SD/HD PNGs, sounds and provenance in Git. The new authored menu backdrop has its own packaged rendering path and is not counted as an original catalog sprite replacement.
Working originals, source references and generation/review drafts under `../data/` remain outside the repository. The bundled original catalog and approved HD runtime snapshot under this repository's `data/` are tracked in Git, as are the bundled game, libraries and runtime manifest. Authored mod packages include their generated SD/HD PNGs, sounds and provenance in Git. The new authored menu backdrop has its own packaged rendering path and is not counted as an original catalog sprite replacement.
The sources were decoded with `tools/hd_art_source.py`, inspected, and passed to the **built-in image_gen tool** using the imagegen skill. Sources, raw generations, prompts, contact sheets, frame metadata and review notes remain in local family folders (`enemies/`, `bosses/`, `effects/`, `equipment/`, `player-light/`, `player-dark/`, and `terrain/`). The superseded initial straight-player proof and its exact generation prompt remain saved locally at:
@@ -96,7 +114,7 @@ That proof PNG has real alpha transparency, is 1254×1254, and was copied unchan
## Pack format
The following is metadata only; artwork belongs in a separately distributed local pack. This example shows one entry from the complete seven-frame light family. Decimal IDs are shown alongside their hexadecimal meaning.
The following shows pack metadata; artwork paths resolve within the selected pack. The bundled approved pack and its artwork are tracked in `data/hd/`. This example shows one entry from the complete seven-frame light family. Decimal IDs are shown alongside their hexadecimal meaning.
```json
{
@@ -136,7 +154,7 @@ Original source locations also constrain palette classes: ordinary art uses indi
HD frames are resampled directly to the selected presentation canvas and quantized to the game palette. They bypass ScaleNx filtering, preserve transparent pixels and use the normal layer order. Indexed output allows palette effects to apply consistently; subtle RGB shades and alpha edges are reduced by the original palette and binary sprite transparency. The validated [terrain renderer](hd-terrain.md) overlays canonical, full-opaque HD tiles on the joined original layer. It shares HD edges and corners where source material classes agree, transitions HD/original boundaries over two logical pixels, and preserves water/fire/flash palette classes. Intact and destroyed IDs are independent targets. The renderer adds no remaster coverage by itself; each terrain family needs the same contextual review before registration.
The metadata-only [completion ledger](hd-completion.json) tracks every one of the 5,753 original picture IDs, including unused enemies, damaged variants, HUD graphics and unnamed terrain. It separates missing, in-progress, candidate, reviewed, registered and render-reachable stages. `tools/hd_job_queue.py` creates 674 disjoint picture jobs, plus 13 classic cinematic and four bitmap-font verification jobs. Original AGX artwork and sharp native glyphs have explicit preservation policies; they are never reported as AI remasters. The ignored `data/hd/jobs/queues/` files assign continuous enemy, boss, equipment/UI, effect/projectile and terrain work with exact source hashes, complete animation families and neighbor/state references. Exact-payload aliases may share reviewed artwork while retaining each ID's source binding.
The metadata-only [completion ledger](hd-completion.json) tracks every one of the 5,753 original picture IDs, including unused enemies, damaged variants, HUD graphics and unnamed terrain. It separates missing, in-progress, candidate, reviewed, registered and render-reachable stages. `tools/hd_job_queue.py` creates 674 disjoint picture jobs, plus 13 classic cinematic and four bitmap-font verification jobs. Original AGX artwork and sharp native glyphs have explicit preservation policies; they are never reported as AI remasters. The external `../data/hd/jobs/queues/` files assign continuous enemy, boss, equipment/UI, effect/projectile and terrain work with exact source hashes, complete animation families and neighbor/state references. Exact-payload aliases may share reviewed artwork while retaining each ID's source binding.
Workers can validate an isolated proposal with `python3 tools/hd_candidate_review.py --candidate ../data/hd/jobs/JOB_ID/candidate.json`. The helper hard-links raw artwork into a temporary pack, links against the newest built Rust game library, and exports all scales 1–4 plus source/logical/4× contact sheets. It records raw artwork hashes and the library identity, warns when asset-loader source is newer than the build, and pages large reviews in groups of sixteen frames to avoid an unbounded giant image. Every page listed in `runtime-contact-sheets.json` requires inspection. It never edits the active pack or generated pixels. A successful gallery still needs coordinator visual approval and separate scene/context evidence.
+4 -4
View File
@@ -47,20 +47,20 @@ Run the portable decoder, timing and cue checks from the repository root:
```sh
LD_LIBRARY_PATH="$HOME/.local/lib" cargo test --locked \
--manifest-path RustRaptor/Cargo.toml --lib cinematics::tests
--lib cinematics::tests
```
Run the original catalog integration checks locally:
```sh
LD_LIBRARY_PATH="$HOME/.local/lib" RAPTOR_TEST_DATA="$PWD/data" \
cargo test --locked --manifest-path RustRaptor/Cargo.toml \
cargo test --locked \
--lib cinematics::tests -- --ignored
```
The checks cover both card palettes, complete logo and introduction durations,
music and sound cue times, all original cinematic delta decoding, all sequence
rates and rendering-rate independence. Original assets and screenshot captures
remain outside version control. The retained native source supplies the frame
rates and rendering-rate independence. Original cinematic assets are included in tracked `data/`; local screenshot
captures remain outside the repository. The retained native source supplies the frame
rates and cue placement; these checks are not a frame-by-frame native video or
whole-sequence PCM comparison.
+2 -2
View File
@@ -122,8 +122,8 @@ Original terrain asset `0x10360` and military sprite `0x102f6` were decoded and
inspected before generating the new art with the built-in imagegen skill.
Mission, enemy and weapon packages include generated masters, packaged
SD/HD art, WAV files and prompt/provenance metadata in Git. The assembly owns
its SD/HD campaign portrait; the soundtrack package owns its MUS composition. Original style-reference images and original
game data remain outside Git. Mission sources are a generated shoreline texture,
its SD/HD campaign portrait; the soundtrack package owns its MUS composition. Original style-reference images remain external; the packaged original
game data is tracked in Git. Mission sources are a generated shoreline texture,
harbor briefing backdrop and transparent supply depot. The source images
remain unchanged; the build step normalizes logical footprints and derives
palette SD versions and HD counterparts.
+114
View File
@@ -0,0 +1,114 @@
# AI agent checklist for building a new mod
Use this checklist for new weapon, equipment, enemy, mission, campaign and music
packages. The user's current request takes precedence. Treat the checked-in
[mod API](modding-api.md), content types and shipped examples as the contract;
do not invent unsupported fields or callbacks.
## 1. Define the behavior
- [ ] Record the requested content, controls, target types and intended role.
- [ ] For equipment, decide whether it is always equipped and fires with Fire,
a selected special, a consumable, or a passive item. Always equipped does not
imply firing without input. State the controls clearly in the shop description.
- [ ] Specify range, cooldown, damage, target limits and interactions with other
equipment. Account for the 320×200 logical canvas and 70/3 simulation ticks
per second; HD artwork must not change gameplay geometry.
- [ ] Check existing API support. Use callbacks and checked commands for mod
behavior. If something is missing, describe a minimal reusable API extension
and coordinate its implementation with the engine agent when authorized.
## 2. Build an independent package
- [ ] Create `mods/<id>/mod.toml`, `content.json`, `scripts/`, `art/` and any
`audio/` or `music/` directories needed by the content.
- [ ] Use a unique lowercase package ID, version, `api_version = 1`, clear
name and description. Declare all script files in `manifest.scripts`.
- [ ] Namespace new definitions with the package ID. Keep inventory item and
weapon IDs distinct; keep IDs stable so saved inventory survives updates.
- [ ] Declare only real dependencies. Verify standalone packages can be enabled
alone. Make complete, explicit overrides only when intentionally required.
- [ ] Omit `legacy` on new content. Use relative paths without traversal or
symlinks, and stay inside the documented package and content limits.
- [ ] Keep equipment capacities and consumable flags consistent with its role.
Define pickup and shop behavior consistently; reusable gear must remain owned.
## 3. Implement scripts safely
- [ ] Use only documented event snapshots, callbacks and commands. Filter dead,
invisible or wrong-type targets and enforce the intended range and target cap.
- [ ] Use deterministic target selection and tie breaks. Avoid duplicate hits,
accidental repeated chaining, screen-wide damage and unnecessary commands.
- [ ] Keep callback work and state bounded. Use the supplied deterministic RNG
for gameplay randomness; do not depend on render rate, wall time or OS state.
- [ ] Handle initially empty state and older saved state. Verify scripts compile,
callbacks have three arguments and command failures roll back cleanly.
- [ ] Choose visual commands appropriate to the effect. Do not use explosion
effects for ordinary muzzle flashes or electrical arcs.
## 4. Ship SD, HD and audio assets
- [ ] Supply a real SD `png` and HD `hd_png` for every authored artwork reference.
Use the same logical dimensions, aspect ratio, frame count and alignment.
- [ ] Preserve actual alpha transparency and padding. Keep sprites legible at
their small SD size, with clear silhouettes and stable frame positions.
- [ ] Inspect both modes after palette conversion in the game renderer. Check
animation strips, shop icons, firing/hit feedback and moving scenes as needed.
- [ ] Ship valid local WAV or DMX effects and MUS scores where applicable.
Keep volumes and repetition comfortable and avoid playing hit sounds on misses.
- [ ] Track final assets, required source masters, prompts, provenance and
reproducible preparation/synthesis recipes with the package. Never commit
original game pixels, the extracted catalog or local reference captures.
## 5. Price and balance equipment
- [ ] Compare original and shipped gear in [weapon balance](weapon-balance.md).
Account for aiming difficulty, effective range, air/ground coverage, splash
or chain caps, recharge, consumption and damage per second.
- [ ] Measure damage through `World::step` with the real scripts over a fixed
duration. Use surviving stationary fixtures to avoid overkill skewing results.
- [ ] Include aligned, off-axis, ground and cluster cases where relevant.
Add a close-range scene for proximity gear, and test a combined loadout for
always-equipped weapons. Keep pilot health and fixture movement controlled.
- [ ] Choose a progression tier and justify the final price. Check purchase,
capacity, duplicate rejection and resale; purchases must not create money.
- [ ] Distinguish controlled measurements from campaign balance. Document
relevant tradeoffs and unresolved playtesting questions without claiming that
every loadout or mission is equally difficult.
## 6. Verify and document
- [ ] Add meaningful portable tests with synthetic images/audio when practical.
Test actual damage, target exclusions, range boundaries, cooldown, finite
target caps, inventory preservation and coexistence with shipped packages.
- [ ] Check deterministic continuation of script state/RNG. Exercise kills and
empty-target situations, not only the happy path with surviving targets.
- [ ] Run the package validation CLI against the original local catalog:
`cargo run --no-default-features -- --mods mods --validate-mods <id>`.
Also validate relevant combined packages. Do not alter the user's active mods.
- [ ] Run focused tests, then required regression checks. Regenerate schemas if
an API type changed, and build the desktop engine if rendering or controls changed.
- [ ] Add a package README with enabling instructions, price, controls, target
behavior, limits, validation commands and a link to artwork provenance.
- [ ] Update repository documentation and balance observations where relevant.
Inspect the final diff and preserve unrelated work.
- [ ] Report what was delivered, how to enable/use it, final prices and validation
results. State any material limitation or unperformed check accurately.
## Local commands
From `RustRaptor/`, replace IDs and test names for the package being authored:
```sh
cargo test --locked --no-default-features --test weapons_mods
cargo run --locked --no-default-features -- --mods mods \
--validate-mods lightning_cannon,lightning_shield
RAPTOR_BALANCE_REPORT="$PWD/.reference/weapon-balance.json" \
cargo test --locked --no-default-features --test weapon_balance \
-- --ignored --nocapture
cargo fmt --all -- --check
```
Use the appropriate test for enemies, missions or music. An unavailable original
catalog is a reason to report the local validation limit, not to bypass portable
tests or deliver broken package references.
+13 -6
View File
@@ -9,13 +9,13 @@ This is an experimental API for the Rust engine. It provides local content packa
Validate the package against your original game data:
```sh
cargo run --no-default-features -- --data ../data --mods mods --validate-mods aurora
cargo run --no-default-features -- --data data --mods mods --validate-mods aurora
```
Run its mission without a window:
```sh
cargo run --no-default-features -- --data ../data --mods mods \
cargo run --no-default-features -- --data data --mods mods \
--enabled aurora --headless aurora:field_trials --ticks 700
```
@@ -88,7 +88,7 @@ New definitions must belong to the package namespace. An existing definition may
| Definition | Properties and behavior |
| --- | --- |
| Weapon/projectile | Damage, integer speed, cooldown in simulation ticks, targeting (`air`, `ground`, `all`), behavior (`straight`, `homing`, `beam`, `spread`, `bomb`, `energy_grab`), firing offsets, optional animation and script. Scripts can emit additional projectiles with explicit velocity. |
| Weapon/projectile | Damage, integer speed, cooldown in simulation ticks, targeting (`air`, `ground`, `all`), behavior (`straight`, `homing`, `beam`, `spread`, `bomb`, `energy_grab`, `scripted`), firing offsets, optional animation and script. Scripts can emit additional projectiles with explicit velocity. `scripted` requires a script and emits no automatic projectile. |
| Item | Price, maximum and initial count, optional weapon, shield/credit effects, consumable/special flags, artwork and script. `initial_count` controls how many units a purchase or pickup adds. |
| Enemy | Health, speed, rewards, air/ground and boss flags, firing cooldown, path points and repeat flag, weapon, dropped item, animation and script. Scripts can query entities and change enemy movement. |
| Mission | Duration, `auto_complete` (default true), optional briefing artwork, ordered tick-based spawns, terrain tile definitions and row-major layout, column count, next mission, optional legacy music asset or namespaced `music_track`, and script. Scripts can manage objectives, spawn waves and decide success/failure. |
@@ -124,7 +124,7 @@ An `art` object requires exactly one of `asset` (an original numeric catalog ID)
PNG animations are horizontal strips of equally sized frames. For example, four 64×64 frames use a 256×64 PNG and may declare logical dimensions of 16×16. The strip width must divide evenly by `frames`; supply consistent canvases and alignment across frames. Alpha below 128 is transparent. Opaque colors are mapped to ordinary entries 0–239 of the selected game palette. Plain PNGs carry no palette-animation labels, so their highlights cannot acquire reserved water, fire or blinking indices 240–255. Artwork already detailed enough for the selected rendering scale bypasses automatic sprite enlargement. Original asset animations use consecutive catalog IDs and retain their native palette labels. Terrain artwork and destroyed terrain replacements follow the same format.
Artwork dimensions and decoding allocation are bounded. PNGs may be up to 4096 pixels in either direction, with at most 4,194,304 pixels and a 64 MiB decoding allocation limit. Logical dimensions are separately validated and stay independent of physical PNG resolution. The extracted original catalog and local base-game remaster proofs stay outside version control; authored mod artwork and sounds are included in Git.
Artwork dimensions and decoding allocation are bounded. PNGs may be up to 4096 pixels in either direction, with at most 4,194,304 pixels and a 64 MiB decoding allocation limit. Logical dimensions are separately validated and stay independent of physical PNG resolution. The packaged original catalog, approved runtime remasters and authored mod artwork/sounds are included in Git; working remaster proofs and source references remain external.
## Rhai callbacks
@@ -151,7 +151,7 @@ fn on_fire(event, state, random) {
| --- | --- |
| `on_spawn` | Enemy: `entity`, `x`, `y`. |
| `on_tick` | Enemy: `entity`, `x`, `y`, `health`, `tick`, `player_x`, `player_y`. Mission: `tick`, `player_x`, `player_y`. |
| `on_fire` | Weapon or firing enemy: `entity`, `x`, `y`, `hostile`, `tick`; enemy callbacks also include `weapon`. Player entity is zero. The normal shot has already been emitted. Enemy callbacks run for each emitted gun shot. |
| `on_fire` | Weapon or firing enemy: `entity`, `x`, `y`, `hostile`, `tick`; enemy callbacks also include `weapon`. Player entity is zero. The normal shot has already been emitted, except for `scripted` weapons, whose script supplies all attacks. Enemy callbacks run for each gun discharge. |
| `on_hit` | Weapon/projectile and damaged enemy: `entity`, `projectile`, `damage`, `x`, `y`; enemy events also include `weapon` and remaining `health`. Scripted enemy damage uses `scripted = true` and omits projectile-specific fields. |
| `on_death` | Enemy: `entity`, `x`, `y`. The entity is retired; use queries to act on surviving entities. |
| `on_pickup` | Item: pickup `entity`. The item and its standard effects have already been awarded. |
@@ -159,7 +159,9 @@ fn on_fire(event, state, random) {
| `on_mission_start` | Mission: `tick = 0`. Runs when the first simulation step dispatches events. |
| `on_mission_end` | Mission: `success`, `tick`. |
Every dispatched event also includes `tick`, `player`, `entities`, `projectiles`, `pickups` and `objectives`. `player` is a snapshot including position, velocity, shields, credits, inventory and selected equipment. `entities` is the current enemy array; each entry includes `entity`, `definition`, position, health, animation and movement state. Projectiles and pickups likewise carry stable entity IDs. These are read-only snapshots: return commands to change the simulation. Later callbacks in a tick can observe commands committed by earlier callbacks. Events raised by commands, such as a spawned enemy, are dispatched on the following tick.
Every dispatched event also includes `tick`, `player`, `entities`, `projectiles`, `pickups` and `objectives`. `player` is a snapshot including position, velocity, shields, credits, inventory and selected equipment. `entities` is the current enemy array; each entry includes `entity`, `definition`, position, `width`, `height`, health, animation, movement state and the definition's `ground` boolean. Filter on `ground` when an attack affects only airborne or ground targets. Projectiles and pickups likewise carry stable entity IDs. These are read-only snapshots: return commands to change the simulation. Later callbacks in a tick can observe commands committed by earlier callbacks. Events raised by commands, such as a spawned enemy, are dispatched in subsequent batches of the same tick, within the 8,192-event limit. Rejected command batches report the mod, script path and callback, and roll back that simulation step and script state.
Use `behavior: "scripted"` for hitscan, chain lightning, proximity zaps or other attacks implemented entirely with commands. Player selection, firing input and weapon cooldowns still apply. An owned item with `special: false` fires its weapon alongside other ordinary equipment when Fire is held; `special: true` makes it selectable. Neither player nor enemy scripted weapons receive a default engine projectile. A script may explicitly emit `projectile`, or pair `damage` with `arc` for an immediate visible discharge. `target` describes the weapon's capability for the shop and governs explicit projectiles; scripts must enforce the intended targets and range for their own `damage` commands.
`state` is JSON-serializable and shared by all callbacks in the same script file. It starts as an empty map, is keyed by `mod_id/script_path`, and is saved with the pilot. Avoid values dependent on wall time, filesystem access or rendering rate. `random` contains 32 deterministic nonnegative integers in the range 0–32,767. Each successful callback advances that script's saved RNG by exactly 32 values, whether or not the script reads them. Missing callbacks do not advance state or RNG.
@@ -191,12 +193,17 @@ Use the `op` field shown below. All fields listed are required unless stated oth
| `credits` | signed `amount` | Adjust credits with saturation at valid limits. |
| `shield` | signed `amount` | Adjust ordinary shield, clamped to 0–100. |
| `effect` | `x`, `y` | Add an explosion effect. |
| `arc` | `x`, `y`, `to_x`, `to_y`, optional `ticks` (3), `anchor`, `to_anchor` | Draw cosmetic branching lightning with a hot white core, blue glow and flicker between two positions. Optional anchors are player (`0`) or existing enemy entity IDs. Endpoints must be within ±32,768; lifetime must be 1–12 simulation ticks; at most 256 arcs may be active. Pair with `damage` to attack. |
| `sound` | numeric `asset` | Queue an original digital sound asset for playback. |
| `play_sound` | namespaced `sound` ID | Queue a validated package-local sound. |
| `objective` | `key`, integer `value` | Set an objective counter. Use a namespaced key. |
| `complete` | none | Complete the mission. |
| `fail` | none | Fail the mission. |
Lightning arcs render in both SD and HD using irregular fractal channels, thin tapered forks and glow that brightens the scene. Geometry and brightness change with simulation age; each discharge receives a cosmetic seed derived from its creation tick and queue position so repeated shots vary. Drawing the same simulation state again gives the same image, and pausing freezes the effect. Arcs persist until their simulation lifetime expires. Forks are visual only and do not hit additional targets. Arcs use a separate cosmetic pool and consume no gameplay RNG, entity IDs or projectile capacity. The pool is excluded from saves and the gameplay digest. Invalid endpoints, lifetime or capacity reject the complete command batch and roll back the tick like other command failures.
`anchor` attaches the starting endpoint, and `to_anchor` independently attaches the destination. Supply absolute world coordinates at creation; each endpoint preserves its offset from the anchor's top-left `x/y` origin as the ship moves. Omitting an anchor keeps that endpoint fixed. Both anchors may be `0` to make a ring segment follow the player, or use `anchor: 0` and `to_anchor: enemy.entity` for a ship-to-ship bolt. Anchor IDs must exist when the command runs; a missing anchor rejects the batch. Endpoints update after simulation movement and API movement commands, and freeze at their last position when the anchored enemy disappears. Cosmetic coordinates clamp to ±32,768 when an attached ship moves beyond those bounds.
Rhai uses an explicit package allowlist for arithmetic, strings, collections, iteration and function helpers. The default language/time packages are excluded, so wall-clock timestamps and native `sleep` cannot be reached, including through function pointers. There are no exposed filesystem, network or OS interfaces. Dynamic `eval` and imports are disabled. Limits are 100,000 operations per callback and a shared 500,000-operation budget per simulation tick; 32 call levels; expression depths of 64/32; arrays of 4,096 entries; maps of 1,024 entries; strings of 16 KiB; 256 commands per callback; and 64 KiB of serialized state per script. See the [Rhai execution-limit API](https://docs.rs/rhai/latest/rhai/struct.Engine.html) for the underlying engine controls. Scripts cannot increase these limits.
## Saves and compatibility
+8 -8
View File
@@ -29,8 +29,8 @@ For development and tests:
export LD_LIBRARY_PATH="$HOME/.local/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
cargo test --locked
cargo test --locked --no-default-features
RAPTOR_TEST_DATA="$PWD/../data" cargo test --locked
RAPTOR_TEST_DATA="$PWD/../data" cargo test --locked -- --ignored
RAPTOR_TEST_DATA="$PWD/data" cargo test --locked
RAPTOR_TEST_DATA="$PWD/data" cargo test --locked -- --ignored
```
Portable fixtures use synthetic assets and the bundled authored mod art/audio. Original integration checks are opt-in and local. Native audio comparisons compile a small retained-source harness with g++ and SDL2 headers; pure Rust playback itself uses no C++ runtime.
@@ -62,12 +62,12 @@ migrate on load; custom combinations are preserved.
## Local asset and platform checks
```sh
cargo run --locked --no-default-features -- --data ../data --verify-assets
cargo run --locked --no-default-features -- --data ../data --mods mods --validate-mods aurora
cargo run --locked --no-default-features -- --data ../data --mods mods \
cargo run --locked --no-default-features -- --data data --verify-assets
cargo run --locked --no-default-features -- --data data --mods mods --validate-mods aurora
cargo run --locked --no-default-features -- --data data --mods mods \
--enabled aurora --headless aurora:field_trials --ticks 700
SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy cargo run --locked -- \
--data ../data --profile-root ../.reference/smoke --smoke-frames 5 \
--data data --profile-root ../.reference/smoke --smoke-frames 5 \
--screenshot ../.reference/menu.png
```
@@ -85,7 +85,7 @@ cmake --build ../raptor/build --target raptor --parallel 8
RAPTOR_REFERENCE_TRACE="$PWD/../.reference/cpp-demo.jsonl" \
RAPTOR_REFERENCE_TICKS=1889 \
../raptor/build/bin/raptor PLAY "$PWD/demos/DEMO1G1_REC")
cargo run --locked --no-default-features -- --data ../data \
cargo run --locked --no-default-features -- --data data \
--replay DEMO1G1_REC --ticks 1889 --trace ../.reference/rust-demo.jsonl
python3 tools/compare_replays.py ../.reference/cpp-demo.jsonl ../.reference/rust-demo.jsonl
```
@@ -98,4 +98,4 @@ The Rust FM/DSP implementation has synthetic sample-by-sample native comparisons
The campaign checks cover all waves and difficulties with assistance, and first-mission tests win without replenishing pilot health or editing enemy state. Wider ordinary playtesting and more complete native state comparisons remain useful. Normal startup includes the original logos, fanfare and intro. Native timing, sound-marker resolution, scene stops and custom logo palettes are checked in [intro validation](intro-validation.md). The refined menu uses an authored hangar backdrop and has a [42-frame screenshot review](menu-validation.md). Base-game HD coverage is partial; bundled mods supply SD/HD art. See [display measurements](performance.md).
Scale2x/3x follows the [published algorithm](https://www.scale2x.it/algorithm); Scale4x applies Scale2x twice. WAV parsing follows the [RIFF chunk format](https://learn.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff-). Original catalog/reference assets remain outside version control. Authored mod artwork and sounds are tracked.
Scale2x/3x follows the [published algorithm](https://www.scale2x.it/algorithm); Scale4x applies Scale2x twice. WAV parsing follows the [RIFF chunk format](https://learn.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff-). The playable catalog, approved runtime HD assets and authored mod artwork/sounds are tracked. Working source references and review captures remain outside the repository.
+57 -10
View File
@@ -1,6 +1,6 @@
# Shipped weapon prices and balance
The three independent weapon mods use the original game's credit scale. Their
The five independent weapon mods use the original game's credit scale. The first three
initial example prices of 6,500, 14,000 and 22,000 made reusable upgrades cheaper
than much weaker original equipment. The revised prices preserve their firing,
damage, scripts, sounds and artwork.
@@ -10,17 +10,20 @@ damage, scripts, sounds and artwork.
| Pulse Cannon | 185,000 | Just above the 175,600-credit Micro Missile primary upgrade. It adds similar sustained damage and also adds a spread burst every third volley. |
| Seeker Swarm | 285,000 | Above the 250,650-credit Mini Gun. Its three missiles track air and ground enemies and hits fragment into at most two nearby enemies. It remains below the 512,850-credit instant Turret. |
| Ion Lance | 425,000 | Below the Turret and the 950,000-credit Death Ray. Its lower damage per target trades against immediate hits and the ability to pierce several enemies in one column. |
| Lightning Cannon | 825,000 | Above the original 725,000-credit Pulse Cannon and below the 950,000-credit Death Ray. Its strong immediate forward hit can chain to three nearby enemies, but it needs an initial target in its aiming lane and the chain has a strict 48-pixel reach. |
| Lightning Shield | 155,000 | A supplementary primary below the 175,600-credit Micro Missile. It adds only a little damage and reaches roughly 12 pixels beyond the pilot's hull; its value comes from covering close airborne threats in every direction while the other guns fire. |
Pulse Cannon is always equipped and fires alongside other primary guns. Seeker
Swarm and Ion Lance occupy the selected special slot and fire with Fire or
Special while selected. All three are reusable, consume no ammunition and have
Swarm, Ion Lance and Lightning Cannon occupy the selected special slot and fire with Fire or
Special while selected. Lightning Shield is always equipped and pulses only while
Fire is held; it does not occupy the selected slot. All five are reusable, consume no ammunition and have
a maximum inventory count of one. Each equipment definition includes a shop
description stating these controls and its target behavior.
## Controlled damage observations
The local benchmark loads the original asset catalog and original registered
weapons, plus all six shipped weapon/enemy packages. Every weapon runs through
weapons, plus eight shipped weapon/enemy packages. Every weapon runs through
the real `World::step` simulation and real scripts at difficulty 2. Each scene
holds Fire for 700 steps, exactly 30 seconds at 70/3 Hz, against 32×32 fixtures
with 1,000,000 health. The pilot remains at the initial position with no other
@@ -44,6 +47,8 @@ cooldown.
| Mod Pulse Cannon | 185,000 | 24.00 | 24.00 | 0 |
| Seeker Swarm | 285,000 | 23.40 | 23.40 | 23.40 |
| Ion Lance | 425,000 | 26.67 | 26.67 | 0 |
| Lightning Cannon | 825,000 | 41.60 | 41.60 | 0 |
| Lightning Shield | 155,000 | 0 | 0 | 0 |
The original forward laser's native beam damage pass reaches ground enemies
despite its historical air target metadata; the observations use its actual
@@ -66,13 +71,39 @@ in the same column: 53.33 combined. It delivered 80.00 combined across three
overlapping column targets. It dealt zero damage to targets outside its launch
column. It is a brief aimed beam, rather than a screen-wide attack.
Lightning Cannon fires every 18 ticks and hits the first target for 32 damage.
In a chain scene with 40 pixels between target centers, it delivered 41.60,
26.00, 15.60 and 10.40 damage/s to four distinct targets, for 93.60 combined.
A fifth neighboring target took zero damage. Each hop chooses the nearest
living, previously unhit target within 48 pixels of the previous hit; it can
chain through air and ground targets and never revisits a target. It missed an
isolated target 76 pixels to the right of its narrow forward acquisition lane.
Its 825,000-credit price reflects better single-target output than the original
Pulse Cannon plus bounded cluster utility, while staying below the Death Ray's
80.00 aligned damage/s. Cluster performance alone does not guarantee campaign
performance: spaced enemies break the chain and weak targets reduce its useful
damage through overkill.
Lightning Shield cannot reach the normal distant fixtures. Against a stationary
aircraft with its hull 28 pixels from the pilot's center, it delivered **5.87
damage/s**. The equivalent ground fixture took zero damage. Against five close
aircraft it dealt 5.87 to each of the four closest targets, for 23.47 combined,
and zero to the fifth. The 28-pixel distance is measured to the nearest point on
the enemy hull, so it reaches only about 12 pixels beyond the pilot's own hull.
Its 155,000-credit price treats this as supplemental coverage near the ship,
below the Micro Missile and mod Pulse Cannon upgrades. Its short reach requires
dangerous proximity, and it provides no protection from collisions or bullets.
Firing alongside Forward Guns preserves its 5.87 close-target damage/s; selecting
another special never disables it. Its pulses consume no equipment.
## Economy and limits
Controlled first-mission runs starting with 100 energy and zero credits earned
42,775 credits at difficulty 1 and 59,025 at difficulty 2 with starter guns.
The in-game registration flow starts with 10,000 credits and 75 energy, matching
the original hangar setup. Compared with the latter controlled gross
reward, these prices represent approximately 3.13, 4.83 and 7.20 such payouts.
reward, the first three prices represent approximately 3.13, 4.83 and 7.20 such payouts.
Lightning Cannon costs about 13.98 and Lightning Shield about 2.63 such payouts.
Repairs and other purchases increase the saving time; later missions have
different rewards. This comparison sets a progression tier and does not promise
an exact purchase mission.
@@ -94,14 +125,30 @@ without granting a permanent shop upgrade or a repeatable resale reward.
Run the local-only test from the repository root with the original catalog:
```sh
RAPTOR_BALANCE_REPORT="$PWD/.reference/weapon-balance.json" \
cargo test --release --manifest-path RustRaptor/Cargo.toml \
RAPTOR_TEST_DATA="$PWD/data" RAPTOR_BALANCE_REPORT="$PWD/.reference/weapon-balance.json" \
cargo test --release \
--no-default-features --test weapon_balance -- --ignored --nocapture
```
`RAPTOR_TEST_DATA` can override the catalog directory. The optional JSON report
records all 96 observations: fifteen weapons in six scenes, plus the three
primary upgrades combined with Forward Guns against air and ground. Assertions
records all 120 observations: seventeen weapons in six scenes, the three original
primary upgrade comparisons with Forward Guns, four additional proximity/chain
scenes for each lightning weapon, and four lightning/Forward Guns comparisons. Assertions
check all-target homing, column piercing, off-axis beam misses, target survival
and unchanged pilot shields. The test uses the Rust engine without SDL or C++.
Original data and locally written reference reports stay outside Git.
The bundled original data is tracked; locally written reference reports stay outside Git. The portable
weapon tests additionally check range boundaries, chain gaps, repeated-hit
exclusion, kills, cooldown, absence of input, removed equipment, combined loadouts
and deterministic continuation.
The opt-in visual proof uses the actual package icons, original palette and
public arc renderer in SD and HD. It writes local, ignored captures:
```sh
cargo test --locked --no-default-features --test weapons_mods \
lightning_mods_render_real_icons_and_discharge_arcs_in_sd_and_hd \
-- --ignored --nocapture
```
Both packages include a numeric `balance-report.json`; these observations do
not include original game artwork or catalog data.