Save/Load Code

Effane

Save/Load Code Tutorial
Reaction score
51
Effane's Save/Load Code tutorial for Intermediate Trigger Makers.

Table of Contents
I.Part 1
1. Basics of Save/Load Codes
2. How do the Alpha Numbers work
3. Setting up an initialization trigger
Part II.
4. Setting up a Save Code Trigger
Part III.
5. Setting up a Load Code Trigger
Part IV.
6. Advanced stuff
7. Sample Code FAQ

Part I

1. Basics of Save/Load Codes

Any WC3 map that requires players to play for very long time periods will most likely need a save code. Even some short game maps like AOS and TDs use save/load codes for transferring player stats from one game to the next.
Now these Save/Load Codes can be very powerful, and very complicated. I hope by the end of this tutorial you have a solid grasp of at least the basic parts of the Save/Load Codes.

These codes are usually managed by systems of triggers. Most codes use either 2 or 3 triggers. I personally perfer to use 3 triggers to break down complexity and to save on process power. This does come at the cost of memory, but not that much.

The three triggers I use are pretty simple categories: Initialization, Save, and Load.
Initialization Trigger, this sets up all the variables, loads the basic Alphanumbers and does all the ground work so players can have everything they need for the next two triggers.
Save, this is obviously the trigger that collects the information and then converts it to a text file.
Load, this is the trigger that takes the Save Code and converts it back into information that can be used to load all the information you had the save code save.

The whole system is based off a simple idea. Change the size of the counting system to a higher number, convert the data to match that and give it to the player to write down. Then reverse the process once the player gives you the information back the next time. The basic tool for all of this is the AlphaNumber system.

2. How do the Alpha Numbers work

AlphaNumbers. These are the whole core of the system for Save/Load Codes. This is why its so important to know what they are and how they do the work for us.
Most people know about two types of number systems already that are around computers. The Binary and the Decimal system. There are two numbers in Binary 0 and 1, while Decimal of course has 10 numbers (0123456789). You could basically veiw these as AlphaNumbers of system 2 and 10.
Now, obviously 10 digit system is alot more compact than the 2 digit system. The number 32 in Decimal is only 2 spaces used, while in binary its 100000 or six digits used. Well if you created a number system greater than 32 number, it would give you a single digit to hold that number.
For almost all of this tutorial I will be using a simple 36 character Alphanumber system as follows: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. With 36 numbers alone, we can compress alot of larger numbers into much smaller digits, saving alot of space.

How do you read numbers like this? Well the number system will go from 0-35. You have to multiply and divide to move from a lower digit to a higher one. The decimal number 36 is actually 10 is this number system. Since it went over the max char of 35, it adds one place further out to the left. While 1296 is 100. Now when you are counting from 34-37 for example it will go like this.

34 = 0Y
35 = 0Z
36 = 10
37 = 11

Now how to convert from Decimal to AlphaNumbers and back.

You need to be able to move back and forth between these two systems. Now basic algebra and loops will be our friend here.

First you have to get your Decimal number. We will work with 123456. And in our 36 character number system.

Now when converting number systems, if you go from little to big, you divide. From bigger to little, you multiply. Simple rule of thumb. For saving from now on, we will always divide (Why would you use less than 10 digits for saving) and for loading we will multiply, keep this in mind.

Since 123456 is Base 10 and we are using 36 character system here we go with dividing. Now keep in mind integer math in WC3 triggers is limited. And we need variables to work from anyways so we will do it all with just four things, + - x /.

-------- Slot1=36 --------
-------- Slot2=1296 --------
-------- Slot3=46656 --------
-------- Slot4=1679616 --------
-------- Slot5=60466176 --------

Now we have to start from the smallest number we can fit the number in the system. Lets say this is a measurement of Player Gold, which by default maxes at 1000000. So we are using a 4 character number here (36x36x36x36=1.6 million).

First we divide by the max character slot minus 1. So we divide by 36x36x36 or 36^3 = 46656.

123456 / 46656 = 2.26... (Now we are going to use just integers for all of this, so everything after the decimal point will get dropped, no rounding at all). => 2.
So we know our first character is number 2 in the first string slot. Which in our number system is 2 actually.

Now we need to get our remainder. You will see later how we achieve that in code, but for now its just = 30144.

Now we go down one power of 36 to 36^2 or 1296. Once again we divide our remainder by 1296 and get the results. 30144 / 1296 = 23.59... or 23. Which converts to N.

Remainder and again we divide by 36^1. 336 / 36 = 9.33... or just 9. Which is equal to 9.

Final run is 36^0 or 1 (Anything to the power of zero is always just 1). 12 / 1 = 12 or C, you should never have a remainder with conversions like this. If you do, then OOOPs....

Now the new number is 2N9C. Not bad for making it smaller.

Now we need to make it go back to a Decimal number. That of course takes Multiplying like I said before. We will start from the left and move right just like above.

To do this we will take the power of 36 to the slot of the Alphanumber, then multiply it against the characters number position and add it all together when you have all the slots done.

2### => 2 x 36^3 => 2 X 46656 = 93312
#N## => 23 x 36^2 = 23 X 1296 = 29808
##9# => 9 X 36^1 = 9 X 36 = 324
###C => 12 X 36^0 = 12 X 1 = 12
-----------------------------------------
123456

Now that we know how to use the number system, we need to start building it. This will require a trigger system.

3. Setting up an initialization trigger

This is the groundwork of our entire trigger. As mentioned before, some people like to include this in their save and load code, but I think its much more efficient to save it in its own trigger and it raises the ability to manage the triggers size by alot, these codes cant get very huge afterall, such as my 57 save/load code in my ORPG consisting of 21 objects.

Here is the demo Intialization trigger included in the code in its entirety.
I will break it down into pieces after this Code Block.

Code:
SaveLoadInitialize
    Events
        Time - Elapsed game time is 0.10 seconds
    Conditions
    Actions
        -------- Need to load your number system in here, right now its 36 chars. --------
        -------- Slot1=36 --------
        -------- Slot2=1296 --------
        -------- Slot2=1296 --------
        -------- Slot3=46656 --------
        -------- Slot4=1679616 --------
        -------- Slot5=60466176 --------
        -------- I like making 0 the actual 0 for the unencrypted system. makes it easier to track stuff later. --------
        Set SaveLoadCharacterSet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
        Set SaveLoadMaxCharacters = 36
        -------- Need to load your encryption system in here, right now its 5 sets. Load code will get broken if you use a '-' in the Number system --------
        Set SaveLoadEncryptionSet[1] = ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
        Set SaveLoadEncryptionSet[2] = GHIJKLMNOPQRSTUVWXYZ0123456789ABCDEF
        Set SaveLoadEncryptionSet[3] = ABCDEFPQRSTUVWXYZ012345GHIJKLMNO6789
        Set SaveLoadEncryptionSet[4] = ASTUVWXYBCJKLMNOPQRZ01234DFEGHI56789
        Set SaveLoadEncryptionSet[5] = HIJKLABCDEVWXYZ0123FGM4567NOPQRSTU89
        Set SaveLoadMaxEncryptionSets = 5
        -------- Now time to populate the Number system. this loop will put the characters into an array which acts like a counting system from 0 till MaxChars --------
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadCharacterNumbers[((Integer A) - 1)] = (Substring(SaveLoadCharacterSet, (Integer A), (Integer A)))
        -------- Make sure you calculate on paper how many numbers per the amount of slots you get from Characters, this will make it MUCH easier to do slot sizes --------
        -------- Size of Levels to be saved for herolevel --------
        Set SaveLoadSlotsHeroLevel = 2
        -------- Load the Heroes into an array to make numbers out of them. --------
        Set SaveLoadHeroesStored[1] = Paladin
        Set SaveLoadHeroesStored[2] = Archmage
        Set SaveLoadHeroesStored[3] = Mountain King
        Set SaveLoadHeroesStored[4] = Blood Mage
        Set SaveLoadMaxHeroesStored = 4
        Set SaveLoadSlotsHero = 2
        -------- Load the Items into an array to make numbers out of them. --------
        Set SaveLoadItemsStored[1] = Dust of Appearance
        Set SaveLoadItemsStored[2] = Minor Replenishment Potion
        Set SaveLoadItemsStored[3] = Potion of Speed
        Set SaveLoadItemsStored[4] = Ring of the Archmagi
        Set SaveLoadItemsStored[5] = Cloak of Shadows
        Set SaveLoadItemsStored[6] = Gauntlets of Ogre Strength +3
        Set SaveLoadItemsStored[7] = Mantle of Intelligence +3
        Set SaveLoadItemsStored[8] = Slippers of Agility +3
        Set SaveLoadItemsStored[9] = Manual of Health
        Set SaveLoadItemsStored[10] = Healing Salve
        Set SaveLoadMaxItemsStored = 10
        Set SaveLoadSlotsItem = 2
        -------- Need to setup slots for Gold and Lumber, 4 chars will cover up to 1.6 mill with 36 chars --------
        Set SaveLoadSlotsGold = 4
        Set SaveLoadSlotsLumber = 4
        -------- Set the Block Size, basically the amount of characters between dashes. --------
        Set SaveLoadBlockSize = 4
        -------- Set the Variables to be stored size, good time to setup your variable positions. --------
        Set SaveLoadVariablesStored[1] = SaveLoadSlotsHero
        Set SaveLoadVariablesStored[2] = SaveLoadSlotsHeroLevel
        Set SaveLoadVariablesStored[3] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[4] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[5] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[6] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[7] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[8] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[9] = SaveLoadSlotsGold
        Set SaveLoadVariablesStored[10] = SaveLoadSlotsLumber
        -------- This variable stops players from loading again after they load the first time. --------
        For each (Integer A) from 1 to 4, do (Actions)
            Loop - Actions
                Set SaveLoadHasLoaded[(Integer A)] = False

