Storylet DSL nerdery

EDIT: I suppose this is technically off-topic for this thread, since I have no DSL nerdery to offer. Mea culpa.


I have been invoked!

Storylets coming natively to SugarCube are largely a product of urging by @Chapel . He’s also informed the design, along with a few other interested parties.

They weren’t on my radar for inclusion until Chapel suggested them, because IMO they’re simply an event system with a fruity nomenclature.

The design isn’t entirely settled yet, so anything I mention which is specific to native SugarCube storylets is subject to change.

 

Assuming that I decide to pull the trigger on the in-passage storylet definitions feature, that’s how SugarCube’s implementation will work, though it does come with some requirements. The current idea is that such passages:

  • Are processed only once at startup.
  • Must be appropriately tagged. I’m not entirely sure what with though. A storylet tag seems like a natural fit, but it’s in consideration to denote external definition passages (see below).
  • Must use the <<storylet>> macro, at the top of the passage, to define the storylet’s details.
  • Must not attempt to specify the associated content passage—because that’s the current passage.
  • Must contain the actual text content of the storylet—empty storylets are disallowed.

Storylets are definitely going to be able to be defined external to their content passages, within special passages—e.g., by special name (StoryInit) or special tag (storylet). It’s a bit more versatile, as you can use either the macro or the base API to define storylets, and has better separation of concerns, so you’re not repeating yourself.

 

Yes. Doing full text scans to find in-passage definitions, and parsing them, across the entire regular passage store is not to be done lightly. It’s something best done once during startup.

Further, needing to ignore the definitions themselves, whatever form they take, later during play is also suboptimal.

 

SugarCube’s native storylets will handle this by using TwineScript conditionals that users are already familiar with—by request, it also allows functions. That said, it does pre-compile each conditional into a callable function for efficiency’s sake.


Here’s a really basic overview of the current design of the two definition macros. Again, subject to change.

Macro: <<storylet>>

Registers passages, listed by their names, as a storylet. You can define the storylet’s conditions, priority, and weight via its child tags.

<<storylet [passageList]>>
	[<<cond conditional>>]
	[<<func function>>]
	[<<groups groupList>>]
	[<<unique>>]
	[<<priority expression>>]
	[<<weight expression>>]
<</storylet>>

A storylet’s passage list associates the definition with the given passages.

A storylet’s conditions—defined via its <<cond>>, <<func>>, <<groups>>, or <<unique>> children—are tested whenever storylets are requested to determine if it is available to be chosen. All of its conditions must yield a truthy result for it to be considered available.

A storylet’s priority—defined via its <<priority>> child—is its relative importance compared to other storylets. When checking availability, only storylets with a priority equal to the highest priority seen during that check are yielded.

A storylet’s weight—defined via its <<weight>> child—is its chance of being randomly selected. When calling for a random storylet, a higher weight increases a storylet’s chance to be chosen.

Macro: <<condgroup>>

Condition groups are named lists of conditions that can be added to any storylet by referencing the group’s name. When referenced, a group’s conditions are added to the storylet when checking for availability as though they were its own.

The special group name :all automatically applies to all storylets.

<<condgroup groupName>>
	[<<cond conditional>>]
	[<<func function>>]
	[<<unique>>]
<</condgroup>>
3 Likes