Previous Entry Share Next Entry

More Twine Thoughts...

So I've successfully--at least, I hope--at least, nothing looks broken--ported the prologue of Cryptic Stitching over to the Twine engine. (We're a long way from playtesting, but rest assured, there will be a call for testers when we get there!)

I'm using the SugarCube version of Twine, which allows for saving the game (a function one could not do without!) and apparently won't clutter up the browser cache in some obscure but apparently significant fashion.*

The differences between the two engines are interesting. StoryNexus is really cool and has a great interface, but has some significant limitations. Twine ultimately looks much more flexible but you have to do a lot more in the guts.

I'm not sorry I started in StoryNexus--the system made me think about what I was doing a lot, and the ultimate Twine result will be heavily influenced by those choices. Switching does allow me to rectify some rather clunky workarounds I developed, based on the fact that I started without any kind of plan. (The travel system in Cryptic Stitching is pretty much held together with chewing gum and paperclips. It will work MUCH BETTER in Twine.)

Some other useful things, at least so far--randomized flavor text and (I think) the ability to have merchants show up in camp at random, without having to visit them. (And the ability to sell ALL of an item, instead of doing it painfully one click at a time, which was clumsy as all hell in StoryNexus and wasted turns and turns and turns.)

Also, no spoilers in the "This card unlocked with:" mouseover, which I found maddening and there was no way to turn off. Also, there are no hidden variables in StoryNexus--everything must be visible to the player in some fashion--so I was making visible variables do some VERY questionable duties. (For example, your yurt, over on the StoryNexus sidebar? That value controls at least three different questlines, possibly more. And if you level your pet lungfish, your inventory says you have two of them. Necessity is a mutha.)

But there's a couple of things I'll miss very much--the inventory system was nice, and the ability to use objects on the fly. For example, at the moment, it's looking like you're going to have to return to your yurt in order to heal yourself, which is less convenient (but does have the advantage of making death more likely! And cool things happen when you die! Everyone should try it at least once!**)***

One thing this is doing it making me re-analyze how I laid the game out. Because of the way StoryNexus worked, with various "areas" that controlled what cards you got, I'm still thinking in terms of areas in the game. Each of these areas is getting a "hub" card--Wool-Tribe, Moon-Stuffing Camp, Withyjack Forest, the Steppes, etc. The hub always allows certain options, coinciding to the pinned cards at the bottom of the screen in StoryNexus. Various quests lead one away from the hub, then back to it (or to another hub.)

One truly great advantage of StoryNexus was the ability to make events seem to take time. If you're chasing the Sinister Frog around, it doesn't happen all in one long run--you chase him, then you do some other stuff, then that damn Frog is staring at you again, and there's a real sense of elapsed time. You are--at least, I hope!--looking forward to getting another Frog card to figure out what happens next.

It's an effect you don't get nearly so much if you just keep clicking choices at the bottom of the screen, ya know?

I think one of the big challenges of Twine will be creating that feeling. If you follow every story line in a linear fashion, there's a lot less anticipation. (The downside being frustration, because goddamnit it, I want to chase the Frog and somebody's trying to get me to use every part of the bloody reindeer again.)

Here's my thought--I'm bouncing this off you guys, since I know there are many coders and designers reading, so feel free to chime in.


One of the useful functions is <<display>> which lets you pull in the contents of another--I keep thinking of them as "cards" because of StoryNexus, so let's go with that, even though they are more properly called "passages"--into the current card you're reading. So our hub card for Moon-Stuffing has

<<display "randomcampflavor">>

<<display "randommerchant1">>

And those are all other cards off to the side which can be full of ugly variables and if/else statements. The first one prints a text string which provides a little local color, and the second one controls the random merchant function, which I am still tinkering with.

Taking the Sinister Frog example, I'm wondering if I could get the emotional impact I want by having

<<display "frogquest">> planted in the hub card.

