Files
RP412/RP_L4/RPL4FE.h
T
CydandClaude Opus 5 47817ca6f5 The setup page is the host's room
Two player requests from the six-player night, one cause between them:
the lobby treated hosting as somewhere you GO, and a role you could only
have by being the machine that went there.

Hosting no longer leaves the setup page. HOST STEAM GAME claims the lobby
and stays put: the button becomes CLOSE LOBBY, joiners list under GAME
LENGTH as they arrive (callsign, vehicle, a cam tag, and WRONG BUILD where
launch would refuse - the reasons launch might say no, standing on the
same screen as the launch button), and the track, weather and length stay
changeable the whole time, republished to the members' rooms as they
change. LAUNCH GAME launches the whole room from right there, and after
the race the host lands back on the same page, lobby still open, roster
still live. The room screen still exists - for members, whose flow is
untouched.

Mechanically: RPL4Lobby_Host's create-then-run-the-room split into
HostOpen (create, publish, return) plus Pump/PublishSetup/RosterLines/
HostLaunch/Leave, with the owner-launch and leave blocks extracted from
the room's message loop so both screens call the same code. The menu gets
a timer that pumps Steam callbacks - nothing else pumps them with no room
running - and republishes dirty picks at most every 1.5s, because Steam
throttles chatty writers. One wrinkle: the lobby publishes through the
RPL4FrontEnd_* accessors, which read globals the menu only wrote on the
way OUT, so publishing from a live menu syncs them first or every publish
would carry the previous visit's picks.

And a member's Live Cam pick now works. It was host-only by design - the
pick published as member data and the room displayed it, but the egg
builder never read it, so a member who chose Live Cam raced their default
loadout instead (the "default Quark - red" Cyd was listed as). The pick
now rides the whole chain - lobby row, hosted-pilot table, egg entry as
hostType=1 / vehicle=camera - and the member machine sets its own cockpit
from its own pick at launch, before the renderers build, exactly as the
host and playback already did. One rule holds it together: SOMEBODY has
to race. If every pilot picks cam, every pick is stripped and the log
says so - a grid of cameras has nothing to point at, and is also the
shape known to hang the map load.

The playtest launch failures while a member had cam picked are not
directly explained - no logs were kept from those attempts - but the
half-implemented state they ran in (flag published, egg ignoring it) is
exactly the seam this closes, and the failure cannot recur in that form:
the pick is now either honoured everywhere or stripped everywhere.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 21:34:12 -05:00

167 lines
5.5 KiB
C

