Total beginner here! So bear with me. ::)
I have in mind to make an episodic game. The game will of course have choices, but I'm also thinking to add things such as inventory, stats, and so on.
First question: How can I save/restore the "state" of the game inside one episode? Which is a simple way for the user to do this (without having him to make effort or manually save stuff...).
Second question: How can I import the choices (and eventually inventory stuff and so on) between each episode? So that, for example, choices made in Episode 1 carry in Episode 2 affecting its behavior. Is there a way to do this?
Thanks in advance to anyone who will take his time to read and answer. I really hope to get positive answer so that I can begin shaping and creating my game. ;D
For question 2, I'm not sure. Sugarcube's save-load won't work, because the web storage mechanism it uses does not allow data to be transferred between different pages. Browser security folks frown on pages sharing data directly - the accepted method is to have the pages on a proper webserver and using cookies.
1. Create a passage within Episode 1 that converts the users data into a JSON string, and then displays this string on screen.
2. Create a passage within Episode 2 that contains an input field that accepts a JSON string, and then convert the string into users data.
3. Get the user to copy and paste the JSON string from Episode 1 onto Episode 2.
Would love to see an example TWS of this.
This is not correct. None of the major browsers (no browsers at all, AFAIK) limit access to localStorage based on page (sessionStorage, yes, but SugarCube doesn't store save data there).
SugarCube's save system was written to allow this very thing, in fact. AFAIK, it's only being used by one story at the moment, and only because it's proving to be so large as to require being split into multiple parts, but it most certainly does work.
And if it's development you're worried about, you could probably use StoryIncludes to keep the episodes in separate files and still compile them into a single HTML file.
Ummm. You do realize that lets people write save hackers? Write a second game that goes fishing in local storage for the save data from the first game, load it, modify it advantageously (+gold, +maxhits, +stats, +weapon damage) and write it back...
Not that most of the idiots that do this stuff read well enough to be following text only games, but all the same...
The danger with this is the same one that bought NWN's locally hosted character play to it's knees. By allowing you to take your character into any story, you are able to 'cheat' by writing story that turned your character into a god and gives them heaps of gold, uber weapons and whatever so they can then poo all over whatever adversaries they meet in anyone else's story.
Now if you could find a pool of trusted authors and work out how to manage the encryption of the save/data files, you might be onto something...
If an individual chooses to hack the game state to improve their own personal experience how does that effect the other people playing the same game?
Most modern browsers come with or have available debuggers which allow the game player to change how the game works, and if they are really serious they could just manually edit the generated HTML anyway.
That was one of my first thoughts. Isn't it extremely easy to cheat on games made with Twine? Is there a way to avoid cheating (server sided stats and so on, even if that requires a bit of PHP or other kind of coding...)?
Thanks again ;D
Search for "Twine SugarCube" in your search engine of choice.
As to stopping people from being able to cheat in a HTML based game, the simple answer is you cant.
The complex answer is that you can try lots of things, each make it a little harder for them but that also makes it harder to develop, and possible inconvenient for your users.
It's the law of diminishing returns, more and more effort for less and less extra protection.
Yes, I'm cognizant of the fact, though I have no idea what your point is supposed to be. What's your proposal to secure a web app to which the player has the source? Not that having the source matters at all, as long as the player has any kind of access to the underlying system (source, binaries, data, network, etc.) then you cannot secure it. Just look at the ongoing war that the games industry wages against everything from piracy to cheating, the war that they are not winning, to see what I mean.
Case in point, this is the primary reason why SugarCube does not support obfuscation, because it's pointless. Normal users aren't going to bother "peeking" and those who are inclined to do so absolutely cannot be stopped by it. So, what purpose does it serve? None, except to be a source of bugs, bloat, and drawing authors into a false sense of security. Which, honestly, makes it even worse than being pointless, it's actively detrimental.
Beyond all that, I'm constantly amazed by people who think they have a right to determine how someone else spends their leisure time. As long as the player's activities aren't impacting other people (i.e. it's not any kind of multiplayer experience), why should anyone else (incl. the author) care what they do?
If the game can encrypt/decrypt the saves then it must have access to the encryption key. If the game has access to the encryption key then a determined player can get access to said key, and then you're back to square one. You cannot secure a system to which users have any kind of non-trivial access, and Twine gives users a whole lot more than trivial access.
Yes, even obfuscated ones. It's beyond trivial. That's not a criticism of Twine headers, BTW, it's just the nature of the beast.
You'd have to keep everything on the server, exposing only the most trivial level of access to the player, and even then I wouldn't give odds that you'd get it right the first time (note how much trouble AAA online games have had getting this right).
greyelf's reply to this is spot on. It's extremely difficult to be totally secure. Generally, the best you can do is to make cheaters work for it a bit (of course, if a game is popular enough, then people with the skills to do so will write cheat utilities which anyone can use).
For a multi-player experience, joining the war on cheating is simply something that you'll probably have to do to protect the "good" players from the "bad" ones. For a single-player experience, what's the point?
Regarding episodic games: Thinking about how good old Tiddlywiki works with importing of tiddlers from other files... Couldn't you load/unload the passages of the game for each episode as and when needed? For example by importing new episode content from a file on a server. Or is it simply too difficult to bother re-implementing that functionality given that modern browsers don't like you messing with the local file system? (i.e. the need for things like the TiddlyFox add-on and Tiddlysaver.jar).
Or could you do this by directly writing the episodes into localStorage and using that data within the rest of Twine? Again, I'm not sure it would be worth the effort to develop that if at least Sugarcube already allows you to access saves in localStorage from one game in another? One large game is apparently doing this, is there a demo of that functionality somewhere?
Thanks for putting the other arguments together so well in this thread. I was surprised that Sugarcube didn't support obfuscation and I thought this might be a problem when deciding on which story format/header to use for stories/games.
From the practical point of view, 'useless' development of obfuscation and deobfuscation code is just wasting time and effort. Trying to hide code or story details simply isn't worth the bother. You have to have them in the browser, scrambled or not, they are there.
If you want look at the HTML to cheat, and you have to work-round any obfuscation, you are simply cheating yourself, so what's the point? It's a bad game or story situation if you get so stuck you have to resort to reading the code!
From the aruments presented here, it actually seems like an ill-conceived feature in Twine which is best ignored and, dare I say, forgotten?
Really? My own reading about web storage gave me the impression that access was restricted on a per-page basis. If it's not, then Sugarcube's load/save is even more useful than I had thought! At least until the browser vendors lock it down (which they probably will - the original Tiddlywiki has become far more difficult to use because the vendors keep removing or locking down functionality.)
They do this mostly to stop people being able to hack your machine.
Not quite. In general, access to Web Storage (specifically, localStorage and sessionStorage) is restricted by origin, so as long as the origin is the same you're golden. The per-session storage area, sessionStorage, is further restricted in that each browsing context receives its own set of per-session storage. IOW, you're largely correct about sessionStorage, but localStorage (which is where SugarCube's save slots are stored) isn't as restricted.
It's unlikely that Web Storage will change. Save for the occasional bug, the various browser's behavior here is largely stable at this point (inconsistent, but stable). The new web storage hotness, IndexedDB, is where all of the current activity is focused.
This somehow got lost in the hacking/cheating aspects of this thread...
If you use SugarCube, you've probably already seen an 'example' of this!
What do you think SugarCube does when you Save to/Load from Disk? It's writing a JSON string of the SugarSube save slots to a file which allows you to load it back again later! That is effectively what you said you wanted as an example, except it is not in the .TWS, it is hidden in the SugarCube save/load system.
Note that, as it is well designed, it checks that you are loading a saved file back into the same story. This means it won't currently work out-of-the-box to transfer saves between different stories.
@TheMadExile: Without short-circuiting using localStorage for a story. Couldn't the current system be extended by sticking to some naming conventions for episodic game/story titles and/or allowing 'data transfer' saves/loads that only contain a particular set of relevant data (for example the player stats and inventory for a RPG)? That way you could transfer the current data to a new episode and then continue to use localStorage to save and load while playing the new game episode.
Off-hand, you could fairly easily do it in one of two ways:
Having some kind of To Be Continued/Episode Complete passage at the end of each episode, in conjunction with the onSave() handler, would allow custom saves to be made. Specifically, the custom save could have its ID set to allow it to be loaded by the next episode (i.e. a post-game save). You could also use this to trim the save data to only what's needed for the next episode and/or transform the save data in some way.
By using the same StoryTitle and differing StorySubtitles. SugarCube's storage subsystem segregates story storage by StoryTitle, so as long as you use the same title, the different episodes would be able to see each others saves. You'd probably want to use the onLoad() handler to trim the save data down to just what was needed and/or transform it as necessary.
You could also combine them. There may also be other ways to handle this that I'm not thinking of at the moment, it's been a while since I've gone over this for someone.
Just wanted to say: while I wasn't the original creator of the obfuscation feature, and while I'm not quite its biggest fan, I vaguely recall its rationale was more to prevent people from possibly seeing spoilers by accident (by hitting view source without thinking through the consequences) rather than intentionally trying to hack the page. Not sure how common that is, but I've left it in anyways.
Thinking about it, it'd probably be more honest about its purpose if it didn't have an obfuscatekey option, and simply advertised itself as "rot13 your game's source" - no one takes rot13 seriously as an encryption method, and acknowledge it as merely an opt-out spoiler-protection scheme.
In my experience most end-users don't know that you can see the html source, nor is it likely that they would understand what they are looking at if they did so.
The ones that do know (how to see it / read it) are aware of what they are about to do, so are making a conscious decision to look at the source for whatever reasons (curious / want answers / etc) are motivating them to do so.
I believe it would be a very rare situation where someone who did not know would accidentally select the 'view source' menu item and see something they did not want to. *smile*
The most likely thing you will see if you accidentally select 'view source' on a Twine story is the Tiddlywiki Copyright notice! 8)
You would probably have to accidentally scroll all the way to the end of the file to see the tiddler store area and accidentally find the right bit of text in the right passage to accidentally find out too much information!
I might have accidentally noticed that one day, by accident!
Accidentally changing things in a Twine story would just be an accident waiting to happen!
Is there any tips to give users to manually preserve the save files/cookies? Eg, instructions for different browsers that could be given of where to look for the cookie save file, so that it could manually copied and 'archived' somewhere outside of the browser's directories, just in case?
AFAIK*, no modern Twine header stores any data (saves, <<remember>>'s $variables, etc) in cookies normally. Cookies should only be used as a final fallback if no other storage methods are available.
* I know that's true for SugarCube, and I believe that's true of the 1.4+ vanilla headers as well (I'm not 100% sure though, so someone please correct me if I'm wrong).
You shouldn't normally have to worry about that. Modern headers generally offer a way to save data outside of the normal browser storage mechanisms.
For the 1.4+ vanilla headers: bookmark/favorite (in the browser sense) the story/game's save bookmark (in the vanilla header sense). I think that's how it works anyway.
For SugarCube: use the save menu's Save to Disk feature, if it's available, to write a save where ever you chose (it's just a normal file at that point).
Ahh, that is all fantastic news, thanks!