Ren'Py Stats

JamieSadistic

Well-Known Member
Dec 19, 2018
1,417
3,514
Hey guys. New dev here!
I've noticed that a lot of games here have stats that can be built up through the duration of the game. I was wondering if there was a certain script to achieve that and in which Renpy file would I go about adding said script?
I'm assuming it would probably go into the "Script.rpy" file but I'm probably mistaken.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
I've noticed that a lot of games here have stats that can be built up through the duration of the game.
I was wondering if there was a certain script to achieve that [...]

Not as such. Well, apart from the script your write yourself.
There are some really complicated ways to do things, but honestly most of those highly technical solutions are overkill for an Adult VN.

I'm assuming it would probably go into the "Script.rpy" file but I'm probably mistaken.

You're not wrong.
In fairness, RenPy doesn't care what the files are called that contain your code. As long as the filename ends in .rpy - RenPy will look there for code.

But again, for simplicity's sake, it makes sense to use the script.rpy file as your starting point.

For each stat, you'll need a variable, a way of changing it's value and a way of checking it's current value to make a decision for your game.

To create a variable, you'll need default. default merely creates a variable and assigns it it's initial value. The default statement is processed as the game is starting and so it doesn't matter where in the code the line exists. That said, the usual convention is to put all the default statements together at or near the top of your script.

To alter the value of a stat variable, you'll need to do some sort of math on it. In most circumstances of an AVN game, that's adding 1 or removing 1 from variable. Though you can do anything you like, add, subtract, multiply, divide, modulus, exponentials, cosine, whatever.

To keep things simple right now, lets simply say that :
  • $ myvar1 += 1 adds 1 to a variable called myvar1.
  • $ myvar1 -= 2 subtracts 2 from the variable myvar1.
  • $ myvar1 = 3 sets the value of myvar1 to be 3. Doesn't matter what it's value used to be, it's 3 now.
The $ is RenPy short form for "do python command". It can also be written as python:. Don't overthink it... it's just the way RenPy does it.

Finally there's altering what your game does based on the current value of a variable or lots of variables.

The usual checks would use one of these:
  • == - check if two values are equal.
  • != - check if two values are NOT equal.
  • > - check if the first value is greater than the second value.
  • < - check if the first value is less than the second value.
  • >= - check if the first value is greater OR EQUAL to the second value.
  • <= - check if the first value is less OR EQUAL to the second value.
The most common checks should probably be ==, >= and <=.

On top of those, you can also mix and match combinations of all those by adding qualifiers like and, or and not.

At the heart of this is one simple rule... the code is checking to see "if something is true". That something can be as simple as myvar1 >= 3 or as complicated as ((myvar1 >= 3) and (dresscolor == "red") and (hour > 21)) or cheating_enabled == True.

Read more about these symbols, etc. at:


So a practical example...
Including some of what I've talked about and some stuff I haven't...

Python:
default helen_love = 4
default helen_hate = 0
default sarah_love = 0
default sarah_hate = 1

default mc_name = "Unnamed"

define narrator = Character("", what_color="#FFFF00")
define mc = Character("[mc_name]")
define h = Character("Helen", color="#04B486")
define s = Character("Sarah", color="#F781F3")


label start:

    scene black with fade

    $ mc_name = renpy.input("What is your name? {i}(Press ENTER for 'Tony'){/i}")
    $ mc_name = mc_name.strip() or "Tony"


label repeat_the_menu:

    menu:
        "Increase [h]'s Love":
            $ helen_love += 1
      
        "Decrease [h]'s Love":
            $ helen_love -= 1

        "Increase [h]'s Hate":
            $ helen_hate += 1
      
        "Decrease [h]'s Hate":
            $ helen_hate -= 1

        "Increase [s]'s Love":
            $ sarah_love += 1
      
        "Decrease [s]'s Love":
            $ sarah_love -= 1

        "Increase [s]'s Hate":
            $ sarah_hate += 1
      
        "Decrease [s]'s Hate":
            $ sarah_hate -= 1

        "Finished"
            jump compare_helen_and_sarah

    "[h] Love=[helen_love], Hate=[helen_hate]. [s] Love=[sarah_love], Hate=[sarah_hate]."
    jump repeat_the_menu


