Lobby loop: auto-rejoin between rounds + seat reclaim + live mission edits

The between-rounds arcade flow (first-playtest-night field request): at
mission end every pod exited, seats dropped, and every round required
everyone to re-run join.bat with no way to adjust the mission.

1. AUTO-REJOIN: StopMission (operator END / mission clock -- NOT a
   window close) sets gBTMissionStoppedByConsole; after the matchlog
   upload btl4main relaunches the pod into the join wait with the same
   cmdline (BT_CALLSIGN/BT_MECH ride the inherited environment).

2. SEAT RECLAIM: the assigned tag is mirrored file-scope
   (BTRelaySelfTag) and re-presented as the 3rd SEAT_REQUEST payload
   field (BT_SEAT_CLAIM); the relay holds a dropped seat for its tag
   for 90s and a returning player gets their EXACT seat back -- static
   ordering across rounds, the real-pod model.  Non-claim joiners skip
   reclaim-held seats.

3. LIVE MISSION EDITS: the console gains "Apply mission settings"
   (enabled while a session runs) writing arena/time/weather/length
   into the session egg; the relay re-reads the file at round reset and
   egg release (roster shape locked mid-session).

Verified 2-pod 3-round: pods self-relaunched after each clock end; the
SECOND-to-rejoin still reclaimed its original seat (ordering held); the
between-rounds edit landed ("mission length now 75s").  Known edge
noted in the KB: a stale ready flag from a not-yet-exited old conn can
satisfy the launch gate mid-rejoin -- operators launch on green dots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-23 00:28:56 -05:00
co-authored by Claude Opus 4.8
parent fa935777cc
commit 8368163b04
7 changed files with 178 additions and 11 deletions
+29
View File
@@ -46,6 +46,10 @@ const char* const ProgName = "btl4";
Application *btl4App = NULL;
HWND hWnd = NULL;
// Set by Application::StopMissionMessageHandler (APP.cpp): the round ended by
// operator/clock (NOT a window close) -- drives the between-rounds auto-rejoin.
int gBTMissionStoppedByConsole = 0;
// GLASS: resolvers for the per-display windows (declared in l4vb16.h), defined
// HERE off the launcher's own app + window pointers. They deliberately do NOT
// touch the `application`/`ghWnd` globals: those are duplicate-defined and bind
@@ -798,6 +802,31 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
BTRelayUploadMatchLog();
}
// LOBBY LOOP (2026-07-23): a round ended by the operator/clock
// relaunches this pod straight back into the join wait -- the arcade
// between-rounds flow (pods rebooted to attract mode; players stayed
// put). BT_SEAT_CLAIM carries our seat tag so the relay gives us the
// SAME seat back (static ordering, real-pod style); BT_CALLSIGN /
// BT_MECH ride the inherited environment so the choice persists.
// Closing the window still exits for good (flag set only by
// StopMission).
if (gBTMissionStoppedByConsole && getenv("BT_RELAY") != NULL)
{
extern const char *BTRelaySelfTag(void);
const char *seat_tag = BTRelaySelfTag();
if (seat_tag != NULL && seat_tag[0] != 0)
SetEnvironmentVariableA("BT_SEAT_CLAIM", seat_tag);
char rejoin_arguments[512];
int m = 0;
for (const char *s2 = lpCmdLine;
s2 != NULL && *s2 && m < (int)sizeof(rejoin_arguments) - 1; ++s2)
rejoin_arguments[m++] = *s2;
rejoin_arguments[m] = 0;
std::cout << "[boot] round ended -- relaunching into the join wait"
<< std::endl << std::flush;
BTFE_RelaunchSelfAndExit(rejoin_arguments); // never returns
}
#ifdef BT_GLASS
//
// Front-end loop (glass step 3): a menu-launched mission returns