So, I'm trying to make a separate Twine 2 story that serves as an Encyclopedia for the main story; with entries being unlocked throughout the story's core progression. When you hit the Encyclopedia button it links to another Twine story, opening in a new tab, that then takes variables from the main story to decide what entries and information are unlocked.

I've been thinking of trying to save the game when they click the button and then having the Encyclopedia load the save game to get at the necessary variables... but how would I do that? Is that even realistic? Or can I pass the values I need as arguments somehow? Perhaps some type of object? I'm a noob when it comes to these types of languages.

The linkage occurs through the file system, so I can't use a URL argument as far as I'm aware...

Also. I want to have it in a separate Twine story not only for organizational means but also for speed and design reasons, just in case you were wondering.

2 Answers

First, a warning: A system like this can only work if both the twine html files are hosted at the same domain. It also will not work locally (i.e. when both files are run from the computer, I hope this isn't what you mean by file system). This is for security reasons; there are no workarounds (or rather, if you find one, you found a bug in your browser).

The Code.

First I made this function in the JavaScript area of my main file (the game):

You can send as many variables as you want, and the whole package is passed over as 'window.passParams' as an array. You can then do whatever you need to with the given data (you'll probably want to 'unpack' it back into individual story variables for easy access).

Note that you can link to another Twine story's play mode by copying the URL you receive when you press the play button and use that for testing, but only in the online version of Twine 2.

Would it not be easier to just use web/local storage to save a key/value pair in the first story, which the other story could open as long as its on the same domain?
...and this should works on both web & locally hosted HTML files.

eg. The same way a save made in one Harlowe based story can be loaded in a different Harlowe based story.

Wow, thank you! That really helps. Very impressive work around without being overly complicated... someday I hope my understanding will be closer to your level. Also, thank you for showing me the example too. I really appreciate it.

And yes, unfortunately, I was referring to the local system. It was a pipe dream... but, I suppose this does make sense. I wanted to try making the game into one convenient package for distribution.

Anyways, Thanks again!

P.S. From the example I found your Holy Land Dev Log. Very impressive stuff. I'm looking forward to playing the demo. Keep up the great work!

This example saves the entire variable store to local storage; you may want to create a smaller object and use that instead, but that should only be a problem if you have lots of variables and are developing for a more limited platform like mobile.

In the main game, just call the function when you need it:

<<run setup.storeState()>>

In the receiving file, you'll probably want to save it to a variable:

<<set $store to setup.unpackVars()>>

Then you can access each variable inside as a property:

/% if you have a variable called $name in the main game, access it like this: %/
<<set $store to setup.unpackVars()>>
<<print $store.name>>

Thanks for the suggestion greyelf, that's a much better idea, I think.

There are a few pieces to the puzzle. You can easily find out which window opened your encyclopædia (it's in window.opener) and send a message that way, and you can then intercept it there with a pre-registered event listener and react to it.

On the "encyclopædia" side:

if(window.opener) {
window.opener.postMessage("GET_DATA", "*");
}

On the "game" side (and using the "openOther" function similar to @Chapel's answer):

Now ... this is one-way communication. You can send data, but you can't receive any, and the receiving side can mutate the data all it wants, it won't be reflected on the sending side. There are also limits to what kind of data you can send, though plain JavaScript values, objects and arrays work fine. Still - with just this you can already implement dynamic loading of passages from external files, for example. Just send the passage's HTML code over as a string.

To get data from the "game" window back to "encyclopædia" window, we need to send a message back. Thankfully, the event already tells us where to do it, via event.source. We also need to register some event handler on the "encyclopædia" side of things, so let's start with this:

The order is important here; we need to have the event listener registered before we ask for data to be sent to that event listener. Now let's implement the data sending. We need to temporarily save the arguments-to-send, then send them when the loaded page requests them (but only once, in case the user reloads the other page):

Thankfully, the last TODO on our list is easy: Just put in Engine.show() in there to re-render the current passage, or Engine.play(...) if you want to go to some passage based on the data received from the other window.

This works just fine directly from the file system and across the network. It works without problems even when the two stories are on different domains, or when one's a local file and one on a server somewhere else. The amount of data transferred is only really limited by your available RAM; you can easily push gigabytes of data either way.