• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

Acehart's help to save/load Spell's with other things

Status
Not open for further replies.
Level 4
Joined
Jan 22, 2019
Messages
15
Hello, how is everything? I would like the help of someone who understands a little about save / load systems.

I want to continue using the acehart system because I have over 200 items already stored. But on my map I would like the spells to be purchased. The easiest way I found for this is to leave these pages as hero spells in the unit, just changing its level beyond the limit, so that the person can only view and will only succeed if they buy or do something.

But my problem is with the Acehart system, there is in the demo that I will make available below the option to save only the inventory or the skills, and there is also the option to save everything I use, however this option does not save the skills.

I spent a few hours trying to put together the ability to save skill but I couldn't.
If you understand and know how to solve my problem, please attach the same demo, just configured the right way.

On my map I'm making, I would like the skills I bought to be saved in a spell book, but I have no idea how it can work.
 

Attachments

  • SaveLoad_Demo_AceHart.w3x
    37.9 KB · Views: 16
  • aaaa.jpg
    aaaa.jpg
    279.3 KB · Views: 19
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
I don't think you can add abilities to a Spellbook outside of the Object Editor. Maybe in the newer versions (1.31+) you can do this through triggers using the Ability Field functions but I doubt it works.

That being said, I'll try to explain how the system works a bit and where you went wrong.

So you've setup the Bloodmage's abilities properly in the SaveLoad Initialization trigger, but you never actually save or load these abilities in the Save Hero / Load Hero triggers.

Here's your save trigger:
  • SaveLoad Save Hero
    • Events
      • Player - Player 1 (Red) types a chat message containing -save as An exact match
      • Player - Player 2 (Blue) types a chat message containing -save as An exact match
      • Player - Player 3 (Teal) types a chat message containing -save as An exact match
      • Player - Player 4 (Purple) types a chat message containing -save as An exact match
    • Conditions
    • Actions
      • -------- Prepare the save array with this player's Hero --------
      • Set VariableSet SaveCount = 0
      • -------- Take all Heroes (assumes there is only one) --------
      • Unit Group - Pick every unit in (Units owned by (Triggering player) matching (((Matching unit) is A Hero) Equal to True).) and do (Actions)
        • Loop - Actions
          • -------- Save the Hero --------
          • Set VariableSet SaveCount = (SaveCount + 1)
          • Set VariableSet TempUnit = (Picked unit)
          • Custom script: set udg_Save[udg_SaveCount] = SaveLoad_Unit2Integer( udg_TempUnit )
          • -------- Hero level --------
          • Set VariableSet SaveCount = (SaveCount + 1)
          • Set VariableSet Save[SaveCount] = (Hero level of (Picked unit))
          • -------- How many items does he carry --------
          • Set VariableSet SaveCount = (SaveCount + 1)
          • Set VariableSet Save[SaveCount] = (Number of items carried by (Picked unit))
          • -------- Add all items --------
          • For each (Integer A) from 1 to 6, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Item carried by (Picked unit) in slot (Integer A)) is owned) Equal to True
                • Then - Actions
                  • -------- The actual item --------
                  • Set VariableSet SaveCount = (SaveCount + 1)
                  • Set VariableSet TempItem = (Item carried by (Picked unit) in slot (Integer A))
                  • Custom script: set udg_Save[udg_SaveCount] = SaveLoad_Item2Integer( udg_TempItem )
                  • -------- The number of charges it has --------
                  • Set VariableSet SaveCount = (SaveCount + 1)
                  • Set VariableSet Save[SaveCount] = (Charges remaining in (Item carried by (Picked unit) in slot (Integer A)))
                • Else - Actions
      • -------- Turn values into code --------
      • Custom script: set udg_Code = SaveLoad_Encode()
      • -------- Show code to player --------
      • Quest - Display to (Player group((Triggering player))) the Secret message: Your code:
      • Game - Display to (Player group((Triggering player))) for 60.00 seconds the text: Code
See how there's no mention of the abilities in this save trigger. How can it save something that doesn't exist?

