- Underbarrel attachments work across IW4, IW5, T5 and T6, including
per-family impact FX, T5 flamethrower streams and T6 launcher fuses.
- Viewmodel notetrack sounds play in third person.
- Transport operations and queues are bounded; Quinn congestion control
returns to its default.
- Match publication, presentation context and prepared content semantics
are qualified and validated; cosmetic and entity occurrence lifecycles
are preserved.
- GPU skinning batches within supported device budgets.
- Immutable UI projections and correlated class replies are reconciled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
spawn() rebuilt the player state with full health for every session state,
and map_restart respawns every client as a spectator, so a dead player, or
a bot that joined mid-round and had not spawned yet, held 100 health.
isAlive() is health above 0, so the scripts counted them alive. At a Search
and Destroy round end the stock _matchdata logging then ran logPlayerLife
on bots added mid-round, which have no spawn fields, and logged 39 script
errors. Sentry turrets also took spectators as live targets.
MW2's spawnPlayer sets self.health = self.maxhealth itself before it calls
spawn(), and spawnSpectator, spawnIntermission and spawnEndOfGame never
touch health. So now only a "playing" spawn fills health to max. A
spectator holds 0, and "dead" and "intermission" keep the health the
client had.
Checked on a Mac with our build (S&D on mp_brecourt, 4 bots, 5 more added
20 s into round 1, then the human dies): before, every spectator held 100
health and the round-1 end logged the _matchdata errors. After, the
spectators held 0, rounds 2, 3 and 4 each started with all 10 players
alive at full health, and no _matchdata error was logged. The IW4L port is
compile-checked only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The AC-130's flare script reads tag_flash_flares from the plane, and every
call failed with "tag does not exist" (7 errors in one Sub Base match, more
on Highrise); the thread stopped and no flares came out. The plane is a
vehicle, not a script mover, so it is never given a posed skeleton, and the
tag lookups found none. Its model is loaded and has the tag.
Tag lookups now pose an entity's model at its origin and angles when it
has no skeleton of its own. getTagOrigin, getTagAngles and linkTo offsets
use the same path.
Checked on the Mac (Sub Base, AC-130, 5 bots): 3 or more script errors
before, none after; the Chopper Gunner, Predator and Pave Low in one match
afterwards, no script errors. On our iPhone build in a Favela match, an
AC-130 ran with no script errors. The flares themselves were not watched
for.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The turret's target was a point 8192 units along the gunner's view, measured
from the helicopter's origin rather than the gunner's eye, and the bullets
fly from the muzzle towards it. Short of that range the two lines don't
meet, so the impacts landed well above the crosshair (about a sixth of the
screen height on a phone). The target is now the end of a trace from the
gunner's eye (the linked weapon view) along the view, ignoring the
helicopter and the gunner, so the bullets go where the crosshair points.
Checked on our iPhone build in Favela matches: before, the bullet impacts
landed about 100 px above the crosshair in a 590 px tall recording; after
this and the overlay centring fix, the bullets and the crosshair lined up
and the gunner got three kills in one run. That build also had a steadier
gunner camera, which is not part of this change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A controller binds its use button as +usereload, which sets USE_RELOAD,
while notifies registered for "+activate" (and "+usereload") only matched
USE. The Chopper Gunner's and the AC-130's thermal toggles listen for
+activate, so on a controller pressing the use button did nothing; a
keyboard sends +activate and worked. Both commands now match either bit, as
the use-button read in scripts already does.
Checked on the Mac (Favela): 'press +usereload' in the Chopper Gunner flips
the picture to black-hot and back. On our iPhone build in a Favela match,
the RELOAD touch button (bound as +usereload) flipped the gunner's picture
several times.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The final killcam rarely reached the local screen, whoever made the winning
kill. Three bugs stacked up.
The winner was never seated. The end-of-match killcam script runs the
killcam for every player, so the attacker is forced to spectate itself, and
spectator resolution refused any self target. An archived seat
(archivetime > 0) may now follow the viewer itself. Live spectating and
cycling still skip yourself.
A seat did nothing for a viewer who was still alive, and every survivor is
alive at the end of a match. seat_applies() lets a seat through only when it
is final or the viewer is dead, and the final flag was hardcoded to false.
It now comes from the script's level.showingFinalKillcam when the seat is
read, for archived seats only, so the end-of-match replay is shown to living
players as well. It also feeds the killcam HUD's game-ended state.
The replay lost remote cameras. The AC-130 and Chopper Gunner camera
(linked_weapon_view) and the Predator link (remote_missile) are per-client
rows, not player state, and the seat snapshot kept the viewer's live row, so
the gunship view fell back to a third-person orbit around the body on the
ground. The seat now copies the focus's archived camera rows into the
viewer's row, with the Predator unlink time moved to the live clock. The
rows are None when the archived focus had no remote camera, so the winner's
own live gunship cannot leak into a replay.
While seated on an archived killcam, a player's live body takes no
movement, fire or weapon-switch input. Only end-of-match seats have a
living body. The AC-130's 40 s timeout can clear the remote state between
the win and the killcam, which unfroze the player; the body then walked
around unseen and the view snapped to the new spot when the killcam ended.
Script button reads still see the raw command.
Checked on the Mac (Estate, scr_dm_scorelimit 100): an AC-130 105 mm shot
wins the match and the final killcam shows the thermal gunship view with
the AC-130 HUD and the Killed By card. A bot wins with an AT4 while the
player lives: the player watches the rocket replay under GAME WINNING KILL.
A bot shoots the player: the ordinary killcam is still the attacker's
first-person replay. On our iPhone build in an Estate match, the final
killcam played after the win and its timer counted down.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Predator script starts the missile 14000 units from its target, or 14000
above the player on maps without Predator spawn points. On Sub Base,
Wasteland, Karachi, Invasion, Rundown, Carnival, Storm and Trailer Park that
start is above the map's sky ceiling, a slab of sky brushes (contents 0x800;
on Sub Base at z 8128-8192), and on Fuel a rooftop Predator starts inside
it. The projectile trace uses MASK_SHOT, which includes the sky bit, so the
missile hit the top of the slab about 1.75 s after launch and blew up some
7,900 units above Sub Base, with the view still a wash of fog. The Predator
works on those maps in MW2, so it has to pass the ceiling there.
A missile is now marked as remote-controlled when a player is linked to it
as its pilot, and keeps the mark for its whole flight, since the control
link is dropped when the pilot dies and the missile must still pass the
ceiling then. The mark goes when the projectile is gone and on game
shutdown. The marked missile's world trace leaves out sky brushes. A second,
sky-only trace over the same tick still stops it on a sky wall or underside
(a sky face with normal z of 0.7 or less) through the usual contact
detonation, so a Predator steered sideways below the ceiling still ends at
the edge of the map. A sky trace that starts inside a sky brush is ignored,
which covers a missile inside the slab and the Fuel start. Every other
projectile keeps the full mask: an RPG fired straight up still explodes on
the ceiling.
Checked on the Mac on Sub Base: the RPG still explodes at z 8127.9. The
unsteered Predator passes z 8192 and reaches the ground about 5.4 s after
launch, with a clear view of the base before impact (before: explosion at
z 8192.1 after 1.75 s). A Predator whose pilot is killed about 1.5 s after
launch still passes the ceiling and lands. One steered flat below the
ceiling explodes on the south sky wall at y -15391.9. On our iPhone build
in a Sub Base match, Predators reached the ground with a clear view before
impact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dead player's body drew whatever shield its player had at that moment,
read from the victim's live client state. That state changes after
death: a bot that respawns with a riot shield in hand gives every one of
its old bodies a shield on the left arm, posed with the body and sunk
into the floor. On mp_subbase this showed as upright shields half in the
floor beside bodies, next to the shield dropped as a pickup.
Each corpse slot now records the shield stowed on the victim's back when
the body is made, and sends it with the corpse pool. A body draws that
shield and nothing else; a live player still draws the one it holds. A
shield held in hand at death is the one dropped as an item, so the body
takes no copy of it.
The corpse pool's wire format changes again, so PROTOCOL_VERSION is 118.
Checked on an iPhone build in two matches with riot-shield bots
(mp_favela and mp_estate), killing bots with the shield held up and
with it on their back: dropped shields lay flat and no shield stood
upright by a body.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client kept a corpse's animation tree only while the corpse's tr_time
stayed the same. The server changes tr_time whenever a body's fall changes:
when it goes over an edge, when it slides down a wall, and when it lands.
Each change copied the tree again from the victim, whose tree is already
gone because a dead player is not posed, so the corpse got a fresh tree
with the death clip back at its first frame. Bodies flew off standing
upright in the clip's first 50 ms, stood against walls, and then played
the whole fall again where they stopped.
The server now stamps each corpse slot with the level time of the death
(spawn_time_ms, sent with the corpse pool), and the client keys the tree
on that time and the victim. Both stay the same for one body's life and
change when the slot holds another body. When there is no victim tree to
copy (a body first seen late, or an entity number that now holds another
body), the fresh tree starts as far into the death clip as the body is
old, so an old body shows the pose it already lies in instead of dying
again.
The corpse pool's wire format changes, so PROTOCOL_VERSION is 117.
Seen on the Mac (mp_favela, point-blank SPAS-12 kills of a bot on an open
terrace, with temporary logging): every body copies its tree once and its
death clip plays once, from the victim's pose to the end. Before, the same
kill copied it 18 times and drew the body upright in the clip's first
50 ms for about 0.8 s. On an iPhone build, point-blank shotgun kills on
mp_favela no longer glided off upright, stood pinned to walls or replayed
their fall.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A body whose death animation carried it past an edge stayed in the air at
its death height, until newer deaths recycled the slot. The open side of
the cliff stairs on mp_estate showed it often. phase_run_corpse_move set a
body resting (TR_INTERPOLATE, not falling) after every unblocked animation
step and never looked for ground there. Its only downward probe ran for
ragdolls, which never start, and its test was reversed.
One body's server tick is now step_corpse:
- on the ground only the animation step's x/y moves the body. It follows
the ground down by up to a stair step (18 units), so it goes down slopes
and stairs without hopping. With nothing within a step below it falls
from rest, so it goes over an edge instead of floating;
- in the air the trajectory keeps its clock and speed, so gravity builds,
and the animation step is added to its base once;
- a falling body that meets a wall slides down it with the vertical speed
it had and lands. Before, it restarted its fall from rest every tick and
stood pinned against the wall for up to a second;
- a body stopped part way on the ground moves its trajectory base with it,
so clients draw it where it stopped.
The clone velocity clamp now holds x and y to 80 in both directions.
Before, only +x and +y were held, so a body thrown toward -x or -y flew
further.
Seen on the Mac (mp_favela, seven point-blank shotgun kills of a bot on an
open terrace, pb_shotgun_death_back2): the body travels 106-111 units (the
clip's root motion is 120), drops over the terrace edge, lands after
0.35 s and slides down the slope without falling again. Against a wall it
slides down and lands in 0.2 s. A player killed 300 units up lands in
0.8 s. On an iPhone build, bodies killed on the mp_estate cliff stairs
dropped onto the slope, and point-blank shotgun kills on mp_favela flew
back a little and dropped.
There is still no ragdoll, so the death clips' root motion still moves the
body, their end poses (legs up, headstands) remain, and limbs can still
reach into walls.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A bullet that hit a script model raised "damage" with the hit bone as the
tagName argument and an empty partName. The destructible script reads a
non-empty tagName as the tag of an attached model and matches it against
its part list. The body bone of a destructible car (the Suburban on Estate)
matches no part, so the damage was dropped and bullets never set a car on
fire. Windows, wheels and lights still broke, because their bones are part
tags either way, and explosions, which carry no bone, worked.
The bone now goes in partName with an empty tagName, as the vehicle damage
notify already does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prepare progression and loading through Bevy scheduling, preserve round HUD and bombsite props, restore grenade and T5 shadow presentation, and keep menus usable while classes load. Report update progress and continue startup after update failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mp_strike's map script breaks its "brokenglass01" panes in main() with
GetGlassArray and DestroyGlass. Neither native was bound, and an unbound
native refuses the whole program at install ("2 unbound natives:
destroyglass getglassarray"), so the map never loaded.
The glass reset now also reads the map's named glass table (a targetname
and its piece indices), and the session installs it next to the glass
panes as a GlassNames resource. getglassarray, getglass, destroyglass
(the existing script shatter), isglassdestroyed and getglassorigin are
bound on top of it. The map script only runs at the next scheduler pass,
after the glass is installed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The riot shield's world model stands upright, as it is carried, with its
origin at the grip. A dropped item gets only the dropper's yaw, so a
dropped shield stood on edge with half of it in the floor: a thin upright
sliver beside the body.
A dropped shield, recognised by its weapon type, is now pitched onto its
back. Guns keep pitch 0 as before. A gun dropped by a swap now keeps only
the yaw of the item it replaces, so a gun swapped for a shield does not
inherit the shield's tilt.
To see it: on Rust, die holding a riot shield after the start grace period.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Walking over a dropped gun of a type you already carry took its ammo and
deleted the whole item. add_ammo_on_ps caps the total at max_ammo, so every
round that did not fit was destroyed with the gun. A touch only fires for a
gun you carry, so every touch pickup is ammo-only, and a victim's gun at the
killer's feet vanished at once when both used the same weapon. The game's
pickup script treats a trigger that swapped nothing as an ammo pickup and
keeps waiting on the item, so the item is meant to stay.
grab_number now takes only the rounds there is room for (stock first, then
the right clip, then the left) and leaves the gun on the ground with the
rest. A gun with nothing left is removed as before. The pickup record
carries only the rounds taken.
With the item staying, one player's ammo touch and another player's swap of
the same gun can land in the same tick. settle_items retired the item's
script entity right after its first trigger, so the death notify ended the
script thread waiting on it and the swap that followed was lost. It now
raises every trigger first and then retires only the items whose row is
gone, so a gun still on the ground keeps its script entity.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
think_item_move ended a fall only on a floor. A falling drop whose trace
hit a wall or a ceiling kept its old falling trajectory but was held at the
contact point on the server, so it hung there for good, while clients, who
draw the trajectory, showed it flying on through the wall and under the
floor.
A blocked fall now rests on a floor, when the trace starts in solid, or on
a hit with no usable normal. A wall or a ceiling restarts the fall from one
unit off the contact point with the velocity into the surface removed. The
push off is traced, so in a tight gap the item moves only as far as is
clear, and rests at the contact point if nothing is. When the push meets a
second surface, as in an acute crease between two walls, the velocity is
clipped against that one too, and if it still points into the first wall
the horizontal part is dropped. Without that the gun bounced from wall to
wall every tick for up to about 1.8 s before it fell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The map keeps at most 16 dropped items, scavenger bags included. When it
was full, push_dropped_item removed the item with the lowest entity number.
Numbers are reused oldest-freed-first once the reuse quarantine is over, so
a fresh drop often took a low number and was removed at the next death
anywhere on the map. Replaying a 10-bot FFA, about half of all drops lived
under 5 s, and a killed soldier's gun often vanished within a second or two.
Each item now carries its drop order (drop_seq, one past the newest live
item) and the cap removes the oldest. Only the authority evicts and the
next value comes from the live items, so drop_seq needs no snapshot field;
items rebuilt from a snapshot carry 0.
Script delete() and the map_restart cleanup removed item rows without
freeing their entity slots, so every drop the game script deleted leaked an
Item slot for the rest of the match. Both now go through
despawn_dropped_item, which removes the row and frees the slot. This has to
land with the cap change: drops that live longer are far more often deleted
by script.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A projectile that reached its cleanup time without exploding (both cleanup
paths in think_projectile), one removed because its script entity was
deleted (settle_projectiles), and every projectile cleared by map_restart
lost its row through remove_projectile_by_number but kept its Missile slot
for the rest of the match. Only splash detonations, whose slot is held for
the dying-missile event and freed when it expires, and pickups gave their
slots back. The leaked slots shrink the dynamic entity pool over a long match;
once it is full the 500 ms reuse wait is skipped and freed numbers are
handed out again in the same frame.
Add FrameWorld::despawn_projectile, which removes the row and frees its
slot, and use it on those paths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
delete() only queues an entity; it is retired at the scheduler's frame
boundary so scripts can still read its fields for the rest of the frame.
isdefined() looked only at retired entities, though, so an entity deleted
earlier in the same frame still tested defined.
The game's scripts expect the opposite. common_scripts/_pipes deletes the
sound of a finished pipe burst and immediately runs array_removeUndefined
on its list. The dead sound stayed in the list, and the next hit on that
pipe faulted in pipe_logic (DistanceSquared on the sound's now-undefined
origin), took the "return false" path, and the pipe never burst again for
the rest of the match (mp_highrise).
isdefined() now also treats an entity with a pending delete as gone.
Field reads are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Constant Radar (Gameplay Options) keeps every player's radar constant
unless an EMP blocks it, and the compass shows every living enemy each
frame, Cold-Blooded or not. Enemy Bots (0-9) and Friendly Bots (0-8, team
modes only) under Team Options add that many bots when the match starts;
a sided bot waits for the local player's team, then answers the team menu
with it or the other one. Free-for-all ignores the friendly count.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One pass over the waiters instead of a quadratic dead-thread scan; a
validated serial-to-entity cache for find_thread; heap collection every
ten ticks walking ids by reference; execute no longer clones each
instruction's location, and keeps the runaway-loop budget local, syncing
it with the runtime only around instructions that can run other threads.
With 12 bots the authority step falls from about 7.1 to 3.6 ms a tick.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MW2's class scripts set specialty_quickdraw, specialty_holdbreath and
specialty_spygame for the pro perks, but no perk bit was mapped, so they
did nothing. With MW2's bits and values:
- quickdraw (perk 26) moves into and out of ADS 1.5 times as fast
(perk_quickDrawSpeedScale) and shortens the ADS-only fire delay to match;
- holdbreath (perk 4) holds the breath 5 s longer (perk_extraBreath), in
the movement code, the breath hint and the gasp sound;
- spygame (perk 32, bit 0 of perks[1]) hides the player's name from
enemies aiming at them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A landing from above 128 units hurts, rising linearly to 100 at 300
(bg_fallDamageMinHeight/MaxHeight); surfaces flagged no-damage spare the
player and soft-landing ones cap it at 10. A hurting landing short of 100
holds the player in a hard landing for damage * 35 + 500 ms (at most 2000)
keeping 0.5 to 0.2 of their speed, as MW2's PM_CrashLand does; heavier
ones keep 0.67. Pmove raises the landing-pain event with the damage and
the authority deals it as MOD_FALLING through the script damage path, so
the game scripts handle it (Commando's immunity included).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picking up a dropped weapon took the press itself. It now takes use held
for ITEM_USE_HOLD_MS (250 ms) on the same weapon; thrown items such as
knives still go on the press. The press start travels in the client
match state, so the protocol is 110.
Over a weapon, use+reload used to do nothing on a tap. The client holds
the reload back while the button is down and sends it on a release
before the hold time, if the same item is still selected, so a tap
reloads and a hold picks the weapon up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decode Black Ops audio natively and load Black Ops II worlds, faction
models, equipment, materials, lighting and weapon camouflage.
Rework capsule collision, solid recovery, penetration, recoil, effects
and sentry placement; synchronize late joins and player event delivery.
Keep local skill ratings and signed player accounts.
Show the selected community and master ping on the main menu. Add twenty
asset-filtered class presets across IW4, IW5, T5 and T6, plus fifty-two
unique player-style names shared by AI bots and dummies. Honor the chosen
dev descriptor in the two-client approved scenario and credit contributors
and weapon, map and attachment QA testers.
Validated with the approved gameplay lifecycle and two-client dev-master
scenarios, installed class-asset audit, bot-name uniqueness checks and
Linux IW4/IW5/T5/T6 gameplay smoke runs. Foreign-weapon match-stat schema
coverage remains incomplete.
- Format with rustfmt and clear the clippy warnings on lines this branch
adds (fixed-size chunks via as_chunks, explicit fallbacks instead of
unwrap_or_default, range patterns, elided lifetimes).
- The engine-supplied equipment script is t6_equipment.gsc.txt, since
publish-check treats any .gsc as game data; FNV constants are named.
- NOTICE credits the Plutonium t6-scripts dump that the equipment
behaviour was worked out from.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A weapon's gunXModel / worldModel slots 1-8 are its camouflage models
(woodland ... orange_fall, numbered as mp/camoTable.csv). They are now
captured, aliased arrays included, and bound per weapon.
Classes carry a camouflage per weapon (classes.txt: two optional trailing
fields, written only when one is set; PersonalClass on the wire, protocol
103). MW2's _class.gsc reads it from customClasses...camo and gives the
weapon with its number; giveWeapon stores it as the slot's weaponModel in
weapon_data, which replicates. First person swaps the gun's materials for
the camouflage model's (it shares the gun's surfaces); third person draws
the camouflage world model.
Create-a-Class goes weapon, attachment, then camouflage, as MW2 does,
offering only the camouflage the weapon has, and MW2's panel shows it
behind the weapon. Console: give ... camo=<name|slot>, bot give ...
camo=<name>.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iw4l_t6/equipment plays T6's equipment effects and sounds: team-coloured
lights on bouncing betties, trophy systems, shock charges and C4, the
betty's launch and burst, the trophy's deploy and intercept flashes, the
shock charge's warning and zap, the sensor's scan, EMP fizzles.
T6 effects are captured with every effect they play in turn (runners and
spawned children), and the report names any the converter refuses. T6
rows use their own projectile explosion effect when it was captured. T6
equipment aliases are captured, and T6 aliases record whether they loop
so scripts can play them. Script effects honour hide()/showToPlayer()
(protocol 104), so team lights, and IW4's tactical insertion flares, show
to their side only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tactical insertion: under IW4 rules offhands are bridged by name only, so
the upstream slot stand-ins no longer hand the scripts a flash for it (it
plants and sets the spawn again); hidden entities stay usable, so its
owner picks it back up.
Equipment stats: read T6 detonate delay/time, damage cone, forward and
view-relative up speed, the detonator flag (C4 detonates) and the
retrievable flag (owner pickup only where T6 allows it).
Equipment behaviour: iw4l_t6/equipment ports T6's bouncing betty, shock
charge, trophy system, sensor and EMP grenades onto IW4's scripts, plus
T6's one-of-each counts, claymore grace and respawn cleanup. The engine
reports those items under their own names, tags thrown grenades with
nativename/weaponmodel, keeps sensors planted, drops the claymore laser
from betty and trophy, and lets objective_team address one player (sensor
pings, drawn in FFA too; protocol 103).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts kept both sides: Steam discovery next to Game Folders and
sibling titles, upstream's profile/account persistence next to the
folder picks and saved position, SAB/FLAC beside blake3, the T6
localize loader on the raw-bytes catalog (cache format 3), and our
tactical insertion equipment mapping with upstream's specialty_null.
The fire-delay fix takes upstream's form. Exit silencing now mutes the
new audio runtime instead of Bevy audio sinks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>