Tiny QBN for Twine/Sugarcube

That’s awesome, thanks for the thorough code example! Looking forward to testing this one out.

I finally got videos recorded and uploaded, so the YouTube playlist now has up-to-date versions of my three original walkthroughs, and a new one for the cards-with-covers example.

1 Like

Moving right along…I added a tiny example (twee, html) for inline choices: things like the products in my Localvore example which need to be filtered like cards but are only available in one place so it’s unnecessarily tedious to make a separate passage for each one. I also wrote a walkthrough explaining the example and uploaded a video version to YouTube.

Huh. These examples seem so short, but that makes almost an hour of video now…

1 Like

Today I simplified storylet priority to use only the three levels that StoryNexus offers. Cards are usually normal. If you tag them important, then they are chosen in preference to normal cards. If you tag them urgent, they block non-urgent cards from being selected at the same time.

I wrote an example (twee, html) and a walkthrough explaining it, and the video is on the playlist.

That’s all the major features working and documented. I still have another six tutorials planned, and it seems like they’re taking me between two and three hours each? I have to figure out the details of what I want to cover, sketch in an example, debug it, write 600-1200 words explaining it, then record and upload a 10-15-minute video. At this point I’m just blasting through the videos in a single take and any bobbles just help show how you debug the stuff, so that’s no big deal. But the rest is a big chunk of time.

Yeah. I’m still hoping to get through all of that by the end of the year, but we’ll see if I feel like putting that much more work into it. The code is getting to be pretty solid: the last couple changes have been easy refactorings and the <<choices>> fix didn’t affect the interface at all, it just removed a limitation. And the remaining features are minor and they all worked last I checked, so I think the interface is stable.

The remaining tutorials on my list are (in no particular order):

  • Debugging: common ways things go wrong, and how to diagnose them.
  • <<fillhand>> draws cards to refill an existing list up to a given size.
  • <<addcard>> and <<removecard>> allow you to remove cards (even sticky cards) from the deck, or add a discarded card back in.
  • I have some stat stuff that does StoryNexus’s Basic Abilities, which have a success chance based on your level relative to the challenge level, and your stats improve the more you use them.
  • If I’m doing stats, I feel like I should also throw in Choice of Games’ Fairmath, and inkle’s preferred ratio-of-positive/negative-to-total-choices, and maybe Chris Crawford’s bounded numbers?
  • Setting up to work with Twee and some cross-platform text editor? If you’re making heavy use of storylets, the connections between passages are being made at runtime, so the Twine editor can’t show you arrows. And making heavy use of tags and creating lots of passages is tedious in the Twine editor. So using Twee makes more sense here than in general. Though maybe someone else has a good getting-started-with-Twee video that I could point people to?

If anyone is reading (or watching) these and has priorities, or has other things they’d like me to cover instead, let me know. Or just let me know if these seem useful or hopelessly obtuse. I like to think I’m good at explaining things, but I don’t really have any idea if I’m going about this in a halfway competent manner.

4 Likes

Yeah… I got involved with holiday stuff and didn’t do any more work on this. Oh well. The repository got 50-ish views and only the first video got anywhere near 10 views, so it’s not like I’m letting lots of people down.


I’m having trouble figuring out any good use for a persistent hand of cards. I put that in because it seemed like a major feature of StoryNexus. But looking at the docs it seems like they may have moved away from it later on. It seems like a design problem waiting to happen. If you have a set of cards that you keep around, then you have to make sure that you can raise your stats to let you play them, and never have stat changes make them unplayable (or make sure there’s a way to discard them).

I dunno. It seems like you could do much the same thing with just qualities and requirements, and in ways that are less likely to break. But if anyone has ideas for a short scenario where you would want to hold a specific set of storylets and play them later, I’m looking for ideas.


