Load File: finalize first-click deterministic apply, add NoReturn, and align docs

- 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.
This commit is contained in:
2026-07-24 21:42:54 -05:00
parent e5561181bb
commit ff650f7bec
7 changed files with 299 additions and 127 deletions
@@ -377,6 +377,7 @@ main
int decal_id ///////VERY IMPORTANT FOR NEW DECAL INTERFACE
int decal_ids[20] //JPP was 18
int update_decal = false
int m_bApplyingAutoLoad = false // suppress skin_box auto decal sync during Load File apply
int ROSTER_top_of_list = 0
int block_launch_or_ready = FALSE
int MAX_ITEMS = 60
@@ -994,26 +995,9 @@ main
// o_decal[x].list_item[15] = "SCORPION"
// o_decal[x].list_item[16] = "331st"
o_decal[x].list_item[0] = "1"
o_decal[x].list_item[1] = "2"
o_decal[x].list_item[2] = "3"
o_decal[x].list_item[3] = "4"
o_decal[x].list_item[4] = "5"
o_decal[x].list_item[5] = "6"
o_decal[x].list_item[6] = "7"
o_decal[x].list_item[7] = "8"
o_decal[x].list_item[8] = "9"
o_decal[x].list_item[9] = "10"
o_decal[x].list_item[10] = "11"
o_decal[x].list_item[11] = "12"
o_decal[x].list_item[12] = "13"
o_decal[x].list_item[13] = "14"
o_decal[x].list_item[14] = "15"
o_decal[x].list_item[15] = "16"
o_decal[x].list_item[16] = "17"
for coolbaby = 17;coolbaby < o_decal[x].list_size+1;coolbaby++
o_decal[x].list_item[coolbaby] = conv$(coolbaby+1)
for coolbaby = 0; coolbaby < MAX_DECAL_COUNT; coolbaby++
o_decal[x].list_item[coolbaby] = conv$(ffa_decal[coolbaby])
o_decal[x].list_item[MAX_DECAL_COUNT] = "00" // bot/default entry
o_decal[x].nselected = 3
decal_ids[x] = 1
@@ -1683,20 +1667,12 @@ main
play press, 1
if callback($$CTCL_LoadAutoFile$$)
{
m_bApplyingAutoLoad = true
// Apply game options using dedicated Auto globals.
// Rookie Mission globals are NOT touched so the Default button keeps working.
int m
if exists(@ConLobbyMission@)
{
@ConLobbyMission@o_game_options[0].nselected = $$g_nAutoGameType$$
for (m = 0; m < @ConLobbyMission@o_game_options[1].list_size; m++)
{
if equal$(@ConLobbyMission@o_game_options[1].list_item[m], $$g_szAutoMission$$)
{
@ConLobbyMission@o_game_options[1].nselected = m
break
}
}
mail(MAIL_LOAD_AUTO_MISSION, @ConLobbyMission@)
}
// Update team state synchronously so slot display is correct on the first click.
@@ -1774,9 +1750,21 @@ main
// The game type may not have propagated to cur_team_val yet
// (MAIL_SET_ROOKIE_MISSION is async); setting both is safe --
// the launch code uses whichever is correct for the active mode.
int nAutoDecal
int nAutoDecalIndex
o_team[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 1)
o_skins[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 2)
o_decal[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 3)
nAutoDecal = callback($$CTCL_GetAutoSlotInt$$, k, 3)
nAutoDecalIndex = 20 // fallback to safe/default decal slot
for (j = 0; j <= MAX_DECAL_COUNT; j++)
{
if (ffa_decal[j] == nAutoDecal)
{
nAutoDecalIndex = j
break
}
}
o_decal[k].nselected = nAutoDecalIndex
initialize(o_mech_variant[k])
if (ROSTER_top_of_list <= k) && (k < ROSTER_top_of_list + ROSTER_DISPLAY_COUNT)
{
@@ -1787,6 +1775,7 @@ main
deactivate(o_mech_variant[k])
}
}
m_bApplyingAutoLoad = false
}
return
}
@@ -2200,6 +2189,24 @@ main
#endif // USE_O_MECH_VARIANT2
break
}
if (sender == o_skins[k])
{
if !cur_team_val
{
o_decal[k].nselected = o_skins[k].nselected
initialize(o_decal[k])
}
break
}
if (sender == o_team[k])
{
if cur_team_val
{
o_decal[k].nselected = team_camo[o_team[k].nselected]
initialize(o_decal[k])
}
break
}
if (sender == o_BotList[k])
{
if (o_BotList[k].nselected != m_naLastSelected[k])
@@ -3116,14 +3123,6 @@ skin_box
{
nLastState = state
p_pane = "Content\\ShellScripts\\Graphics\\Multiplayer\\LobbySkins\\skin" letters[state] "4.tga"
if cur_team_val
{
o_decal[id].nselected = team_camo[o_team[id].nselected]
}
else
{
o_decal[id].nselected = o_skins[id].nselected
}
}
render p_pane, SKIN_BOX_X-35,location.Y
@@ -3222,6 +3221,8 @@ decal_box
}
if (dstate != nLastdState)
{
if (dstate < 0) || (dstate > 20)
dstate = 20
nLastdState = dstate
d_pane = "Content\\ShellScripts\\Graphics\\Multiplayer\\LobbyDecals\\decal_" decals[dstate] ".tga"
}
@@ -570,7 +570,15 @@ main
//-------------------------------------------------------------------------
nTempParam = HEAT_PARAMETER
if callback($$GetLocalNetworkMissionParamater$$,nTempParam)
{
o_game_options[7].state = 2
nTempParam1 = WEAPON_JAM_PARAMETER
if callback($$GetLocalNetworkMissionParamater$$,nTempParam1)
o_game_options[14].state = 2
else
o_game_options[14].state = 0
initialize(o_game_options[14])
}
else
{
o_game_options[7].state = 0
@@ -686,6 +694,170 @@ main
}
}
}
// [automaticmode] Handle Load File in a dedicated early path for BOTH sender contexts.
// This prevents MAIL_LOAD_AUTO_MISSION self-mails from falling through to
// generic game/map handlers that re-apply Rookie defaults.
if (getmessage() == MAIL_LOAD_AUTO_MISSION)
{
// Phase 1: ensure game type is selected and rebuild map list for that type.
if (o_game_options[0].nselected != $$g_nAutoGameType$$)
{
o_game_options[0].nselected = $$g_nAutoGameType$$
callback($$SetNetworkMissionParamater$$, game_type, selection_to_standard[o_game_options[0].nselected])
if (callback($$InitNetworkScenarios$$))
{
callback($$GetGameTypeString$$, selection_to_standard[o_game_options[0].nselected])
callback($$GetNetworkScenarios$$, o_game_options[1].list_item[])
o_game_options[1].list_size = $$networkScenarioCount$$
initialize(o_game_options[1])
if ($$networkScenarioCount$$ == 0)
{
deactivate(o_game_options[1])
deactivate(@conlobby@o_launch_button)
}
else
{
activate(o_game_options[1])
activate(@conlobby@o_launch_button)
}
}
last_selected_game = o_game_options[0].nselected
}
// Phase 2: resolve mission by name in the current (game-type-specific) map list.
int auto_map_index
auto_map_index = 0
int found_auto_map
found_auto_map = 0
int mk
for (mk = 0; mk < o_game_options[1].list_size; mk++)
{
if equal$(o_game_options[1].list_item[mk], $$g_szAutoMission$$)
{
auto_map_index = mk
found_auto_map = 1
break
}
}
if !found_auto_map
auto_map_index = 0
if (o_game_options[1].nselected != auto_map_index)
o_game_options[1].nselected = auto_map_index
callback($$SetNetworkMissionParamater$$, game_type, selection_to_standard[$$g_nAutoGameType$$])
callback($$SetNetworkMissionParamater$$, map_type, o_game_options[1].nselected)
callback($$SelectNetworkScenario$$, o_game_options[1].nselected)
last_selected_map = o_game_options[1].nselected
// visibility
o_game_options[2].nselected = $$g_nAutoVisibility$$
callback($$SetNetworkMissionParamater$$, visibility, o_game_options[2].nselected)
// weather
o_game_options[3].nselected = $$g_nAutoWeather$$
callback($$SetNetworkMissionParamater$$, weather, o_game_options[3].nselected)
// time of day
o_game_options[4].nselected = $$g_nAutoTimeOfDay$$
callback($$SetNetworkMissionParamater$$, night_parameter, o_game_options[4].nselected)
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
// time limit
int nAutoTL = $$g_nAutoTimeLimit$$
int temp_num
if nAutoTL >= 0
temp_num = nAutoTL
else
temp_num = TIME_VALUE_DEFAULT
int m
for (m = 0; m < o_game_options[5].list_size; m++)
{
if (makeint(o_game_options[5].list_item[m]) == temp_num)
{
o_game_options[5].nselected = m
break
}
}
callback($$SetNetworkMissionParamater$$, time_limit, temp_num)
// radar
int nTempParam = radar
int nTempValue = $$g_nAutoRadar$$
o_game_options[6].nselected = nTempValue
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// heat
nTempParam = HEAT_PARAMETER
nTempValue = $$g_nAutoHeat$$
if nTempValue
o_game_options[7].state = 2
else
o_game_options[7].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// friendly fire
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
nTempValue = $$g_nAutoFriendlyFire$$
if nTempValue
{
o_game_options[8].state = 2
nTempValue = 100
}
else
{
o_game_options[8].state = 0
nTempValue = 0
}
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// splash
nTempParam = SPLASH_ON_PARAMETER
nTempValue = $$g_nAutoSplash$$
if nTempValue
o_game_options[9].state = 2
else
o_game_options[9].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// unlimited ammo
nTempParam = UNLIMITED_AMMO_PARAMETER
nTempValue = $$g_nAutoUnlimitedAmmo$$
if (nTempValue == 0)
o_game_options[10].state = 2
else
o_game_options[10].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// no return
nTempParam = num_of_lives
nTempValue = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
nTempParam = respawn_onoff
nTempValue = $$g_nAutoNoReturn$$
if nTempValue
o_game_options[11].state = 2
else
o_game_options[11].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// weapon jam
nTempParam = WEAPON_JAM_PARAMETER
nTempValue = $$g_nAutoWeaponJam$$
if nTempValue
o_game_options[14].state = 2
else
o_game_options[14].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// advance mode
nTempParam = ADVANCE_MODE_PARAMETER
nTempValue = $$g_nAutoAdvanceMode$$
if nTempValue
o_game_options[15].state = 2
else
o_game_options[15].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// armor mode
nTempParam = ARMOR_MODE_PARAMETER
nTempValue = $$g_nAutoArmorMode$$
if nTempValue
o_game_options[16].state = 2
else
o_game_options[16].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
mail(MAIL_LOAD_AUTO_MISSION_DONE, this)
return
}
if (sender == @conlobby@)
{
if (getmessage() == -7777)
@@ -832,82 +1004,6 @@ main
mail(MAIL_PREVIOUS_MISSION_PARAMS, this)
return
}
// [automaticmode] Load File button: apply Auto globals, separate from Rookie Mission defaults
if (getmessage() == MAIL_LOAD_AUTO_MISSION)
{
callback($$SetNetworkMissionParamater$$, game_type, selection_to_standard[$$g_nAutoGameType$$])
// visibility
o_game_options[2].nselected = $$g_nAutoVisibility$$
callback($$SetNetworkMissionParamater$$, visibility, o_game_options[2].nselected)
// weather
o_game_options[3].nselected = $$g_nAutoWeather$$
callback($$SetNetworkMissionParamater$$, weather, o_game_options[3].nselected)
// time of day
o_game_options[4].nselected = $$g_nAutoTimeOfDay$$
callback($$SetNetworkMissionParamater$$, night_parameter, o_game_options[4].nselected)
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
// time limit
int nAutoTL = $$g_nAutoTimeLimit$$
int temp_num
if nAutoTL >= 0
temp_num = nAutoTL
else
temp_num = TIME_VALUE_DEFAULT
int m
for (m = 0; m < o_game_options[5].list_size; m++)
{
if (makeint(o_game_options[5].list_item[m]) == temp_num)
{
o_game_options[5].nselected = m
break
}
}
callback($$SetNetworkMissionParamater$$, time_limit, temp_num)
// radar
int nTempParam = radar
int nTempValue = $$g_nAutoRadar$$
o_game_options[6].nselected = nTempValue
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// heat
nTempParam = HEAT_PARAMETER
nTempValue = $$g_nAutoHeat$$
o_game_options[7].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// friendly fire
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
nTempValue = $$g_nAutoFriendlyFire$$
o_game_options[8].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// splash
nTempParam = SPLASH_ON_PARAMETER
nTempValue = $$g_nAutoSplash$$
o_game_options[9].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// unlimited ammo
nTempParam = UNLIMITED_AMMO_PARAMETER
nTempValue = $$g_nAutoUnlimitedAmmo$$
o_game_options[10].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// weapon jam
nTempParam = WEAPON_JAM_PARAMETER
nTempValue = $$g_nAutoWeaponJam$$
o_game_options[14].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// advance mode
nTempParam = ADVANCE_MODE_PARAMETER
nTempValue = $$g_nAutoAdvanceMode$$
o_game_options[15].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// armor mode
nTempParam = ARMOR_MODE_PARAMETER
nTempValue = $$g_nAutoArmorMode$$
o_game_options[16].state = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// Finalize via self-mail: initialize(this) and mail(-9998,parent) must run
// in a sender==this context to avoid the 'gui_objects have no parent' crash.
mail(MAIL_LOAD_AUTO_MISSION_DONE, this)
return
}
}
if (sender == this)
{
@@ -1088,7 +1184,36 @@ main
if (getmessage() == MAIL_LOAD_AUTO_MISSION_DONE)
{
initialize(this)
mail(-9998, parent)
nTempParam = UNLIMITED_AMMO_PARAMETER
if ($$g_nAutoUnlimitedAmmo$$ == 0)
{
o_game_options[10].state = 2
nTempValue = 0
}
else
{
o_game_options[10].state = 0
nTempValue = 1
}
initialize(o_game_options[10])
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
nTempParam = num_of_lives
nTempValue = 0
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
nTempParam = respawn_onoff
if ($$g_nAutoNoReturn$$)
{
o_game_options[11].state = 2
nTempValue = 1
}
else
{
o_game_options[11].state = 0
nTempValue = 0
}
initialize(o_game_options[11])
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
mail(-9998, @conlobby@)
return
}
if (getmessage() == MAIL_PREVIOUS_MISSION_PARAMS)
@@ -1268,7 +1393,7 @@ main
mail(MAIL_PREVIOUS_MISSION_PARAMS, this)
}
if ((sender == o_game_options[0]) || ((sender == this) && (getmessage() == MAIL_SET_ROOKIE_MISSION))) && (o_game_options[0].nselected != last_selected_game)
if ((sender == o_game_options[0]) || ((sender == this) && ((getmessage() == MAIL_SET_ROOKIE_MISSION) || (getmessage() == MAIL_LOAD_AUTO_MISSION)))) && (o_game_options[0].nselected != last_selected_game)
{
callback($$SetNetworkMissionParamater$$, game_type, selection_to_standard[o_game_options[0].nselected])
@@ -1321,7 +1446,7 @@ main
mail(MAIL_SET_ROOKIE_MISSION_PARAMS, this)
}
if ((sender == o_game_options[1]) || ((sender == this) && (getmessage() == MAIL_SET_ROOKIE_MISSION))) && (o_game_options[1].nselected != last_selected_map)
if ((sender == o_game_options[1]) || ((sender == this) && ((getmessage() == MAIL_SET_ROOKIE_MISSION) || (getmessage() == MAIL_LOAD_AUTO_MISSION)))) && (o_game_options[1].nselected != last_selected_map)
{
callback($$SetNetworkMissionParamater$$, map_type, o_game_options[1].nselected)
callback($$SelectNetworkScenario$$, o_game_options[1].nselected)