Save files persisting through updates?

As far as I understand (correct me if I'm wrong), save files are locked to the version of the game they were saved on. So, you can't use a save file to pick up from a later version of the game. This makes sense to me but I'm looking for a way around it.

To me, I'm mostly concerned with character setup. It'd be great if my players didn't have to start from scratch whenever I release a new update, since I give quite a few options. Would it be possible to export some variables into a txt or csv so that players can upload it to future versions?


One way that has been proposed before...
Add a command called "savegame"
have the character and story setting printed to the screen.
tell the player to copy the full screen (the text box area),
and save that to a text file "Save.txt"
Add another command "loadgame" that will open the Save.txt file and load the character info.
Your save info and load info must line up for it to work.
One idea, encode the data so that the player would not know what to edit.


How do you load files into the game, though? I can't find any instruction on that.


GetFileData (string file name) --- I think this one will read the file
GetFileURL(string filename) --- I think will identify the file
I haven't played with the commands (yet), but you can find a little bit more info in the documentation, under Resources below.


When you save a game in Quest, it saves everything. The save game IS the game, in whatever state. You do not even need the original game to play the saved game.

I have a library here which will save to "localStorage" if the game is played in the browser.
https://github.com/ThePix/quest/blob/master/SaveLoad.aslx
https://github.com/ThePix/quest/wiki/Library:-Save-and-Load

localStorage is a special section of your harddrive the browser controls and keeps separate for security. However, that is not available in the desktop version.

An earlier version uses DarkLizerd's idea of puttting the data to screen for the player to copy-and-paste to file, which is the only way with the desktop. I will at some point modify my library to allow both methods.


It shouldn't be that hard to allow localStorage to work in the desktop version of Quest.

We seem to currently have:

        ' KV added this next line of code to actually set CefSharp's path to the temp fold AppData\Local\Temp
        ' CefSharp writes a debug.log to the current directory, so set it to the Temp folder
        settings.CachePath = Path.GetTempPath()

I believe this is also the directory where Cef saves a file for JS localstorage; if it's set to a temp directory, the browser runs in incognito mode and prevents saving.

You should really be setting the cachepath to a sane directory (possibly based on the game's ID?).

If you want to stop it filling the disk with logfiles, that's what settings.LogSeverity = LogSeverity.Disable is for. Or set settings.LogFile to a path under the temp directory while leaving CachePath somewhere sane.


coughSaveLoadcoughUpdatecough :P I love you guys.


@mrangel & Pixie

If you want to stop it filling the disk with logfiles, that's what settings.LogSeverity = LogSeverity.Disable is for. Or set settings.LogFile to a path under the temp directory while leaving CachePath somewhere sane.

That was my purpose, and the change to the code doesn't even always stop debug.log from being created in the game's directory.

Now I'm wondering if my added code to set settings.CachePath could have introduced any little bugs into the system . . .

I'm going to change it back and commit the changes on GitHub.


I believe this is also the directory where Cef saves a file for JS localstorage; if it's set to a temp directory, the browser runs in incognito mode and prevents saving.

I could never figure out how the heck that works, but I seem to recall finding numerous posts in the Visual Studio forums which mentioned how that (old) version of Chromium simply won't allow saves to localStorage.


This may or may not help, but here's code I added to that same file to save a txt file to the hard drive during play:

    Private Sub WriteToLog(data As String)
        Dim logPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\Quest Logs"
        Dim gameName = Split(CurrentGame.Filename, "\")(Split(CurrentGame.Filename, "\").Length - 1)
        gameName = gameName.Replace(".aslx", "")
        If Not System.IO.Directory.Exists(logPath) = True Then
            System.IO.Directory.CreateDirectory(logPath)
        End If
        If Not System.IO.File.Exists(logPath + "\" + gameName + "-log.txt") = True Then
            Dim file As System.IO.FileStream
            file = System.IO.File.Create(logPath + "\" + gameName + "-log.txt")
            file.Close()
        End If
        My.Computer.FileSystem.WriteAllText(logPath + "\" + gameName + "-log.txt", data + Environment.NewLine, True)
End Sub

It works along with JS.saveLog().

I initially had it coded so that the author could save whatever text he or she wanted to a text file, but we ended up leaving that out.


You do not even need the original game to play the saved game.

I thought the saved games check for the existence of the original game and refuse to load if not found?

UPDATE

Yep. Just checked. If the original game is not on the disk, you get:

FAILED TO LOAD GAME
The following errors occurred:
Error: Could not find file 'C:\Users\KV\Documents\Quest Games\Downloaded Games\Xanadu - In the Compound - Revenge.quest'.


I'm glad my thread has stimulated some conversation~

I'm still lost, though. The documentation on GetFileData and GetFileURL is pretty sparse and I'm not sure what to do with them. Pixie's SaveLoad library is also too much for me to implement at this point, as I have way too many variables that could change and this would just be too much overhead for me to deal with. (Though I appreciate the suggestion!)

At this point, I'd be happy with only save/loading the character creation variables. Is there a simple function I can use to quickly export a string to a text file, and then another function to retrieve that string? Would I be able to utilize Log() for this to export some kind of cheat-code-like string the player can paste into the input box?


It would have been nice if the save/load was as simple as it is in Basic:
(open file for saving)
open "MyFile.txt" for output as #1
(save the data you want saved)
print #1, player.name, player.HP, player.Str….
(close file)
close #1

(open file for reading)
open "MyFile.txt" for input as #1
(read the contents)
Input #1, player.name, player.HP, player.Str….
(close file)
close #1


RH, I had a look at your log/transcript system, and as far as I can see it only works for the web player, not the desktop. Is that right?

The issue with the desktop version is the version of Chrome is so old, as someone said. Anyone fancy looking at how to update it? We have had issues in the past uploading updates to the web (and manowar is consequently reluctant to make changes!), but this should be only changing the desktop, so that should not be a problem.


I had a look at your log/transcript system, and as far as I can see it only works for the web player, not the desktop. Is that right?

I thought it was the other way around. (I may be misremembering. In fact, it's highly probable.)

https://github.com/textadventures/quest/issues/1054#issuecomment-429636361


The issue with the desktop version is the version of Chrome is so old, as someone said. Anyone fancy looking at how to update it?

I tried and tried (and tried) to update Chromium, but I don't know enough about anything involved.


I'm interested in this too but I don't understand what is going on in this thread. How can I implement this in my game? I only want to save the character creation variables. GetFileData and GetFileURL don't have a lot of documentation at all. Is there a tutorial on this somewhere? I assume that these let you "load" the file, but what is the Quest function for creating/saving an external file?


what is the Quest function for creating/saving an external file?

There isn't one. GetFileData lets you load a file which is zipped up inside the game file.
On the web version, you can get around this by storing your game data in cookies, which are a function of the web browser rather than Quest itself, or in a LocalStorage (which is like a next-generation cookie). Unfortunately, neither of these work in the desktop version of Quest.


I'm working on a way around this. I'm basically conjoining everything as a list and exporting that as a code, which the player can copy/paste into later versions of the game. I'm using Split() to put the code into a NewList() and assign the values using ListItem(). Like:

code = NewList()
code = Split (result)
player.alias = ListItem (code, 0)
player.test = ListItem (code, 1)

However, this doesn't play well with booleans... It's just assigning them as strings. Is there a way around this instead of checking if each string is a "true" or "false"? Is there a function for converting strings into booleans?


Is there a way around this instead of checking if each string is a "true" or "false"?

player.someattribute = (ListItem (code, 5) = "true") is a quick way to convert to a boolean. You can use (x = y) as an expression that returns true if the values are equal, and false otherwise.

Alternatively, if you know the value in the string is going to be either "true" or "false", you could do player.someattribute = eval (ListItem (code, 5)). Eval treats a string as an expression, and works equally well for booleans or integers.


Ah, that's very helpful! Thank you.


Hmm, actually, I get the following error when I use player.test = eval (ListItem (code, 1)):

Error running script: Error compiling expression 'eval (ListItem (code, 1))': FunctionCallElement: Could find not function 'eval(Object)'

For reference, player.test is a boolean that is set to "true". Is this because the player is pasting the code in as a string and so the value in the list is a string?


No. Eval expects a string.

Your error message suggests that the string in result doesn't contain a ;. Split returns a list with a single item, which is number 0. So when you access ListItem (code, 1) you get null, and eval complains because it only works on strings, and null is (technically) an object.


No, the way I'm printing them is player.alias + ";" + player.test + ";" Also, they're assigned just fine using ListItem() so long as eval() and ToInt() aren't there; they're just being assigned as strings instead of the variable types that I want.

EDIT: It seems like this works fine when I separate the functions. (For instance, player.test = ListItem (code, 1) and THEN player.test = eval (player.test)) Does Quest have a problem with embedded functions like eval (ListItem (code, 1))?


Sorry, I always forget that.
With the built-in functions, Quest does strict type checking. So it causes an error because ListItem can return an object.

That's why there is a separate function StringListItem which only works with stringlists. player.test = eval (StringListItem (code, 1)) should work, because Split returns a stringlist.

I was building a similar system, but designed to account for the fact that you might want to add more variables to the system later. So it would generate a string like: player=42:alias=6:"John"strength=2:34someflag=4:true. In that case, because the string values have quotes around them, you can just use eval for all data types. (in this version I ditched the ; between the different values, and instead put =6: or similar before each data value: the number of characters which need to be eval'ed. This means that you don't need to worry about strings which contain a " or ; when splitting it up, and also produces a string which is slightly more compressible using the javascript version of the gzip algorithm.

There is one big problem with systems like this: script attributes. You can't create or modify script attributes on the fly. Your system cannot check whether any firsttime blocks have already been run; so you need to avoid using those. And if you have scripts which assign script attributes using the => operator, you won't be able to easily restore that either; unless you have a set of special scripts designed to set those script attributes to the correct values, which is quite a bit of extra work.


Log in to post a reply.

Support

Forums