I realized recently that you can use <<addcard>> as a convenient method for linear stories whose storylets are separated in time. One of the good things about doing storylets in a hypertext tool like Twine is that you can build plain old branching narrative structures “inside” a storylet whenever you want. But what if you want, say, an ongoing discussion (argument? running gag?) with an NPC?

The storylets might be separated by arbitrary amounts of other content, so you can’t just use links. But creating a progress variable seems clunky. You have to remember to increment it every time, and make sure that there’s a storylet that happens at every increment. And what if you want to insert another storylet in the middle of the arc? You would have to renumber everything that came after.

So I finally realized that you can just make passages that have requirements (“you are in the same location with the NPC”) but aren’t marked as cards (except for the first). They aren’t in the deck, so they will never be found. Then you can just “link” them from the previous storylet by saying <<addcard "argue with Lloyd about poultry management">> or whatever.

And that’s all you have to do. No managing an extra “story-arc-progress” number. If you want to add more storylets in the middle, you only have to fix the link in the storylet just before where you’re adding the new one(s). And…hmm. I bet I could even make the <<addcard>> macro accept Twine link syntax as well as quoted strings, and then the editor could show arrows between the parts of the sequence. How cool would that be?

I’m a patient person, so no worries from my end.

Having a way to discard cards for hand management with a persistent hand of cards would seem to be pretty important for a story designed around the concept. I wouldn’t worry about making cards unplayable (especially for some things which are mutually exclusive) because the game state (with good design) could return to a point were they become playable again. The player question is whether to continue to hold onto it for that possibility or to discard them to make room for something useful in the short term. I’ll think some more about this at any rate.

The <<addcard>> trick for time separated content is an interesting design choice. Progress qualities is something Fallen London was using but I would agree that inserting new content is more difficult with them being pre-numbered like that. Adding parallel content is easy, because they would share the same requirements, but you’d have to find and edit the whole chain to insert something inbetween after the fact. Arrows in the editor would indeed be cool.

Yeah, designing a game around hand management seems like it would require a certain amount of careful design. And I can see how you would do that.

But where does a hand of storylets make narrative sense? That’s the thing I’m struggling with. You’re giving the player a random subset of the stories that make sense here, but you want to keep that particular set of choices around for a while? Oh. How long is a while? I see. So you might draw a hand that is the set of vendors and interesting people that are at the bazaar on a given day, and that won’t change until you go to sleep and come back the next day.

Or a hand of the people who live in your neighborhood, and some stories might result in them moving out and then you draw a new person to move in. Things like that. OK, now I’m getting the idea. Cool.


As for the <<addcard>> trick, you can certainly do progress qualities instead. I was just thinking it might be easier for linear or simply-branching storylines with time separated content.

Greyelf pointed out recently that you can create dummy arrows by putting links inside comment markers:

/*
[[Study]]
[[Billiard Room]]
[[Parlor]]
*/

SugarCube will ignore everything between /* and */, but the Twine editor doesn’t know about that syntax so it will create arrows (and new passages, if they don’t exist). Clever.

And you can change the color of a passage tag at any time, and Twine will mark all passages with that color. So that would help with finding and re-numbering parallel content. Start at the end, change req-progress-eq-5 to red, fix all the red-marked passages, change it back to grey, and repeat. Or if you’re working in Twee you should be able to just search-and-replace each tag across your whole story.

Edit: Ooh. Or you could name each stage of the progress quality instead of numbering them, and keep a global list of the order. Then you’d just have to type the new name into the list and everything would just work. It would be a small piece of code, and I bet I could wrap that in a simple macro. Sweet.

1 Like

In Storynexus it wasn’t so much a “hand” of cards - There was usually a deck or multiple decks you could draw from. That would lay out up to three cards chosen by a deal which were active. Playing these removed them and let you draw another - if you had three, you couldn’t draw, so game elements could be designed around the player having to play a card. I did this to advance time - if you got three “The Clock Strikes” cards you had to choose one and advance time to be able to draw again.