label compare_helen_and_sarah:

    if helen_love == sarah_love:
        jump picked_nobody

    if helen_love > sarah_love:
        jump picked_helen

    jump picked_sarah


label picked_sarah:

    mc "So, I think [s] is the girl for me."
    if sarah_hate >= 4:
        s "Fuck off, [mc]."
    else:
        s "Oh, [mc]. You're wonderful. Let's go have lots of babies"

    jump the_end


label picked_helen:

    mc "So, I think [h] is the girl for me."
    if helen_hate >= 4:
        h "Fuck off, [mc]."
    else:
        h "Oh, [mc]. You're wonderful. Let's go have lots of babies"

    jump the_end


label picked_nobody:

    mc "I can't make my mind up."
    "[mc] lived a sad and lonely life, having never really been willing to make hard choices when they were needed."
    jump the_end


label the_end:

    "Thanks for playing my game. Goodbye."

    return

I tend to use the Character variables instead of their names in dialogue, because it means I can change their names at any point I want. Or expand the game to allow the player to pick all the significant character names themselves. It's probably overkill for this example. But I wanted to show some things that are possible.

Edit: Something I meant to add... Be careful when considering stats. It's very easy to just +1 or -1 any time that makes sense to a decision by the player. But as a developer you need to consider what happens when the game DOESN'T follow the "sexy route".

It's so easy to write code like if becky_affection >= 9:, but you need to give serious thought about those players who score below 9. Lots of games tend to follow a "content" -vs- "no content" path. Where if the player doesn't make the right choices, then the player sees nothing. But where's the fun in that?

Additionally, be very careful of making decisions based on the maximum value a number COULD be. Again, it's easy to code something like if yasmine_horniness >= 6. But if that 6 is the best value a player could have scored by that point in the game... what about all those players who made a single mistake? Who picked 1 or 2 "wrong" choices?

Stats systems done without thought can just end up with people who NEED a full walkthrough just to play your game. Sometimes you have to find ways to reward players who don't take the "perfect" route.

Edit2: I added the "picked_nobody" code at the last moment. But added it in the wrong place. Fixed that now. Also added an extra jump to make it less likely a fuckup like that should happen by accident.

