Commit Graph
42 Commits
Author SHA1 Message Date
Stefan MaierandClaude Opus 5.5 ba3997e2f4 VR multiview: what the game projects itself gets its depth's parallax
Sprites, light volumes (a plasma bolt's glow) and lens flare tests are
projected on the CPU into screen pixels with w 1 and their depth in z, and
the widgets' vertex program takes them to clip space: taken for a point
1 world unit away, a bolt 30 away stood 3 m off in stereo and seemed to be
swallowed half way. Where w is 1 and depth is tested, the depth comes from
z by the shared camera's projection (mv_depth), and the eye's offset is by
it. (Also logs, once each, the other targets the pass draws into.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:24:49 +02:00
Stefan MaierandClaude Opus 5.5 df45daed55 VR multiview: the sky as though infinitely far
The sky is drawn about the camera (its view has no position), so no eye
stands aside of it; the eye's offset made it a dome a few metres away,
flat and swimming (the sea in 'Halo' is the sky's). Its draws take rows
without the offset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 18:52:40 +02:00
Stefan MaierandClaude Opus 5.5 d462f80fa9 VR: draw both eyes in one pass (multiview, first cut)
With GL_OVR_multiview2 (vr.multiview), the scene is drawn once, from a
camera between the eyes whose view takes in both (plus a margin), into a
two-layer back buffer: every NV2A vertex program gets a two-view variant
that moves each view's clip position to its eye (x' = a x + b w + c, from
the shared view's and the eye's edges and the eye's place; nv2a_vsh.c),
screen-space geometry excepted. Sampling the back buffer meanwhile reads
the left eye's picture; visibility counts are halved. The host copies each
layer to its eye's image (host_xr_copy_layer_array).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:37:28 +02:00
Stefan MaierandClaude Opus 5.5 428d5f113a VR: vehicle guns converge on the player's aim again, crosshair there
The game steers a vehicle gun's shots (within its deviation cone) at what
the camera aims at; VR had replaced that camera with the barrel's own
line, right on foot but not seated, where a Banshee's nose rises as it
hovers and a tank's turret lags: the Banshee's crosshair rode high. Seated,
the camera is now the player's eyes and the unit's aim (the stick's steer,
the controller at a gun), and the crosshair floats on that line; the
barrel-line crosshair is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:02:39 +02:00
Stefan MaierandClaude Opus 5.5 73e9bed243 VR test aid: both sticks held in spawn the map's next vehicle
debug.vehicle_spawn: holding both thumbsticks in for 1.5 s puts the next
vehicle the map has loaded (not the Pelican, dropship or lifepod) a few
metres ahead of the player, cycling through them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:55:25 +02:00
Stefan MaierandClaude Opus 5.5 167ec9a573 VR: a manned vehicle gun's crosshair on the line it fires along
A vehicle's gun, once manned, fires along its own barrel (not the aiming
vector) from its primary trigger, moved onto the vehicle's camera line if
it fires from its camera. The crosshair ran from the right hand along the
controller instead, and the Scorpion's shells landed above and behind it.
It now floats on the gun's own line (weapon_vr_manned_gun_line), as the
turret actually points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:47:23 +02:00
Stefan MaierandClaude Opus 5.5 8756b1ba22 VR: raise the eyes over a hull by set heights only
The collision model's top lifted the Scorpion's driver onto the turret as
it swung over him (screenshots); it never caught anything the set heights
did not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:33:14 +02:00
Stefan MaierandClaude Opus 5.5 043f2c6db6 VR: a Warthog's driver sits nearer the windscreen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:28:49 +02:00
Stefan MaierandClaude Opus 5.5 bcc40772f8 VR: the Scorpion's driver sees out over its hull
Like the Ghost's: the driver sits down in the hull (screenshot: the
compartment's inside). The raise applies to a vehicle's driver and gunner
only; riders on a tank's back sit on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:27:33 +02:00
Stefan MaierandClaude Opus 5.5 75e7036b61 VR: eyes raised over a Ghost's hood, a Banshee, a Covenant gun's shield
Their collision models leave out what hid the view (screenshots: the
Ghost's hood arches over the rider's eyes, the Shade's shield sits at
them). The eyes now rise by a set height per kind of hull
(vr.ghost_eye_raise, vr.banshee_eye_raise, vr.turret_eye_raise), and at
least over the collision model's top.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:05:54 +02:00
Stefan MaierandClaude Opus 5.5 4ab1661ac5 VR: see out over a Ghost's, a Banshee's or a Covenant gun's hull
Their riders sit down in the hull, drawn from behind in the game; from the
rider's head the view met its inside. The eyes now rise to above the hull's
top over the head and up to 50 cm ahead of it (a downward ray against the
vehicle's own collision model), plus vr.enclosed_seat_clearance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 14:52:35 +02:00
Stefan MaierandClaude Opus 5.5 4577b96fca VR: a vehicle's gun works as by its handles: tipped down, it rises
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:11:16 +02:00
Stefan MaierandClaude Opus 5.5 6146294562 VR: no crosshair at a wheel with no gun to aim
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:05:37 +02:00
Stefan MaierandClaude Opus 5.5 2c32a7032c VR: own body at the wheel and the gun, gunner view back, clearer glass
Seated as a driver or gunner, the player's body is drawn (its hands on
the wheel or the gun's handles, as the seat animates them), its head
shrunk to nothing out of the eyes' way. A gunner's view is moved back from
the gun's sights (vr.gunner_camera_back). Glass tints and reflects half as
much (vr.glass_strength), which up close hid the view through the
Warthog's windscreen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:50:55 +02:00
Stefan MaierandClaude Opus 5.5 e9e5984e11 VR: vehicles in first person, steered with the right stick
Seated, the view stays behind the player's own eyes (vr.vehicle_first_person)
and turns with the vehicle, smoothly between ticks (its interpolated
heading); the head looks around freely, and recentring faces the vehicle's
forward. A driver who steers by facing (jeep, boat, plane, scout, fighter)
steers with the right stick: aside up to vr.vehicle_steer_degrees off the
heading, up and down for pitch (vr.vehicle_pitch_degrees). Gunners, the
tank's driver and passengers aim with the right controller, and turn in
the seat with the stick. The crosshair and its distance follow the
vehicle's aim. While the vehicle turns the player, the eye images darken
from their edges (vr.comfort_vignette, host_xr_set_vignette).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:41:49 +02:00
Stefan MaierandClaude Opus 5.5 0656429c11 VR: the held grenade in the palm at hand size; throws keep their speed
The held grenade is drawn in front of the left palm (vr.grenade_right,
_forward, _up from the grip) at 0.55 of its size (vr.grenade_scale).
A hand-thrown grenade is no longer brought up to the projectile's final
velocity, which made every throw as far; strength now runs from 0.25 to
full at 5 m/s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:58:02 +02:00
Stefan MaierandClaude Opus 5.5 dc4a724f8a VR: throw grenades by hand
The left trigger holds the grenade in the hand (the game keeps it there
past the throw animation); letting go throws it from the left hand, along
the fastest the hand moved over its last 150 ms, as hard as that was (full
at 4 m/s). Without a throw (vr.grenade_throw_speed, 1.5 m/s) the game
throws as before. The left hand's swing is no melee while throwing, and
the arms keep their pose through the throw animation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:37:43 +02:00
Stefan MaierandClaude Opus 5.5 74ad349bbf VR: draw the crosshair in its own pass, keep HUD messages whole
The crosshair used to be cut out of the HUD image (an 80x80 region around
the centre) and moved to where the weapon aims, taking with it whatever
else lay there, such as part of the reload prompt. Now it is drawn alone
first (hud_draw_crosshair), captured into its layer, and the HUD is drawn
afterwards without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:48:12 +02:00
Stefan MaierandClaude Opus 5.5 c8e64f3b2b VR: shots start from the crosshair's own point
Shots started at an offset from the unit's eye point (its sight
position), the crosshair at the same offset from the drawn camera; the two
need not agree, and the shots ran parallel to the crosshair's line, a few
centimetres higher (plain on the pistol's small crosshair). Both now start
at the same point in the world, the drawn weapon's muzzle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:37:35 +02:00
Stefan MaierandClaude Opus 5.5 e2954e6e71 VR: turn each weapon so its barrel points where it aims; scope on it
First-person models point their barrels in towards the screen's centre,
so the model pointed a few degrees left of where the controller aims and
shots, the crosshair and the scope went. The weapon camera is now turned
by the barrel's direction at the ready (the gun node's axis nearest the
camera's forward), which is logged per weapon, and the scope's disc sits
over the barrel as drawn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:10:57 +02:00
Stefan MaierandClaude Opus 5.5 c3b72b5848 VR: shots and the crosshair start from the weapon as drawn
Each weapon's first-person model sits differently in the hand, and the
pistol's barrel ran a few centimetres left of the controller's aim, so its
crosshair sat right of it. Shots, the crosshair and the laser now start at
the gun node as drawn at the ready, along the controller's aim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:11:25 +02:00
Stefan MaierandClaude Opus 5.5 917a2757ac VR: the crosshair where the weapon aims; the weapon stays zoomed in
- The weapon's own crosshair (red on an enemy, as in the HUD) is taken
  from the HUD's centre and floats where the weapon aims, as far away as
  what it aims at, facing the eyes, as large as the HUD showed it
  (vr.crosshair). The laser is off by default (vr.laser) and never shows
  over the menus.
- Zoomed in, the first-person weapon stays in the hand (the game hides
  it), the HUD's crosshair and zoom overlays give way to the scope, which
  has a fine cross of its own, and the scope's disc is 10 cm across.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:01:00 +02:00
Stefan MaierandClaude Opus 5.5 2581d7ee9c VR: a scope for the zoom, on a disc over the weapon
Zoomed in, the player's view is drawn once more, from the weapon along
its aim through the zoom's field of view, into a small square of the
back buffer (the first-person weapon left out), and shown on a disc over
the barrel that magnifies what it covers of the view by the zoom's
magnification (vr.scope_size). The weapon's zoom mask and filters no
longer darken the HUD before the eyes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:16:30 +02:00
Stefan MaierandClaude Opus 5.5 87f552ea5e VR: the laser follows the barrel while a reload turns the weapon
While an animation turns the weapon away from where it aims (reloads,
drawing and putting it away, posing, venting), the laser follows the gun
node's turn from its ready pose. The ready pose is now kept only while
the weapon is held ready or firing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:49:04 +02:00
Stefan MaierandClaude Opus 5.5 1ae451d3cb VR: melee damage from the swing's speed
The game scales a player's melee damage by the forward run (the lunge),
and a VR player punches standing: blows hit but did next to nothing. The
swing's speed now weighs the blow (half at 2 m/s, full at 4; three
quarters on the right grip), unless the run gives more. Melee attacks and
what they hit are logged in debug.txt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:21:47 +02:00
Stefan MaierandClaude Opus 5.5 62f451d8dc VR: a natural free left hand, melee by swinging
- The free left hand lines up with the controller as a hand holds it:
  fingers along it, the knuckles (little finger to index) up its handle,
  the wrist behind its grip.
- Thrusting a hand forward (vr.melee_swing_speed) is a melee attack; the
  right grip still is too.
- Through a melee attack the gun stays in the hand; its animation would
  swing it before the camera.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 21:42:05 +02:00
Stefan MaierandClaude Opus 5.5 1882ae06bf VR: arms that follow the hands, the left hand free or on the weapon
- The first-person arms' upper arms and forearms are turned (two-bone
  IK) to run from the player's shoulders, below the head, to the wrists,
  instead of floating with the weapon.
- The left wrist follows the left controller, its fingers with it,
  unless the grip closes at the weapon's foregrip (vr.two_hand_reach):
  then the hand holds the weapon, which aims along both hands.
- Left controller: grip holds the weapon, Y switches weapons, X is the
  flashlight, and held switches grenades.
- The first-person skeleton's nodes are logged once per weapon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 21:25:07 +02:00
Stefan MaierandClaude Opus 5.5 fff0df8d86 Android: fix audio, which never played; VR: wider look-at tests
- SDL 3.4 holds an audio stream's lock through its callback, and the
  game's data was put into the stream from the thread that runs the
  game's callback, which then waited for that lock for ever: the first
  callback never returned and nothing was heard. The data is now
  gathered and put in by SDL's own thread once the game is done.
- debug.audio_log logs the level of the mixed sound.
- In VR a player's unit sees what its head points at within 15 degrees,
  or what the weapon's laser points at, since the head only points
  roughly where the eyes look (the training's flashing lights ask for
  5 degrees).
- vr.log_performance also logs the unit's looking vector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:43:16 +02:00
Stefan MaierandClaude Opus 5.5 bdd6ad3fc8 VR: the unit looks where the head looks
Scripts test where the player looks (unit_can_see_point, the unit's
looking vector), and the head only set it while the game let the player
turn; the training's "target each of the flashing lights" never passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:24:43 +02:00
Stefan MaierandClaude Opus 5.5 a4f4bbb6f0 VR: turning the head counts as looking around
The training at the start of the campaign waits for the look input
(player_control.c's action tests, from facing_delta), which the head
never produced. The view's turning since the last test counts too, once
past a few degrees.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:14:03 +02:00
Stefan MaierandClaude Opus 5.5 282991fc07 VR: aim with the right controller, the weapon in the hand
With vr.aim_with = "controller" (the default), on foot:
- the unit's aiming vector comes from the right controller, while its
  facing (the body, the view and the movement) keeps following the head;
- shots start at the muzzle of the weapon in the hand, kept inside the
  level from the camera as before;
- the first-person weapon and hands are posed from the controller
  (vr.weapon_forward/right/down place the model in the hand);
- the HUD's crosshair, which marks where the head looks, is left out, and
  a laser runs from the weapon to what it aims at (vr.laser).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:01:53 +02:00
Stefan MaierandClaude Opus 5.5 ce59138a2b Play in VR on OpenXR headsets (Quest 3/3S, Steam Frame)
The Android port gets an OpenXR session in the host (Khronos loader, core
OpenXR plus XR_KHR_opengl_es_enable): on a headset the game keeps its
640x480 layout drawn at the eye images' resolution, renders the player's
view once per eye from the tracked eye poses through asymmetric frusta,
and shows the HUD and menus as a head-locked or room-fixed quad layer.
The head aims the player; the right stick turns; the Touch controllers
map onto the Xbox pad; rumble goes to the controllers. Frames without a
player view (menus, loading, cinematics) go onto a screen in the room.

A marker file, xr_test, runs a self-test of the session, layers, colour
path and controllers without game data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:17:19 +02:00
Stefan MaierandClaude Opus 5.5 07de435468 Build the Android port on macOS hosts
Use the NDK's prebuilt toolchain for the build host instead of assuming
linux-x86_64, and make the StdDef.h wrapper use #include_next so that it
does not include itself on case-insensitive file systems.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:57:47 +02:00
MrBruh f7ee09b8e3 Move settings to config.toml 2026-09-27 23:56:37 +13:00
MrBruh bd9876ac9b Mouse support in menus 2026-09-27 22:05:55 +13:00
MrBruh 50eae19bac Native resolution fullscreen with F11 toggle 2026-09-27 20:42:09 +13:00
Jonas VolmanandClaude Opus 5.5 9a376181f5 Port: grow the game state and object pools for 128 players
The Xbox game state (0x345000 bytes at 0x80061000) ends exactly where the
map-linked tag cache begins and has 948 bytes free, so a 128-player
session cannot even allocate its player datums. The native builds now
place a 16 MB game state (CPU 0xFC0000, GPU 0x40000) at 0x81A00000, above
the tag cache and below everything the Xbox memory window hands out
top-down, and grow the pools that scale with the number of players:

- objects: 2048 -> 8192 headers, 1 MB -> 8 MB pool; the garbage limits
  keep January's proportions (5/10/20 % of the pool, 2.5/5/10 % of the
  headers, 75/50/30 active garbage objects per 16 players)
- cluster partition reference lists 2048 -> 8192 (collideable and
  noncollideable objects, lights); a full list drops objects out of
  rendering, collision and sphere queries
- effects 256 -> 2048, effect locations 512 -> 4096
- particles 1024 -> 8192 (render_particles' visible list, filled without
  a bound check, follows), particle systems 64 -> 256, their particles
  512 -> 4096
- contrails 256 -> 1024, contrail points 1024 -> 8192
  (MAXIMUM_CONTRAIL_POINTS stays the pool size for the same reason)
- lights 896 -> 4096, object looping sounds 1024 -> 4096
- cached object render states and rendered objects 256 -> 1024
- script object-list references 128 -> 1024, objects one explosion can
  damage 64 -> 256

The values live in port/linux/include/halo_port_capacity.h, included by
halo_port_limits.h. With 128 player datums the CPU part holds 14,256,908
bytes (2,258,164 free). Saved games and cores grow to 16 MB. Every change
is under HALO_LINUX; the MSVC objects are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:18:07 -07:00
Jonas VolmanandClaude Opus 5.5 db207ea1a4 Networking: 128 players on up to 128 machines in the native builds
The Xbox game allows 16 players on 4 machines (4 split screen players
each). The native builds raise both limits to 128, keeping 4 players per
machine, and leave the byte-matching build unchanged: every change is
under HALO_LINUX (the MSVC objects compare identical).

- Limits: every local copy of the player and machine limits, and the
  bare 4s and 16s that stood for them, follow halo_port_limits.h. The
  player data array, the machine-to-player table (and its reset) and the
  per-tick update arrays grow with them.
- Records: the copies of struct network_game agree on the larger layout
  and check it against halo_port_limits.h; maximum_player_count becomes
  a byte (128 does not fit a signed char); network_player_is_valid
  checks the machine against the machine limit, not the split screen
  one; a machine's input carries MAXIMUM_LOCAL_PLAYERS actions (16/4
  would have become 128/128).
