The six secondary displays sit over the viewscreen like the pod's bezels
and have nothing to say once the race is over. Worse, the radar sits dead
centre along the bottom edge - directly on top of the winner's spot, so
the one position that matters was the one you could not see.
They are hidden when the podium comes up, which uncovers the canvas the
3D is already being drawn on. No matching show: the mission is over by
then, and the next race builds a fresh cockpit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pod hall stood the finishers on a numbered platform when the race
ended. All of it shipped in this repo and none of it ever ran here: the
stand geometry, the eight ranked dropzones win1-win8 in every one of the
11 maps, and the sequence that places the racers on them. The sequence
lived on RPL4PlaybackApplication - the mission-review build - behind a
spool file, so the app the pods actually race has never called it.
RPL4Application now has its own StopMission handler that ranks the
finishers, drops each onto their spot, freezes them, re-sorts the name
plates into finishing order and frames a camera on the stand. It fires
once: StopMission arrives twice, from the console at the buzzer and again
from the player when the ending fade expires, and only the first is the
end of the race.
Ranking works in football as well as a race. CalcFootballRanking ranks
only the RunnerPlayers group, which would have placed the runners and
stopped - but nothing calls it. What runs is Player::CalcRanking, every
frame, over every scoring player by score.
Three pieces of the original had been stubbed out in the D3D9 port and
are restored:
SetViewAngle was an empty function, so the 45 degrees the sequence asks
for did nothing. It now rebuilds the projection the way DPLReadINIPage
does and pushes it, and sets viewRatio, which nothing had written since
the DPL body was commented out.
winnersCircleFogStyle was an empty case. The stand sits far off the
track in open ground where the track's own fog leaves it dark; this is
the blue-violet the original used, with the fog pushed back to 100/1050
and the clip plane pulled to 1100.
The end-of-mission fade had to be told to stand down. It multiplies the
fog colour and both fog distances toward zero every frame - correct when
a race just ends, fatal to anything shown afterwards. That fade is what
made the podium a black screen, and it took a while to find because
every frame was being built and presented correctly the whole time.
The presentation camera overrides D3DTS_VIEW between the eye renderable
writing it and ExecuteImplementation reading it back for the draw calls,
so no CameraShip is needed. It builds with LookAt LH, not RH: the
projection is LH, and RH aims the camera the opposite way - ask to look
down at the stand and you get the sky behind you. The engine's own eye
renderable is right to use RH, because its forward and up come out of the
entity matrix already in that convention.
The mission is held open 11 seconds rather than 3. That fade timer is the
only thing keeping the simulation and the renderer alive once the race is
over, and it has no upper bound on the ending path.
Switches, all off-by-default behaviour aside: RP412PODIUM=0 skips it,
RP412PODIUMCAM=0 keeps the cockpit view, RP412PODIUMSTANDOFF/HEIGHT/AIM
frame the shot, RP412MISSIONSECONDS overrides the menu game length (the
shortest it offers is 3:00, a long wait when what you are testing is the
buzzer), and RP412RENDERDIAG=1 reports what a frame is made of.
Verified end to end on Wiseguy's Wake: the stand, its tiers, the blue 2
and 3, the red 4 through 8 and all eight name bays, held steady for the
full 11 seconds and then handing off to the results screen.
Known gaps: the name plates are blank, because the player1-8 textures are
runtime name bitmaps that do not resolve as files in this port, and your
own vehicle has no exterior model - you see the others, not yourself.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Version string, zip name and README. Cut as its own release rather than
replacing 4.12.3's asset again: the three test machines need to be able
to tell builds apart from what the log and the README say, and a binary
that reports 4.12.3 while carrying the lobby work defeats exactly that.
This one is about the lobby. Both rooms show the host's mission setup,
the football team sheet names each player's VTV, and a lobby holds eight
players rather than four.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The lobby capped at four, which is half a grid. The pod hall raced eight
and the egg builder already carries the owner plus maxExtraPilots, so
eight members fit with room to spare. CreateLobby now asks Steam for
eight and the roster arrays follow.
Checked what eight has to travel through before raising it: the go
roster is 43 bytes a member against an 800 byte buffer, the score sheet
41 against 600, and the pods list 21 against 512, so all three hold
eight with margin. The member side parses the go string with a cursor
rather than a fixed array, and RegisterRoster walks the count it is
given, so neither needed touching.
The layout is the part that could not just be renumbered. Rows were a
fixed sixteenth of the window, and eight of those ran off the bottom of
every window we support - the buttons are laid out upward from the
bottom edge while the roster runs down from the top, so the two meet in
the middle. The room now measures the band between the title and the
topmost button and sizes its rows to it, counted in half rows as
setup lines + gap + eight rows + gap + hint
so the row height falls out of the space actually available. It never
grows past the old sixteenth, so a two player lobby does not get circus
sized rows, and when the band cannot give eight rows the room the font
needs, the block is drawn in a font that does fit rather than letting
rows overlap.
The minimum row is the font cell plus two, not the cell plus an eighth.
That sounds like a detail and is not: at 1920x1080 the generous version
missed by one pixel and paid for it by dropping the conditions line out
of every football lobby, which is the one thing in the room nobody can
see for themselves.
Verified live on hosted lobbies at 1904x1041, and modelled across every
window size from 3440x1440 down to 800x480 in race and football, host
and member. Race keeps both setup lines everywhere; football, which
carries four stacked buttons, keeps both down to 1080 and drops to one
below that.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The room told you who was in it and nothing about what you were about to
fly into. Only the owner's menu decides the mission, so nobody else could
see the track or the conditions until the race had already started.
The owner now publishes its picks as lobby data (track, time of day,
weather, game length) and the room draws them under the title: the track
on its own line, the conditions under it. Published as display names
rather than catalog keys, because the map list differs between race and
football and resolving it at the source saves the room from knowing
which table a key came from.
Football also names the VTV now. The team sheet was team and position
only, but the vehicle still decides how someone plays the position, and
it was already travelling as member data, just never drawn. Both roster
rows now run keys back through the catalogs, so nobody reads bttlbrg
where Battle Barge belongs, and the rows widened from the middle half to
two thirds to carry three fields.
The setup lines are only taken if they fit. Buttons are laid out upward
from the bottom edge while the roster runs down from the top, so on a
short window the two extra lines would have pushed the roster into MY
TEAM. The room measures the gap first and takes two lines, one, or none.
Checked against every window size from 3440x1440 down to 640x400 in both
scenarios.
Verified live on a hosted lobby. Race shows the track, the conditions
line, and Battle Barge / Red. Football shows the same setup with Battle
Barge, Blue / Aqua, Crusher, tracking the MY TEAM and MY POSITION
buttons as they cycle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Version string, zip name and README. This one is about the screen:
the cockpit scales both ways and re-fits on resize keeping 16:9, -fit
runs it borderless over the monitor at a matched render size, the six
secondary displays are the players to scale and the radar to place,
and the button banks reach under the glass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes the gap left by the football commit. Members publish their
picks as lobby member data (tm/ps) alongside their loadout, and the
owner publishes the scenario (sc) so members know when the picks
matter. The lobby room turns into a team sheet: each member row shows
their team and position, and MY TEAM / MY POSITION buttons cycle the
local pick and republish it live, so everyone watches the sides fill
out before the host launches.
The egg builder honors explicit picks and only fills gaps:
- pilots who chose a team get it; the rest are spread across the
host team and one other so the sides stay balanced
- a team with no volunteer runner promotes its first UNPICKED member,
never overriding someone who chose crusher or blocker
- if two pilots on a team both claim runner, the first keeps it and
the second lines up
- colors stay derived: runner in the team runner color, everyone else
in the team color
Verified: a three-pilot egg puts the host on crusher in team color
with an unpicked teammate promoted to runner in runner color, the
other side gets its own runner, and the teams/pilots blocks group
correctly; the lobby room cycles picks and repaints the roster; both
scenarios still pass their single-player regressions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The setup menu gains a SCENARIO group. Picking Football relayouts the
menu live: the track list swaps to the football-legal set (drops
Paingod Passage and the race build of Freezemoon Freeway, adds the
football build headmf - RPConfig per-scenario invalid lists), the
COLOR and BADGE columns become TEAM and POSITION, and the title
reads MARTIAN FOOTBALL.
The egg builder was restructured around one flat pilot table so both
scenarios share it. Football emits scenario=football, per-pilot team=
and position= entries, and the [teams] / [team::X] / [pilots::X] /
[teambitmap] blocks in RPFootballMission layout (team name bitmaps
generated by the same GDI plasma renderer as pilot names). Colors are
derived rather than chosen, as the arcade did it: the runner wears the
team runner color, crushers and blockers the team color. Multi-pod
games alternate pilots across two teams and give each team exactly one
runner, honoring the host own position pick.
Verified end to end: Football launches from the menu, the engine loads
the football mission (the cockpit shows the RUNNER - GO FOR POINTS
panel), the console marshals it to a scored finish, and the Death Race
path still passes its regression unchanged.
Known gap: lobby members cannot pick their own team or position yet -
the host pick seeds a deterministic assignment.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Carries the worldwide lobby-search filter for cross-region internet
testing (the only change since 4.12.1 besides the README rewrite).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README.md rewritten around the lineage: Red Planet 4.10 on the
Tesla 1 pod platform, 4.11 the Win32 port, 4.12 the Steamification
of 4.11 - with the arcade-to-consumer replacement table, current
status (v4.12.1 verified on three machines), playing/building/docs
sections brought up to date.
And ahead of internet-wide beta testing: lobby search now applies the
worldwide distance filter - Steam defaults to roughly same-region
results, which would have hidden lobbies from cross-region testers
even though joining them works fine.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The environ.ini reader now skips comments (# or ;), blank lines, and
anything that is not KEY=VALUE, so the shipped file documents the
whole configuration surface: the core settings as-shipped (controls,
renderer, gauge canvas, plasma, single-window cockpit, frame rate,
Steam networking), the optional toggles (keyboard lighting, stick
flip, AA, particles, plasma scale/position, fixed seed), LAN hosting
without Steam, the developer/testing switches (RP412DEVKEYS,
L4CONSOLELEN, the Steam self-test), and the arcade multi-monitor
heritage variables. Stale L4MFDSCALE reference dropped from the
README.
Verified: the game boots on the commented file with values applied
(controls line honored, Steam transport up from the in-file switch).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per the user: the game never reads the pilot keypad, so the numpad
becomes the flight cluster - 8/2/4/6 stick, 7/9 pedals, 0 trigger -
with Shift/Ctrl as throttle up/down and Alt as reverse thrust. That
frees the entire letter board: W/A/S/D/Q/E return to their printed
MFD bank positions and B goes back to being the gap key, so the
default profile now carries the complete unmodified vRIO bank layout.
The keypad addresses stay bindable (arcade key events) but ship
unbound.
Alt as a held flight control meant every release popped the window
menu and stole focus - WndProc now eats SC_KEYMENU. Shift/Ctrl/Alt
key-name aliases added to the parser alongside the .NET names.
Profile parses clean (59 key buttons, 8 key axes); single-player
cycle and key-bomb tests green (Alt+Q abort unaffected).
Machines with an existing bindings.txt keep their old map - delete
the file to take the new defaults.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round seven was the first complete Steam race: three machines, five
minutes, wall deaths respawning, the console ending the race on time,
and rematches launched from the same lobby. The one gap the run showed:
only the owner saw scores - members went straight back to the room.
The owner now publishes its console results (host, score, name, keyed
by the race nonce) into lobby data right after teardown; members pull
the sheet (waiting up to 8s for it to land), inject it into the local
results intake, and the same RACE RESULTS screen shows on every
machine before the room.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round six raced all three machines (staging fix confirmed) and then
exposed what happens when a pod leaves mid-mission - which arcade pods
never did.
The B crash dump named it exactly: VTV::TakeDamageMessageHandler
resolved message->inflictingEntity to NULL (the entity belonged to the
departed owner) and dereferenced it - Verify is compiled out in
release. Collision damage from an entity that no longer exists is now
ignored.
And the race B and C were left in was a zombie: the owner (console)
had aborted, so the mission clock would count up forever and the
death/respawn flow hung with nobody to arbitrate. Lobby-member races
now set gConsoleLossEndsMission: losing the console mid-mission posts
StopMission locally, the pod tears down, and lands back in the lobby
room. Arcade -net pods keep the re-listen-and-wait behavior.
Loopback hosted race still green.
For the drivers: the ampersand key is the arcade mission-abort - that
was every crash-on-keypress so far; and a sleeping Bluetooth pad wakes
on the Xbox button and hot-connects within 3 seconds (PadRIO
re-probes).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round five reached the race - full mesh on all three machines, eggs,
ACKs, mission running - but the owner raced ALONE. Cause: the engine
self-runs a pod at WaitingForLaunch when its console host is not
online (the arcade no-console fallback), and the owner''s in-process
console never connects to its own pod. On fast-loading owners the
self-run beat the console''s staging gate, so RunMission was never
sent and the members sat staged at black screens until someone hit
the & emergency-abort key.
gConsoleMarshalsLaunch (APPMGR) now tells the engine an in-process
console owns the launch: the network-race install sets it and the
owner holds at WaitingForLaunch with everyone else; plain single
player leaves it False and auto-runs as always. Verified on loopback:
all pods staged - RUN is back in the hosted-race log and both the
hosted race and the single-player cycle pass.
Also: unhandled-exception minidumps (rpl4crash.dmp beside the exe,
dbghelp loaded lazily) so test-machine crashes hand back stacks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round four reached one step from the race: eggs delivered, both
members ACKed with complete meshes, one member entered LoadingMission.
Two failures remained, both now fixed.
One: Steam reports incoming callers under locally-allocated ALIAS
FakeIPs, not their global ones - the owner accepted both mesh legs
but its identity check compared the alias against the egg address and
never counted the connections (no Connected to GameMachineHost on the
owner). The peer table now carries each member SteamID (lobby go
roster gained a field) and Accept resolves the caller identity back
to the global FakeIP the egg promised.
Two: mission load stalls the game thread for 10-30s with nothing
pumping, and Steam default 10s connected-timeout sheared every
connection mid-load (end reason 4001, rx ages 11.5-20.5s - right at
load duration). Connected timeout is now 90s; TCP never timed out an
idle arcade link and races pump every frame once running.
Self-test still green (ping, survives listener close).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RPL4LOBBY implements the multiplayer front door on ISteamMatchmaking.
The setup menu grows HOST STEAM RACE / JOIN STEAM RACE buttons when
the Steam wire is live; hosting creates a tagged public lobby, joining
finds one. Every member publishes FakeIP + fake ports + persona +
loadout as member data; the room screen lists members (host marked)
and gives the owner a launch button.
Launching writes a nonced go-roster into lobby data. Each pod
registers every peer with the Steam transport (two-port peer table:
engine console/game ports map to Steam fake ports on connect) and
enters the race: the owner through the hosted-race path - it builds
the multi-pilot egg from real personas and loadouts and its console
marshals everyone - and members as network pods that boot straight
into WaitingForEgg for the owner to feed over the wire.
The lobby outlives races: members loop back through WinMain into the
room (no local console needed - MissionCompleted is waived for member
races), and the owner returns to the room after its results screen.
Leaving the lobby clears the hosted-race priming.
Verified on this box: menu buttons appear under RP412STEAM=1, hosting
creates a lobby on the Steam backend, the room runs and leaves back to
the menu; single-player cycling and the LAN hosted race both still
pass. Full three-account mesh test is next, on real hardware.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The lobby-owner-as-console architecture, in-engine. RPL4CONSOLE gains
RPL4LocalConsole_InstallNetworkRace: the owner pod switches to network
mode and meshes like any pod (egg fed locally via FeedLocalEgg, which
now opens the ConsoleOnly state gate), while the console tick also
marshals REMOTE pods over NetTransport speaking the exact arcade
protocol - egg chunks with 5s-retry-until-ACK, 1Hz state polling,
RunMission once every pod stages at WaitingForLaunch, StopMission at
expiry (remotes first, local pod holds until their EndMission scores
land), score intake labeled with [pilots]-order names on the results
screen.
The front end builds the multi-pilot egg: RP412HOSTPODS lists member
console channels (lobby stand-in; the Steam lobby feeds the same
path), RP412HOSTPORT/RP412HOSTADDR set the owner side.
Winsock Connect now redials with a fresh socket per attempt (a refused
TCP socket is dead; the old loop reused it) bounded at 120s - needed
whenever a peer boots after the caller, which is the normal Steam
lobby launch order.
Verified on loopback: member pod in -net, owner hosting from its menu;
mesh completed both sides, 30s race, remote score collected over the
wire (host 3), local stop after the drain, results screen shows both
pilots by name in one process that returns to the menu.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Steamworks SDK 1.64 vendored at extern/steamworks_sdk_164 (headers +
win32 redistributables only; .gitignore trims the rest). Both projects
build with RP412_STEAM; activation stays behind the RP412STEAM=1
environment switch, so plain desktop runs never touch Steam.
L4STEAMTRANSPORT.cpp implements NetTransport on ISteamNetworkingSockets
with FakeIP: SteamNetTransport_Install brings up SteamAPI, relay
network access, and a two-port FakeIP identity (fake port 0 = console
channel, 1 = game mesh), then swaps the process wire; any failure logs
the reason and the game carries on over TCP. Addressing keeps the
engine untouched: all pods share the -net port convention, eggs carry
fakeip:engineport, and the transport alone translates engine ports to
Steam fake ports via the lobby-fed peer table (RegisterPeer). Connect
mirrors the TCP retry-while-refused loop; Receive normalizes message
lanes back into the stream semantics CheckBuffers expects.
Runtime verified on this box: RP412STEAM=1 under AppID 480 came up as
169.254.59.52 (fake ports 32256/32257); without Steam credentials it
falls back to TCP cleanly; default boot logs no Steam lines at all.
steam_api.dll ships in the dist.
Next: the lobby layer (ISteamMatchmaking member data -> RegisterPeer +
egg build + RPL4CONSOLE marshal), which needs a second account to test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After a console-marshaled race ends, the race loop now shows a RACE
RESULTS screen (place / pilot / final score, sorted descending, with a
CONTINUE button) before returning to the setup menu. Scores come from
the local console's intake; single-player rows carry the pilot's own
name, additional pods show their host number until the Steam roster
maps IDs to personas.
The setup menu also keeps the player's selections and pilot name across
races now instead of resetting to defaults each cycle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WinMain now wraps the engine block in a loop: when a front-end-launched
mission ends under the local console, the setup screen comes back in the
same process instead of exiting (the arcade relaunch-per-mission model).
Replaces the CreateProcess self-respawn - required for Steam, where the
lobby and sockets must survive across races.
Second-cycle re-init crash fixed: d3d_OBJECT kept a static texture cache
keyed by filename, so race 2 got IDirect3DTexture9 pointers created on
race 1 destroyed device and died at first draw (DrawMesh AV). The cache
is now flushed in ~DPLRenderer before the device is released, and
ParticleEngine::Initialize drops particles left over from the previous
mission. Verified: three consecutive 30s races in one PID, each stopped
on time by the console with final scores collected.
Also: L4CONSOLELEN env override for test-length races, and the console
exposes MissionCompleted() for the loop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Domain correction from playtest: hand-fed eggs are a developer shortcut
- a mission only ends on a console command, so the clock hits 00:00 and
counts up forever. Even single-player games need a console marshal.
RPL4CONSOLE is that console. Like the real one it lives on its own
thread: it owns the mission clock and raises the stop request at the
selected length; the app-manager per-frame hook (new gPerFrameHook seam
in APPMGR, called while the application global is live - the loop
condition NULLs it on exit, which ate the first attempt) executes the
engine-safe part, dispatching the same StopMissionMessage TeslaConsole
sent. Final scores flow in through a new RP-layer sink
(gConsoleScoreSink in RPCNSL): RPPlayer feeds it the same score it
sends a real console at mission end.
It also inherits the launcher role: the application tears down after a
stop (arcade pods were relaunched per mission by TeslaLauncher), so
WinMain respawns the process when the console ended the mission,
landing back on the race-setup screen. L4NetworkManager grows
FeedLocalEgg (the single-user egg-inject path, callable mid-session)
for the future in-process loop.
Verified end to end: menu -> 3:00 race -> stop dispatched exactly on
time -> final score collected (host 1 = 4113) -> process respawned with
the front end up. -egg runs stay unmarshaled (the dev shortcut).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Starting without -egg, -net, or -mr now boots a race-setup screen
(RP_L4/RPL4FE.cpp) instead of aborting: track / vehicle / color / badge
/ time-of-day / weather / race length plus pilot name, populated from
TeslaConsole''s RPConfig.xml catalog (Death Race scenario). LAUNCH
builds the egg exactly as the console did - the RPMission.ToEggString
port, including the pilot name pre-rendered to 1bpp plasma bitmaps
(128x32 + 64x16) via GDI with the console''s auto-shrink font logic and
the verbatim ordinal graphics - writes frontend.egg, and injects it
into the standard egg-load path (new L4Application::
SetEggNotationFileName).
The menu is a GDI child of the main window (pod green-on-black, double
buffered, mouse driven, EDIT control for the name) running a modal loop
before engine init; closing the window exits cleanly. Found and fixed
along the way: the empty egg CString holds a NULL representation
(operator! is the safe emptiness test), and the modal loop needed a
queue nudge for launch clicks delivered via SendMessage.
Verified end to end: boot -> menu -> LAUNCH -> generated egg (7.5KB) ->
racing in the 1080p cockpit with score and mission clock running.
start-windowed.bat now boots into the front end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The main game window becomes the cockpit shell (enlarged, clipping
children); every display folds in as a chrome-less child pane in the
pod interior arrangement:
[ MFD UL ] [ MFD UC ] [ MFD UR ]
[ plasma (reduced) ][ viewscreen (centered) ]
[ MFD LL ] [ Map ] [ MFD LR ]
The 3D scene presents into a black STATIC viewscreen child via
Present's hDestWindowOverride (new gMainPresentWindow global) - no
swap-chain changes, and STATIC's transparent hit-testing keeps mouse
input over the 3D view flowing to the game window. MFDSplitView gains a
parent/child mode; PlasmaScreen::Position reparents the glass into the
shell. Main window class background goes black for the cockpit gaps.
Verified by screenshot: live green gauges (LIFT CUT / BOOST / CHUTE /
trigger-program screens) with their red button strips, the 3D canyon in
the centered viewscreen, plasma score glass at its left, map with lit
amber preset lamps - one window, 976x1132 client at 50% scale.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The arcade startup hid the cursor unconditionally in release builds -
correct for a pod, but desktop windowed play needs the mouse for the
on-screen cockpit buttons and the cursor vanished over every display
window. Hide (and restore) it only when running fullscreen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hand-converted the four .vcproj projects to .vcxproj (Win32, v143,
Windows 11 SDK + DXSDK June 2010 for d3dx9/dxerr only). WinTesla.sln now
builds the v143 projects; the legacy solution is kept as WinTesla_vc9.sln.
Kept: /Zp1 in Munga_L4+RP_L4, Unicode, x86, /DYNAMICBASE:NO,
/FORCE:MULTIPLE (header-defined globals still duplicated across TUs).
Changed: CRT unified to /MD(d); import libs linked by the exes instead of
merged into Munga_L4.lib; WINDOWS_IGNORE_PACKING_MISMATCH and
_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS defined;
legacy_stdio_definitions.lib for the June-2010 dxerr.lib.
Source fixes, all behavior-preserving: Time gains standard (non-volatile)
copy-ctor/assignment overloads (rvalues cannot bind to volatile& in
standard C++); operator==(SOCKADDR_IN&,...) made inline; L4DINPUT's
Enum*Callback pair renamed DIEnum* (collided with L4CTRL's under LTCG);
std::ios.in -> std::ios::in in CAMMGR.cpp.
Verified: VC9 baseline rebuilt from this tree first, then the v143 build
compared against it in a sandboxed game working copy - identical logs and
behavior through RIO init (against vRIO) and mission load, including the
same pre-existing AV in d3d_OBJECT::LoadTexture (L4D3D.cpp:262) that both
toolchains hit; documented in BUILD.md 4 as the next debugging target.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verified full build with VC++ 2008 Express SP1 + Windows SDK v6.0A + DirectX
SDK (June 2010): 4 Projects succeeded, 0 failed (Release|Win32). Outputs:
Release\rpl4opt.exe, Release\RPL4TOOL.exe, lib\Munga_L4.lib, lib\DivLoader.lib.
Two projects referenced DirectX but were never repointed at $(DXSDK_DIR)
(they had no hardcoded path to replace earlier):
- DivLoader.vcproj: add "$(DXSDK_DIR)Include" to both compiler configs
(was failing on D3DX9.h).
- RPL4TOOL.vcproj / RPL4TOOL VS2008.vcproj: add "$(DXSDK_DIR)Lib\x86" to the
linker search path (was failing with LNK1181 on dinput8.lib).
.gitignore: ignore the build-output static libs that land in lib/
(Munga_L4.lib, DivLoader.lib); the dependency libs OpenAL32.lib and
libsndfile-1.lib stay tracked.
BUILD.md / docs/BUILD-NOTES.md: record the verified build, the CLI recipe,
and the DXSDK_DIR stale-environment gotcha.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Express editions of Visual C++ ship without ATL. The only ATL usage was
in MUNGA_L4/L4APP.cpp (atlbase.h/atlconv.h + USES_CONVERSION/W2A macros, all
in that one file) for wide-to-ANSI conversion of command-line arguments.
- Replace the ATL includes with a self-contained L4WideToAnsi helper (a
WideCharToMultiByte wrapper) and local USES_CONVERSION/W2A macros that
reproduce ATL's W2A semantics. All call sites consume the result immediately
(stricmp / CString assignment / atoi / atol), so behaviour is unchanged.
- Set UseOfATL="0" in Munga_L4.vcproj, RP_L4.vcproj and their VS2008 variants.
- Document the Express build path and the confirmed June 2010 DirectX SDK in
BUILD.md (new section 6) and docs/BUILD-NOTES.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:
- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies
Removed stale Subversion metadata and added .gitignore/.gitattributes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>