Now let's look at AceHart's own Save Abilities trigger:
  • SaveLoad Save Abilities
    • Events
      • Player - Player 1 (Red) types a chat message containing -save as An exact match
      • Player - Player 2 (Blue) types a chat message containing -save as An exact match
      • Player - Player 3 (Teal) types a chat message containing -save as An exact match
      • Player - Player 4 (Purple) types a chat message containing -save as An exact match
    • Conditions
    • Actions
      • -------- Prepare the save array with this player's Hero --------
      • Set VariableSet SaveCount = 0
      • -------- Take all Heroes (assumes there is only one) --------
      • Unit Group - Pick every unit in (Units owned by (Triggering player) matching (((Matching unit) is A Hero) Equal to True).) and do (Actions)
        • Loop - Actions
          • -------- Save the Hero --------
          • Set VariableSet SaveCount = (SaveCount + 1)
          • Set VariableSet TempUnit = (Picked unit)
          • Custom script: set udg_Save[udg_SaveCount] = SaveLoad_Unit2Integer( udg_TempUnit )
          • -------- Hero level --------
          • Set VariableSet SaveCount = (SaveCount + 1)
          • Set VariableSet Save[SaveCount] = (Hero level of (Picked unit))
          • -------- Add all abilities --------
          • For each (Integer A) from 1 to SaveLoad_Abilities_LastIndex, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Level of SaveLoad_Abilities[(Integer A)] for (Picked unit)) Greater than 0
                • Then - Actions
                  • -------- The actual ability --------
                  • Set VariableSet SaveCount = (SaveCount + 1)
                  • Set VariableSet Save[SaveCount] = (Integer A)
                  • -------- Its level --------
                  • Set VariableSet SaveCount = (SaveCount + 1)
                  • Set VariableSet Save[SaveCount] = (Level of SaveLoad_Abilities[(Integer A)] for (Picked unit))
                • Else - Actions
      • -------- Turn values into code --------
      • Custom script: set udg_Code = SaveLoad_Encode()
      • -------- Show code to player --------
      • Quest - Display to (Player group((Triggering player))) the Secret message: Your code:
      • Game - Display to (Player group((Triggering player))) for 60.00 seconds the text: Code
See where it says: -------- Add all abilities --------
Below that line is where it saves all of the abilities. This is done by Looping over every ability that you've setup in your Initialization trigger. In this demo's case that'd be the 4 abilities used by Bloodmage. It then checks if the picked Hero has the ability, and if it does then it saves that abilties index (Integer A) and it's Level.

Now onto loading. When it comes time to load this data you'd do something similar to what's shown in AceHart's Load Abilities trigger:
  • For each (Integer SaveCount) from (SaveCount + 1) to TempInteger, do (Actions)
    • Loop - Actions
      • For each (Integer A) from 1 to Save[(SaveCount + 1)], do (Actions)
        • Loop - Actions
          • Custom script: call SelectHeroSkill( GetLastCreatedUnit(), udg_SaveLoad_Abilities[ udg_Save[ udg_SaveCount ] ] )
      • Set VariableSet SaveCount = (SaveCount + 1)
In this case the Custom script is ordering the Bloodmage to spend Skill Points into his abilities. Note that there's 2 Loops here, the first one loops over the last indexes in the Save[] array, and the second loops X times, where X is the Level of the ability. Note that this is the very last thing that's loaded, which is intentional because otherwise it'd need an extra Save variable to track the number of saved abilities the hero had. This would be necessary so that it knows how many abilities it should try to load in the first place. So if you wished to load other data after the abilities then you'd need to take this into consideration.

You could modify this to instead Add abilities to the Hero if you don't wish to spend skill points and deal with the Hero Skill menu.
You'd replace that Custom script line with something like this:
  • Unit - Add SaveLoad_Abilities[Save[SaveCount]] to Last created unit
  • Unit - Set Level of SaveLoad_Abilities[Save[SaveCount]] for Last created unit to Save[SaveCount + 1]
That would add the ability to the hero and set it's level.
 
Last edited:
Level 4
Joined
Jan 22, 2019
Messages
15
How do you show the GUI code like that?

I understood what you meant, but my problem is to make saving skills work with the items, when I try to do what you said, when I load the code, sometimes it comes with wrong items, wrong skills. Can you send me a map with that fixed?