and then have "frogquest" be randomized , so that, say, two out of three times there was a call to "frogquest," you get nothing, and the third time, the next stage of the Sinister Frog pops up. (Essentially you'd need to wander through the hub and then it might or might not appear.)

If you follow it, well and good, if not, the next time you show up, there's a 1-in-3 chance it'll be there. (Or 1-in-4 or 1-in-10 or whatever. That's a balance issue, and will come out in playtesting, I expect.)

(My random event design is a little clunky, but not, I think, particularly onerous--assign a random number to a variable every time the card is called, and if the random number is X, the linked quest line comes up. Once the quest line is completely finished, calling the card does nothing--well, prints a space, actually--and should be largely invisible to the player.)

My only fear is that if I do this too much, I risk winding up with WALL OF OPTIONS on the hub card, as ten different quests all fight for space. The randomization may help keep that down, but then again, it may not. I suppose I could even randomize which <<display>> options come up--assign them all a number value and roll a random number and pull up whichever number comes up, but now we're getting into walls of variables...

I dunno, anybody got any thoughts?


* I understand nothing.

**In the game. Obviously.

***The code problem is thus--I can make an inventory button on the sidebar which displays your inventory when clicked easily enough, and then returns you to the game using a function <<back>>. This function returns you to the last page you were on without retrigging the functions on that page. (Otherwise, you could just sit on a page where you got paid and just visit your inventory over and over again to retrigger the function that increases your money.) However, if I want anything that happens on that inventory page to stick--using healing herbs, say--I have to use the function <<return>> which does re-trigger the functions on whatever page you were on, which could potentially be a game-destroying bug.

So I think I'm making an executive decision that the only way to get healed is to go back to your yurt, unless one of you clever devils can think of a workaround. *grin*

(Deleted comment)
I am...having a difficult time parsing this. I think a whiteboard would be required.

I think I may be doing some of what you suggest, but I'm having a hard time making a jump to the abstract from the concrete.

(Deleted comment)
A counter! That's not a bad notion. At least for key quests!

Wow, that's gonna be a hella complex set of if/else statements, though...I'm sure there's a way to simplify it all down, if I knew more about code, but I can see it rapidly going off the rails...

As the above poster said, I'm not familiar with your engine. However, for the "whoops, randomly all 10 active quests decided to be available" problem, what you can do instead is to have a pool from which you draw your quest cards. You'd seed this pool with a bunch of generic things that would always be potentially available. Then, when the Frog quest is active, you'd add a "continue Frog quest" card to the pool.

So when you arrive in camp, the game creates a pool with, say, 10 "generic" cards like going on a hunting expedition, waxing your stitching, chatting up the next-yurt neighbors, etc. Then you add the Frog quest card, making a pool of 11 total cards. Then you draw 3 cards (or whatever) from the pool and make them available to the player.

If you want a card to be more likely to show up, you can seed it multiple times in the pool, and then do some finagling when you draw cards to make certain that you don't draw the same card multiple times. The simplest way might well be to re-generate the pool after each card draw, and exclude cards that have already been drawn from being added to the pool.

I hope that made sense, and I also hope it's not completely impossible in the Twine engine! Incidentally, there's something poetic about using an engine called "Twine" when your characters are all made out of stitches and fluff.

Hmm...maybe, yeah, set the display function to go to a...let's call it a pool card, and that pool card pulls 3 random quests to'd be a set of nested displays. I could break it down by--oh, "fluff" cards and "keyquest" cards...

Lord, this is complicated. Half the problem is getting the stuff written down in the whiteboard in my head...

(Deleted comment)
(Deleted comment)
(Deleted comment)
(Deleted comment)
A possible solution to the inventory problem would be to use CSS and have the inventory window be a normally hidden element rather than an entirely separate page...

Hmm, looking into the Twine wiki and the CSS documentation, this may not be a very practical solution. It probably can be done, but I'm not sure it would be worth the effort. But maybe the idea will spark someone else to come up with a better way?

this comment gave me an idea about a user-made macro called 'replace'! I posted it at the bottom.

Could you 'return' to a different page than you started from? Or have an intermediate page with no unsafe triggers that you went to first before being bounced to your inventory?

Or not return, but instead keep track in some variable of where to go next if you use an inventory item from here?

Or else just disable the inventory unless you were on a 'safe' page which could hopefully be more pages than just your yurt?

I don't know anything about the system, so I'm not sure if any of those are practical. Well, the last one probably is.

Another, perhaps-overcomplicated, way of dealing with the inventory-page problem:

On every page that does something important that should only happen once, you put a variable: "important_thing_has_happened".

Then, instead of just doing the important thing when the player arrives there, you first check whether that variable is set, and if it isn't set you do the thing and then set the variable.

This way, there's no harm in returning to the page again; nothing happens twice.

One disadvantage of this is that it makes everything a little more complicated. However, one advantage is that you then don't have to worry about the "getting paid repeatedly" sorts of bugs as much because it's much harder to have them accidentally happen.


Well, if the important thing that happens doesn't recur, you could use an <<if visited() < 2>> (have I been here before?) test and only trigger the variable change if it's true. Then you could safely use <<return>>.

If, however, you want players to be able to get to the same "you got paid" screen more than once, this would run into the same problem that the important_thing variable does.

(Deleted comment)
So ... here's a thought about the inventory.

There's a JavaScript macro called <<replace>> that Twine masters like the Porpentine use on the regular. It could potentially be used to 'show' and 'hide' an inventory within a passage without leaving that passage via a link at the bottom (or top) of every passage (where you want the players to be able to access it).

The code for replace is here if you'd like to play with it. :)

Ooooh. Thank you for the link!

I've never used the Twine engine (although I've dabbled in writing wiki extensions, which sounds kind of similar when I look at the documentation), and I mostly use Python rather than Javascript, but if you're dealing with unwieldy if-else ladders it sounds like you might need a Javascript language feature tutorial.

Not one of those tutorials that tell you how to modify HTML elements when the user clicks on the page; just a tutorial which tells you about functions and data structures and stuff (since it sounds like the Javascript is used to manipulate variables in the game, not to interact directly with what the user is doing in the browser).

I have found one which looks pretty good. I have heard dire warnings about a spam trap, so I will say only that you should google "eloquent javascript". The beginning of the tutorial is all about generic programming concepts, using Javascript. It only gets into "web programming" towards the end.

P.S. Cryptic Stitching is pretty cool, and I'm looking forward to its new incarnation. :)

"The management question, therefore, is not whether to build a pilot system and throw it away. You will do that. […] Hence plan to throw one away; you will, anyhow."
-- Fred Brooks, The Mythical Man-Month,

I'm mostly saying stuff Graydon says in a very different way, but...

I think the whole yurt thing is the wrong solution looking for a problem.

The "traditional" way of doing inventory operations is to have the commands that operate on your inventory be things available on every page -- look at the old Lucasarts games, for instance; wherever you are, you can select an item, and select a verb to use it with, and possibly another item or an item currently visible on the screen (depending on the verb). This is a -much- more natural way of expressing inventory than the way StoryNexus does it, and is something you can do much more easily in a system with real code underneath it (like Twine) than in a kinda-code system like SN.

The question, then, is the best way to express inventory access/operation. What I'd do is have an inventory tab that's always accessible -- you can have a variable that determines whether it's -visible-, as the player might want it collapsed much of the time, but the player should be able to open their inventory from every page, so every page should have the inventory tab included (I think, since Twine is code-based, that you -might- be able to code it as a single-page app with location actually being a variable that decides what real location to include in the main section, and all operations just triggering a reload--which would let you code subtabs in that single main page and simplify the overall layout a lot, but that's putting the cart before the horse), with its display depending on whether it's currently collapsed or not. If it's collapsed, the player has a single inventory operation available -- "expand". If it's expanded, the player can select any inventory item, and then gets presented with a set of verbs to use on it.

