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

[Misc] Save/Load by AceHart

Level 2
Joined
Oct 18, 2010
Messages
4
Yes, there's already plenty of them around.

But, well, they didn't really work as I needed it.
And, they didn't really work as I needed it.
Not to mention that they didn't really work as I needed it.


So, here's my own.

Any and all comments and feedback welcome.
(Other than "Can you please stop making maps? Thank you.")


My actual question was: What do I want this to be able to do?
And I wanted something that can be used to save just about anything, be it Heroes, items, health, number of kills, your grand-ma's shoe-size (rounded down), ...

And, hey, I wrote it myself! Which also counts for something.
For example, it clearly says that I have too much free time currently.


Let's say you want to save a Hero and the player's Gold:
Set Save[1] = Player 1's current Gold
Set Save[2] = Hero[ Player number of Player 1 ]
Set SaveCount = 2
...

Simple?
Yes.

Now, we want to add the Hero's level:
Set Save[1] = Player 1's current Gold
Set Save[2] = Hero[ Player number of Player 1 ]
Set Save[3] = Level of (Hero[ Player number of Player 1 ])
Set SaveCount = 3
...

Yes, that's it already.

Adding lumber too?
Set Save[1] = Player 1's current Gold
Set Save[2] = Player 1's current Lumber
Set Save[3] = Hero[ Player number of Player 1 ]
Set Save[4] = Level of (Hero[ Player number of Player 1 ])
Set SaveCount = 4
...

Need to add something else?
Well, then do it.



Have fun,
Try it all,
Run your own system,
Find bugs (Bugs? What bugs?).


Yours,
AceHart



Yet Another Save / Load Code


This is much less a tutorial than a "How do I use it?" guide.


I'm not going to bore you with 500+ lines of GUI code triggers.

Why not?
You won't get it anyway...
More seriously though, simply because no one's going to read it all.

And, actually, only the "save" and "load" parts are in GUI, for easier reading.
The actual coding / decoding is in JASS.


What's it doing?

You want a save / load code in your map?
Well, take this map, copy the needed parts over to yours, done.

All in all, it takes a bunch of numbers, converts them into a code.
When you type that code back in, the numbers will be reconstructed.
That's it.

I'm kidding, right?
Well, no.

That is really all this map is doing.
It takes a bunch of numbers, turns them into a code that can be typed back to reconstruct those numbers.


Inner workings:

1: take all numbers and make a huge string from that
2: pretend that's a number in base 11
3: convert to base 36

Unless you really insist, that's all the details I'm going to post here.

Feel free to ask whatever you don't get.


Importing to your map:

I've provided three different "a player types '-save' / '-load <code>'" versions.
Have a look, take the one you like, and copy & paste the category you like into your map.

