It looks like you're new here. If you want to get involved, click one of these buttons!
::Room
There is a [[pencil]] here, ripe for the taking, as well as a juicy-looking [[nectarine]].
::pencil
<<set $havepencil to 1>>[[Taken|Room]].
But having the page clear itself just to say "Taken" is hardly ideal. So the obvious thing to do is to switch to Jonah and use CSS to remove the passage titles. Trouble is, the player still has to click on a "back" link to return to the location they were previously in, even though that passage is still displayed on screen. If the player tries to immediately take the nectarine by clicking the perfectly visible link, Jonah will automatically rewind, and now the player doesn't have the pencil anymore. And if the author wanted to move the inventory items around, they'd have to make sure to update all the 'back' links accordingly. This is not ideal.
Wikifier.linkFunction = function(title, el, callback) {
return function() {
if (title) {
state.display(title, el, null, callback);
}
else if (typeof callback == "function") {
callback();
}
};
};
Then we can obviate the 'back' links in the spoke passages. But that's a problem. If the player takes the pencil, then bookmarks the page and reloads, they will end up back at the pencil passage with no way of returning to a hub, which would practically break the game. So, I decided to force Jonah to always take you back to the most recent hub location whenever the page is loaded, if there is one. In the restore function, I added these lines:
if (vars.variables['room']) this.display(vars.variables['room'], null, "back");
else this.display(vars.passage.title, null, "back");
Then, a prerender function is used to store the current passage title in a variable called 'room', but only if the passage is tagged as a "hub":
prerender.hub = function (content) {
if (this.tags.indexOf("hub")==0) {
new Wikifier(content, '<<clearall>><<set $room = "'+this.title+'">>');
new Wikifier(content, '!!'+this.title);
}
}
This is still problematic, however, because if the player saves and then reloads, any control logic that was executed in a spoke node will not be saved. So again, the player will take the pencil, bookmark, reload, go back to the hub, but won't have the pencil. Confusing. So, I just forced Jonah to resave the variables after every display operation and to update the hash accordingly. At the end of the display function:
this.saveVariables(D, source, callback);
this.hash = this.save();
if (tale.canUndo()) window.location.hash = this.hash;
Finally, I made a quick and dirty <<clearall>> macro for manually clearing the screen:
macros['clearall'] = {
handler: function(place, macroName, params, parser) {
removeChildren($('passages'));
},
init: function() { }
}
This macro is called in the prerender function so that any passage tagged 'hub' will first clear the screen, in addition to saving the current hub location in the room variable and printing a title header. The default title header is removed in CSS:
.passage .title { display:none; }
Hence the resulting code is very simple:
::Room [hub]
There is a [[pencil]] here, ripe for the taking, as well as a juicy-looking [[nectarine]].
::pencil
<<set $havepencil to 1>>Taken.
The player can take the pencil and nectarine in two clicks. If they save and reload, they will still have the goods, and they will be returned to the hub location.
::Room
There is a <<click "pencil">><<append "#end">><<pencil>><</append>><</click>> here, ripe for the taking, as well as a juicy-looking [[nectarine]].
<span id="end"></span>
This is extremely messy. It's possible to make a new macro to automate the process, but it's not worth it in this case. If the player takes the pencil and then saves and reloads the game, they will no longer have it, and the game won't say so. This is because the game state is only updated on a passage transition, but this is not a passage transition anymore.
Comments
Twine is just the GUI you use to collate/edit the passages that will be contained within the HTML file you build/generate using it.
It is the Story Formats that control how the core part of your story works, what default features / macros it has and the generally layout of the HTML generated by the story format's build-in javascript engine. One common feature that most of the existing formats have in common is the general way they handle History and Variable storage.
It is true that the current ones are not really designed to handle RPG features like Inventories, Shops, Equipment, Combat, Visiting the same location multiple times (Hubs), etc but because all of the existing story formats are Open Source there is no reason that one cant be cloned (Forked) and changed to support these types of features. Similar to how you did in your review except on a more permanent bases.