Ren'Py Tutorial How-To have a dynamic story that react to player choices.

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,862
16,011
While Kinetic Novels are good, if you want to really interest your players, you need to involve them, at least a little, into your story. And the only way to achieve this is to offer them choice that really change the story.

There's nothing more uninteresting, than a game that don't care of your choices. The author offer you the possibility to spy at a girl while she shower, and being a nice guy (it's the first choice of the game), you decide to not do it. You're then sent to the breakfast scene, where you've the surprise to see the girl angry, because she know you spied on her...
Don't look at me, it's a real example that come from a real game available here. And it's far to be the only game like that, alas. You're presented some choice, but if you don't pick the right one, you'll be facing a story that make no sense.
It doesn't matter if the changes implied by your decision are small or big, as long as they exist and are shown in your game. If the player decide to not do something, then the characters should not react as if he did it. It's the basis, and we (players) shouldn't have to say it.

Then, once you've started to follow this path, why not go further, and make your game, and therefore the characters in it, have a long time memory of the decision made by the player ?
He decided to spy on the girl and she caught him ? Well, too bad for him, right. The girl didn't care this much, she have a crush for him, but she's the teasing type, and she'll remind him regularly that he's a pervert who spy at showering girls.
It will not change much to your story, but it will give it more depth. The characters aren't just puppets following a script, they have a memory and really act differently, depending of your action as player.

Achieving this isn't really difficult, and I'll now tell you what you need to know.



1) Keep track of the choices made by the player.

Each time a choice is significant to your story, the game need to remember it. It's because of this memory of the different choices made by the player, that you'll be able to present him a different content adapted to his decision.
While, globally speaking, this mean assigning a value to a variale, or altering the value of a variable, how you'll do it depend both of you and the choice itself. By example, you don't keep track of a relationship in the same way than you keep track of an inventory. And how you keep track of an inventory depend of how you want to handle the said inventory.

Note that it's recommended to use significant names for your variables, in order to easily remember what choice they handle, and at the opposed what variable store "this change".


a) The use of a counter value.
This method is generally used to keep track of the evolution of the player regarding a given subject. It can also be used to keep track of the number of time you did something particular.​
You don't have permission to view the spoiler content. Log in or register now.


b) The use of a balance value.

This is a variation of the counter value, but will the counter generally have a value that goes from 0 to whatever, here the value can be negative. It's generally used to keep track of the player behavior, in order to tweak his personality and make the game react accordingly to this.​
You don't have permission to view the spoiler content. Log in or register now.



c) The use of a simple Boolean value ; AKA "flag".

This method is generally used to remember of one time events.​
You don't have permission to view the spoiler content. Log in or register now.


It can also be used for event that happen more than once, but this time it's really significant for the story.​
You don't have permission to view the spoiler content. Log in or register now.



d) The use of a semaphore.

A semaphore is a variation around Boolean value. You use them when the choice isn't limited to a Yes/No situation.​
You don't have permission to view the spoiler content. Log in or register now.

Note that you can also use integers to represente the choice. In this case you would use giftForTheDate = 1 or giftForTheDate = 2. But this is obviously less easy to use, because you've to remember what thie 1 or 2 value represent.​


e) The use of an inventory list.

This is generally used to handle inventories, but it can come handy for some other situations.​
You don't have permission to view the spoiler content. Log in or register now.

Note that I used string as value, but you can also use objects that will describe the item. It's just that this goes beyond the scope of this How-To.​




2) Change the game flow accordingly to the choices made by the player.

Knowing what the player chose have no interest if you can't make the game react differently, accordingly to them. And the main difference that a choice imply, is the scene that you'll see "now".
Basically speaking, the scene you'll present now will depend of the value store by a variable. Therefore, you'll have to test this variable, then decide where the game have to go next, depend of its value. But how you'll do this test depend of the kind of value you'll have to deal with.

Note that I'll use a basic jump branching in my examples, but the branching can be done in many other way. In the same way, I'll only use if structures for the test, while there's some other methods that can possibly be used. But the scope of this How-To is to present the different ways to deal with story branching, not the different ways to branch to a label or to perform multiple test.



a) A simple flag.

It's the most basic test, either the player made the choice, or he didn't. This mean that you have only two possibles outcome, with one that will be "by default".​
You don't have permission to view the spoiler content. Log in or register now.



b) A semaphore.

