[Trigger] Save system - Multiple save files

BIG EDIT: It seems my game is now broken from testing this stuff. Every time I try to save a game, the game client crashes to desktop. I have tried reinstalling the game, deleting my saved games folder, clearing computer cache/temp files, recreating the Warcraft III registry entry, nothing works. A simple save game instance in a regular melee map crashes the game, every time. No idea what to do at this point...

Hey, I am using a save/load system similar to that which is used in the Founding of Durotan, just heavily modified, and partly built from scratch. The idea is that players can travel freely back and forth between 7 maps, while all information is saved and loaded in every map. This much works.

I wanted to utilize the normal save function of Blizzard, and have made a system where the players can only save in designated areas. To do this, I hide the "Save Game" frame from the menu when players are outside of the save zones. This also works fine.

These two ways of saving are completely different, and needs to be handled differently. One is SYSTEM saving (the first example), and the other is USER saving (the second example). For the USER SAVE, I use a US_ prefix to separate them from the SYSTEM save variables when I store them in the game cache. This works fine.

So far, USER saving works, but only when players use ONE save file. If the players try to use TWO or MORE save files, here's what happens:
  1. Player in map A equips an item
  2. Player saves the game, with item equipped. Let's call this save "MAIN".
  3. Player transitions to map B
  4. Player unequips the previously equipped item while in map B
  5. Player saves the game, with item unequipped. Let's call this save "SECONDARY".
  6. The player then LOADS the game file "MAIN"
  7. This leads to the player loading into map A, with the item unequipped, while stats remain

So my theory is this; The USER SAVE variables stored in the game cache are being overwritten, since I don't keep an array of these variables. So it's like I set a point variable that isn't an array to two different locations. The first location will naturally be overwritten. That's exactly what is happening here too, variables are being overwritten. So I figured I'd save the save file names to strings every time the game was saved, and keep track of how many times the game has been saved. Then I store the variables I want to save in the game cache dependent on the current save count. In theory it should work, but it just doesn't. I have added debug messages that verifies that the saved game count does in fact increment. Here's what I have tried:

In the trigger "User Save" the important part is the first 3 triggers that are being ran, namely "User Save Detect Existing Save", "User Save Increment Saves", and "User Save Store Increment and Names". The first one loops through the total amount of times the players have saved, checks if the saved game file name equals to Save_String[integer A]. If the saved game name has a match, Save_Current is set to the same as integer A. Save_Current is used to determine what current save number the players are on. If there are no matches, Save_Current is set to 0, to indicate that this is the first time the players have saved the game manually with this saved game file name (a new save file). Then the next trigger is ran, where if it is a new save (Save_Current = 0), then the Save_Count integer is incremented by 1, Save_Current is set = to Save_Count, and Save_String[Save_Current] is set = to saved file name. Finally the Save_Count and the Save_String[] variables are saved to the game cache so the players keeps track of the total amount of saves and save files across saves and maps.
  • User Save
    • Events
      • Game - The game is about to be saved
    • Conditions
      • System_Save Equal to False
    • Actions
      • Trigger - Run User Save Detect Existing Save <gen> (ignoring conditions)
      • Trigger - Run User Save Increment Saves <gen> (ignoring conditions)
      • Trigger - Run User Save Store Increment and Names <gen> (ignoring conditions)
      • -------- -- --------
      • Trigger - Run User Save Units Locations Facing <gen> (ignoring conditions)
      • Trigger - Run User Save Load Remove Units <gen> (ignoring conditions)
      • Trigger - Run User Run Save <gen> (ignoring conditions)
      • Game Cache - Save CommonCache.
      • Wait 0.00 seconds
      • Trigger - Run User Load Add Units <gen> (ignoring conditions)
  • User Save Detect Existing Save
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 1 to Save_Count, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Saved-game filename) Equal to Save_String[(Integer A)]
            • Then - Actions
              • Set VariableSet Save_Current = (Integer A)
              • Skip remaining actions
            • Else - Actions
              • Set VariableSet Save_Current = 0
  • User Save Increment Saves
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Save_Current Equal to 0
        • Then - Actions
          • Set VariableSet Save_Count = (Save_Count + 1)
          • Set VariableSet Save_Current = Save_Count
          • Set VariableSet Save_String[Save_Current] = (Saved-game filename)
        • Else - Actions
  • User Save Store Increment and Names
    • Events
    • Conditions
    • Actions
      • Game Cache - Store Save_Count as Save_Count of Variables in CommonCache
      • For each (Integer A) from 1 to Save_Count, do (Actions)
        • Loop - Actions
          • Game Cache - Store Save_String[(Integer A)] as (Save_String + (String((Integer A)))) of Variables in CommonCache