Edit3: 2 Typos in the narrator definition. Changed color="#00FFFF" to what_color="#FFFF00". (It makes any non-character speech appear in yellow rather than the default color. It's a tiny change, but a nice refinement).
 
Last edited:

JamieSadistic

Well-Known Member
Dec 19, 2018
1,417
3,514
Not as such. Well, apart from the script your write yourself.
There are some really complicated ways to do things, but honestly most of those highly technical solutions are overkill for an Adult VN.




You're not wrong.
In fairness, RenPy doesn't care what the files are called that contain your code. As long as the filename ends in .rpy - RenPy will look there for code.

But again, for simplicity's sake, it makes sense to use the script.rpy file as your starting point.

For each stat, you'll need a variable, a way of changing it's value and a way of checking it's current value to make a decision for your game.

To create a variable, you'll need default. default merely creates a variable and assigns it it's initial value. The default statement is processed as the game is starting and so it doesn't matter where in the code the line exists. That said, the usual convention is to put all the default statements together at or near the top of your script.

To alter the value of a stat variable, you'll need to do some sort of math on it. In most circumstances of an AVN game, that's adding 1 or removing 1 from variable. Though you can do anything you like, add, subtract, multiply, divide, modulus, exponentials, cosine, whatever.

To keep things simple right now, lets simply say that :
  • $ myvar1 += 1 adds 1 to a variable called myvar1.
  • $ myvar1 -= 2 subtracts 2 from the variable myvar1.
  • $ myvar1 = 3 sets the value of myvar1 to be 3. Doesn't matter what it's value used to be, it's 3 now.
The $ is RenPy short form for "do python command". It can also be written as python:. Don't overthink it... it's just the way RenPy does it.

Finally there's altering what your game does based on the current value of a variable or lots of variables.

The usual checks would use one of these:
  • == - check if two values are equal.
  • != - check if two values are NOT equal.
  • > - check if the first value is greater than the second value.
  • < - check if the first value is less than the second value.
  • >= - check if the first value is greater OR EQUAL to the second value.
  • <= - check if the first value is less OR EQUAL to the second value.
The most common checks should probably be ==, >= and <=.

On top of those, you can also mix and match combinations of all those by adding qualifiers like and, or and not.

At the heart of this is one simple rule... the code is checking to see "if something is true". That something can be as simple as myvar1 >= 3 or as complicated as ((myvar1 >=3) and (dresscolor = "red") and (hour >21)) or cheating_enabled == True.

Read more about these symbols, etc. at:


So a practical example...
Including some of what I've talked about and some stuff I haven't...

Python:
default helen_love = 4
default helen_hate = 0
default sarah_love = 0
default sarah_hate = 1

default mc_name = "Unnamed"

define narrator = Character("", color="#00FFFF")
define mc = Character("[mc_name]")
define h = Character("Helen", color="#04B486")
define s = Character("Sarah", color="#F781F3")


label start:

    scene black with fade

    $ mc_name = renpy.input("What is your name? {i}(Press ENTER for 'Tony'){/i}")
    $ mc_name = mc_name.strip() or "Tony"


label repeat_the_menu:

    menu:
        "Increase [h]'s Love":
            $ helen_love += 1
          
        "Decrease [h]'s Love":
            $ helen_love -= 1

        "Increase [h]'s Hate":
            $ helen_hate += 1
          
        "Decrease [h]'s Hate":
            $ helen_hate -= 1

        "Increase [s]'s Love":
            $ sarah_love += 1
          
        "Decrease [s]'s Love":
            $ sarah_love -= 1

        "Increase [s]'s Hate":
            $ sarah_hate += 1
          
        "Decrease [s]'s Hate":
            $ sarah_hate -= 1

        "Finished"
            jump compare_helen_and_sarah

    "[h] Love=[helen_love], Hate=[helen_hate]. [s] Love=[sarah_love], Hate=[sarah_hate]."
    jump repeat_the_menu


label compare_helen_and_sarah:

    if helen_love == sarah_love:
        jump picked_nobody

    if helen_love > sarah_love:
        jump picked_helen


label picked_nobody:

    mc "I can't make my mind up."
    "[mc] lived a sad and lonely life, having never really been willing to make hard choices when they were needed."
    jump the_end


label picked_sarah:

    mc "So, I think [s] is the girl for me."
    if sarah_hate >= 4:
        s "Fuck off, [mc]."
    else:
        s "Oh, [mc]. You're wonderful. Let's go have lots of babies"

    jump the_end


label picked_helen:

    mc "So, I think [h] is the girl for me."
    if helen_hate >= 4:
        h "Fuck off, [mc]."
    else:
        h "Oh, [mc]. You're wonderful. Let's go have lots of babies"

    jump the_end


label the_end:

    "Thanks for playing my game. Goodbye."
  
    return

I tend to use the Character variables instead of their names in dialogue, because it means I can change their names at any point I want. Or expand the game to allow the player to pick all the significant character names themselves. It's probably overkill for this example. But I wanted to show some things that are possible.
You are a godsend, my friend. You answered exactly what I needed and you even gave me way more than I asked. You're a value to this community without a doubt.
I've read a lot of different tutorials here and there but a lot of it didn't make sense to me. The way you explained it caused the information to click, so I thank you. I will also most definitely be bookmarking this post along with all of your signature links.