Hello All,
I've been rewriting an old Renpy game to learn the framework. I've decided to share some of the technical details of my work, so hopefully it'll be useful to someone. It was hard for me to find tutorials for the things I wanted to do. And if someone has an easier way to do the same thing, I would love to learn about it. This is meant more for amateur programmers, so more advanced developers probably won't find this interesting.
I'll start by saying that one of the most important aspects of development (in my opinion) is organization. Code should be easy to read and easy to navigate to reduce future development time fixing bugs and adding features. If you've poked around some of the codebases of some of the larger abandoned games, you'll realize how large and unwieldy some of the files are. One of the main reasons a game may be abandoned is due to the accumulation of what the software industry calls "technical debt". The game becomes too difficult or time consuming to change because of how bloated, hard to understand, or intertwined the current code is. It doesn't have to perfect, but spending extra time to organize your codebase by separating out features in smaller, digestible pieces will only help you in the long run if you want to add features or new routes down the line.
So back to the game development. Here's the structure of how the original game dealt with minor responsive dialogue in their game.
There's nothing wrong with the above code, and it's even the right solution for many scenarios, especially if the dialogue is key information. But it's annoying to do this over and over again for minor dialogue that has no real impact on the story, which is why most games don't bother.
Below is my scenario:
I have a system in the game called "status". The value of status can be either "Beta", "Alpha", or "Neutral". The status can change throughout the game based on the choices of the player.
For example, I want the mother of the player character to respond differently to in-game dialogue based on this player determined status. So I created a python function that will retrieve different text depending on that status.
The above example text is very specific to my project but can be easily modified to reflect another.
This function constructs a string that can then be used to retrieve a line of text stored in a variable. In the game, time progresses by day, so I have a different variable file for each day to keep it organized. "DayNr" is an int variable that increases whenever a day passes. "strId" is a string that will be passed in the function to identify which block of variables should be pulled from. And "status" is the same variable that was discussed before.
For this example, the line of text the mother is responding to is simply:
mc "I love you, Mom."
Again, the above example text is very specific to my project but can be easily modified to reflect another. It is kept in a separate file from the main script code so it's easily scannable.
In the above variables, the "5" comes from "DayNr". The "status" in the variable name shouldn't need to be explained again at this point. And the "mombrstresponse" is the "strId" being passed in the function. To more easily manage this system, I keep my script code and my flavor text variables in separate files. If modifying your flavor text variables, it is quite easy to split the screen in your IDE to show your script code next to a variable list.
So in the script code, this section of dialogue would appear like this:
But wait? I put the function as an inline expression in the dialogue? That is correct. A developer named Feniks created a script that allows this. It can be downloaded for free, but it's such a useful tool that I encourage you to donate a few dollars. It can be found
With the addition of other variable flags or conditions, you could make even more complex dialogue trees. The retrieve_response function could also be modified to accept additional parameters or have more internal logic. This will add varying degrees of complexity to your code, though, so it might be better to just separate out the script with if statements and labels in that case.
I have been able to use the same labels for multiple routes by carefully using this function once or twice in a section, though.
CAVEATS:
The above code is really only useful for more nuanced changes, or flavor text. I would never use this method to do anything major like determining path routing or delivering key story dialogue. It is NOT intended to completely replace "if" statements in the codebase. It has a very specific use case.
Again, it also relies on organization. I have my flavor text variables separated out into different files. If you try to put script code, functions, variables all together in one file, I could see this getting confusing real quick.
I would also not use this method for recurring dialogue. For ease of use, it should be used for one time scripted events and it would probably be best to never reuse the same "id" just to makes things easier for yourself. In my example, this wouldn't be a problem, because I have "DayNr" as a parameter that would make the variable names different, but I'm still using an "id" only once.
Despite the limitations, I still think it's a useful tool for the developer toolbox. Like in the above example, a character responding with "an eye roll" to an "I love you" gives a completely different vibe to a scene than if she reacted with a "smile and a touch on the arm". A lot of games don't feature a lot of minor responsive changes and I do think it's a value add to a project if used correctly.
-------
Okay, that's it. If anything above doesn't make sense or needs to be expanded, let me know. I'll try to address any questions.
And if you have a different solution for the same kind of feature, please let me know. I want to know what other people are doing.
I've been rewriting an old Renpy game to learn the framework. I've decided to share some of the technical details of my work, so hopefully it'll be useful to someone. It was hard for me to find tutorials for the things I wanted to do. And if someone has an easier way to do the same thing, I would love to learn about it. This is meant more for amateur programmers, so more advanced developers probably won't find this interesting.
I'll start by saying that one of the most important aspects of development (in my opinion) is organization. Code should be easy to read and easy to navigate to reduce future development time fixing bugs and adding features. If you've poked around some of the codebases of some of the larger abandoned games, you'll realize how large and unwieldy some of the files are. One of the main reasons a game may be abandoned is due to the accumulation of what the software industry calls "technical debt". The game becomes too difficult or time consuming to change because of how bloated, hard to understand, or intertwined the current code is. It doesn't have to perfect, but spending extra time to organize your codebase by separating out features in smaller, digestible pieces will only help you in the long run if you want to add features or new routes down the line.
So back to the game development. Here's the structure of how the original game dealt with minor responsive dialogue in their game.
You don't have permission to view the spoiler content.
Log in or register now.
There's nothing wrong with the above code, and it's even the right solution for many scenarios, especially if the dialogue is key information. But it's annoying to do this over and over again for minor dialogue that has no real impact on the story, which is why most games don't bother.
Below is my scenario:
I have a system in the game called "status". The value of status can be either "Beta", "Alpha", or "Neutral". The status can change throughout the game based on the choices of the player.
For example, I want the mother of the player character to respond differently to in-game dialogue based on this player determined status. So I created a python function that will retrieve different text depending on that status.
You don't have permission to view the spoiler content.
Log in or register now.
This function constructs a string that can then be used to retrieve a line of text stored in a variable. In the game, time progresses by day, so I have a different variable file for each day to keep it organized. "DayNr" is an int variable that increases whenever a day passes. "strId" is a string that will be passed in the function to identify which block of variables should be pulled from. And "status" is the same variable that was discussed before.
For this example, the line of text the mother is responding to is simply:
mc "I love you, Mom."
You don't have permission to view the spoiler content.
Log in or register now.
In the above variables, the "5" comes from "DayNr". The "status" in the variable name shouldn't need to be explained again at this point. And the "mombrstresponse" is the "strId" being passed in the function. To more easily manage this system, I keep my script code and my flavor text variables in separate files. If modifying your flavor text variables, it is quite easy to split the screen in your IDE to show your script code next to a variable list.
So in the script code, this section of dialogue would appear like this:
You don't have permission to view the spoiler content.
Log in or register now.
But wait? I put the function as an inline expression in the dialogue? That is correct. A developer named Feniks created a script that allows this. It can be downloaded for free, but it's such a useful tool that I encourage you to donate a few dollars. It can be found
You must be registered to see the links
. The above line of code will read and execute the function between the "<>" first and then the generated string will be used to retrieve a variable.With the addition of other variable flags or conditions, you could make even more complex dialogue trees. The retrieve_response function could also be modified to accept additional parameters or have more internal logic. This will add varying degrees of complexity to your code, though, so it might be better to just separate out the script with if statements and labels in that case.
I have been able to use the same labels for multiple routes by carefully using this function once or twice in a section, though.
You don't have permission to view the spoiler content.
Log in or register now.
CAVEATS:
The above code is really only useful for more nuanced changes, or flavor text. I would never use this method to do anything major like determining path routing or delivering key story dialogue. It is NOT intended to completely replace "if" statements in the codebase. It has a very specific use case.
Again, it also relies on organization. I have my flavor text variables separated out into different files. If you try to put script code, functions, variables all together in one file, I could see this getting confusing real quick.
I would also not use this method for recurring dialogue. For ease of use, it should be used for one time scripted events and it would probably be best to never reuse the same "id" just to makes things easier for yourself. In my example, this wouldn't be a problem, because I have "DayNr" as a parameter that would make the variable names different, but I'm still using an "id" only once.
Despite the limitations, I still think it's a useful tool for the developer toolbox. Like in the above example, a character responding with "an eye roll" to an "I love you" gives a completely different vibe to a scene than if she reacted with a "smile and a touch on the arm". A lot of games don't feature a lot of minor responsive changes and I do think it's a value add to a project if used correctly.
-------
Okay, that's it. If anything above doesn't make sense or needs to be expanded, let me know. I'll try to address any questions.
And if you have a different solution for the same kind of feature, please let me know. I want to know what other people are doing.
Last edited: