Save/Load Code

Discussion in 'Tutorial Repository' started by Effane, Aug 4, 2006.

  1. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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
     
    • Like Like x 14
  2. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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.
     
  3. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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.
     
  4. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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.***
     

    Attached Files:

  5. jpres

    jpres New Member

    Ratings:
    +15 / 0 / -0
    Hey on first post when it has like
    ----A=192---
    ----A=325---
    or whatev, the second one is repeated twice
     
  6. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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.
     
    • Like Like x 1
  7. jpres

    jpres New Member

    Ratings:
    +15 / 0 / -0
    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?
     
  8. Lord_Kakashi

    Lord_Kakashi The Wabbits are attacking

    Ratings:
    +27 / 0 / -0
    Very nice ^-^
     
  9. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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
     
    • Like Like x 1
  10. Azylaminaz

    Azylaminaz Vox Populi

    Ratings:
    +91 / 0 / -0
    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)?
     
  11. undeadorcjerk

    undeadorcjerk The Ulitimate TheHelper.net Lurker

    Ratings:
    +220 / 0 / -0
    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)
     
  12. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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.
     
    • Like Like x 1
  13. Azylaminaz

    Azylaminaz Vox Populi

    Ratings:
    +91 / 0 / -0
    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.
     
  14. Chocobo

    Chocobo White-Flower

    Ratings:
    +410 / 0 / -0
    How many digits returns the Save Code?

    Also, does it protects for the player name?
     
  15. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    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.
     
    • Like Like x 1
  16. Lobster

    Lobster Old Fogey ofthe site

    Ratings:
    +92 / 0 / -0
    Can you mkae a full list of the variables you used, and what type they are?

    Im having some trouble with that. :banghead:
     
  17. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    They are now listed in the FAQ, you could also just open the map and look them up there.
     
  18. Chocobo

    Chocobo White-Flower

    Ratings:
    +410 / 0 / -0
    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?
     
  19. Effane

    Effane Save/Load Code Tutorial

    Ratings:
    +51 / 0 / -0
    #-####-####-####-####-####-####-#


    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.
     
  20. Chocobo

    Chocobo White-Flower

    Ratings:
    +410 / 0 / -0
    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))))))
     

Share This Page