Here, the test become a little more complicated, because it's not anymore a basic binary situation. You'll have to test each values, and branch depending of it. Worse, it's a situation where there's no default choice.​

You don't have permission to view the spoiler content. Log in or register now.



c) A counter value.

Like for the semaphore, you're facing more than a possible outcome, but unlike the semaphore, you can't test each value individually. Well, you can, but it would make no sense, since more than one value would lead to the same result. Therefore, to deal with a counter value, you generally define different ranges, that all lead to the same outcome.​
Once you've those range, you test them increasingly. But there's a trap, the very first range should be the last one tested. Or more precisely, it should be seen as the default possibility ; what will happen if every all test are negative.​

You don't have permission to view the spoiler content. Log in or register now.



d) A balance value.

You deal with them in the same way than counter values, but you've to remember that there's possibly negative values. This mean that there's generally no default value in this case.​

You don't have permission to view the spoiler content. Log in or register now.



e) An inventory list.

The case of an inventory list, is generally near to the one of a flag or a semaphore, because not all the possible value in the list matter at a given time. Yet, list are tested in a particular way, so I'll still present an example.​

You don't have permission to view the spoiler content. Log in or register now.





3) Offer choice in accord with the choices previously made by the player.

Another way for the game to react to player choices is to open, or close, opportunities depending of them. And by chance, Ren'Py menu offer you the possibility to do this really easily. Indeed, it permit you to condition the presence of a menu to the result of a test.
Like those test are exactly the same that for the branching, I'll no just present one example. But obviously, the way to write the test still depend of the type of value you'll have to deal with at this moment.
You don't have permission to view the spoiler content. Log in or register now.

Note that, unlike with branching, here the differents options aren't mutually excluding. The higher will be the value of girlLove, the more options will be offered to the player. If you want to have more exclusive choices, you'll need to use interval test in place of the regular ones.
You don't have permission to view the spoiler content. Log in or register now.
Here, it will be either the invitation for a coffee date, or the invitation to a dinner date.



4) Tweak the scene depending of the choices made by the player.

Another way to make a story react to the player choice is to tweak a scene. It's not something big, generally just a dialog line added, or changed, here and there. But having the other characters remembering of the previous interactions, especially when they are optional, is always an interesting plus for your story.
You don't have permission to view the spoiler content. Log in or register now.


5) Tweak the visual part depending of the choices made by the player.

It's probably the most significant adaptation, after the possibility to see a scene or not, that can depend of the player choices. What he'll see will depend of the choices he previously made. Generally, this is badly done, the author doing a copy/past of the scene, then change the images that will be shown. While it works, this present many drawbacks.
Firstly, it imply more works for the author, both when making the game, and while correcting it ; you've to remember to report the correction to all the variation of the scene. Secondly, it open the gate for bugs (twice more CG name to write mean twice more opportunitie to make a typo), and it complicte the testing, since you've to test all the variation of the scene. Thirdly, it break the skip feature ; the player will have to manually pass the whole scene again, just because this time the CG are, sometimes siglthly, different.

You can do this change by using a variation of the preceding point. Instead of changing a dialog line, you change the image shown.
You don't have permission to view the spoiler content. Log in or register now.

But there's a more interesting way to do this and, it will be the exception that confirm the rule, for once I'll go further than the basic approach. The scene statement have a expression property that permit you to dynamically built the name of the image to show.

You don't have permission to view the spoiler content. Log in or register now.
Each scene will build the name image accordingly to the value of the swimwearStyle variable. This mean that the first image will be either beach01bikini, beach01sexy or beach01onepiece, while the second image will be either beach02bikini, beach02sexy or beach02onepiece.
This while be exactly the same than something like this:
You don't have permission to view the spoiler content. Log in or register now.
Except that you don't have to have three version of the same scene. Therefore, there less risk of typo. If you have a correction to make, you'll make it only once. And if the player choose the traditional swimsuit in one play, and the sexy bikini in another, he'll be able to skip the scene the second time.



5) Conclusion.

By just following this How-To, you would already be able to offer a story that will stick more closely to the player choices, and this is something that your players will appreciate. But, as I said, this is a basic introduction. Ren'Py being an engine that offer many opportunities, there's way more than can be done, and everything I presented here can be done with even more dynamism. Therefore, don't hesitate to tweak the solution I presented here, and to test on your own.


Edit: Fixed the issues with the formatting of the code.
 
Last edited:

Lou111