- Protocol: a message holds at most 4095 bytes (its header has a 12-bit
  length), so the 13 KB game settings record is sent in 3.5 KB pieces
  that clients reassemble; the per-tick update of 128 players (3,857
  bytes) fits. Buffers and the packet codec's limits grow to match, and
  the game search uses protocol version 2 so these builds and the Xbox
  game never see each other's games.
- Connections: the host accepts a client connection per machine (the
  split screen count stood in for it), FD_SETSIZE is 256, stream writes
  send all of a message or drop a peer that stops reading instead of
  corrupting the stream, and the input and update queues are larger.
- Host: lobby changes are sent at most every 250 ms instead of on every
  change (a full lobby would otherwise send ~650 MB), in-game joins wait
  in a queue instead of being dropped, the random name and colour
  pickers stop looping forever once names or colours run out, machines
  get 60 s to load a map, and the debug dump lists only the slots in
  use (128 empty slots took seconds to log).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:18:07 -07:00
Jonas VolmanandClaude Opus 5.5 08cd0c01d0 Port: add session-limit header and system link address settings
halo_port_limits.h (force-included by the Linux and Windows prefix
headers) defines the native builds' multiplayer limits, 128 players on up
to 128 machines, and the struct network_game layout that follows from
them. Game sources use it only under HALO_LINUX, so the matching build
keeps the Xbox limits (16 players, 4 machines).

xnet.c gains two settings: HALO_NET_ADDRESS binds the game's sockets to
one local address and reports it as the machine's system link address,
so several instances can share one computer on different loopback
addresses; HALO_NET_BROADCAST sends the game's broadcasts to a list of
addresses instead, for machines broadcasts do not reach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:18:07 -07:00
MrBruh a06ef74eec Detach framerate from gameplay simulation 2026-09-26 21:49:07 +12:00
MrBruh e29125b50e Port decomp to Android 2026-09-26 16:16:00 +12:00
MrBruh ebb0eac50b Port decomp to Linux 2026-09-26 12:15:09 +12:00