LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Please help me save Game Variables

Root / Programming Questions / [.]

Z_E_R_OCreated:
I need a save function for game variables and a loading one. I used to have one that involved str$ But now I don't what I mean by save variables is Gold, Level, Powers, Etc.... Please help if you can :) I can't finish any of my current projects without it.

If you have just numbers, you can save them to a DAT file
DIM DAT[5] '5 is an example. YOU HAVE TO USE THIS NO MATTER WHAT
DAT[0]=GOLD 'Starts at 0 and ends at the number minus one. (in this case, it ends at 4)
DAT[1]=LVL 'Etc.
SAVE "DAT:DAT FILE",DAT
however, if you have any text you CANNOT SAVE IT TO A DAT FILE and MUST SAVE THE TEXT TO A TXT FILE! example:
DIM TX$ 'you only need this if you have OPTION STRICT on
TX$="Your Text String Here"
SAVE "TXT:TEXT FILE",TX$

Yo @DaSonicMario Thanks a lot, Saving is working. Do you know how i would load?

It really helped btw :)

If you have just numbers, you can save them to a DAT file
DIM DAT[5] '5 is an example. YOU HAVE TO USE THIS NO MATTER WHAT
DAT[0]=GOLD 'Starts at 0 and ends at the number minus one. (in this case, it ends at 4)
DAT[1]=LVL 'Etc.
SAVE "DAT:DAT FILE",DAT
however, if you have any text you CANNOT SAVE IT TO A DAT FILE and MUST SAVE THE TEXT TO A TXT FILE! example:
DIM TX$ 'you only need this if you have OPTION STRICT on
TX$="Your Text String Here"
SAVE "TXT:TEXT FILE",TX$
^This is by far the easiest route, but if it gets too complicated you can opt for just one long string separated with qualifying tags, like xml. I've used that method a lot, and have yet to hit the string length cap. Simple explanation: MEM$="[GOLD]Amnt of gold[/][LEVEL]I dunno, 1?[/][POWERS]yaddaya[/]" and so forth. The benefit of going this route is you can easily edit the save files themselves, and once you've written a save and load DEF you can use it with everything.

Thank you Sagesscript I had a save system I made that worked well in my old projects. Every comment is helping. How would I setup a load def?

I can post an in-depth tutorial tomorrow (Gotta go DM for some needy ppl) If it suffices, though, you write a DEF that searches your mem$ for a given tag, like '[GOLD]'. After you've retrieved the appropriate index (which would be the character after the ']' in said tag), you then search for the starting index of the next '[/]'. Grab the stuff in the middle of the 2 indices and slap that bad boy into a VAL() function if it isn't a string and you're golden. I find it best to write 2 of each, one for values and another for text. So you would have 2 defs: for example's sake one named GET_DATA and one named GET_DATA$ for returning the strings. I've probably butchered that explanation but I hope it helps. Come to think of it, there's probably a tutorial somewhere on the forum that shows an even more efficient method of doing the same thing. If there isn't (I'll check later), I think I'll write one.

here's how to load using the way i told you about: DEF:
DIM DAT[5]  'Once again, the 5 is an example
LOAD "DAT:DAT FILE",DAT,FALSE
TXT:
LOAD "TXT:TXT FILE",FALSE OUT TX$