Trigger setup time can actually be on initialization, but I dont personally trust WC3 to load things properly in that spot, and honestly you can load the trigger after a .10 second while your doing something else like broadcasting info, showing a movie, whatever that will keep the player busy while its loading.

Code:
        -------- Need to load your number system in here, right now its 36 chars. --------
        -------- Slot1=36 --------
        -------- Slot2=1296 --------
        -------- Slot2=1296 --------
        -------- Slot3=46656 --------
        -------- Slot4=1679616 --------
        -------- Slot5=60466176 --------
        -------- I like making 0 the actual 0 for the unencrypted system. makes it easier to track stuff later. --------
        Set SaveLoadCharacterSet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
        Set SaveLoadMaxCharacters = 36

This first block of code is basically notes, it helps alot to use a calculator and make your numbers ahead of time so you know how many slots you need.
The SaveLoadCharacterSet variable is a string that holds your number system. Make sure you avoid things like Spaces, and in this systems case, Dashes and Lower Case Chars. Also keep in mind your players need to type these codes in. Not everyone is a typing master.

Code:
        -------- Need to load your encryption system in here, right now its 5 sets. Load code will get broken if you use a '-' in the Number system --------
        Set SaveLoadEncryptionSet[1] = ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
        Set SaveLoadEncryptionSet[2] = GHIJKLMNOPQRSTUVWXYZ0123456789ABCDEF
        Set SaveLoadEncryptionSet[3] = ABCDEFPQRSTUVWXYZ012345GHIJKLMNO6789
        Set SaveLoadEncryptionSet[4] = ASTUVWXYBCJKLMNOPQRZ01234DFEGHI56789
        Set SaveLoadEncryptionSet[5] = HIJKLABCDEVWXYZ0123FGM4567NOPQRSTU89
        Set SaveLoadMaxEncryptionSets = 5

The above code creates an encryption system. While this is crucial for game purposes, right now its nice to know it just exist. I will cover this more later.

Code:
        -------- Now time to populate the Number system. this loop will put the characters into an array which acts like a counting system from 0 till MaxChars --------
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadCharacterNumbers[((Integer A) - 1)] = (Substring(SaveLoadCharacterSet, (Integer A), (Integer A)))

Here is the code that builds your Number system. Since we cant make a computer count from 0-Z we have to instead give it a way to count using something it already knows, the Decimal system. We do this by assigning each letter in our CharacterSet to an index in an Array (SaveLoadCharacterNumbers[]). As you may have noticed, the array goes from 0-35, not 1-36. This is so you can use the 0, without it our number system wouldnt be the same.

Code:
        -------- Make sure you calculate on paper how many numbers per the amount of slots you get from Characters, this will make it MUCH easier to do slot sizes --------
        -------- Size of Levels to be saved for herolevel --------
        Set SaveLoadSlotsHeroLevel = 2
        -------- Load the Heroes into an array to make numbers out of them. --------
        Set SaveLoadHeroesStored[1] = Paladin
        Set SaveLoadHeroesStored[2] = Archmage
        Set SaveLoadHeroesStored[3] = Mountain King
        Set SaveLoadHeroesStored[4] = Blood Mage
        Set SaveLoadMaxHeroesStored = 4
        Set SaveLoadSlotsHero = 2
        -------- Load the Items into an array to make numbers out of them. --------
        Set SaveLoadItemsStored[1] = Dust of Appearance
        Set SaveLoadItemsStored[2] = Minor Replenishment Potion
        Set SaveLoadItemsStored[3] = Potion of Speed
        Set SaveLoadItemsStored[4] = Ring of the Archmagi
        Set SaveLoadItemsStored[5] = Cloak of Shadows
        Set SaveLoadItemsStored[6] = Gauntlets of Ogre Strength +3
        Set SaveLoadItemsStored[7] = Mantle of Intelligence +3
        Set SaveLoadItemsStored[8] = Slippers of Agility +3
        Set SaveLoadItemsStored[9] = Manual of Health
        Set SaveLoadItemsStored[10] = Healing Salve
        Set SaveLoadMaxItemsStored = 10
        Set SaveLoadSlotsItem = 2
        -------- Need to setup slots for Gold and Lumber, 4 chars will cover up to 1.6 mill with 36 chars --------
        Set SaveLoadSlotsGold = 4
        Set SaveLoadSlotsLumber = 4
        -------- Set the Block Size, basically the amount of characters between dashes. --------
        Set SaveLoadBlockSize = 4

This here is the base level setup for the items to be stored. Notice Items and Heroes are in an array ahead of time. This is so they can converted to decimal equivalancies which will make it much easier to handle, and also shrinks the information size down alot.
At the end of each section you will notice a Slots variable. This is an integer that holds how many chars each variable uses. You can change this to modify the size of information that will be stored. Refer to the Slots# comments at the very beginning for idea how much each variable will enable you to hold.

Code:
        -------- Set the Variables to be stored size, good time to setup your variable positions. --------
        Set SaveLoadVariablesStored[1] = SaveLoadSlotsHero
        Set SaveLoadVariablesStored[2] = SaveLoadSlotsHeroLevel
        Set SaveLoadVariablesStored[3] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[4] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[5] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[6] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[7] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[8] = SaveLoadSlotsItem
        Set SaveLoadVariablesStored[9] = SaveLoadSlotsGold
        Set SaveLoadVariablesStored[10] = SaveLoadSlotsLumber

This code was intended for a loop action in the save/load code, but I never implemented it. So its really not used. BUT this code does give you a chance to map out where you plan to have your characters in order at.

Code:
        -------- This variable stops players from loading again after they load the first time. --------
        For each (Integer A) from 1 to 4, do (Actions)
            Loop - Actions
                Set SaveLoadHasLoaded[(Integer A)] = False

This code isnt really necessary, but its very good to have safety code like this. If the player typed in -load twice, they could be in trouble if you didnt have something to track them. This action is just a redundant check to make sure they can load properly.

Part 2
Part 3
Part 4
 
Part II.

4. Setting up a Save Code Trigger

Save codes are somewhat complicated to make. This trigger will be lengthy, and you will likely have to read this a few times to understand how things up top roll down into things later. Its all a large chain reaction in the end. When playing with the code yourself, make use of the Game - Send Message entries I made. They are perfect for troubleshooting and studying how something works in real time.

Now to look at the whole code, then to break it down into pieces.