Active Member
Jun 2, 2018
541
685
I love refresher courses! Thanks for taking the time to write this and I hope your knees get well soon!
I've gotta implement scene expression in my code. Your example made that very clear to me.

This is a must-read for anyone starting out.
However, it doesn't matter what stage the developer is at, I can 100% guarantee they have no idea what the word "semaphore" means. (It doesn't mean you're half-way through your second year in college)
 
  • Like
Reactions: 666dudeguy69

gojira667

Member
Sep 9, 2019
315
308
c) A counter value.
...
You don't have permission to view the spoiler content. Log in or register now.
The girlLove tests here need to be done in reverse order for how they are written. E.G. $ girlLove = 17 will still jump someLabel.

You don't have permission to view the spoiler content. Log in or register now.
I know it's implied, but perhaps add the explicit jumps to which label depending on swimwearStyle or a pseudo-code line to that effect.

Also, I agree that scene expression is pretty slick.
 
Last edited:
  • Like
Reactions: Lou111

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,862
16,011
The girlLove tests here need to be done in reverse order for how they are written.
Yeah, I saw that, and the many engrish parts :(
I'll wait that the medicine stop making me see flying pink elephants, and I'll edit it into something less messy.
 
  • Haha
Reactions: osanaiko

Rich

Old Fart
Modder
Donor
Respected User
Game Developer
Jun 25, 2017
2,556
7,346
I'll wait that the medicine stop making me see flying pink elephants, and I'll edit it into something less messy.
LOL

In your "simple flag," it's more "Pythonic" to do
Code:
if ownComputer:
than
Code:
if ownComputer is True:
While "is True" is going to work perfectly, it will lead people astray in the reverse case, because
Code:
if ownComputer is False:
will NOT succeed if you've set your default to None and never explicitly changed the value to False. On the other hand
Code:
if not ownComputer:
will succeed in either the False or None cases, since both are "falsey".

I'm sure you know all that, but the newbies that use your (very well written) examples could be led astray, so why not give them the version that is least likely to make they say "WTF?" Thus, if you updated your example to show
Code:
if ownComputer:
   do something if you own a computer
and
Code:
if not ownComputer:
   do something if you don't own a computer
and
Code:
if ownComputer:
    do something
else:
    do something else
I think you'd be leading them down the righteous path...
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,862
16,011
I think you'd be leading them down the righteous path...
Yeah, I blame the flying pink elephants for that, and also the fact that it was the middle of the night ;)

I'll make this less ambiguous in the rewrite, and I'll also probably be a little more technical. After all, expression isn't limited to scene, and adding to the concept an overview of the different options would be interesting. Seeing what it possible could lead some readers to have new ideas.
 

LuluVixen

New Member
Oct 11, 2021
1
0
Hey this is awesome, and it couldn't have come at a better time for me too! Thanks for being so detailed, a lot of the tuts online that talk about Renpy coding in the context of visual novels don't really go much into depth when it comes to coding in branching storylines/choices and making the game have a "memory" of those choices so to speak, so this is a really good jumping off point for me.

There's just something about having a character in a game remember how you treated them in the past that satisfies me and makes me want to recreate that feeling for myself. Thank you!
 
Sep 4, 2020
91
47
For more advanced takes on this topic, look at the Authoring/Resources/Theory and Practice section at intfiction.org. There's at least one doctoral dissertation (no, really) and other deep dives into game design. Some of the higher-level conceptual analyses are fascinating reading, delving into network and graph theory (I recommend reading "Standard Patterns in Choice-based Games"). Once you can visualize what sort of network of nodes your game is going to be (time cave? gauntlet? sorting hat?), then the programming tends to suggest itself.
 

pontiffprick

Newbie
Jun 23, 2020
48
393
For more advanced takes on this topic, look at the Authoring/Resources/Theory and Practice section at intfiction.org. There's at least one doctoral dissertation (no, really) and other deep dives into game design. Some of the higher-level conceptual analyses are fascinating reading, delving into network and graph theory (I recommend reading "Standard Patterns in Choice-based Games"). Once you can visualize what sort of network of nodes your game is going to be (time cave? gauntlet? sorting hat?), then the programming tends to suggest itself.
Really useful site, thanks for the rec
 

DoctorPervic

Well-Known Member
Game Developer
Aug 13, 2019
1,079
4,424
Is there a variable that you can set in game at the start for example you want to have two paths. One you are a strait guy the other you are bisexual

So in the variable you would have a yes or no