Open the custom script section (at the top of the trigger list is your map's name, click there):
Copy & paste anything in there to your map.

Done.


The real deal:

Trigger:
SaveLoad Save
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
-------- Those values need saving --------
Set Save[1] = 123
Set Save[2] = 456
Set Save[3] = 7890
-------- The number of values we have --------
Set SaveCount = 3
-------- Turn values into code --------
Custom script: set udg_Code = SaveLoad_Encode()
-------- Show code to player --------
Quest - Display to (Player group((Triggering player))) the Secret message: Your code:
Game - Display to (Player group((Triggering player))) for 60.00 seconds the text: Code


> Player - Player 1 (Red) types a chat message containing -save as An exact match

The most basic use.
A player types "-save".

> Set Save[1] = 123
> Set Save[2] = 456
> Set Save[3] = 7890

Some numbers (123, 456 and 7890) are put into the "Save" array.

> Set SaveCount = 3

We set "SaveCount" to how many numbers we have, 3 with this example.

> Custom script: set udg_Code = SaveLoad_Encode()

This calls the code generator.
It will take the three (as set in "SaveCount") values in the "Save" array.
And return the save code in some global variable called "Code".

> Quest - Display to (Player group((Triggering player))) the Secret message: Your code:
> Game - Display to (Player group((Triggering player))) for 60.00 seconds the text: Code

Show the code to the player.


Looks simple?
I hope so.

Now, those three numbers probably don't make much sense, but, that's also not the point.
The point was more to have something to look at, to see how it works.

You may wonder how to get a Hero into that "Save" array.
Valid question.

Unfortunately, you can't just write:
Set Save[1] = Unit-type of ("Paladin").

Which is why I provided a custom JASS function to do so.

In the example trigger "SaveLoad Save Hero", there's this line:
> Set TempUnit = (Picked unit) ("Picked unit"? Well, it's inside a "Pick every unit" loop, that's why.)
> Custom script: set udg_Save[udg_SaveCount] = SaveLoad_Unit2Integer( udg_TempUnit )

As you may see, in GUI, if this were possible, this would say:
Set Save[SaveCount] = Unit-type of (TempUnit)

You have your Heroes in some unit array called "Heroes"? Indexed by player number?
No problem, use
> Set TempUnit = Heroes[ Player number of (Triggering player) ]
> Custom script: set udg_Save[udg_SaveCount] = SaveLoad_Unit2Integer( udg_TempUnit )

Again, in GUI, if this were possible, would read:
Set Save[SaveCount] = Unit-type of (Heroes[Player number of (Triggering player)])

Should be simple enough, even for people that never used any JASS before.


There's also the equivalent for items:
> Set TempItem = (Item carried by (Picked unit) in slot (Integer A))
> Custom script: set udg_Save[udg_SaveCount] = SaveLoad_Item2Integer( udg_TempItem )


Now, since it uses JASS to turn unit or item types into numbers, there's also something to do it the other way around?
Yes, there is:
> Custom script: set udg_TempUnitType = SaveLoad_Integer2Unit(udg_Save[udg_SaveCount])
> Unit - Create 1 TempUnitType for (Triggering player) at ((Triggering player) start location) facing Default building facing degrees
and
> Custom script: set udg_TempItemType = SaveLoad_Integer2Item(udg_Save[udg_SaveCount])
> Hero - Create TempItemType and give it to (Last created unit)

Those are used when loading a code.


As a complete example on how to load a Hero:
Trigger:
SaveLoad Load Hero
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, 6)) Equal to (Matched chat string)
(Length of (Entered chat string)) Greater than 6
Actions
-------- Try to decode what was typed --------
Set Code = (Substring((Entered chat string), 7, (Length of (Entered chat string))))
Custom script: set udg_Validate = SaveLoad_Decode( udg_Code )
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Validate Equal to False
Then - Actions
-------- Invalid code --------
Game - Display to (Player group((Triggering player))) the text: There's some error in this code, sorry.
Skip remaining actions
Else - Actions
-------- It worked, let's do something with it --------
Set SaveCount = 1
Custom script: set udg_TempUnitType = SaveLoad_Integer2Unit(udg_Save[udg_SaveCount])
Unit - Create 1 TempUnitType for (Triggering player) at ((Triggering player) start location) facing Default building facing degrees
Set SaveCount = (SaveCount + 1)
Hero - Set (Last created unit) Hero-level to Save[SaveCount], Hide level-up graphics
Set SaveCount = (SaveCount + 1)
For each (Integer A) from 1 to Save[SaveCount], do (Actions)
Loop - Actions
Set SaveCount = (SaveCount + 1)
Custom script: set udg_TempItemType = SaveLoad_Integer2Item(udg_Save[udg_SaveCount])
Hero - Create TempItemType and give it to (Last created unit)
Set SaveCount = (SaveCount + 1)
Item - Set charges remaining in (Last created item) to Save[SaveCount]


In more details:

> 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

We wait for some player to type "-load <code>".

> (Substring((Entered chat string), 1, 6)) Equal to (Matched chat string)
> (Length of (Entered chat string)) Greater than 6

If the message he typed didn't start with "-load " or if it did but there was no code, this trigger won't run.

> Set Code = (Substring((Entered chat string), 7, (Length of (Entered chat string))))

Take the part that comes after "-load ", i.e. the actual code.

> Custom script: set udg_Validate = SaveLoad_Decode( udg_Code )

Call the decoding function.
This function will refill the "Save" array with all numbers that were saved with in that code.
It will set "SaveCount" to how many numbers it did find.
And, finally, it will return either "true" or "false", a result we catch in some variable called "Validate" (of type "Boolean").

> If (All Conditions are True) then do (Then Actions) else do (Else Actions)
> - Validate Equal to False

If "Validate" is false, as opposed to true, there's some problem with the code.
Missing characters, swapped characters, wrong player... some problem.

> Game - Display to (Player group((Triggering player))) the text: There's some error in this code, sorry.
> Skip remaining actions

So, yes, didn't work. Tell the player and skip the rest of the trigger.

> Set SaveCount = 1
> Custom script: set udg_TempUnitType = SaveLoad_Integer2Unit(udg_Save[udg_SaveCount])

The first thing we put into the "Save" array was the Hero.
We also take the Hero out of it first.

> Unit - Create 1 TempUnitType for (Triggering player) at ((Triggering player) start location) facing Default building facing degrees

Create the Hero.

> Set SaveCount = (SaveCount + 1)
> Hero - Set (Last created unit) Hero-level to Save[SaveCount], Hide level-up graphics

Set his level to whatever level he had when saved.