#pragma once
#include "..\munga\style.h"
//########################################################################
//############################ RPL4 Front End ############################
//########################################################################
//
// The in-game race setup: shown when the game starts with no egg, no
// network, and no mission-review mode. Presents the Death Race catalog
// (track / vehicle / color / badge / time / weather / length + pilot
// name), builds the mission egg locally - the same NotationFile text
// TeslaConsole generated, including the pre-rendered plasma name
// bitmaps - and hands its path back for the standard egg-load path.
//
// Returns True with egg_path_out filled when the player launches;
// False if they close the window instead.
//
Logical
RPL4FrontEnd_Run(
HINSTANCE instance,
HWND main_window,
char *egg_path_out,
int egg_path_size
);
// The race length (seconds; 0 = endless) selected at the last
// successful launch - the local console marshals the mission with it.
int
RPL4FrontEnd_LastMissionSeconds();
// [pilots]-order pilot names of the last launched race (owner first),
// comma separated - labels for the network console's results intake.
const char *
RPL4FrontEnd_LastPilotNames();
//
// The callsign the player typed on the setup screen (persisted in
// pilot.cfg). The lobby publishes this as the member name: what somebody
// writes in the box is what the room and the race should call them.
// Empty, or still the untouched default, when they have never set one.
//
const char *
RPL4FrontEnd_Callsign();
// How the last Run() ended: a plain race, hosting a network race (the
// console marshals the other pods), or entering one as a member pod
// (the lobby owner's console marshals us; no local egg, no console).
enum FELaunchMode
{
FELaunchSingle = 0,
FELaunchHost,
FELaunchMember
};
int
RPL4FrontEnd_LastLaunchMode();
// The player's persisted loadout (lobby member data). Buffers: 24/16/24.
void
RPL4FrontEnd_GetLoadout(char *vehicle, char *color, char *badge);
//---------------------------------------------------------------
// This player's mission setup as display names. Only the host's
// picks decide the mission, so the lobby owner publishes these for
// everyone else to read - names rather than keys, because the map
// catalog differs between race and football and resolving it here
// saves the room from knowing which table a key belongs to.
//---------------------------------------------------------------
const char *
RPL4FrontEnd_SelectedMapName();
const char *
RPL4FrontEnd_SelectedTimeName();
const char *
RPL4FrontEnd_SelectedWeatherName();
const char *
RPL4FrontEnd_SelectedLengthName();
//---------------------------------------------------------------
// Catalog key -> display name, for the keys that travel as lobby
// member data. Unknown keys come back unchanged rather than blank.
//---------------------------------------------------------------
const char *
RPL4FrontEnd_VehicleNameForKey(const char *key);
const char *
RPL4FrontEnd_PositionNameForKey(const char *key);
const char *
RPL4FrontEnd_TeamNameForKey(const char *key);
//---------------------------------------------------------------
// Football team / position: the catalogs, and this player's picks.
// The lobby publishes the picks as member data and lets members
// cycle them in the room; the host's egg builder honors them.
//---------------------------------------------------------------
int
RPL4FrontEnd_TeamCount();
const char *
RPL4FrontEnd_TeamName(int index);
const char *
RPL4FrontEnd_TeamKey(int index);
int
RPL4FrontEnd_PositionCount();
const char *
RPL4FrontEnd_PositionName(int index);
const char *
RPL4FrontEnd_PositionKey(int index);
int
RPL4FrontEnd_GetTeamIndex();
void
RPL4FrontEnd_SetTeamIndex(int index);
int
RPL4FrontEnd_GetPositionIndex();
void
RPL4FrontEnd_SetPositionIndex(int index);
// True when this player's setup menu has Football selected (the host's
// pick decides the mission; members use it to know what to show).
Logical
RPL4FrontEnd_IsFootballSelected();
//
// True when this player's setup menu has YOUR ROLE on Live Cam. Only the
// HOST's pick is acted on - the host is the one that writes the egg - so
// the lobby publishes this and then shows it against the owner's row
// only. A member who picked it still races, which is what their row goes
// on saying.
//
Logical
RPL4FrontEnd_IsCameraRole();
// Hosted-race pilots fed by the Steam lobby: overrides the
// RP412HOSTPODS parsing with real personas and loadouts. owner_address
// is this pod's mesh IP (the FakeIP); count 0 clears the override.
struct FEHostedPilot
{
char address[64]; // mesh (game port) address for [pilots]
char name[32];
char vehicle[24];
char color[16];
char badge[24];
// football: the member's own picks, empty = assign one for them
char team[32]; // team key ("Red/Pink", ...)
char position[16]; // "runner" / "crusher" / "blocker"
// the member picked Live Cam: hostType=1, vehicle=camera in the egg.
// Somebody still has to race - the egg builder strips every cam pick
// if honouring them would leave nothing to point a camera at.
Logical camera;
};
void
RPL4FrontEnd_SetHostedPilots(
const char *owner_address,
const FEHostedPilot *pilots,
int count
);
// The between-races results screen: shows the last mission's final
// scores (from the local console) with a CONTINUE button. Returns
// immediately when there are no results (first boot). False only if
// the player closed the window instead of continuing.
Logical
RPL4FrontEnd_ShowResults(
HINSTANCE instance,
HWND main_window
);