Then there were “pinned” cards, which is what probably though of as “the hand” since they were at the bottom of the screen, although they were essentially permanently available cards which could become available from choosing a branch on a drawn card, or just appear based on what SN called “settings”. Cards and decks could be sorted to only show in certain settings and cards could change the active setting - which might be thought of as a region or a location instead of a hand of cards, but often served other purposes like a time period of the current narrative.

So one example of how I used cards - If you’re in a setting called the “Town Square”, some pinned cards may appear that represent buildings you could examine, and a deck to draw from “Observe your Surroundings” which caused Town Square setting events to happen “An Overheard Conversation” “A guard saunters past”. The pinned cards might have branches on them the player could choose to enter buildings (which is why they’re always available,) which would change the setting to “Tavern” where you’d get new pinned cards like “Talk to the Barkeep”, “Play Darts”… Meanwhile, drawing from the deck(s) in the Tavern setting could cause random things to happen like “A bar-fight breaks out!” which might force you into a new “bar fight” setting with its own different deck of storylets and encounters, or “A Mysterious Stranger” with its chance of appearing which might contain branch-choices like “Talk to the Stranger” “Attack the Stranger” “Pickpocket the stranger” which you wouldn’t have if that card hadn’t been drawn to the table. Either the drawn “table” cards could be thought of as a “hand” as well as the pinned cards since those are the ones you can keep around.

The pinned “hand” of cards probably doesn’t necessarily make structural sense in Tiny QBN since the author can accomplish that with permanent links normally in Twine, however perhaps there might be a mechanism where drawn cards could force something like removing or adding a linked choice to your permanent options in the Twine storylet. In SN, all player interactions were from cards and you didn’t have just regular choice links, though that was often a requested feature that people often wished for when learning the system.

2 Likes

Ah, so you almost always could play the cards that you drew, but you might not want to? And those three cards would go away when you switched locations so you would be able to draw a new three from a deck in the new location? That would make more sense to me.

1 Like

I have too many projects…but I got around to implementing the progression-variable helpers.

You can now say <<progress "$var" state1 state2 ...>> in your StoryInit passage to create a progression variable. I think it makes the most sense to use strings (names) for the states, but you could use numbers if your brain works that way.

Use <<advance "$var">> to advance it, or <<advance "$var" n>> to move it multiple steps (or a negative number of steps).

Then you can tag your cards with req-var-during-value, req-var-before-value, or req-var-after-value to check a progress variable.

I started sketching an example (twee source, html). It doesn’t do anything yet, it’s just a static test that the code all mostly works. But you could look at the source or import the HTML into Twine to play with it.


I also made it so you can <<addcard [[Passage Title]]>>. SugarCube supports links as macro arguments, so that was very easy.

I’ll try to flesh out the example this weekend so that it demonstrates both techniques, and write a walkthrough with more detail. But it’s pretty simple (I think? Maybe that’s just me being a programmer).

2 Likes

Bah. I got a nasty flu, which turned into a chest cold and laryngitis and wiped me out for about a month. I’m just finally getting around to catching up on my hobby projects.

So this isn’t about my library, but adjacent:

Jonathan Li filmed Emily Short’s storylets talk at the London IF meetup on January 29th, and that is up on YouTube. An hour and a half, but well worth watching. They do a collaborative design exercise (which predictably turns chaotic very quickly) and it’s cool to see it run by someone with enough experience that she can pull relevant bits out of the chaos on the fly and keep it moving forward. And there’s a nice mention of TinyQBN at 20:57.

4 Likes

I got a bit of time in yesterday. I wrote some documentation about tracking progress that talks about when I think various method are most effective. And it gives some details of how to use <<addcard>> links for simple independent story arcs, and how to use <<progress>> and <<advance>> to manage progress variables that have more storylets depending on them.