You could do the same thing with a "verbs" tab if you want a set of generic verbs that aren't tied to inventory items (like examine, say, "pick up", etc, depending on how much like traditional inventory IF games you want to be vs action games a la SN).

(Deleted comment)
(Deleted comment)
(Deleted comment)
(Deleted comment)
(Deleted comment)
(Deleted comment)
(Deleted comment)
(Deleted comment)
While I know this is going to sound like gobbledegook (probably), do you know if in addition to JQuery Twine uses JQuery UI? If so, it should be fairly straightforward to code up something using a dialogue box and an AJAX call to manage and use inventory without ever leaving or entering the's possible without JQuery UI, but it's a lot more fiddly as you have to do everything yourself. Might be worth asking?

Twine itself just takes a file of macro calls and formats them as tiddywiki data. The real heavy lifting is done by the "target" templates. SugarCane does not have jQuery ui, but SugarCube (and as a derivative, CrypticCube) might, since the save/load UI is all in the javascript sources.

{{display "randomcampflavor"}}
{{display "randommerchant1"}}

I read this as "Display Random Camp Flavor" and "Display Randommer Chant". :)

so that, say, two out of three times there was a call to "frogquest," you get nothing, and the third time, the next stage of the Sinister Frog pops up

Now this is something that can get really frustrating for the player. Player is looking for something, they try some action, and nothing happens. Does that mean they need to try some other action, or keep trying the same thing? And the "show random subset of active quests" would make it even harder to tell if you're doing the right thing or not.