To give an example of how I save variables to the game cache when user saving:
  • User Save Talents
    • Events
    • Conditions
    • Actions
      • Set VariableSet LoopInteger = 0
      • For each (Integer A) from 1 to 6, do (Actions)
        • Loop - Actions
          • Set VariableSet LoopInteger = (LoopInteger + 1)
          • Game Cache - Store SkillpointsCharacters[LoopInteger] as (US_CharacterTalents + ((String(LoopInteger)) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store CharacterUnlocked[LoopInteger] as (US_CharacterUnlocked + ((String(LoopInteger)) + Save_String[Save_Current])) of Variables in CommonCache
      • Set VariableSet LoopInteger = 0
      • For each (Integer A) from 0 to 62, do (Actions)
        • Loop - Actions
          • Game Cache - Store Char1TalentsOwned[(Integer A)] as (US_Char1TalentsOwned + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char2TalentsOwned[(Integer A)] as (US_Char2TalentsOwned + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char3TalentsOwned[(Integer A)] as (US_Char3TalentsOwned + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char4TalentsOwned[(Integer A)] as (US_Char4TalentsOwned + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char5TalentsOwned[(Integer A)] as (US_Char5TalentsOwned + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char1TalentsUnlockable[(Integer A)] as (US_Char1TalentsUnlockable + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char2TalentsUnlockable[(Integer A)] as (US_Char2TalentsUnlockable + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char3TalentsUnlockable[(Integer A)] as (US_Char3TalentsUnlockable + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char4TalentsUnlockable[(Integer A)] as (US_Char4TalentsUnlockable + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store Char5TalentsUnlockable[(Integer A)] as (US_Char5TalentsUnlockable + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
  • User Save Quests
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 2000, do (Actions)
        • Loop - Actions
          • Game Cache - Store QJ_Completed[(Integer A)] as (US_QJ_Completed + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store QJ_Discovered[(Integer A)] as (US_QJ_Discovered + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store QJ_Progress1Int[(Integer A)] as (US_QJ_Progress1Int + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store QJ_Progress2Int[(Integer A)] as (US_QJ_Progress2Int + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store QJ_Progress3Int[(Integer A)] as (US_QJ_Progress3Int + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store QJ_Progress4Int[(Integer A)] as (US_QJ_Progress4Int + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
          • Game Cache - Store QJ_Progress5Int[(Integer A)] as (US_QJ_Progress5Int + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache
  • User Save Bestiary
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 0 to 35, do (Actions)
        • Loop - Actions
          • Game Cache - Store BSTRY_UnitExamined[(Integer A)] as (US_BSTRY_UnitExamined + ((String((Integer A))) + Save_String[Save_Current])) of Variables in CommonCache

This way of saving variables worked fine BEFORE I tried implementing the fix for multiple save files. The ONLY thing that changed in the way that I store variables in the game cache is that I added " + Save_String[Save_Current]))" as an extra string concatenation in the category label in the cache saving triggers.

As for what happens; I get random crashes when loading the game, and values are weird/incorrect.

I know this is a lot to take in, information wise, but I'm at my wits end.

EDIT: I forgot to include how I LOAD variables as well.

When the game is loaded, the trigger called "Load 1 Init" first creates a cache from CommonCache.w3v, then sets it equal to CommonCache, and then all data is reloaded from the disk. Then it detects whether or not this is a system load, and runs the corresponding trigger. This works fine. So when "Run User Load" is ran, it uses the variable Save_Current to determine what save this currently is. This variable is not saved and loaded anywhere, and is only in the maps, so Blizzard internal saving should handle Save_Current. The only time Save_Current is manipulated is whenever the game is saved. That way it's saved "into" the maps, never to the game cache.
  • Load 1 Init
    • Events
      • Game - A saved game is loaded
    • Conditions
    • Actions
      • Cinematic - Fade out over 0.00 seconds using texture Black Mask and color (0.00%, 0.00%, 0.00%) with 0.00% transparency
      • Cinematic - Fade in over 4.00 seconds using texture Black Mask and color (0.00%, 0.00%, 0.00%) with 0.00% transparency
      • Game Cache - Create a game cache from CommonCache.w3v
      • Set VariableSet CommonCache = (Last created game cache)
      • Game Cache - Reload all game cache data from disk
      • -------- Detect System load --------
      • Set VariableSet System_Load = (Load SystemLoad of Variables from CommonCache)
      • -------- Proceed loading as normal if it's a system load --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • System_Load Equal to True
        • Then - Actions
          • Set VariableSet LeftFromMap = (Load LeftFromMap of Variables from CommonCache)
          • Trigger - Run Load 2 Triggers <gen> (ignoring conditions)
        • Else - Actions
          • Set VariableSet LeftFromMap = (Load LeftFromMap of Variables from CommonCache)
          • Trigger - Run User Load <gen> (ignoring conditions)
  • User Run Load
    • Events
    • Conditions
    • Actions
      • -------- ---- --------
      • -------- Load the Save_String[] variables --------
      • Trigger - Run User Save Load Increment and Names <gen> (ignoring conditions)
      • -------- ---- --------
      • -------- Proceed with loading the variables below --------
      • Trigger - Run User Load New Games <gen> (ignoring conditions)
      • Trigger - Run User Load Combat <gen> (ignoring conditions)
      • Trigger - Run User Load Equipment <gen> (ignoring conditions)
      • Trigger - Run User Load Formation <gen> (ignoring conditions)
      • Trigger - Run User Load Items <gen> (ignoring conditions)
      • Trigger - Run User Load Talents <gen> (ignoring conditions)
      • Trigger - Run User Load Day Night Cycle <gen> (ignoring conditions)
      • Trigger - Run User Load Torch <gen> (ignoring conditions)
      • Trigger - Run User Load Walk <gen> (ignoring conditions)
      • Trigger - Run User Load interior DNC Fog <gen> (ignoring conditions)
      • Trigger - Run User Load Map System <gen> (ignoring conditions)
      • Trigger - Run User Load Quests <gen> (ignoring conditions)
      • Trigger - Run User Load Bestiary <gen> (ignoring conditions)
  • User Save Load Increment and Names
    • Events
    • Conditions
    • Actions
      • Set VariableSet Save_Count = (Load Save_Count of Variables from CommonCache)
      • For each (Integer A) from 1 to Save_Count, do (Actions)
        • Loop - Actions
          • Set VariableSet Save_String[(Integer A)] = (Save_String + (String((Integer A))))

And as an example of actually loading the variables:
  • Load Talents
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 6, do (Actions)
        • Loop - Actions
          • Set VariableSet SkillpointsCharacters[(Integer A)] = (Load (CharacterTalents + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet CharacterUnlocked[(Integer A)] = (Load (CharacterUnlocked + (String((Integer A)))) of Variables from CommonCache)
      • For each (Integer A) from 0 to 62, do (Actions)
        • Loop - Actions
          • Set VariableSet Char1TalentsOwned[(Integer A)] = (Load (Char1TalentsOwned + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char2TalentsOwned[(Integer A)] = (Load (Char2TalentsOwned + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char3TalentsOwned[(Integer A)] = (Load (Char3TalentsOwned + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char4TalentsOwned[(Integer A)] = (Load (Char4TalentsOwned + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char5TalentsOwned[(Integer A)] = (Load (Char5TalentsOwned + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char1TalentsUnlockable[(Integer A)] = (Load (Char1TalentsUnlockable + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char2TalentsUnlockable[(Integer A)] = (Load (Char2TalentsUnlockable + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char3TalentsUnlockable[(Integer A)] = (Load (Char3TalentsUnlockable + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char4TalentsUnlockable[(Integer A)] = (Load (Char4TalentsUnlockable + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet Char5TalentsUnlockable[(Integer A)] = (Load (Char5TalentsUnlockable + (String((Integer A)))) of Variables from CommonCache)
  • Load Formation
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 0 to 9, do (Actions)
        • Loop - Actions
          • Set VariableSet CFCharacterIndex[(Integer A)] = (Load (CFCharacterIndex + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet CFOccupied[(Integer A)] = (Load (CFOccupied + (String((Integer A)))) of Variables from CommonCache)
  • Load Quests
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 1 to QJ_IndexNumber, do (Actions)
        • Loop - Actions
          • Set VariableSet QJ_Completed[(Integer A)] = (Load (US_QJ_Completed + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet QJ_Discovered[(Integer A)] = (Load (US_QJ_Discovered + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet QJ_Progress1Int[(Integer A)] = (Load (QJ_Progress1Int + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet QJ_Progress2Int[(Integer A)] = (Load (QJ_Progress2Int + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet QJ_Progress3Int[(Integer A)] = (Load (QJ_Progress3Int + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet QJ_Progress4Int[(Integer A)] = (Load (QJ_Progress4Int + (String((Integer A)))) of Variables from CommonCache)
          • Set VariableSet QJ_Progress5Int[(Integer A)] = (Load (QJ_Progress5Int + (String((Integer A)))) of Variables from CommonCache)
 
Last edited:
Top