Code:
SaveModuleSingle
    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
        -------- This PlayerGroup is so you can broadcast the correct player the message in the end. --------
        Player Group - Add (Triggering player) to SaveLoadPlayerGroupFocus
        -------- Decide how many variables the system will store --------
        Set SaveLoadMaxVariablesStored = 10
        -------- Default everything and load the basic stuff. Needs to happen each trigger activation or bad things happen. --------
        Set SaveLoadChecksumChar = <Empty String>
        Set SaveLoadEncryptedString = <Empty String>
        Set SaveLoadEncryptionKey = <Empty String>
        Set SaveLoadCheckSumInt = 0
        Set SaveLoadPreEncryptionString = <Empty String>
        Set SaveLoadFinalString = <Empty String>
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = <Empty String>
        For each (Integer A) from 1 to SaveLoadMaxVariablesStored, do (Actions)
            Loop - Actions
                Set SaveLoadTempStrings[(Integer A)] = <Empty String>
        -------- Setup the encryption for use. --------
        Set SaveLoadEncryptionKeyInt = (Random integer number between 1 and SaveLoadMaxEncryptionSets)
        Set SaveLoadEncryptionKey = SaveLoadCharacterNumbers[SaveLoadEncryptionKeyInt]
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = (Substring(SaveLoadEncryptionSet[SaveLoadEncryptionKeyInt], (Integer A), (Integer A)))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptionKey
        -------- Now to start converting things to save --------
        -------- Final string will be Encryption+Hero+HeroLevel+ItemsX6+Gold+Lumber+Checksum --------
        -------- Hero first --------
        For each (Integer A) from 1 to SaveLoadMaxHeroesStored, do (Actions)
            Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (Unit-type of SaveLoadPlayerHeroSingle[(Player number of (Triggering player))]) Equal to SaveLoadHeroesStored[(Integer A)]
                    Then - Actions
                        Set SaveLoadConversionInteger = (Integer A)
                    Else - Actions
        Set SaveLoadPowerOfCurrent = (SaveLoadSlotsHero - 1)
        For each (Integer A) from 1 to SaveLoadSlotsHero, do (Actions)
            Loop - Actions
                Set SaveLoadPowerOfMaxNumber = 1
                For each (Integer B) from (Integer A) to (SaveLoadSlotsHero - 1), do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHero - (Integer A)) Greater than or equal to 1
                    Then - Actions
                        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                        Set SaveLoadTempStrings[1] = (SaveLoadTempStrings[1] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHero - (Integer A)) Less than 1
                    Then - Actions
                        Set SaveLoadTempStrings[1] = (SaveLoadTempStrings[1] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                    Else - Actions
                Set SaveLoadConversionInteger = SaveLoadConversionRemainder
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[1]
        -------- now to create the string section for the hero level --------
        Set SaveLoadConversionInteger = (Hero level of SaveLoadPlayerHeroSingle[(Player number of (Triggering player))])
        Set SaveLoadPowerOfCurrent = (SaveLoadSlotsHeroLevel - 1)
        For each (Integer A) from 1 to SaveLoadSlotsHeroLevel, do (Actions)
            Loop - Actions
                Set SaveLoadPowerOfMaxNumber = 1
                For each (Integer B) from (Integer A) to (SaveLoadSlotsHeroLevel - 1), do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHeroLevel - (Integer A)) Greater than or equal to 1
                    Then - Actions
                        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                        Set SaveLoadTempStrings[2] = (SaveLoadTempStrings[2] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHeroLevel - (Integer A)) Less than 1
                    Then - Actions
                        Set SaveLoadTempStrings[2] = (SaveLoadTempStrings[2] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                    Else - Actions
                Set SaveLoadConversionInteger = SaveLoadConversionRemainder
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[2]
        -------- Now the Items carried by hero --------
        -------- Item Slot1-6 courtesy the loop C --------
        For each (Integer IntegerC) from 1 to 6, do (Actions)
            Loop - Actions
                Set SaveLoadConversionInteger = 0
                For each (Integer A) from 1 to SaveLoadMaxItemsStored, do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Item-type of (Item carried by SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] in slot IntegerC)) Equal to SaveLoadItemsStored[(Integer A)]
                            Then - Actions
                                Set SaveLoadConversionInteger = (Integer A)
                            Else - Actions
                For each (Integer A) from 1 to SaveLoadSlotsItem, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsItem - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (SaveLoadSlotsItem - (Integer A)) Greater than or equal to 1
                            Then - Actions
                                Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                                Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                                Set SaveLoadTempStrings[(IntegerC + 2)] = (SaveLoadTempStrings[(IntegerC + 2)] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                            Else - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (SaveLoadSlotsItem - (Integer A)) Less than 1
                            Then - Actions
                                Set SaveLoadTempStrings[(IntegerC + 2)] = (SaveLoadTempStrings[(IntegerC + 2)] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                            Else - Actions
                        Set SaveLoadConversionInteger = SaveLoadConversionRemainder
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[(IntegerC + 2)]
        -------- Now to convert the Gold into the strings --------
        Set SaveLoadConversionInteger = ((Triggering player) Current gold)
        For each (Integer A) from 1 to SaveLoadSlotsGold, do (Actions)
            Loop - Actions
                Set SaveLoadPowerOfMaxNumber = 1
                For each (Integer B) from (Integer A) to (SaveLoadSlotsGold - 1), do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsGold - (Integer A)) Greater than or equal to 1
                    Then - Actions
                        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                        Set SaveLoadTempStrings[9] = (SaveLoadTempStrings[9] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsGold - (Integer A)) Less than 1
                    Then - Actions
                        Set SaveLoadTempStrings[9] = (SaveLoadTempStrings[9] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                    Else - Actions
                Set SaveLoadConversionInteger = SaveLoadConversionRemainder
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[9]
        -------- Now to convert the Lumber into the strings --------
        Set SaveLoadConversionInteger = ((Triggering player) Current lumber)
        For each (Integer A) from 1 to SaveLoadSlotsLumber, do (Actions)
            Loop - Actions
                Set SaveLoadPowerOfMaxNumber = 1
                For each (Integer B) from (Integer A) to (SaveLoadSlotsLumber - 1), do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsLumber - (Integer A)) Greater than or equal to 1
                    Then - Actions
                        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                        Set SaveLoadTempStrings[10] = (SaveLoadTempStrings[10] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsLumber - (Integer A)) Less than 1
                    Then - Actions
                        Set SaveLoadTempStrings[10] = (SaveLoadTempStrings[10] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                    Else - Actions
                Set SaveLoadConversionInteger = SaveLoadConversionRemainder
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[10]
        -------- Now to combine the current finished strings. --------
        For each (Integer A) from 1 to SaveLoadMaxVariablesStored, do (Actions)
            Loop - Actions
                Set SaveLoadPreEncryptionString = (SaveLoadPreEncryptionString + SaveLoadTempStrings[(Integer A)])
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString
        -------- Now to create a checksum for security, there are many ways to create this number. We will use the previous variables since its easy. --------
        Set SaveLoadCheckSumInt = 0
        For each (Integer A) from 1 to (Length of SaveLoadPreEncryptionString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadPreEncryptionString, (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                            Then - Actions
                                Set SaveLoadCheckSumInt = (SaveLoadCheckSumInt + (Integer B))
                                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadCheckSumInt))
                            Else - Actions
        Set SaveLoadConversionInteger = SaveLoadCheckSumInt
        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadMaxCharacters)
        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadMaxCharacters))
        Set SaveLoadChecksumChar = SaveLoadCharacterNumbers[SaveLoadConversionRemainder]
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadChecksumChar
        -------- Now we have all the characters ready to combine and encrypt fully, then package it pretty. --------
        -------- This will convert the characters to the encrypted data set. It will also place a '-' every specified number of characters. --------
        Set SaveLoadPreEncryptionString = (SaveLoadPreEncryptionString + SaveLoadChecksumChar)
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString
        For each (Integer A) from 1 to (Length of SaveLoadPreEncryptionString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadPreEncryptionString, (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                            Then - Actions
                                Set SaveLoadEncryptedString = (SaveLoadEncryptedString + SaveLoadEncryptionNumbers[(Integer B)])
                            Else - Actions
                Set SaveLoadConversionInteger = (Integer A)
                Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadBlockSize)
                Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadBlockSize))
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        SaveLoadConversionRemainder Less than or equal to 0
                    Then - Actions
                        Set SaveLoadEncryptedString = (SaveLoadEncryptedString + -)
                    Else - Actions
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptedString
        -------- Now for the final string, which will be the unencrypted key, and the rest of the encrypted information --------
        Set SaveLoadFinalString = ((SaveLoadEncryptionKey + -) + SaveLoadEncryptedString)
        -------- And now to broadcast all the hard work --------
        Game - Display to SaveLoadPlayerGroupFocus for 300.00 seconds the text: SaveLoadFinalString
        Player Group - Remove all players from SaveLoadPlayerGroupFocus

Now on to slay this beast of a trigger... :eek:

Code:
    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

This is the event. Its pretty simple, EVENTS are unlike conditions, only one has to be true for it to activate the trigger. Basically when the player types exactly "-save" or any form of capitalization of it, the trigger will activate. Remember, WC3 doesnt recognize case for most comparisons, but its unreliable which ones.