About book skills, I put my character in an empty book. So when he buys a skill, another skill book with the purchased skill is added. As there is a trigger that removes the book, then the skill goes into that book that previously had nothing.
Isn't there any way to save the skills in the book?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570

If you load the wrong data then you're doing things out of order or making a mistake somewhere. Make sure that all of the variables are setup correctly. For example SaveLoad_Abilities_LastIndex needs to be equal to the total number of abilities that can be saved. The same idea applies to the Item's LastIndex variable as well.

Also, keep in mind that the methods used in that demo map aren't necessarily needed and depending on what you want to save/load your method could differ. For example, AceHart setup his demo map to use the Hero Skill Menu / Skill Point system that Heroes use by default. You don't have to do that, you could save skills for a non-hero unit if you really wanted to.

Regarding how to save the skills in the book. You need to track and save the skills that have been purchased throughout the game. This way when you load these skills you can "rebuild" the spellbook again using the method you described:

"So when he buys a skill, another skill book with the purchased skill is added. As there is a trigger that removes the book, then the skill goes into that book that previously had nothing."

What I would do is keep track of the skills purchased in a Hashtable/Array throughout the game.
Here's an example of that. Note that Player1Skills[] should really be using a Hashtable and not an Array IF your map is multiplayer. If it's singleplayer then this Array is fine. It can easily be adapted into a Hashtable as the two are fairly similar in concept.

Here's the array of possible skills and an integer to keep track of how many there are:
  • Skills[1] = Fire
  • Skills[2] = Ice
  • Skills[3] = Lightning
  • TotalSkills = 3
Then here's the array of player 1's skills purchased and an integer to keep track of how many have been purchased so far for that player. You'd want to convert Player1Skills[] to use a Hashtable instead if your map is multiplayer:
  • Player1Skills[1] = Lightning
  • Player1Skills[2] = Fire
  • PlayerTotalSkills[1] = 2
So by default PlayerTotalSkills[1] = 0 and Player1Skills[] is empty.
Then when Player 1 purchases a Skill you increase PlayerTotalSkills[1] by 1.
Then you Set Player1Skills to the Skill purchased like so:
  • For each Integer A from 1 to TotalSkills do -> If Skills[Integer A] = Skill Purchased then Set Player1Skills[PlayerTotalSkills[1]] = Integer A
Or if you know the Index of the Skill Purchased you can skip the Loop entirely and just plug that in -> Set Player1Skills[PlayerTotalSkills[1]] = 3

When it comes time to save, you Loop over all of the possible skills similar to how it's done with Items. But you only want to Save skills if the player actually has some so check for that first.
  • If PlayerTotalSkills[1] > 0 then do...
  • For each Int B from 1 to PlayerTotalSkills[1] do...
  • For each Int A from 1 to TotalSkills do...
  • If Skills[IntA] = Player1Skills[IntA] then do...
  • SaveCount = SaveCount + 1
  • Set Save[SaveCount] = Int A
  • ///
  • SaveCount = SaveCount + 1
  • Set Save[SaveCount] = PlayerTotalSkills[1]
After that you want to save PlayerTotalSkills[1]. You need that data to determine how many skills to load.

Then when it comes time to load you first load PlayerTotalSkills[1] so you can figure out how many skills the player had. Then you use that value in your For Loop while loading:
  • SaveCount = SaveCount + 1
  • Set PlayerTotalSkills[1] = Save[SaveCount]
  • ///
  • If PlayerTotalSkills[1] > 0 then do...
  • For each Int B from 1 to PlayerTotalSkills[1] do...
  • For each Int A from 1 to TotalSkills do...
  • If Skills[IntA] = Player1Skills[IntA] then do...
  • SaveCount = SaveCount + 1
  • Set Player1Skills[IntB] = Save[SaveCount]
At this point you'll have all of Player 1's skills loaded and can rebuild the spellbook using this information. Again, you'd loop from 1 to PlayerTotalSkills[1] and run the actions for adding/removing the spellbooks for each skill.
 
Last edited:
Status
Not open for further replies.
Top