A full 16-'Mech roster plus a cameraship silently refused to launch: the console
sat in nLaunchState 3 ("loading") forever with no crash and no error. 15 mechs +
camera worked, and 16 mechs with no camera worked.
Two independent bugs, both counting the cameraship against the 16 'Mech slots.
1. Session capacity (broke all-human rosters)
CTCL_DefaultHostSetup derived the camera reserve from
CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount(). Those counters read the CTCL
tesla table, which is only populated when CTCL_IsConsoleOrCOOP() is true --
i.e. only on the console. But the machine that creates the network session is
the cameraship pod (CTCL_DoMission sets g_nServer = nCameraship, and that pod
runs CTCL_DoCreateGame -> CTCL_DefaultHostSetup(0) -> Mech4CreateGame ->
gos_CreateGame(..., Environment.NetworkMaxPlayers, ...)).
On that pod both counters return 0, so the reserve collapsed to +0 and the
session was created with dwMaxPlayers = 16. The 17th connection was refused,
CTCL_CheckServerReady never saw nCount == g_nTeslas + 1, and the launch hung.
Fixed by reserving with a constant, MW4_CAMERASHIP_RESERVE (4, matching
MAX_CAMERAS), which is valid on every machine regardless of the tesla table.
2. Bot admission (broke any roster containing bots)
MW4Shell::AddBot rejects when (player_count + bot_count) >= m_maxPlayers.
player_count is the DirectPlay player count, which includes the cameraship
connection, so with m_maxPlayers = 16 the last bot was silently refused.
g_nBOTs then never matched the connected lancemates and the same readiness
check spun forever.
Fixed by subtracting cameraship participants from player_count under CTCL,
via a new CTCL_CountCameraShipsInGame() helper (non-bot entries with
m_nMechIndex == 0). Cameraships hold a network slot but pilot no 'Mech, so
they must not consume a 'Mech slot.
Also applies the constant reserve in the PLAYER_LIMIT_PARAMETER path, guarded by
!CTCL_IsNone() so a standalone non-pod host keeps its exact configured limit.
This supersedes commit f76dc05f, which had the right formula but evaluated it on
the console rather than on the pod that actually creates the session.
Note for later: m_maxPlayers is serialized in only 5 bits (MWApplication.cpp),
so 31 is the hard ceiling for any future player-cap work. See
RAISING-PLAYER-CAP.md.
Requires rebuild: MW4.exe (Release + Profile). No script or resource changes.
Verified: compiles clean, console launches. Pod testing pending.
Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
- Stabilize Load File first-click behavior across mission/map/options/slots.
- Fix map sequencing by rebuilding game-type scenario list before mission lookup.
- Resolve mission-name miss to map index 0 fallback for selected game type.
- Fix decal handling: map INI decal IDs to dropdown indices, clamp invalid indices, display actual decal IDs in UI labels, and avoid redraw-time decal overwrite.
- Fix option apply timing and UI visibility issues, including Weapon Jam refresh.
- Add NoReturn support end-to-end: parse/store in MW4Shell auto globals, expose script variable, and apply to respawn/no-return mission params and UI checkbox.
- Update autoconfig spec to reflect actual parser/default/fallback behavior and add NoReturn examples.
Issue 1 — double press to fix team/FFA display:
cur_team_val is updated by ConLobbyMission's -9998 signal which was async.
Fix: call SetNetworkMissionParamater(team_allowed, ...) directly in ConLobby
before the slot loop, then re-read cur_team_val via CTCL_GetTeamParams.
This is synchronous so the slot display is correct on the first click.
New file keys: TeamAllowed=0/1, TeamCount=2 (default 2 teams).
Issue 2 — Default button broken after Load File click:
CTCL_LoadAutoFile was overwriting g_nRookieGameType/g_szRookieMission etc.
so the Default button loaded the last auto-file params instead of defaults.
Fix: 14 new dedicated g_nAutoXxx/g_szAutoMission globals. CTCL_LoadAutoFile
populates ONLY these. Rookie Mission globals are never touched.
New MAIL_LOAD_AUTO_MISSION (-6666) sent to ConLobbyMission applies the Auto
globals (mirrors MAIL_SET_ROOKIE_MISSION_PARAMS but uses g_nAutoXxx).
ConLobby reads game type/mission from Auto globals directly into the
ConLobbyMission dropdowns (@ConLobbyMission@o_game_options[N].nselected).
Files changed:
MW4Shell.cpp: 16 new globals, StartUp/ShutDown registration, CTCL_LoadAutoFile
ConLobby.script: MAIL_LOAD_AUTO_MISSION define, updated handler
ConLobbyMission.script: MAIL_LOAD_AUTO_MISSION define + handler
autoconfig-file-spec.html: document TeamAllowed + TeamCount fields
Rebuild required: MW4.exe (Release + Profile).
1. Expose g_bAutomaticMode as gosScript variable so ConLobby can check
it at init time. o_load_file.state is set to 3 (disabled/hidden) if
automaticmode != 1 in options.ini. Button is fully visible and active
only when the feature is intentionally enabled.
Rebuild required: MW4.exe (Release + Profile).
2. Remove cur_team_val conditional for team/skin slot assignment.
Previously, only one of o_team[k] or o_skins[k] was set depending on
cur_team_val at click time, but MAIL_SET_ROOKIE_MISSION propagates the
new game type asynchronously -- cur_team_val would not reflect the
file's GameType until the next frame, requiring a second click.
Fix: always set both o_team[k] and o_skins[k] unconditionally. The
mission launch code uses whichever is relevant for the active mode;
the other is harmlessly ignored. No rebuild (script-only).
Script calls callback(CTCL_GetAutoSlotInt, k, 0/1/2/3) where 0-3 are
integer literals. The script engine passes literals as (void*)N directly
(not as pointers), so INTPARM(1) = *((int*)data[1]) dereferences NULL
when field=0, producing the 'Attempt to read from NULL' STOP.
Fix: VALUEPARM(1) = (int)data[1] reads the value without dereferencing.
k (data[0]) remains INTPARM because it is a script variable (passed as
a pointer to the variable's storage, not a literal).
Also add exists(@ConLobbyMission@) guard before MAIL_SET_ROOKIE_MISSION
for defensive safety if the sub-script is not running.
Rebuild required: MW4.exe (Release + Profile).
options.ini [automaticmode] section:
automaticmode=1
automaticfile=c:\path\to\config.ini
Right-click was considered then dropped in favor of a dedicated button
at 467,510 (below Pick Cond., left of Reprint).
C++ (MW4Shell.cpp):
- SAutoFileSlot struct + g_aAutoSlots[16], g_bAutomaticMode, g_szAutomaticFile globals
- [automaticmode] ini read at StartUp
- CTCL_LoadAutoFile: checks file exists, reads [mission] page into existing
g_nRookieXxx globals + [slot0]..[slot15] pages into g_aAutoSlots[]; returns 1 if loaded
- CTCL_GetAutoSlotName(out_str, k): pilot name for slot k
- CTCL_GetAutoSlotMech(out_str, k): mech display name for slot k
- CTCL_GetAutoSlotInt(k, field): Type/Team/Skin/Decal for slot k (fields 0-3)
- Register/unregister all 4 callbacks in StartUp/ShutDown
Script (ConLobby.script):
- o_load_file button at 467, 510
- Handler: CTCL_LoadAutoFile -> if loaded, sends MAIL_SET_ROOKIE_MISSION to
ConLobbyMission (game options), clears all slots, then applies per-slot data
in a loop (pilot names, mech by display-name lookup in allowed_mechs[], team,
skin, decal). USE_ALLOWED_MECHS/non-ALLOWED_MECHS both handled via #if.
File not consumed (stays on disk); external app overwrites for next load.
Rebuild required: MW4.exe (Release + Profile).
MW4Shell.cpp:
- CTCL_DefaultHostSetup (non-coop): replaced hardcoded
Environment.NetworkMaxPlayers=16 with
params->m_maxPlayers + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount())
so DirectPlay reserves one extra slot per installed cameraship.
CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount() = camera-only seat count.
- SetNetworkMissionParamater / PLAYER_LIMIT_PARAMETER: applied the same
camera-slot formula when the host changes the player limit at runtime.
Also restored the gos_NetServerCommands(gos_Commend_UpdateMaxPlayers)
call (was accidentally dropped) and the missing break that caused
fall-through into JOIN_IN_PROGRESS_PARAMETER.
- COOP branch: no change (capped at 9+bots; camera seats not needed there).
ConLobby.script:
- Raised the launch-guard cap from nTempPlayerCount > 16 to > 17,
allowing the 17th connection (the cameraship) to not trigger the
'Too many player/bots' error.
Incremental Release + Profile builds (0 errors) picking up the
CRIOMAIN.CPP UpdateThrottle change; rel.bin\MW4.exe and MW4pro.exe
deployed to MW4\. Build logs in build-env\build_pr4_*.log.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes the if(lT!=0) guard in UpdateThrottle that made an exact-zero
throttle reading keep the previous throttle value; adds a negative
clamp. Zero now falls into the deadzone branch -> ZERO_THROTTLE.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
-tbaud <rate> (9600-921600) overrides the COM1 baud rate while keeping
old-RIO (type 0) protocol behavior unchanged; independent of -trio.
SetupComm buffers 2/2 -> 1024/1024 only when the override is active.
Rebuilt Release + Profile (0 errors), deployed rel.bin\MW4.exe to MW4\.
run-firestorm driver: game-start now takes optional extra args.
CLAUDE.md: branch notes incl. the CP949 comment-encoding hazard
(mw4 sources must be edited byte-safely).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FS507D_20161015 release analysis wrap-up (drop itself is gitignored; art-review
folder kept local for review):
- Recovered the only assets our tree lacked: 13 hsh HUD/radar/mech bmps and the
two 5.07D lobby decals (decal_46/47.tga, extracted from release props.mw4 via
a ported gos_LZDecompress).
- ResourceImagePool.cpp: missing-texture placeholder is now LAB_ONLY (editor
keeps degraded mode); Release restores the original fatal STOP. Release +
Profile rebuilt, 0 errors.
Console script reconciled:
- ConLobby.script.new ("BattleTech Console V5.0.7Df", newest revision anywhere)
promoted to Content\ShellScripts\ConLobby.script; .new removed; stale loose
deploy copy removed. Verified in-game (console title shows V5.0.7Df).
- Corrected CLAUDE.md: the release never "renamed" the console to
ComputerPlayer.script -- the resource packer stores script contents under
alphabetically skewed entry names (runtime resolves the same pairing).
Packer quirks documented (stale entry carry-forward on incremental builds,
name/content skew in directory sweeps).
Mechlab bug fix (first FireStorm bug hunt):
- New-Mech dialog showed blank rows for Wolfhound/Zeus and crashed (KERNELBASE
read AV) when creating a Zeus. Root cause: newmech in chassis.script created
its Type droplist without setting $$m_listBoxSize$$, so capacity defaulted to
60 while 65 chassis were written in -- OOB script-array writes. Fixed by
sizing the list from $$m_chassisCount$$. Latent stock-MW4 bug armed when the
FireStorm roster passed 60 chassis. Verified: Zeus variant creates cleanly.
props.mw4 fully repacked (decals + promoted console + mechlab fix, junk
.new/.org entries gone); game deploy refreshed at MW4\. Gitignore: FS507D drop
and player-created MW4\Resource\Variants.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.