And inspired by Em Lazer-Walker’s piece, I wrote the shortest instructions I could for setting up Tweego and VSCode. So if you have ever been curious whether a text-based workflow might work for you, I think this is about as easy as it gets right now. It’s basically:

  • Install Tweego.
  • Install VSCode and tell it to install the Twee2 highlighting extension.
  • Download my minimal blank VSCode/Twee project and unzip it.

It sets up VSCode to run Tweego so you don’t have to use the command-line directly.

1 Like

Hopefully you don’t mind, but I linked to your article at r/twinegames.

1 Like

Sure! And…I dashed that off fairly quickly, so let me know if omissions or trouble spots come to your attention. For example, this morning I realized that I hadn’t mentioned story formats at all, so I fixed that.

You might want to read that post then, since Greyelf added a suggestion.

Yeah, thanks. I did see the comment, but my VSCode/Tweego project already has a tasks.json: that’s its main purpose. So it wasn’t clear what the suggestion was: how do these two examples differ from what I’m already doing? Is any of that necessary or useful? Probably, but I haven’t found time yet to look at them carefully enough to decide what I should do differently, or if Greyelf has those files hosted somewhere and I should just link to them, or what.

@JoshGrams
My examples were more about showing others that it is possible to do more than hard-wire a specific call to tweego, than suggesting that either your or lazerwalker’s current VSCode setup needed to be changed.

1 Like

Thanks. There’s some very cool stuff in your examples: I love that you can build just the current file using a format selected from a dropdown. That’s amazing for messing with little examples in response to people’s questions.

Sooo…looks like I’ll be joining Cat Manning at NarraScope to strengthen the coding side of a talk that’s sort of an end-to-end beginners’ guide to one way of designing and prototyping a quality-based narrative. I’m thoroughly psyched about this! It should be a great talk (and one of many other great talks), so if you’re within reach of Urbana-Champaign the last weekend in May, come on out to the conference.

3 Likes

I’ve had a couple people working through the tutorials and telling me where they fall down, which is great. So I’ve been fixing up a few bits of documentation. And so far it sounds like they’re more-or-less serviceable, or at least not completely terrible.

Also, working toward the NarraScope talk I’ve been looking at choosing results based on die rolls. There are so many ways to do this that I’m not sure it belongs in the library. It seems more like something that should have idioms and examples which you can adapt to your story.

I built a small example (html, twee) of doing Powered by the Apocalypse style die rolls. That’s a family of story-focused rules-light tabletop RPGs (here’s a decent overview of some of the ideas) where all rolls are 2d6 plus a player stat (ranging from -1 to 2, initially) and 10+ means success with at most minor complications, 7-9 is mixed success (you get what you want, but there are complications), and on 6 or less the GM (or “Master of Ceremonies”) does something to make the player’s life interesting.

Here's stat roll widget (not TinyQBN-specific).
/%

Usage: <<roll $stat mixed=7 good=10>>
	(mixed and good thresholds are optional)

Result: sets one of _bad or _mixed or _good to true.

Note that 2d6 is NOT the same as a d12: for instance you are six times
more likely to roll a 7 than a 12. Trivia: the more dice you roll and
add together, the closer the probability is to a Gaussian bell curve.

%/
<<widget "roll">><<silently>>
	/% clear any previous values %/
	<<set _bad to false>>
	<<set _mixed to false>>
	<<set _good to false>>
	/% roll 2d6 and add the stat %/
	<<set _roll to random(1,6) + random(1,6)>>
	<<set _rollstring to _roll + '+' + $args[0]>>
	<<set _roll to _roll + $args[0]>>
	/% check the result and set variables %/
	<<if _roll lt ((def $args[1])? $args[1] : 7)>>
		<<set _bad to true>>
	<<elseif _roll lt ((def $args[2])? $args[2] : 10)>>
		<<set _mixed to true>>
	<<else>>
		<<set _good to true>>
	<</if>>
<</silently>><</widget>>
1 Like