86 Commits

Author SHA1 Message Date
vtroc7 acc57a5c9d Make underbarrel attachments work across families, bound transport and qualify match publication
- 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>
2026-10-16 16:28:56 +03:00
vtroc7 fc3d8eaf60 Improve class admission, GPU skinning, BO2 feedback and session resilience
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:27:34 +03:00
vtroc7 5b4897bc56 Merge treuenten gameplay, effects and map-loading fixes
Includes PRs #100, #101, #102, #103, #104, #105, #106, #107 and #108.
2026-10-14 10:55:29 +03:00
JohnM 4ee1865ca0 Spawn spectators with no health so scripts stop counting them alive
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>
2026-10-13 20:42:59 +10:00
JohnM 35a6ecb4da Resolve tags on vehicles, so the AC-130 drops its flares
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>
2026-10-13 20:28:49 +10:00
JohnM ffa55e17f3 Aim the Chopper Gunner's turret at the point under the crosshair
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>
2026-10-13 20:27:53 +10:00
JohnM 2d9123a73e Fire +activate player-command notifies on a controller's use button
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>
2026-10-13 20:27:28 +10:00
JohnM 5bc6a31500 Show the end-of-match killcam to every player, the winner included
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>
2026-10-13 20:22:07 +10:00
JohnM f5ab715755 Let the Predator fly down through the sky ceiling
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>
2026-10-13 20:22:07 +10:00
JohnM f5fe2e7598 Keep the shield a body had on its back when it died
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>
2026-10-13 20:20:48 +10:00
JohnM 8d93a3102e Play a body's death animation once instead of restarting it as it falls
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>
2026-10-13 20:20:48 +10:00
JohnM fa0a1c3e17 Let dead bodies fall off edges, slide down walls and follow the ground
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>
2026-10-13 20:20:48 +10:00
JohnM 6fffe52947 Let bullets set cars on fire
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>
2026-10-13 13:29:02 +08:00
vtroc7 efe6db6981 Restore native soldiers, barrels, chat and tracers; align weapon unlock admission 2026-10-12 00:05:28 +03:00
vtroc7 08b4224efd Add Theater editing and chat, improve controller UI, audio, combat and network recovery
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:43:30 +03:00
vtroc7 b8ded62c23 Restore T5 character animation, killfeed colors and killcam audio continuity 2026-10-11 00:10:03 +03:00
vtroc7 a2f189df10 Scope match lifetimes and restore gameplay and menu presentation
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>
2026-10-10 23:01:34 +03:00
vtroc7 5273074e72 Integrate contributor rendering, gameplay and development fixes 2026-10-10 01:33:23 +03:00
JohnM 7157feb9bd Bind the script glass functions so Strike loads
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>
2026-10-10 01:18:51 +08:00
JohnM 0a0d598a22 Lay a dropped riot shield flat on the ground
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>
2026-10-10 00:14:22 +08:00
JohnM d04ea2af59 Leave a dropped gun on the ground when only its ammo is taken
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>
2026-10-10 00:13:38 +08:00
JohnM 10c5c84c6c Slide dropped weapons down walls instead of hanging in the air
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>
2026-10-10 00:12:47 +08:00
JohnM 21e2bd00f7 Remove the oldest dropped weapon at the limit, not the lowest-numbered one
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>
2026-10-10 00:11:35 +08:00
JohnM 72cd946147 Free a projectile's entity slot when it ends without exploding
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>
2026-10-10 00:10:14 +08:00
JohnM 9c4d4320f4 Treat a deleted entity as undefined for the rest of its frame
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>
2026-10-10 00:08:34 +08:00
vtroc7 91217cd0ac Restore native effects and objectives, scope zoom, camouflage and lighting 2026-10-08 22:04:32 +03:00
vtroc7 a2f4e0b857 Restore cross-game class previews and loadout customization 2026-10-08 00:19:44 +03:00
vtroc7 983fd97853 Publish prepared presentation contracts and predict local bullet impacts 2026-10-07 22:44:14 +03:00
vtroc7 25c008b391 Prepare coherent match assets, native camouflages and server releases
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:30:21 +03:00
vtroc7 7eff9406fb Connect native soldier hands and finalize match rule integration 2026-10-07 12:52:50 +03:00
vtroc7 19b9438bab Merge pull requests #71 #72 from NeptuneTheGoat 2026-10-07 12:52:25 +03:00
vtroc7 ea45cf7dcc Preserve native families, soldier hands and T6 world materials 2026-10-07 00:13:36 +03:00
neptune 682f714148 Add Constant Radar, Enemy Bots and Friendly Bots game rules
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>
2026-10-06 16:36:47 -04:00
neptune 96e9f701d5 Speed up the GSC scheduler and instruction loop
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>
2026-10-06 16:36:47 -04:00
vtroc7 d655b952cb Prepare asset products, restore T6 rendering and select community servers 2026-10-06 15:57:22 +03:00
vtroc7 330de12a8e Keep gameplay comments focused on runtime invariants 2026-10-06 10:16:40 +03:00
vtroc7 31ef165292 Merge pull requests #67 #68 #69 #70 from NeptuneTheGoat 2026-10-06 10:15:21 +03:00
neptune b60d4b4170 Give the Sleight of Hand, Steady Aim and Cold-Blooded Pro perks effect
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>
2026-10-06 00:26:43 -04:00
neptune b4736cadb1 Deal fall damage on hard landings as MW2 does
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>
2026-10-06 00:26:43 -04:00
neptune fc7ea850d5 Hold use to pick up a weapon; tap use+reload over one to reload
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>
2026-10-05 18:22:42 -04:00
vtroc7 f026f5fca0 Improve runtime readiness, rendering, audio and Linux game discovery 2026-10-05 23:41:16 +03:00
vtroc7 65052d3f51 Add native T5 audio, Black Ops II maps, independent movement, late join, skill ratings and varied bot loadouts
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.
2026-10-05 13:13:28 +03:00
vtroc7 9313f6c8be Merge pull requests #59 #64 #65 from gitoutofthere and NeptuneTheGoat 2026-10-04 16:20:36 +03:00
neptune bb575b897c Tidy the Black Ops II work for review
- 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>
2026-10-03 17:21:51 -04:00
neptune 9c00565bd9 Give MW2 weapons their camouflage
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>
2026-10-02 21:05:05 -04:00
neptune e3ff4be7d1 Give Black Ops II equipment its own effects and sounds
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>
2026-10-02 17:53:22 -04:00
neptune 818ba83cc8 Run Black Ops II equipment as Black Ops II does
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>
2026-10-02 16:12:02 -04:00
neptune f7c3b953ee Merge upstream master (d352dbd) into bo2-weapons
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>
2026-10-02 14:04:01 -04:00
vtroc7 d48a9f6502 Steam MW2 discovery, embedded licences, weapon variants, lock-on launchers, double-barrel fire and a two-client dev-master scenario
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:36:24 +03:00
vtroc7 3694c35041 Audio control runtime, typed player accounts, self-updates, thermal and shellshock screens, third person, guided killstreak HUD, player cards, a lobby cheats toggle and god mode
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 15:57:27 +03:00