It would be a lot faster and simpler if you store the LENGTH of each string. (you won't be able to edit it manually as easily though). (this code only works with strings, but I have a more complex version that supports numbers and arrays too) For example, if GOLD$ is "27", the save string would be: CHR$(5)+"GOLD$"+CHR$(2)+"27" This way, it knows how many characters to read, and doesn't need to check EVERY SINGLE ONE. Also it doesn't prevent you from using characters like [ in your variable name/values (you could actually store one of these save data strings INSIDE OF another!)
VAR GOLD$="27",SAVE$
ADDVAR SAVE$,"GOLD$"
'reset GOLD$ to make sure it works
GOLD$="0"
'This should set GOLD$ back to "27"
READVARS SAVE$

'I'm adding _ before variable names in these functions so they don't have the same name as variables you're using (otherwise it won't work)

'this adds a variable to your save data
DEF ADDVAR _S$,_VAR$
 'store the length of the variable name
 INC _S$,CHR$(LEN(_VAR$))
 'store the variable name
 INC _S$,_VAR$
 'get the value of the variable
 VAR _VALUE$=VAR(_VAR$)
 'store the length of the value
 INC _S$,CHR$(LEN(_VALUE$))
 'store the value
 INC _S$,_VALUE$
END

'this restores the values of the saved variables
DEF READVARS _S$
 VAR _I,_A
 'loop until the end of the string
 WHILE _I<LEN(_S$)
  'get length of variable name
  _A=ASC(_S$[_I])
  'get variable name
  VAR _NAME$=MID$(_S$,_I+1,_A)
  INC _I,_A+1
  'get length of value
  _A=ASC(_S$[_I])
  'get value
  VAR _VALUE$=MID$(_S$,_I+1,_A)
  INC _I,_A+1
  'set variable to value
  VAR(_NAME$)=_VALUE$
 WEND
END
They way it gets/sets the value of variables is using VAR(). Basically, VAR("NAME") is the same as NAME. So you could do VAR("X")=1 in place of X=1, for example. This does mean that it only works with global variables, though. (but you could probably use some tricks to get around this)

thanks guys. I was getting discouraged, I really appreciate all the help :)

'--- WHAT I USE FROM TIME TO TIME: FORGIVE MY MESS :3 ----
COMMON DEF SAVE_VAR TB$,VL,IM$ OUT OM$
 OM$=IM$+"["+TB$+"]"+STR$(VL)+"[/]"
END
COMMON DEF SAVE_VAR$ TB$,IS$,IM$ OUT OM$
 OM$=IM$+"["+TB$+"]"+IS$+"[/]"
END
COMMON DEF GET_VAR TB$,M$ OUT VL
 VAR SI%=INSTR(0,M$,"["+TB$+"]")+LEN(TB$)+2
 VAR EI%=INSTR(SI%,M$,"[/]")-1
 VAR STRVAL$=MID$(M$,SI%,EI%-SI%+1)
 VL=VAL(STRVAL$)
END
COMMON DEF GET_VAR$ TB$,M$ OUT OS$
 VAR SI%=INSTR(0,M$,"["+TB$+"]")+LEN(TB$)+2
 VAR EI%=INSTR(SI%,M$,"[/]")-1
 VAR STRVAL$=MID$(M$,SI%,EI%-SI%+1)
 OS$=STRVAL$
END
Here you can see how these DEFS are implemented...
Spoiler
VAR MEM$=""  'HAVE A STRING FOR THE MEMORY, LOADED OR NO
'--------------------------------------------------------
'NOW WE SAVE WHATEVER VARIABLES NEED TO BE SAVED, USING
'THE APPROPRIATE DEFS. STORE ANY SINGLE VARIABLE YOU WANT...

 SAVE_VAR$ "FNAME","Seiji",MEM$ OUT MEM$
 SAVE_VAR$ "LNAME","Serenity",MEM$ OUT MEM$
 SAVE_VAR "AGE",30,MEM$ OUT MEM$
'  !NOTE THAT THE LAST VARIABLE CALLED SAVE_VAR, NOT SAVE_VAR$!
'   THIS IS BECAUSE IT IS NOT A STRING LIKE THE TWO ABOVE IT 
'  --------------------------------------------------------'
'  THE RESULTING STRING READS: 
'         "[FNAME]Seiji[/][LNAME]Serenity[/][AGE]30[/]"
'  MAKING THE SAVED STRING FILE ITSELF SUPER EASY TO DEBUG &
'  EDIT!

'####TESTING GROUNDS#######
'-- NOW WE LOAD SOME VARIABLES FROM OUR MEMORY STRING 
'   AGAIN, USING GET_VAR$ FOR STRINGS AND GET_VAR FOR THE REST

 GET_VAR$ "FNAME",MEM$ OUT FNAME$
 GET_VAR$ "LNAME",MEM$ OUT LNAME$
 GET_VAR   "AGE",MEM$ OUT AGE

 ?FNAME$+" "+LNAME$+" is "+STR$(AGE)+" years old."
'   THIS WILL OUTPUT  "Seiji Serenity is 30 years old." 
While wasteful with letter space in your string, this tedious method gives you a worry-free one file only save string to keep track of. The version I actually use is far more in depth, able to initialize arrays and the such using specialized tags like "[,]" and "[%]" making it more powerful than it seems at first glance. I'm sure there is a more efficient manner of achieving this, with less space used such as exclusive one character tabs like obscure ascii characters, but the premise will remain the same. Also, you do not have to sacrifice '[' or ']' usage with this method, it is why I use INSTR. In the rare event that it did conflict, you could use one of those obscure characters to check for and substitute, but I can't conceive of any such conflict short of wanting to store '[/]' as a value or '/' as a tab. There are pros and cons to both my and 12Me21's approach. His leaves a far shorter string with a little quicker speed, mine allows any variable scope, really. Like all tools at your disposal pick any method that easiest suits your goal. Hope it helps you :) Edit: Sry for all of the edits, I'll be better about them from now on now that my less-than-observant self has noticed the preview button.

'--- WHAT I USE FROM TIME TO TIME: FORGIVE MY MESS :3 ----
COMMON DEF SAVE_VAR TB$,VL,IM$ OUT OM$
 OM$=IM$+"["+TB$+"]"+STR$(VL)+"[/]"
END
COMMON DEF SAVE_VAR$ TB$,IS$,IM$ OUT OM$
 OM$=IM$+"["+TB$+"]"+IS$+"[/]"
END
COMMON DEF GET_VAR TB$,M$ OUT VL
 VAR SI%=INSTR(0,M$,"["+TB$+"]")+LEN(TB$)+2
 VAR EI%=INSTR(SI%,M$,"[/]")-1
 VAR STRVAL$=MID$(M$,SI%,EI%-SI%+1)
 VL=VAL(STRVAL$)
END
COMMON DEF GET_VAR$ TB$,M$ OUT OS$
 VAR SI%=INSTR(0,M$,"["+TB$+"]")+LEN(TB$)+2
 VAR EI%=INSTR(SI%,M$,"[/]")-1
 VAR STRVAL$=MID$(M$,SI%,EI%-SI%+1)
 OS$=STRVAL$
END
Here you can see how these DEFS are implemented...
Spoiler
VAR MEM$=""  'HAVE A STRING FOR THE MEMORY, LOADED OR NO
'--------------------------------------------------------
'NOW WE SAVE WHATEVER VARIABLES NEED TO BE SAVED, USING
'THE APPROPRIATE DEFS. STORE ANY SINGLE VARIABLE YOU WANT...

 SAVE_VAR$ "FNAME","Seiji",MEM$ OUT MEM$
 SAVE_VAR$ "LNAME","Serenity",MEM$ OUT MEM$
 SAVE_VAR "AGE",30,MEM$ OUT MEM$
'  !NOTE THAT THE LAST VARIABLE CALLED SAVE_VAR, NOT SAVE_VAR$!
'   THIS IS BECAUSE IT IS NOT A STRING LIKE THE TWO ABOVE IT 
'  --------------------------------------------------------'
'  THE RESULTING STRING READS: 
'         "[FNAME]Seiji[/][LNAME]Serenity[/][AGE]30[/]"
'  MAKING THE SAVED STRING FILE ITSELF SUPER EASY TO DEBUG &
'  EDIT!

'####TESTING GROUNDS#######
'-- NOW WE LOAD SOME VARIABLES FROM OUR MEMORY STRING 
'   AGAIN, USING GET_VAR$ FOR STRINGS AND GET_VAR FOR THE REST

 GET_VAR$ "FNAME",MEM$ OUT FNAME$
 GET_VAR$ "LNAME",MEM$ OUT LNAME$
 GET_VAR   "AGE",MEM$ OUT AGE

 ?FNAME$+" "+LNAME$+" is "+STR$(AGE)+" years old."
'   THIS WILL OUTPUT  "Seiji Serenity is 30 years old." 
While wasteful with letter space in your string, this tedious method gives you a worry-free one file only save string to keep track of. The version I actually use is far more in depth, able to initialize arrays and the such using specialized tags like "[,]" and "[%]" making it more powerful than it seems at first glance. I'm sure there is a more efficient manner of achieving this, with less space used such as exclusive one character tabs like obscure ascii characters, but the premise will remain the same. Also, you do not have to sacrifice '[' or ']' usage with this method, it is why I use INSTR. In the rare event that it did conflict, you could use one of those obscure characters to check for and substitute, but I can't conceive of any such conflict short of wanting to store '[/]' as a value or '/' as a tab. There are pros and cons to both my and 12Me21's approach. His leaves a far shorter string with a little quicker speed, mine allows any variable scope, really. Like all tools at your disposal pick any method that easiest suits your goal. Hope it helps you :) Edit: Sry for all of the edits, I'll be better about them from now on now that my less-than-observant self has noticed the preview button.
Oh, I wasn't even thinking about random access. Yeah, this method might be better for that purpose (be careful that your stored strings don't use [NAME] or [/] though...) Also, strings are passed as references, so you could do something like:
COMMON DEF SAVE_VAR$ NAME$,VALUE$,MEM$
 INC MEM$,"["+NAME$+"]"+STR$(VALUE$)+"[/]"
END

COMMON DEF SAVE_VAR$ NAME$,VALUE$,MEM$
 INC MEM$,"["+NAME$+"]"+STR$(VALUE$)+"[/]"
END
Huh, I didn't know you could INC a string. That would have been helpful in, like, 20 dozen instances. Thanks for the tip :)