Code:
        -------- This PlayerGroup is so you can broadcast the correct player the message in the end. --------
        Player Group - Add (Triggering player) to SaveLoadPlayerGroupFocus
        -------- Decide how many variables the system will store --------
        Set SaveLoadMaxVariablesStored = 10
        -------- Default everything and load the basic stuff. Needs to happen each trigger activation or bad things happen. --------
        Set SaveLoadChecksumChar = <Empty String>
        Set SaveLoadEncryptedString = <Empty String>
        Set SaveLoadEncryptionKey = <Empty String>
        Set SaveLoadCheckSumInt = 0
        Set SaveLoadPreEncryptionString = <Empty String>
        Set SaveLoadFinalString = <Empty String>
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = <Empty String>
        For each (Integer A) from 1 to SaveLoadMaxVariablesStored, do (Actions)
            Loop - Actions
                Set SaveLoadTempStrings[(Integer A)] = <Empty String>
        -------- Setup the encryption for use. --------
        Set SaveLoadEncryptionKeyInt = (Random integer number between 1 and SaveLoadMaxEncryptionSets)
        Set SaveLoadEncryptionKey = SaveLoadCharacterNumbers[SaveLoadEncryptionKeyInt]
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = (Substring(SaveLoadEncryptionSet[SaveLoadEncryptionKeyInt], (Integer A), (Integer A)))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptionKey

This entire section is all about loading stuff. Its good to get all of that loading out of the way early on. It will make it easier to track things to change, and when mistakes happen. notice alot of Zero or Null sets. Thats to clear out information from prior Save/Load codes. Without doing this, you will have the same information keep bleeding over and over till nothing works.
Also you have the playergroup at the beginning. its used to track the Player that triggered the event easier for broadcasting the created info, once done with the trigger the group will get cleared.
The part after the comment, Setup the Encryption for use. It actually randomizes the encryption string used to convert the final string of code over to something that will be cryptic enough to stop players from making their own codes easily.

Code:
        -------- Hero first --------
        For each (Integer A) from 1 to SaveLoadMaxHeroesStored, do (Actions)
            Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (Unit-type of SaveLoadPlayerHeroSingle[(Player number of (Triggering player))]) Equal to SaveLoadHeroesStored[(Integer A)]
                    Then - Actions
                        Set SaveLoadConversionInteger = (Integer A)
                    Else - Actions
        Set SaveLoadPowerOfCurrent = (SaveLoadSlotsHero - 1)
        For each (Integer A) from 1 to SaveLoadSlotsHero, do (Actions)
            Loop - Actions
                Set SaveLoadPowerOfMaxNumber = 1
                For each (Integer B) from (Integer A) to (SaveLoadSlotsHero - 1), do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHero - (Integer A)) Greater than or equal to 1
                    Then - Actions
                        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                        Set SaveLoadTempStrings[1] = (SaveLoadTempStrings[1] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHero - (Integer A)) Less than 1
                    Then - Actions
                        Set SaveLoadTempStrings[1] = (SaveLoadTempStrings[1] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                    Else - Actions
                Set SaveLoadConversionInteger = SaveLoadConversionRemainder
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[1]

This is the hero save section. Basically all the sections work the same way. They always have the same flow. Get data into Decimal format. Break the Decimal down to a String of Characters using the new number system. Add the new number to the TempStrings array to hold for later use. While thatss over simplying, lets break this code down to the basic components: The Type Matching, Decimal to AlphaNumbers Conversion, and Saving to a String.

Finding the Type Match of the Hero.

Code:
        For each (Integer A) from 1 to SaveLoadMaxHeroesStored, do (Actions)
            Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (Unit-type of SaveLoadPlayerHeroSingle[(Player number of (Triggering player))]) Equal to SaveLoadHeroesStored[(Integer A)]
                    Then - Actions
                        Set SaveLoadConversionInteger = (Integer A)
                    Else - Actions

In this code its pretty simple. We use a Loop A to search through the array we created in the Initialization trigger till we find the match for our hero. You will notice that if you have a Null in the Array, it will check that too, but its okay if it does that.

Now once it finds the match, it then converts the matching unit type, to an integer by just saving the Integer A. Fairly simple isnt it?

Code:
        For each (Integer A) from 1 to SaveLoadSlotsHero, do (Actions)
            Loop - Actions
                Set SaveLoadPowerOfMaxNumber = 1
                For each (Integer B) from (Integer A) to (SaveLoadSlotsHero - 1), do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHero - (Integer A)) Greater than or equal to 1
                    Then - Actions
                        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadPowerOfMaxNumber)
                        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadPowerOfMaxNumber))
                        Set SaveLoadTempStrings[1] = (SaveLoadTempStrings[1] + SaveLoadCharacterNumbers[SaveLoadConversionDividedInt])
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        (SaveLoadSlotsHero - (Integer A)) Less than 1
                    Then - Actions
                        Set SaveLoadTempStrings[1] = (SaveLoadTempStrings[1] + SaveLoadCharacterNumbers[SaveLoadConversionRemainder])
                    Else - Actions
                Set SaveLoadConversionInteger = SaveLoadConversionRemainder

Now this is a bit more complicated, but not too bad if you take it a bit at a time.
First thing it does is setup the number of times it will go through the system. This is where your slot variables come into play. In this case it will go through the Loop A twice, ##.
Now first thing it does is perform a X to the Power of Y (first loop B).
This is due to the fact that WC3 doesnt do powers for integers, you have to convert to Reals then back to Integers, its much cleaner just to use a Loop to do it.
After it makes it through the first Loop B, it then goes on to the second. What this does is it does the first layer of division and then sets the Alphanumber and the remainder.
Notice there are two IFs, this is because when you hit 0 for your power, you dont need to divide anymore, so just set the last digit to Remainder.

Basic flow of this for the hero type. Slots = 2

Loop A (Integer A = 1)
Loop B (First)
Power to 36^1.
Loop B (Second)
Convert

Loop A (Integer A = 2)
Loop B (First)
Power to 36^0
Loop B (Second)
Convert

And with that it will be done. All the conversions are the same in that base component. Now I will skip all the rest of the conversions, they are mostly the same thing, with some modifications depending what I was converting.

Code:
        -------- Now to combine the current finished strings. --------
        For each (Integer A) from 1 to SaveLoadMaxVariablesStored, do (Actions)
            Loop - Actions
                Set SaveLoadPreEncryptionString = (SaveLoadPreEncryptionString + SaveLoadTempStrings[(Integer A)])

This is simple stuff. All it does is use a loop to combine all the now created strings.

Code:
        -------- Now to create a checksum for security, there are many ways to create this number. We will use the previous variables since its easy. --------
        Set SaveLoadCheckSumInt = 0
        For each (Integer A) from 1 to (Length of SaveLoadPreEncryptionString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadPreEncryptionString, (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                            Then - Actions
                                Set SaveLoadCheckSumInt = (SaveLoadCheckSumInt + (Integer B))
                                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadCheckSumInt))
                            Else - Actions
        Set SaveLoadConversionInteger = SaveLoadCheckSumInt
        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadMaxCharacters)
        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadMaxCharacters))
        Set SaveLoadChecksumChar = SaveLoadCharacterNumbers[SaveLoadConversionRemainder]
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadChecksumChar

Now remember when I said we would start talking about encryption and security later. Its that time.
This code set uses a simple Checksum for verifying a player didnt make up the code. What we do here is simple. Take the entire completed string, make each digit a Decimal really quick, add it all together, then divide by MaxCharacters, the remainder is the checksum. This makes its a 1:36 chance for players to guess the right checksum if they want to try to foil the system. Thats enough to stop most people.

Code:
        -------- Now we have all the characters ready to combine and encrypt fully, then package it pretty. --------
        -------- This will convert the characters to the encrypted data set. It will also place a '-' every specified number of characters. --------
        Set SaveLoadPreEncryptionString = (SaveLoadPreEncryptionString + SaveLoadChecksumChar)
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString
        For each (Integer A) from 1 to (Length of SaveLoadPreEncryptionString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadPreEncryptionString, (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                            Then - Actions
                                Set SaveLoadEncryptedString = (SaveLoadEncryptedString + SaveLoadEncryptionNumbers[(Integer B)])
                            Else - Actions
                Set SaveLoadConversionInteger = (Integer A)
                Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadBlockSize)
                Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadBlockSize))
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        SaveLoadConversionRemainder Less than or equal to 0
                    Then - Actions
                        Set SaveLoadEncryptedString = (SaveLoadEncryptedString + -)
                    Else - Actions