then in the scene code you would put something to tell renpy to show the bisex scene instead of regular scene if the player chose bisex path?

Thanks
 
Last edited:

DoctorPervic

Well-Known Member
Game Developer
Aug 13, 2019
1,079
4,424
I figured it out, if anyone wants to know it is this.

put this as your choice
Code:
    menu:
        v "Please Chose If You Want To Be Bisexual In The Game, This Means You Will Have Regular Sex Plus Gay Sex And With DickGirls. If You Chose No, Then You Will Only Have Male On Female Sex."
        "Yes, I want Bisex, Gay sex, DickGirl sex":
            $ BisexRout="Yes"
            v "[BisexRout]"
        "No, I only want Male on Female sex":
            $ BisexRout="No"
            v "[BisexRout]"
then when you want the option in your game to show bisex content you put
Code:
if BisexRout=="yes":
    youi "Oh, look, im bisexual."
if BisexRout=="no":
    youi "Oh, look, im not bisexual."
 
  • Like
Reactions: FranceToast

HiEv

Member
Sep 1, 2017
384
783
If you're interested, there was a related discussion over at the (Interactive Fiction) forums, though it had a bit more Twine-based slant. However, most of the tips and discussion should be relevant here as well.

See:

A lot of it is not only about how to make your game react to player choices, but also how to make sure that the player realizes that their choices actually matter, so that they don't mistakenly feel like the game is too linear or "on rails".
 
  • Like
Reactions: gojira667
Sep 4, 2020
91
47
I saw a talk online (recorded for YouTube) in which the developer talked about "choices" and "branches". A "choice", by their definition, was a option that had no impact on the story other than minor dialog fluctuations.

"Do you order a large coffee or a latte while waiting for Beau to show up?"

[She was part of a company writing dating games for teen girls.] The choice might alter the dialog with Beau later ("Oh, I think I'll order a [her earlier choice] too!") which might seem impactful ("Oh wow, I got lucky and ordered his favorite drink") but really isn't.

A "branch" changes the plot. It opens certain paths closes off others, and alters the ending (obviously).

Interestingly, their data suggested that "choices" matter more than "branches", as a steady drumbeat of choices keeps the player engaged, but since replays are relatively few, more people don't explore branches. They pick the branch consistent with their personal preferences, and stick with that.

Now we're talking about teen girl dating games here. A girl who is repelled by jocks in Real Life is never going to take that branch, and will always pick the nerdy guy when that early game branch is presented ("Do you flirt with football quarterback Beau or do you help Emmett pick up the books he dropped when Beau tripped him?"). Few players, according to their data, went back and played the other branch.

It might be different with the games here, since part of the game is to unlock all the naughty pictures. Which has me thinking... is Twine or any choice-based system the right one for this sort of game?

[More in the next post]
 
  • Like
Reactions: coijga
Sep 4, 2020
91
47
[Thoughts flowing from the last post, where the notion of "branch" and "choice" are described]

OK, so if Twine and other branch/choice-based game systems are rarely played multiple times, are they the right platform for a naughty VN where the goal is to unlock all the gallery pictures?

Any given path only unlocks are portion of the total. Since a "branch" (see the previous post) closes certain paths, you can't unlock all the pictures on any single playthrough. You have to start at the beginning and select a different set of branches. And then again. And then again. Each playthrough unlocks a few more pictures, most of the pictures being the same. So playthrough 1 unlocks 20 pictures. Playthrough 2 unlocks 8 new pictures (total of 22 pictures, with 14 of the same pictures as the first playthrough). Playthrough 3 unlocks only 2 new pictures (you changed a late-game branch in this case).

Playthroughs have diminishing returns in terms of the rewards. So yeah, I can imagine repeat plays are relatively rare. I know I don't repeat play, at least not immediately. I will replay only after a significant break.

An alternate game platform is TADS. This is the classic Infocom go-west/take-key/unlock-door model of game. I looked at TADS hard as a platform. It's really quite an impressive system. My problem with it is that it is old -- last official release was 2013. And the IDE software has glitches running under a current Windows OS. Unless someone starts maintaining it again, the TADS IDE is going to continue to degrade. Maybe there's an alternate modern IDE for TADS, but I didn't find one.