> Set SaveCount = (SaveCount + 1)
> For each (Integer A) from 1 to Save[SaveCount], do (Actions)

The code had a counter for how many items the Hero carried, this line will recreate an equal amount.

> - Set SaveCount = (SaveCount + 1)
> - Custom script: set udg_TempItemType = SaveLoad_Integer2Item(udg_Save[udg_SaveCount])

Read the next value, and convert it to an item-type.

> - Hero - Create TempItemType and give it to (Last created unit)

Create the item for the Hero.

> - Set SaveCount = (SaveCount + 1)
> - Item - Set charges remaining in (Last created item) to Save[SaveCount]

Set the charges to those saved.


There's also a save / load version called "SaveLoad ALL".
Which saves several Heroes, complete with items and charges, experience, position and the player's Gold.

Feel free to change to whatever you need in your map.


More on Heroes and items and general initialization:

Have a look at "SaveLoad_Initialization".
See those Hero and item arrays?
Well, if you're going to use this to save Heroes and items, or just one of those,
I strongly recommend putting them all in those arrays.

The code will still work for Heroes or items that aren't in the array, it will even (try to) compress it a bit,
but, still, if the Hero, or the item, isn't found in the array, the code will be longer.
With six items on your Hero, it's several characters difference already.


Other stuff of interest are the following three lines:
> Set SaveLoad_Alphabet = ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

The code you get will consist of upper case letters and digits.
You can change this if you want.
You could, for example, only use "ABC123", and the code would only use those.

However, the less characters, the longer the code.

So, I can just add abc...z too to have more characters and I will get a shorter code?
Yes, but, that's where the next line comes into play:
> Set SaveLoad_CaseSensitive = False

If your code uses both upper and lower case characters, this must be set to true.

By default, if you get "ABCD-1234" as code, and type "abcd-1234", it will work.
But, if the code is case sensitive, you must type it back exactly as you got it.

I wouldn't recommend changing this, but, well, your map, your choice.

> Set SaveLoad_UsePlayername = True

The code includes a simple check for the player that got it, and compares it, later on, when you type it back.
If you set this to false, the code won't care for the player.


Questions that are usually asked for Save / Load Codes:

Q: I used this to save three Heroes, complete with items, charges, position, experience, strength, agility, intelligence, my Gold and Lumber and my current top "kills" and "deaths" scores...
A: Impressive. Though, while this works just fine, the code length will be out of league...

Q: I forgot to put my Hero into the "SaveLoad_Heroes" array, but the code still worked.
A: Yes.

Q: I didn't add my Hero to the Hero array, got a working code, but it was very long.
A1: Put Heroes and items into the provided "hero" and "item" arrays, as seen in "SaveLoad_Initialization".
A2: That's the very reason to have those arrays.

Q: If I put a second Hero on your demo map, and enable the triggers in the "all" category, it will give me a code for both Heroes at once?
A: Yes.

Q: Why is the "initialization" trigger repeated three times?
A: Because, usually, you just copy & paste the category you need, not all of them. Keeps it simpler to import to your map.

Q: How many "digits" does it use to save a Hero (just the Hero, no level, attributes, items, ...)?
A: Best case: less than one.

Q: How many "digits" does it use worst case to save a Hero?
A: More than one.

Q: Can it save Strength / Agility / Intelligence?
A: Yes.

Q: Can it save both Gold and Lumber?
A: Yes.

Q: How much Gold can I save?
A: All you can carry.

Q: Can it save Lumber only?
A: Yes.

Q: LEAKS!
A: STFU.

Q: This must use heavy encryption, right?
A: Security through obscurity never works.

Q: What digit, in the final code, holds the Hero's level if I put it in Save[3]?
A: No idea.

Q: My Heroes can go up to level 666, will this still work?
A: Yes.

Q: So, if I want to save some other thing, like the number of units owned by Neutral Hostile killed so far with that Hero, I can simply add another number to the save array, and it will turn that too into a code?
A: Yes.

Q: I'm l33t!
A: Cool...

Q: Why is that thing in JASS?
A: Doing heavy math in GUI is a pain.

Q: Why isn't everything in JASS then?
A: ...



Anything I forgot here?
Something not very clear yet?

Let's hear it.
 

Attachments

  • SaveLoad_Demo_AceHart.w3x
    38.2 KB · Views: 216
Level 2
Joined
Oct 18, 2010
Messages
4
I don't wont to say it's mine!!!!!
it's Aceheart's
but i rly wanna share this with all ppl on this forum
'cause this is the simplest save/load Ever!
and this is help me very much.... so pls..
lots of ppl on this forum search for s/l code...
Your choice, but at least tell me how i can share this with all others?
 
Top