Now for the encryption. This takes that already loaded random encryption string and then converts the preencrypted string one char at a time till it runs out of chars. Now you will notice that there is a small section that does division, remainders and an IF statement with a condition for a '-'. Thats just for looks for the players. But its also not terribly complicated. It just takes the Dashes integer (SaveLoadBlockSize) setup in the Initialization trigger and puts dashes in the right places for us.

Code:
        -------- Now for the final string, which will be the unencrypted key, and the rest of the encrypted information --------
        Set SaveLoadFinalString = ((SaveLoadEncryptionKey + -) + SaveLoadEncryptedString)
        -------- And now to broadcast all the hard work --------
        Game - Display to SaveLoadPlayerGroupFocus for 300.00 seconds the text: SaveLoadFinalString
        Player Group - Remove all players from SaveLoadPlayerGroupFocus

This is always the best part of a long trigger. The wrap up that shows all of the great work you did. notice the playergroup gets cleared as the clast thing, this sets it up for the next time the trigger is used.
 
Part III.

5. Setting up a Load Code Trigger

Now we know how to put stuff into the code. But its of little use in there. We need to reverse the process and then create all the things like Hero, Levels, Gold, Items and Lumber!

Here is the code... :D

Code:
LoadModuleSingle
    Events
        Player - Player 1 (Red) types a chat message containing -load as A substring
        Player - Player 2 (Blue) types a chat message containing -load as A substring
        Player - Player 3 (Teal) types a chat message containing -load as A substring
        Player - Player 4 (Purple) types a chat message containing -load as A substring
    Conditions
        (Substring((Entered chat string), 1, 5)) Equal to -load
    Actions
        -------- This PlayerGroup is so you can broadcast the correct player the message in the end. --------
        Player Group - Add (Triggering player) to SaveLoadPlayerGroupFocus
        -------- This will confirm if the player has loaded before since last reset. --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                SaveLoadHasLoaded[(Player number of (Triggering player))] Equal to True
            Then - Actions
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: You have loaded you...
            Else - Actions
        -------- Decide how many variables the system will store --------
        Set SaveLoadMaxVariablesStored = 10
        -------- Default everything and load the basic stuff. Needs to happen each trigger activation or bad things happen. --------
        Set SaveLoadTriggerErrored = False
        Set SaveLoadChecksumChar = <Empty String>
        Set SaveLoadEncryptedString = <Empty String>
        Set SaveLoadEncryptionKey = <Empty String>
        Set SaveLoadPreEncryptionString = <Empty String>
        Set SaveLoadFinalString = <Empty String>
        Set SaveLoadEncryptionKeyInt = 0
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = <Empty String>
        For each (Integer A) from 1 to SaveLoadMaxVariablesStored, do (Actions)
            Loop - Actions
                Set SaveLoadTempStrings[(Integer A)] = <Empty String>
        -------- Now we need to pick up our load code from the message --------
        Set SaveLoadFinalString = (String((Substring((Entered chat string), 7, (Length of (Entered chat string))))) as Upper case)
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadFinalString
        -------- Now we need to break the string into 2 parts, Encryption set number and encrypted string --------
        Set SaveLoadEncryptionKey = (Substring(SaveLoadFinalString, 1, 1))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptionKey
        Set SaveLoadEncryptedString = (Substring(SaveLoadFinalString, 2, (Length of SaveLoadFinalString)))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptedString
        -------- Setup the encryption for use. --------
        For each (Integer A) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
            Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        SaveLoadEncryptionKey Equal to SaveLoadCharacterNumbers[(Integer A)]
                    Then - Actions
                        Set SaveLoadEncryptionKeyInt = (Integer A)
                        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadEncryptionKeyInt))
                    Else - Actions
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = (Substring(SaveLoadEncryptionSet[SaveLoadEncryptionKeyInt], (Integer A), (Integer A)))
        -------- Now to Decrypt the Encrypted Section and remove the Dashes --------
        Set SaveLoadPreEncryptionString = <Empty String>
        For each (Integer A) from 1 to (Length of SaveLoadEncryptedString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadEncryptedString, (Integer A), (Integer A))) Equal to SaveLoadEncryptionNumbers[(Integer B)]
                            Then - Actions
                                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadCharacterNumbers[(Integer B)]
                                Set SaveLoadPreEncryptionString = (SaveLoadPreEncryptionString + SaveLoadCharacterNumbers[(Integer B)])
                            Else - Actions
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString
        -------- Now to seperate the strings out before reading --------
        -------- Workaround for a bug involving String length being used twice in an action. --------
        Set IntegerC = (Length of SaveLoadPreEncryptionString)
        Set SaveLoadChecksumChar = (String((Substring(SaveLoadPreEncryptionString, IntegerC, IntegerC))) as Upper case)
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (SaveLoadChecksumChar +  = From Load)
        Set SaveLoadPreEncryptionString = (Substring(SaveLoadPreEncryptionString, 1, ((Length of SaveLoadPreEncryptionString) - 1)))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString
        -------- Verify the Checksum to prove the code is correct. 1:MaxChars chance of being an error that would allow code to process. --------
        Set SaveLoadCheckSumInt = 0
        For each (Integer A) from 1 to (Length of SaveLoadPreEncryptionString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadPreEncryptionString, (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                            Then - Actions
                                Set SaveLoadCheckSumInt = (SaveLoadCheckSumInt + (Integer B))
                                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadCheckSumInt))
                            Else - Actions
        Set SaveLoadConversionInteger = SaveLoadCheckSumInt
        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadMaxCharacters)
        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadMaxCharacters))
        Set SaveLoadChecksumCharCompare = SaveLoadCharacterNumbers[SaveLoadConversionRemainder]
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (SaveLoadChecksumCharCompare +  = Compare)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                SaveLoadChecksumChar Not equal to SaveLoadChecksumCharCompare
            Then - Actions
                Game - Display to SaveLoadPlayerGroupFocus the text: Either your code is...
                Set SaveLoadTriggerErrored = True
            Else - Actions
        -------- This IF is to make sure once they fail the checksum they cannot continue through the trigger. --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                SaveLoadHasLoaded[(Player number of (Triggering player))] Equal to False
                SaveLoadTriggerErrored Equal to False
            Then - Actions
                -------- Need to break each part of the String apart to each variable stored. --------
                Set IntegerC = 1
                -------- First the hero type --------
                Set SaveLoadTempStrings[1] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsHero - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[1]
                Set IntegerC = (IntegerC + SaveLoadSlotsHero)
                -------- Now the Hero level --------
                Set SaveLoadTempStrings[2] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsHeroLevel - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[2]
                Set IntegerC = (IntegerC + SaveLoadSlotsHeroLevel)
                -------- now the Items X6 --------
                For each (Integer A) from 1 to 6, do (Actions)
                    Loop - Actions
                        Set SaveLoadTempStrings[((Integer A) + 2)] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsItem - 1))))
                        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[((Integer A) + 2)]
                        Set IntegerC = (IntegerC + SaveLoadSlotsItem)
                -------- Now the Player Gold --------
                Set SaveLoadTempStrings[9] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsGold - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[9]
                Set IntegerC = (IntegerC + SaveLoadSlotsGold)
                -------- Finally the lumber --------
                Set SaveLoadTempStrings[10] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsLumber - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[10]
                Set IntegerC = (IntegerC + SaveLoadSlotsLumber)
                -------- Start performing actions and building the players stuff --------
                -------- The ReBirth of a Hero! --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsHero, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsHero - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[1], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Unit - Create 1 SaveLoadHeroesStored[SaveLoadMultiple] for (Triggering player) at (Center of Regions[1]) facing 270.00 degrees
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                Set SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] = (Last created unit)
                -------- Give that man a raise! --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsHeroLevel, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsHeroLevel - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[2], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Hero - Set SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] Hero-level to SaveLoadMultiple, Hide level-up graphics
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- Time to Accessorize! --------
                For each (Integer IntegerC) from 1 to 6, do (Actions)
                    Loop - Actions
                        Set SaveLoadMultiple = 0
                        For each (Integer A) from 1 to SaveLoadSlotsItem, do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = 1
                                For each (Integer B) from (Integer A) to (SaveLoadSlotsItem - 1), do (Actions)
                                    Loop - Actions
                                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                                    Loop - Actions
                                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                            If - Conditions
                                                (Substring(SaveLoadTempStrings[(IntegerC + 2)], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                            Then - Actions
                                                Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                            Else - Actions
                        Hero - Create SaveLoadItemsStored[SaveLoadMultiple] and give it to SaveLoadPlayerHeroSingle[(Player number of (Triggering player))]
                        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- Show me the money! --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsGold, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsGold - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[9], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Player - Set (Triggering player) Current gold to SaveLoadMultiple
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- How much wood could a woodchuck chuck, if a woodchuck could chuck wood? --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsLumber, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsLumber - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[10], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Player - Set (Triggering player) Current lumber to SaveLoadMultiple
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- All done, now to tell the player how good we did! --------
                Set SaveLoadHasLoaded[(Integer A)] = False
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: Load Successful. We...
            Else - Actions
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: Load Unsuccessful! ...
        Player Group - Remove all players from SaveLoadPlayerGroupFocus

Load codes are mostly more loops and lots of IF statements. Thats nothing too hard for us is it?

Code:
    Events
        Player - Player 1 (Red) types a chat message containing -load as A substring
        Player - Player 2 (Blue) types a chat message containing -load as A substring
        Player - Player 3 (Teal) types a chat message containing -load as A substring
        Player - Player 4 (Purple) types a chat message containing -load as A substring
    Conditions
        (Substring((Entered chat string), 1, 5)) Equal to -load

Event is basically a substring event. They type in something with "-load" in it and it triggers.
Condition is important when looking for substrings though. Last thing we want is a player typing a message to another player telling them that they need to type -load <code> and the game trying to load that. So we check to see if "-load" is in the beginning of the Entered Message.

Code:
    Actions
        -------- This PlayerGroup is so you can broadcast the correct player the message in the end. --------
        Player Group - Add (Triggering player) to SaveLoadPlayerGroupFocus
        -------- This will confirm if the player has loaded before since last reset. --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                SaveLoadHasLoaded[(Player number of (Triggering player))] Equal to True
            Then - Actions
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: You have loaded you...
            Else - Actions
        -------- Decide how many variables the system will store --------
        Set SaveLoadMaxVariablesStored = 10
        -------- Default everything and load the basic stuff. Needs to happen each trigger activation or bad things happen. --------
        Set SaveLoadTriggerErrored = False
        Set SaveLoadChecksumChar = <Empty String>
        Set SaveLoadEncryptedString = <Empty String>
        Set SaveLoadEncryptionKey = <Empty String>
        Set SaveLoadPreEncryptionString = <Empty String>
        Set SaveLoadFinalString = <Empty String>
        Set SaveLoadEncryptionKeyInt = 0
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = <Empty String>
        For each (Integer A) from 1 to SaveLoadMaxVariablesStored, do (Actions)
            Loop - Actions
                Set SaveLoadTempStrings[(Integer A)] = <Empty String>
        -------- Now we need to pick up our load code from the message --------
        Set SaveLoadFinalString = (String((Substring((Entered chat string), 7, (Length of (Entered chat string))))) as Upper case)
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadFinalString

More loading and clearing of variables. But also note that it grabs the EnteredMessage and drops it into the SaveLoadFinalString for us to use, if you will also notice, the Upper Case part of the String gathering. Its important due to the weirdness of WC3 and case sensitivity and for players that dont type the code all in Upper Case. You can modify this if you want to use a system that combines Upper and Lower Case.

Code:
        -------- Now we need to break the string into 2 parts, Encryption set number and encrypted string --------
        Set SaveLoadEncryptionKey = (Substring(SaveLoadFinalString, 1, 1))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptionKey
        Set SaveLoadEncryptedString = (Substring(SaveLoadFinalString, 2, (Length of SaveLoadFinalString)))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadEncryptedString
        -------- Setup the encryption for use. --------
        For each (Integer A) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
            Loop - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        SaveLoadEncryptionKey Equal to SaveLoadCharacterNumbers[(Integer A)]
                    Then - Actions
                        Set SaveLoadEncryptionKeyInt = (Integer A)
                        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadEncryptionKeyInt))
                    Else - Actions
        For each (Integer A) from 1 to SaveLoadMaxCharacters, do (Actions)
            Loop - Actions
                Set SaveLoadEncryptionNumbers[((Integer A) - 1)] = (Substring(SaveLoadEncryptionSet[SaveLoadEncryptionKeyInt], (Integer A), (Integer A)))

