Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/snippets/features.7066.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- (#7066) Add a quick load hotkey that loads the game from the special quick save file.
3 changes: 3 additions & 0 deletions loc/US/strings_db.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4464,6 +4464,8 @@ key_desc_0405="Dock"
key_desc_0407="Select all Bombers (Normal)"
key_desc_0408="Select all Bombers (Torpedo)"

key_desc_quick_load="Load the game from the special quick save file"

keymap_category_0000="UI"
keymap_category_0004="Selection"
keymap_category_0025="Camera"
Expand Down Expand Up @@ -5293,6 +5295,7 @@ sCDR_Victoria="sCDR Victoria"
sCDR_ZanIavow="sCDR Zan-Iavow"
saveload_0001="Saving game..."
saveload_0002="Quick Save in progress..."
saveload_QuickLoad="Loading Quick Save..."
score_0001="No Rush Time Elapsed"
score_0002="Unit Cap Reached"
score_0003="Observer"
Expand Down
1 change: 1 addition & 0 deletions lua/keymap/alternativeKeyMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ defaultKeyMap = {
['F10'] = 'toggle_main_menu',
['F11'] = 'toggle_disconnect_screen',
['F12'] = 'show_objective_screen',
['Shift-F9'] = 'quick_load',

['1'] = 'group1',
['2'] = 'group2',
Expand Down
1 change: 1 addition & 0 deletions lua/keymap/defaultKeyMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ defaultKeyMap = {
['F10'] = 'toggle_main_menu',
['F11'] = 'toggle_disconnect_screen',
['F12'] = 'show_objective_screen',
['Shift-F9'] = 'quick_load',
['1'] = 'group1',
['2'] = 'group2',
['3'] = 'group3',
Expand Down
1 change: 1 addition & 0 deletions lua/keymap/hotbuildKeyMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ defaultKeyMap = {
['F10'] = 'toggle_main_menu',
['F11'] = 'toggle_disconnect_screen',
['F12'] = 'show_objective_screen',
['Shift-F9'] = 'quick_load',

['1'] = 'group1',
['2'] = 'group2',
Expand Down
4 changes: 4 additions & 0 deletions lua/keymap/keyactions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1834,6 +1834,10 @@ local keyActionsGame = {
action = 'UI_Lua import("/lua/ui/game/gamemain.lua").QuickSave(LOC("<LOC QuickSave>QuickSave"))',
category = 'ui',
},
['quick_load'] = {
action = 'UI_Lua import("/lua/ui/game/gamemain.lua").QuickLoad(LOC("<LOC QuickSave>QuickSave"))',
category = 'ui',
},
['toggle_key_bindings'] = {
action = 'UI_Lua import("/lua/ui/dialogs/keybindings.lua").CreateUI()',
category = 'ui',
Expand Down
1 change: 1 addition & 0 deletions lua/keymap/keydescriptions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ keyDescriptions = {
['cam_free'] = "<LOC key_desc_0104>Toggles camera free mode",

['quick_save'] = "<LOC key_desc_0130>Save the game to a special quick save file",
['quick_load'] = "<LOC key_desc_quick_load>Load the game from the special quick save file",
['mouse_help'] = "<LOC key_desc_0132>Turn the mouse button help icon on/off",

['create_build_template'] = "<LOC key_desc_0181>Create a build template based on the current selection",
Expand Down
56 changes: 56 additions & 0 deletions lua/ui/game/gamemain.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ local ordersControl = false

local OnDestroyFuncs = {}

--- game's "Non-Interactive Sequence" state as synced from Sim
---@type 'on' | 'off' | false
local NISActive = false
local isReplay = false
local waitingDialog = false
Expand Down Expand Up @@ -932,6 +934,9 @@ local rangePrefs = {
}

local preNISSettings = {}

--- Called by user sync to set the NIS mode state and do callbacks for the states
---@param state 'on' | 'off'
function NISMode(state)
NISActive = state
local worldView = import("/lua/ui/game/worldview.lua")
Expand Down Expand Up @@ -1032,6 +1037,8 @@ function ShowNISBars()
end
end

--- Returns true if the game is in a "Non-Interactive Sequence"
---@return boolean
function IsNISMode()
if NISActive == 'on' then
return true
Expand Down Expand Up @@ -1117,6 +1124,55 @@ function QuickSave(filename)
end
end

--- Called by key action to load a special quick save file.
---@param filename string
function QuickLoad(filename)
if not SessionIsActive()
or not SessionIsMultiplayer()
then
--#region Duplicate code from QuickSave
Comment on lines +1130 to +1133

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix the quick-load eligibility condition; it currently allows replay/no-session paths.

The condition not SessionIsActive() or not SessionIsMultiplayer() is too permissive and does not enforce replay exclusion. That diverges from the quicksave-style guard and can trigger quick-load in unsupported contexts.

💡 Suggested fix
 function QuickLoad(filename)
-    if not SessionIsActive()
-        or not SessionIsMultiplayer()
-    then
+    if (SessionIsActive() or WorldIsLoading())
+        and not SessionIsMultiplayer()
+        and not SessionIsReplay()
+    then
         --#region Duplicate code from QuickSave
         local saveType
         if import("/lua/ui/campaign/campaignmanager.lua").campaignMode then
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lua/ui/game/gamemain.lua` around lines 1130 - 1133, The quick-load
eligibility check is too permissive; replace the current condition `if not
SessionIsActive() or not SessionIsMultiplayer() then` with the same guard used
by the QuickSave logic and explicitly exclude replay/no-session paths by adding
an explicit replay check (use the existing SessionIsReplay() symbol) so the
branch only runs when the session/state truly matches QuickSave's allowed
conditions.

local saveType
if import("/lua/ui/campaign/campaignmanager.lua").campaignMode then
saveType = "CampaignSave"
else
saveType = "SaveGame"
end
local path = GetSpecialFilePath(Prefs.GetCurrentProfile().Name, filename, saveType)
--#endregion

local statusStr = "<LOC saveload_QuickLoad>Loading Quick Save..."
local status = UIUtil.ShowInfoDialog(GetFrame(0), statusStr)

--#region Duplicate of `/lua/ui/dialogs/saveload.lua` `CreateLoadDialog` `DoLoad`
SetFrontEndData('NextOpBriefing', nil)
local SaveErrors = {
WrongVersion = '<LOC uisaveload_0005>Wrong version for savegame "%s"',
CantOpen = '<LOC uisaveload_0004>Couldn\'t open savegame "%s"',
InvalidFormat = '<LOC uisaveload_0006>"%s" is not a valid savegame',
InternalError = '<LOC uisaveload_0007>Internal error loading savegame "%s": %s',
}
local InternalErrors = {
['eof'] = "<LOC Engine0027>EOF reached during serialization.",
['noread'] = "<LOC Engine0028>Error reading file stream during serialization.",
['nowrite'] = "<LOC Engine0026>Error writing data during serialization. Possibly out of disk space.",
}

local worked, error, detail = LoadSavedGame(path)
if not worked then
UIUtil.ShowInfoDialog(GetFrame(0),
-- note - the 'Unknown error...' string below is intentionally not localized because
-- it should never show up. If it does, add the error string to SaveErrors.
LOCF(SaveErrors[error] or ('Unknown error ' .. repr(error) .. 'loading savegame %s: %s'),
Basename(path, true),
InternalErrors[detail] or detail),
"<LOC _Ok>")
end
--#endregion

status:Destroy()
end
end

defaultZoom = 1.4
function SimChangeCameraZoom(newMult)
if SessionIsActive() and
Expand Down