The code problem is thus--I can make an inventory button on the sidebar which displays your inventory when clicked easily enough, and then returns you to the game using a function {{back}}. This function returns you to the last page you were on without retrigging the functions on that page. (Otherwise, you could just sit on a page where you got paid and just visit your inventory over and over again to retrigger the function that increases your money.) However, if I want anything that happens on that inventory page to stick--using healing herbs, say--I have to use the function {{return}} which does re-trigger the functions on whatever page you were on, which could potentially be a game-destroying bug.

I don't know anything about Twine (or even Javascript), but is it possible to split the page-with-entry-functions into 2 pages?
A: entry functions only, last one automatically moves you to B
B: display location and actions available

Then the inventory can safely {{return}} you to B without re-triggering all the stuff now in A. But I don't know if "automatically move" is an option, or if there are any limits on the number of pages. Also, this would make things even more complicated when the entry functions affect the actions available; you can use variables that are only used by A and B, but that can get messy.

Edited at 2014-03-04 09:34 pm (UTC)

Or maybe you could just add to each relevant page:
{{display "usableinventoryitems"}}

random quests happening:

First, check the possibility of each quest coming up this trip through the hub, store every result you get.
Then, pick ONE of these results at random to display.

I dunno how easy it is to implement this in Twine but this sounds like a good way to avoid "oh god I have ten quests vaguely in progress and they ALL CAME UP AT ONCE".

I pointed some game-designer friends of mine to this post ( and the reactions I got were (excerpts):

"She's definitely pushing these systems past where they're meant to go. I'd be interested in gathering a bunch of use cases to see if there's a better design for it."
"Agreed. It sounds like she's outgrown the beginner IF tools and needs to move to something like Inform or TADS. If she's not familiar with Galatea (the game), then she should look into it since it does a lot of what she's looking to do."
pursuant to which:

Hope this helps!


How did I outgrow an engine in TWO DAYS?!

Well, I have Kevin on the case. I'm really quite sold on Twine, actually, and I think I CAN make a lot of things work, but it may require having my in-house code guy hammering on the tools with a rubber chicken.

(Deleted comment)
(Deleted comment)
[Error: Irreparable invalid markup ('<if [...] "yes">') in entry. Owner must fix manually. Raw contents below.]

<<if $haveMotor eq "yes">>
Thanks for showing me this! I poked around and found a few things.

1) Invisible links!

[[@@font-weight:normal; <html><font color="black">TEXT TO BE DISPLAYED</font></html>@@|PASSAGE NAME]]

Link will still highlight when hovered over, though removing that seems a trifle mean. Just replace "black" with your default text color.

2) I put a link in the sidebar to a passage named "Inventory". On that passage, I put the following:

<<if $haveMotor eq "yes">>You have the motor.<<endif>>
<<if $haveCarrot eq "yes">>You have the carrot. Joyous.<<endif>>
<<if $havePinwheel eq "yes">>You have the pinwheel.<<endif>>
<<if $haveStick eq "yes">>You have the stick.<<endif>>
<<if $haveLock eq "yes">>You have the lock.<<endif>>
<<if $loftCool eq "yes">>The loft is cool now.<<endif>>
You've found <<print $photoCount>> mission files.
~[[Return to game.|previous()]]

A little basic, I admit, but one could format it however.

Overall, it's very exciting!

Edited at 2014-03-06 04:15 am (UTC)

As for the code, would it be annoying for inventory to open in a new window? Because that wouldn't have to go back and therefore shouldn't trigger anything.


Log in

No account? Create an account