This basically takes our newly acquired string and breaks it into two parts, then it loads the encryption system for us in the right EncryptionSet from earlier, wrong one, and it will not decrypt right.

Code:
        -------- Now to Decrypt the Encrypted Section and remove the Dashes --------
        Set SaveLoadPreEncryptionString = <Empty String>
        For each (Integer A) from 1 to (Length of SaveLoadEncryptedString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadEncryptedString, (Integer A), (Integer A))) Equal to SaveLoadEncryptionNumbers[(Integer B)]
                            Then - Actions
                                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadCharacterNumbers[(Integer B)]
                                Set SaveLoadPreEncryptionString = (SaveLoadPreEncryptionString + SaveLoadCharacterNumbers[(Integer B)])
                            Else - Actions
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString

This then converts the encrypted string left over, to an unencrypted string for us one character at a time.

Code:
        -------- Now to seperate the strings out before reading --------
        -------- Workaround for a bug involving String length being used twice in an action. --------
        Set IntegerC = (Length of SaveLoadPreEncryptionString)
        Set SaveLoadChecksumChar = (String((Substring(SaveLoadPreEncryptionString, IntegerC, IntegerC))) as Upper case)
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (SaveLoadChecksumChar +  = From Load)
        Set SaveLoadPreEncryptionString = (Substring(SaveLoadPreEncryptionString, 1, ((Length of SaveLoadPreEncryptionString) - 1)))
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadPreEncryptionString

This short section covers the breaking apart of the string into two nice little strings, one for Checksum char and one for the string we need to break apart later.

Code:
        -------- Verify the Checksum to prove the code is correct. 1:MaxChars chance of being an error that would allow code to process. --------
        Set SaveLoadCheckSumInt = 0
        For each (Integer A) from 1 to (Length of SaveLoadPreEncryptionString), do (Actions)
            Loop - Actions
                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                (Substring(SaveLoadPreEncryptionString, (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                            Then - Actions
                                Set SaveLoadCheckSumInt = (SaveLoadCheckSumInt + (Integer B))
                                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadCheckSumInt))
                            Else - Actions
        Set SaveLoadConversionInteger = SaveLoadCheckSumInt
        Set SaveLoadConversionDividedInt = (SaveLoadConversionInteger / SaveLoadMaxCharacters)
        Set SaveLoadConversionRemainder = (SaveLoadConversionInteger - (SaveLoadConversionDividedInt x SaveLoadMaxCharacters))
        Set SaveLoadChecksumCharCompare = SaveLoadCharacterNumbers[SaveLoadConversionRemainder]
        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (SaveLoadChecksumCharCompare +  = Compare)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                SaveLoadChecksumChar Not equal to SaveLoadChecksumCharCompare
            Then - Actions
                Game - Display to SaveLoadPlayerGroupFocus the text: Either your code is...
                Set SaveLoadTriggerErrored = True
            Else - Actions
        -------- This IF is to make sure once they fail the checksum they cannot continue through the trigger. --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                SaveLoadHasLoaded[(Player number of (Triggering player))] Equal to False
                SaveLoadTriggerErrored Equal to False
            Then - Actions

This section checks the Checksum given inside the code against a code generated on the fly. If it doesnt match, the last thing it does is change the TriggerErrored variable to be used later to lock out the load process.

Code:
                -------- Need to break each part of the String apart to each variable stored. --------
                Set IntegerC = 1
                -------- First the hero type --------
                Set SaveLoadTempStrings[1] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsHero - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[1]
                Set IntegerC = (IntegerC + SaveLoadSlotsHero)
                -------- Now the Hero level --------
                Set SaveLoadTempStrings[2] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsHeroLevel - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[2]
                Set IntegerC = (IntegerC + SaveLoadSlotsHeroLevel)
                -------- now the Items X6 --------
                For each (Integer A) from 1 to 6, do (Actions)
                    Loop - Actions
                        Set SaveLoadTempStrings[((Integer A) + 2)] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsItem - 1))))
                        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[((Integer A) + 2)]
                        Set IntegerC = (IntegerC + SaveLoadSlotsItem)
                -------- Now the Player Gold --------
                Set SaveLoadTempStrings[9] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsGold - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[9]
                Set IntegerC = (IntegerC + SaveLoadSlotsGold)
                -------- Finally the lumber --------
                Set SaveLoadTempStrings[10] = (Substring(SaveLoadPreEncryptionString, IntegerC, (IntegerC + (SaveLoadSlotsLumber - 1))))
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: SaveLoadTempStrings[10]
                Set IntegerC = (IntegerC + SaveLoadSlotsLumber)

