Storylets in Ren'Py

I’m considering making a work using Ren’Py, but I’d like to get a better grasp on what is possible before investing a lot of time in the development system and discovering it won’t do what I want it to do.

What I want to know is how well it supports storylets, which for my purposes are story snippets that don’t have to occur in each playthrough. Specifically, I’m wondering if it would be possible to implement the structure sometimes called beads on a string or, as Emily Short calls it, branch and bottleneck.

And if it is possible to create such a story structure and you happen to know of instructions or sample code that would give me some idea of how to do so, I’d be grateful if you posted a link.

1 Like

I’ve only dabbled in Ren’py, but I’m pretty sure you can make multiple paths and conversations that branch and bottleneck. Hubs are a good story structure.

You mention storylets so it sounds like you’re also wanting some random chance to come into play to vary the text? I’m sure this is possible in Ren’Py (Doki had so much random stuff) but you have to get into the scripting language I would reckon.

If you’re not committed to Ren’Py, you might want to also check out Elm Story which is still in development. I assume if you’re looking at Ren’Py you want VN style character portraits, and the paradigm is building lots of discreet game and conversation structures and hooking them together.

What I like is you can have a choice lead to multiple passages, and it will pick one randomly. Paths between text and choice nodes is where you can place conditions that disqualify, require, or weight the chance of choosing that path based on variables, and also tweak variables as the player traverses that path.

2 Likes

Thank you for the help and for suggesting Elm Story. I’d been curious about it, and now it looks like I have another reason to check it out!

1 Like

Ren’Py can definitely branch-and-bottleneck. Unless otherwise specified, every code snippet below should be at the same number of tabs as whatever was above it. Also note that my instructions are for Ren’Py 7 - the ones for Ren’Py 8 may be the same, or they may be slightly different. Some of this may seem really basic, but each step is being built upon.

To directly send a player to a scene:
label blobpart

(content)

scene othersplatpart

If you’re wanting to bottleneck from several branches, simply make sure every scene you wish to bottleneck ends with the same scene as “othersplatpart”, and then have a section that starts with “label othersplatpart”.

To branch by choice:
menu:

[tab] Choice 1:

[2x tabs] Consequences of choice 1, usually ending in a scene command as discussed above

[tab] Choice 2:

[2x tabs] Consequences of choice 2, usually ending in a scene command as discussed above

(the next bit should go back to the same number of tabs as the "menu:" command).
To branch by quality / skill / attribute / event flag / other thing set by a specific other event

At the beginning, you need:

default gloop = False
default points = 0 default colour = Inapplicable`

Note that “something” can be True or False (useful for event flags), a number (useful if you’re planning to add, subtract or otherwise do maths on it) or letter(s) (handy if, for example, you’re using it to record a location).

There should be at least one opportunity to change that “default” if branches or bottlenecks will depend on this. Make that happen by doing one of the following:

$ gloop == True
$ gloop == False
$ points == 3
$ points += 2
$ points -= 1
$ colour == Green

Note that the dollar sign means this is a line of Python. After that is the name of the attribute affected. The first sign after the attribute name states what’s being done with it. Equals means “the attribute is”, + means “the attribute is being added to” and - means “the attribute is being taken away from”. The second equals tells the program… …something. Not sure what, but it’s compulsory. Also, letters are case-sensitive.

When you need it, you can use if-then statements to control the movement through the work:

if gloop == True:

[tab] $ points += 1

[tab] scene happyending

else:

[tab], scene nextscene

Make sure whatever comes next is written at the same tab level as “if:” or “else:”.

Note that it’s also possible to compare an attribute with a preferred target. Ren’Py uses “less than” and “more than”:

if points >= 5:

[tab] You return from the swamp to be greeted by jubilant villagers, and hold aloft you [colour] gloop in triumph. Within a year, your village has become a local centre for excellence in gloop searching because of the guidance you gave your fellow villagers on the topic.

elif points <= 2:

[tab] You briefly consider returning to your village, but you could really do with more gloop.

elif points == 5::

[tab] You return to your village with enough gloop to repair your neighbour's wall as well as your own. A fine friendship develops over the next few months, due to your habit of walking to the swamp every week to spot aesthetically pleasing examples.

else:

[tab] You have enough gloop to go home, fix that unsightly hole in your wall and enjoy a nice cup of tea by the fire.

In order to have something happen randomly:

$ randomnum = renpy.random.randint(1,4)

The “randint” part means only whole numbers can be selected. The numbers in the brackets are the smallest and largest numbers that can be randomly selected.

Later, you simply use “randomnum” as an attribute, as if it was the non-random “gloop” or “points” earlier.

How to make a menu choice only appear if certain choices are met:
menu:

[tab] Wade into the swamp again if points <=6:

[tab x2] Consequences of wading into the swamp again

[tab] Emerge triumphant if gloop == True:

[tab x2] Consequences of emerging triumphant

There are a few other pieces of code that would be useful to you, but it's possible to get some content not appearing on every playthrough just with these code snippets and the easier parts of the Ren'Py tutorial that comes with the Ren'Py download.  The [official documentation](https://www.renpy.org/doc/html/) has lots more bits of code to experiment with, and I'm happy to answer more specific questions.
2 Likes