With TADS-like games, there are no branches or choices, but puzzles. For a naughty game, that would be something like catching a peek of the girl in her bedroom. In a Twine/Ren'Py game, you're given the choice of "Peek" or "Don't peek" -- the choice is stark (and usually obvious -- peek of course!). In a TADS-game, the task is to use a ladder to see in the bedroom through the window -- but the ladder is in the garage, and your older brother is working on his muscle car in there every night, and you need to distract him, but for that you need to get his girlfriend to call him, and for that you need to get her number, and so on.

There are no branches or choices, just a blocked-off section of the gamespace that becomes available when you line up the puzzle solution elements successfully. That blocked-off section doesn't go away. You can focus on a school puzzle for a while and later, when you figure out how to distract your brother so you can get the ladder and so on, you will get to peek, and that thread will advance (more accurately, new gamespaces are unblocked).

There might be bad endings, but by and large, you don't replay a TADS game. You backtrack to previously visited locations to see if you missed something, or play with your inventory to discover combinations of items that can solve a puzzle. Within the same playthrough, you eventually hit all the markers.

[Of course, you can build a TADS-like experience with Twine/Ren'Py, but that's not what the solutions were designed for. As such, the programmer has to do a lot of heavy lifting, while doing a CYOA game just works out of the box.]

[And yes, you can save-scum your way into exploring all the branches. But two points on that. First, it's called "scumming" for a reason. It's not bad like kicking puppies is bad, but it is runs counter to the notion that choices matter. And second, it requires work. "Which save is the save that had that branch on it? Dammit, I lost track!" and the classic "Dammit, I should have saved there!" Or you can be lazy, and just download the walkthrough.]
 
Last edited:
  • Thinking Face
Reactions: sakosux

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,862
16,011
I saw a talk online (recorded for YouTube) in which the developer talked about "choices" and "branches".
Ok, so, how do you implement this in Ren'Py ? Because, after all, it's the main goal of this thread: Explaining how to handle story branching in Ren'Py.


Not that I care this much, but authors that don't use Ren'Py would also benefit from this kind of information... but never read this thread.
Side note: The rewrite is in progress, but actually my priority is to finish the port of my tools/helpers to Python 3.x since the branch 8.x of Ren'Py will now come really soon.
 
Sep 4, 2020
91
47
Ok, so, how do you implement this in Ren'Py ? Because, after all, it's the main goal of this thread: Explaining how to handle story branching in Ren'Py.


Not that I care this much, but authors that don't use Ren'Py would also benefit from this kind of information... but never read this thread.
Side note: The rewrite is in progress, but actually my priority is to finish the port of my tools/helpers to Python 3.x since the branch 8.x of Ren'Py will now come really soon.

Gosh, I don't really know. I don't use Ren'Py, and I'm not a Python programmer (not being good with Python is why I don't use Ren'Py). Just that the question got me thinking at a meta-level about game models and how they handle state. And then from there, how costly is it to explore different game states -- and how the cost of that impacts the playability of the game.

In CYOA, choices define available paths. You can't (normally) jump onto another path without going back to play that choice again. In TADS-like games, it's not about paths but about unlocking "rooms" (what I called a gamespace). The path, such as it is, is really the accessible gamespaces that hold the clues and props required to unlock a subsequent gamespace, with the game being the effort to assemble the right combination to unlock it. And then using the newly revealed elements to unlock the next one.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,862
16,011
Just that the question got me thinking at a meta-level about game models and how they handle state.
Then why don't you start a thread that will address the problem at meta-level ? It would have a better visibility and therefore what you'll say be seen by everyone who need/want to see it.
 
  • Like
Reactions: stevejackhammer

46n2

Member
Jun 29, 2021
391
1,105
Appreciate your efforts on this very much, AON (yourself and many others throughout these Forums, in fact).

I’m a Writer, now considering dipping my toes into this type of thing. Been farting around with some necessary components enough to recognize I might be willing - if not enjoy - the time required from all these various applications, to go ahead and bite into that apple. Just HOW MUCH is necessary would obviously be the largest deterrent. And I’m sure that’s extensive enough well beyond my current scope of comprehension.

So that’s where we tend to end, right?

“Let’s not leave the cave. There’s way to much out there to deal with.”

But then someone comes in, from Out There, and starts drawing pictures on the walls. So then you’ve got a greater comprehension of what you might be dealing with, beyond them.

At which point, we make a more informed… drum roll please… Choice ; )


Again, very much appreciate you squeezing some of these important elements into a scroll more readily digestible. Enough to know whether I can properly grasp it well enough to give it a go, eh.

Ya got me thinkin’ I might.

*cheers*