This code breaks the larger string into smaller strings then puts them into the TempStrings for use. IntegerC is used to make sure the substrings are the right size, otherwise it would be harder to change the size of something on the fly.

Code:
                -------- Start performing actions and building the players stuff --------
                -------- The ReBirth of a Hero! --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsHero, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsHero - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[1], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Unit - Create 1 SaveLoadHeroesStored[SaveLoadMultiple] for (Triggering player) at (Center of Regions[1]) facing 270.00 degrees
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                Set SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] = (Last created unit)
                -------- Give that man a raise! --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsHeroLevel, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsHeroLevel - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[2], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Hero - Set SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] Hero-level to SaveLoadMultiple, Hide level-up graphics
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- Time to Accessorize! --------
                For each (Integer IntegerC) from 1 to 6, do (Actions)
                    Loop - Actions
                        Set SaveLoadMultiple = 0
                        For each (Integer A) from 1 to SaveLoadSlotsItem, do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = 1
                                For each (Integer B) from (Integer A) to (SaveLoadSlotsItem - 1), do (Actions)
                                    Loop - Actions
                                        Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                                For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                                    Loop - Actions
                                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                            If - Conditions
                                                (Substring(SaveLoadTempStrings[(IntegerC + 2)], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                            Then - Actions
                                                Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                            Else - Actions
                        Hero - Create SaveLoadItemsStored[SaveLoadMultiple] and give it to SaveLoadPlayerHeroSingle[(Player number of (Triggering player))]
                        Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- Show me the money! --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsGold, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsGold - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[9], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Player - Set (Triggering player) Current gold to SaveLoadMultiple
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- How much wood could a woodchuck chuck, if a woodchuck could chuck wood? --------
                Set SaveLoadMultiple = 0
                For each (Integer A) from 1 to SaveLoadSlotsLumber, do (Actions)
                    Loop - Actions
                        Set SaveLoadPowerOfMaxNumber = 1
                        For each (Integer B) from (Integer A) to (SaveLoadSlotsLumber - 1), do (Actions)
                            Loop - Actions
                                Set SaveLoadPowerOfMaxNumber = (SaveLoadPowerOfMaxNumber x SaveLoadMaxCharacters)
                        For each (Integer B) from 0 to (SaveLoadMaxCharacters - 1), do (Actions)
                            Loop - Actions
                                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    If - Conditions
                                        (Substring(SaveLoadTempStrings[10], (Integer A), (Integer A))) Equal to SaveLoadCharacterNumbers[(Integer B)]
                                    Then - Actions
                                        Set SaveLoadMultiple = (SaveLoadMultiple + ((Integer B) x SaveLoadPowerOfMaxNumber))
                                    Else - Actions
                Player - Set (Triggering player) Current lumber to SaveLoadMultiple
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: (String(SaveLoadMultiple))
                -------- All done, now to tell the player how good we did! --------
                Set SaveLoadHasLoaded[(Integer A)] = False
                Game - Display to SaveLoadPlayerGroupFocus for 30.00 seconds the text: Load Successful. We...

This is the final part of the code. It converts every TempStrings[] to a decimal then creates the type of item as needed. Then at the end sends out a message that its done with loading. Always good to inform the player when something worked. Also notice the SaveLoadHasLoaded is set to True for this player. That will keep them from loading twice.

Thats all there is to loading from the code.
 
Read The Faq!

Part IV.

6. Advanced stuff

This section is dedicated to all the cool extras you could do if you wanted to modify this code. Of course you could just make it save more things, but thats not what this is about.

A. You can make the code save the charges on an Item. All you do is convert the items charges remaining into an integer, convert and add after the item is saved. It could possibly use alot of slots though if you want to save something that stacks to well over the size of the MaxChars.

B. You can enlarge the character set to:
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()_+=,.<>?/:";'{}[]|\~`
Thats alot of characters to use, and you could reduce the save code to 93 chars. That would reduce the code size by up to 50%, BUT thats only if you are storing very large numbers. For small things, it will not work unless you use compression/combination techniques not discussed here.

C. You could add some method to make sure the code is only usable by players. A couple methods to do this.
Simple but bruteforce way, convert the playername into the code. But that means you will likely have the same number, if not more characters than the playername. Not an ideal solution having 15-30 characters to save a playername.
More elegant way. Make the playername part of the checksum. You could take all the numbers made from the code, and then the total of what the player has, then checksum that. It would produce a single character for you to work with, and would be much harder to defeat this system.

D. Saving multiple heroes. Just treat the heroes like the items were done. Each hero is expected in a place and the code just remember what that place is. This only would work well for Final Fantasy Epic ORPG type games where only one hero has items, and all heroes are known from the beginning.

E. Combination of variables to save code space.
Large character sets are terrible for efficiency on small numbers. When saving multiple numbers smaller than 10 its often easy to just combine the numbers like this. 1,9,6,2,3,4 would be 1X100000+9X10000+6X1000+2X100+3X10+4 = 196234. Then something that would have taken 6 slots to track, now takes 4. Saving a few chars could be nice for some players who dont like to type alot.

7. Sample Code FAQ
(Yes. I want you to read the FAQ!)


Q. How large of numbers can this thing handle? By Default? With simple Modifications?

A. 1295 Heroes, Levels, and Items. 1.6 mill gold and lumber. You can go as large as the integer system will allow though for the items. But I doubt you would go beyond 46655 for items, heroes, levels, and other small things, thats just 3 slots for each item. While gold and lumber I could see going till 5 or 6 slots in some maps. Thats easy for the code to handle by just changing Slots variables in the Initialization trigger.

Q. What are all of the variables named and what type are they?
A. Variable list as follows.
Arrays:
-String types: SaveLoadCharacterNumbers[100], SaveLoadEncryptionNumbers[100], SaveLoadEncryptionSet[10], SaveLoadTempStrings[100]
-Integer Type: SaveLoadVariablesStored[24]
-Unit Types: SaveLoadHeroesStored[100], SaveLoadHeroSingle[4]
-Region Type: Regions[9]
-Boolean Type: SaveLoadHasLoaded[4]

Single:
-String type: SaveLoadCharacterSet, SaveLoadChecksumChar, SaveLoadChecksumCharCompare, SaveLoadEncryptedString, SaveLoadEncryptionKey, SaveLoadFinalString, SaveLoadPreEncryptionString
-Integer type: SaveLoadBlockSize, SaveLoadCheckSumInt, SaveLoadConversionDividedInt, SaveLoadConversionInteger, SaveLoadConversionRemainder, SaveLoadEncryptionKeyInt, SaveLoadMaxCharacters, SaveLoadMaxEncryptionSets, SaveLoadMaxHeroesStored, SaveLoadMaxItemsStored, SaveLoadMultiple, SaveLoadPowerOfCurrent, SaveLoadPowerOfMaxNumber, SaveLoadSlotsGold, SaveLoadSlotsHero, SaveLoadSlotsHeroLevel, SaveLoadSlotsItem, SaveLoadSlotsLumber
-Boolean type: SaveLoadTriggerErrored
-PlayerGroup: SaveLoadPlayerGroupFocus

Q. Why wont the Save/Load Code when cut and pasted into my map save heroes and items? It just gives me 3-AAAA-AAAA-AAAA-AAAA-7HU9-AA9J-H or so...
A. You need to put the hero into the hero tracking array variable. This little variable makes like MUCH easier and is a much have. Read the following.
Code:
Set SaveLoadHasLoaded[(Player number of (Triggering player))] = True
        Unit - Create 1 SaveLoadHeroesStored[(Random integer number between 1 and SaveLoadMaxHeroesStored)] for (Triggering player) at (Center of Regions[(Random integer number between 1 and 9)]) facing Default building facing degrees
        Set SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] = (Last created unit)

Whats happening here is first it sets the SaveLoadHasLoaded, this is to stop people from loading over and over, that would be bad. Then you are creating a hero. That we all should have mastered by now, if your map starts with a hero on it, then instead assign all player heroes to a tempUnitGroup and then use pick all in group and perform multiple actions.
Now, each hero needs to be put into another variable to track them. This is a powerful and fast way to get them without any craziness later.

Notice the following.
Code:
        Set SaveLoadPlayerHeroSingle[(Player number of (Triggering player))] = (Last created unit)

This basically grabs the last created unit, the hero. And then finds out what hero it is and assigns that hero to a unit array with the index (spot its stored in) as the player number.
Then to retrieve that hero all you do is access the Array with the player number and viola, you got your hero without using pick/unitgroups and all the leaks/processor cycles.


***Attached is the SaveLoadCode.W3X map. You can copy anything you see in the map, but make sure to always give credit please.***
 

Attachments

  • SaveLoadCode.w3x
    39.8 KB · Views: 3,460
Hey on first post when it has like
----A=192---
----A=325---
or whatev, the second one is repeated twice
 
Thanks, I fixed that typo.

Hope this helps alot of people. Took me about 15 hours to get this all done. Its not perfect polished, but its definetly 95% rocksolid.

Any other mistakes, please mention them. i will fix them and update here when I correct them.

**jpres: Updated the FAQ on how large the default code can get. Its very possible to get very big. Its nearly infinite when it comes to modifying it though. You can go as big as the integer system will let you go.
 
K, and i'm wondering please tell me how far this code can go.
Max Hero Level Save/Load = 99?
Max Gold = 1.6Mil?
And does it save stats also?
 
LOL, was over 90000 characters worth waiting for? :nuts:

I hope it really helps people out. I kinda feel I rushed some parts of it, so if something needs clarification just ask, no questions are dumb questions. But if you ask what a trigger is that will get you the cut and paste tutorial links :D
 
Now keep in mind integer math in WC3 triggers is limited. And we need variables to work from anyways so we will do it all with just four things, + - x /.
Can't you just use a conversion from a real, it adds so much more math ways(Square, square root, power, sine, cosine, tangent, and ext)?
 
dude thanks, i put this in my favorites so i can look it up if i ever got to the big giaganic map that requires alot of time to complete. (its like the 10th map on the list)
 
Reason I didnt use the conversion to Real. Its actually using alittle bit more horsepower anyways. Function calls like PowerOf, Root, and more arent built for efficiency, they are there for convenience. And when ever dealing with conversions there is a chance it will do what it wants to do. Which is bad when players play something for 8 hours. save code. Then comeback tomarrow to find out they have a bad load code because something shaved a decimal.

I weighed the use of reals, and I know its just powers of integers so it should be safe. But in the end the value just isnt there for something that can be handled with a Loop B with less cycles, more control and reliably.

And I didnt need anything besides PowerOf. All the rest can go back into the Trig Drawer where it came from.
 
I see, anyways, the ones you get from conversion are only used in like..... 0 of all maps.... But anyways, if you have that much time on your hands to do that saving tutorial, you need something to do :p. Well, I haven't read it, I don't know if I will, it is long.... But I have to give you credit, you must like to help people.
 
This one returns X-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-X by default.
I didnt want to go nuts with things like playername saving and heavy compression of items, just because the intent was a tutorial. Not a code sample.

I plan to add to the FAQs or Advance sections more code snippits with how to add in things like playername and compression in a full blown manner other than the short ideas I mentioned there. But thats as time permits.
 
Can you mkae a full list of the variables you used, and what type they are?

Im having some trouble with that. :banghead:
 
They are now listed in the FAQ, you could also just open the map and look them up there.
 
Effane said:
This one returns X-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-X by default.
I didnt want to go nuts with things like playername saving and heavy compression of items, just because the intent was a tutorial. Not a code sample.

I plan to add to the FAQs or Advance sections more code snippits with how to add in things like playername and compression in a full blown manner other than the short ideas I mentioned there. But thats as time permits.

I was thinking it will only take 24 digits, but 26..

I mean : 1 digit for hero type, 3 digits for level, 4 digits for gold, 4 digits for lumber, 12 digits for all items : 24

What are the 2 digits missing?
 
#-####-####-####-####-####-####-#


The first slot is the Deencryption Character, its the only character that isnt encryption and its used as a key to revert the whole thing to unecrypted strings.

The second and third are Hero type. I used a 2 digit system so people could have a default system capable of 50 heroes.

4th and 5th are level. I dont know why anyone would need 3 digits for level. thats 1295 levels with 2 alone. 3 would be 46655 levels.

6th/7th, 8th/9th, 10th/11th, 12th/13th, 14th/15th, and 16th/17th are the items in slot order. each is two digits.

18th-21st are the gold slots. 22nd-25th are the lumber slots.

The last slot is an encrypted checksum. This is an anti cheating character. I covered its use breifly in the tutorial, but it sounds like I need to read the tutorial again and polish it up a bit.


It sounds so easy for me to understand these things, but this is my third one I have built from scratch. First I scrapped. Hated it with a passion. Second is the highly advanced one, but its not good for a Tutorial as it uses about every trick I had in my arsenal except some more powerful compressions which were too much like a sledgehammer for pounding in thumbtacks.


This one was a ground up for the sake of a tutorial. But I actually like this one alot, but it does have some small limitations. I never did make it truly expandable on the fly, as you still need to enter in the loops for variables by hand. I had some code setup for handling everything given to it on the fly, but that didnt make it in the final code for several reasons. Someday I might just release a modified version of my ORPG save codes, which will have alot more crazy stuff in it for compression and flexibility.
 
If someone gets what this does and how it works I give him rep (I know answer, but I want to see the knowledge of TheHelper community).
It is also a useless for Save Load codes, but it is the best protection for very small save load codes (1 digit to 30 digits are considered as small, 31 to 45 digits are medium, and 39 to 80 are big).

Code:
 For each (Integer A) from 0 to ((Length of SaveCode1) - 1), do (Actions)
     Loop - Actions
            Set SaveCode2 = (SaveCode2 + (Substring(SaveCode1, ((Length of SaveCode1) - (Integer A)), (((Length of SaveCode1) - (Integer A))))))
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    +1
  • Varine Varine:
    I've been really into this
  • Varine Varine:
    It's a musical retelling of The Odyssey
  • Varine Varine:
    Also if you want mixed drinks without alcohol, there's a handful of non-alcoholic 'spirits'. Ritual Zero and Free Spirit are the two brands I've tried and they are alright. They don't have a TON of options, but they have some gin and whiskey alternatives that are fun to play with.
  • Varine Varine:
    I got a couple bottles to make some mixy drinks around holidays when I mostly want to drink, they aren't exact replacements but they are surprisingly close.
  • Varine Varine:
    I ended up with some hop water things that I really like instead for when I want to feel like I'm participating
  • Varine Varine:
    I just got moved to unsupervised probation, so I can get away with drinking a bit now. I technically am not supposed to, but I don't think I get checked anymore. I really want to smoke weed but it scares me
  • The Helper The Helper:
    Happy Wednesday! I am not feeling it today, my teeth are bothering me, or the fragments that were left behind are coming up and it is extra painful today. Don't ever let them tell you that getting full dental implants is easy. They have to pull all your teeth to do those and apparently they are not very good at getting all the teeth out all the time.
    +1
  • The Helper The Helper:
    That is true with Dentures too. I am taking the day off and working from home. The big difference is though, I am not drinking anymore so I have a nice tea and coffee regimen set up :)
  • Varine Varine:
    I wish i had a 3D scanner
  • Varine Varine:
    That would make what I'm doing SO much easier
  • Varine Varine:
    I guess I could just take a picture of it and then use that as a reference. I have a circuit board with some weird holes I can't get measured right
  • Varine Varine:
    Oh I got a Klipper mod for my big printer! It comes with a bunch of parts and I don't totally understand what it does but apparently it's way better than Marlin, which is I think what it currently runs
    +1
  • The Helper The Helper:
    Nice!
  • Varine Varine:
    You're people in Florida safe? The only couple I know are safe but I think they evacuated.
  • The Helper The Helper:
    They are without power but safe. Flood damage and stuff alot of tornados hit east Florida. No fatalities or injuries to any of my people that I know of
  • The Helper The Helper:
    They have been through all the Florida hurricanes they are like me I have been through every texas hurricane for the last 50 years.
  • The Helper The Helper:
    Never evacuated.
  • The Helper The Helper:
    Check out this bad ass Chicken Noodle soup recipe - https://www.thehelper.net/threads/crack-chicken-noodle-soup.196687/
  • The Helper The Helper:
    Happy Saturday!
    +1

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top