Ren'Py Display variables on a stats screen?

9thCrux

--Waifu maker--
Game Developer
Oct 22, 2017
844
3,232
Hello there,

I have been trying to design a stats screen for my game, I want to display the value of two variables per character on a stats screen:

So lets say we have a variable for friendship (1) and one for love (2).

Python:
#Character's friendship and love variables.
default Tiff1 = 100
default Tiff2 = 5

default Smi1 = 10
default Smi2 = 5

default Joa1 = 5
default Joa2 = 5

default Dar1 = 5
default Dar2 = 10
Then I want to display those values on a screen which has an specific background image:
stats_concept.png

I'm guessing I need to use screen language to do so...

Python:
screen stats:
    add "MyStatsScreenBackground.jpg"
    image button auto "MyCloseWindowButton_%s.png" xpos 1600 ypos 700 focus_mask True action Hide(stats)
And I want to use a key to show the stats screen:

Python:
init pyton:
    config.keymap['stats'] = "ctrl_K_s"
So players can use Ctrl+ S keys to show the stats screen... I think.

Well now the main question is how to display the variables, and how to display them on a specific area on the screen.
I want to use a grid to show the friendship values under the stars on the image, and the love values under the hearts on the image, the image is just a WIP by the way.
As far as I know I need to use a vbox with a grid value modifier to do something like that:

Python:
screen stats:
    vbox:
        grid 3 3:
            vbox:
                #display variables values

I need to learn how to display the variable's values and how to move them around on the stats screen to place them on the right spot on the background image.

Thanks for your help.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,234
[I'm in hurry, so I'll be short for once, don't hesitate to ask for more if needed]

Your stat screen is 9 times the same structure, so you can make a screen that will a screen that will be this structure :

Python:
# The part of the screen for each girl
# Parameter is the girl to works with
screen girlStat( girl ):

     # The main block for the data
     # No need to position it, it will be automatic
     # You have two row.
     hbox:

        # The first row is the portrait for this girl.
        # The effective names are Tiffportrait.png, Smiportrait.png, ...
        # The name is computed in real time, depending of the 
        # parameter given to the screen.
        add ( "images/stats/{}portrait.png".format( girl ) )

        # The second row is the values.    
        vbox:

            # The star, should be positionned
            add "gui/star.png"

            # Aerate a little, let 5 pixels
            null height 5

            # And the associated value
            # All variables are stored in an object named "store"
            # All variables can be addressed indirectly with
            # /getattr/. Build the name a the variable to get it
            # Here it's for Tiff1, Smi1, ...
            text ( "{}".format( getattr( store, girl + "1" ) ) )
            # If the values are in an object dedicated to this girl
            # use getattr( girl, "starValue" ) instead, assuming
            # that the objects are named 'Tiff', 'Smi', ...

            # Aerate a little, let 20 pixels this time
            null height 20

            # Repeat for the second value
            add "gui/hearth.png"

            # Aerate a little, let 5 pixels
            null height 5

            text ( "{}.format( getattr( store, girl + "2" ) ) )


# The main screen for the stats
screen stats():
   
    # The grid will position the data automatically.
    # I use a 6 entry example, because you gave only 4 
    # names, and I need to explain something regarding
    # /grid/
    grid 3 2:
       # Proceed for all the girls
       for g in [ "Tiff", "Smi", "Joa", "Dar", None, None ]:
          # Either you display the data for the girl
          if not g is None:
              # By adding the 'girStat' screen inside this one
              # passing it the name of the actual girl.
              use girlStat( g )

          # Or you display an empty entry.
          # This is needed because /grid/ expect to have the exact
          # Number of entry. So here you need to fill to 6, which is
          # the reason why there's the two /None/ at the end of the
          # list above.
          else:
              null witdh 1
Like I said, I'm in hurry, so I wrote it totally on the fly. But minus typo that I can have made, it should give you the expected result, including the positioning of each element, without the need to explicitly give them a position.
 

9thCrux

--Waifu maker--
Game Developer
Oct 22, 2017
844
3,232
[I'm in hurry, so I'll be short for once, don't hesitate to ask for more if needed]

Your stat screen is 9 times the same structure, so you can make a screen that will a screen that will be this structure :

Python:
# The part of the screen for each girl
# Parameter is the girl to works with
screen girlStat( girl ):

     # The main block for the data
     # No need to position it, it will be automatic
     # You have two row.
     hbox:

        # The first row is the portrait for this girl.
        # The effective names are Tiffportrait.png, Smiportrait.png, ...
        # The name is computed in real time, depending of the
        # parameter given to the screen.
        add ( "images/stats/{}portrait.png".format( girl ) )

        # The second row is the values. 
        vbox:

            # The star, should be positionned
            add "gui/star.png"

            # Aerate a little, let 5 pixels
            null height 5

            # And the associated value
            # All variables are stored in an object named "store"
            # All variables can be addressed indirectly with
            # /getattr/. Build the name a the variable to get it
            # Here it's for Tiff1, Smi1, ...
            text ( "{}".format( getattr( store, girl + "1" ) ) )
            # If the values are in an object dedicated to this girl
            # use getattr( girl, "starValue" ) instead, assuming
            # that the objects are named 'Tiff', 'Smi', ...

            # Aerate a little, let 20 pixels this time
            null height 20

            # Repeat for the second value
            add "gui/hearth.png"

            # Aerate a little, let 5 pixels
            null height 5

            text ( "{}.format( getattr( store, girl + "2" ) ) )


# The main screen for the stats
screen stats():

    # The grid will position the data automatically.
    # I use a 6 entry example, because you gave only 4
    # names, and I need to explain something regarding
    # /grid/
    grid 3 2:
       # Proceed for all the girls
       for g in [ "Tiff", "Smi", "Joa", "Dar", None, None ]:
          # Either you display the data for the girl
          if not g is None:
              # By adding the 'girStat' screen inside this one
              # passing it the name of the actual girl.
              use girlStat( g )

          # Or you display an empty entry.
          # This is needed because /grid/ expect to have the exact
          # Number of entry. So here you need to fill to 6, which is
          # the reason why there's the two /None/ at the end of the
          # list above.
          else:
              null witdh 1
Like I said, I'm in hurry, so I wrote it totally on the fly. But minus typo that I can have made, it should give you the expected result, including the positioning of each element, without the need to explicitly give them a position.

I will have to look closer to this code, is setup in a different way that what I had in mind.
Seems better than my idea because I can even add new girls later on without having to re-make the whole background image; the background image I have has the stars and hearts fixed in one place, they're part of the image.

Thanks for taking the time to answer. :giggle:
 
Last edited:

Bad Buster

Newbie
Oct 27, 2022
18
78
[I'm in hurry, so I'll be short for once, don't hesitate to ask for more if needed]

Your stat screen is 9 times the same structure, so you can make a screen that will a screen that will be this structure :

Python:
# The part of the screen for each girl
# Parameter is the girl to works with
screen girlStat( girl ):

     # The main block for the data
     # No need to position it, it will be automatic
     # You have two row.
     hbox:

        # The first row is the portrait for this girl.
        # The effective names are Tiffportrait.png, Smiportrait.png, ...
        # The name is computed in real time, depending of the
        # parameter given to the screen.
        add ( "images/stats/{}portrait.png".format( girl ) )

        # The second row is the values.   
        vbox:

            # The star, should be positionned
            add "gui/star.png"

            # Aerate a little, let 5 pixels
            null height 5

            # And the associated value
            # All variables are stored in an object named "store"
            # All variables can be addressed indirectly with
            # /getattr/. Build the name a the variable to get it
            # Here it's for Tiff1, Smi1, ...
            text ( "{}".format( getattr( store, girl + "1" ) ) )
            # If the values are in an object dedicated to this girl
            # use getattr( girl, "starValue" ) instead, assuming
            # that the objects are named 'Tiff', 'Smi', ...

            # Aerate a little, let 20 pixels this time
            null height 20

            # Repeat for the second value
            add "gui/hearth.png"

            # Aerate a little, let 5 pixels
            null height 5

            text ( "{}.format( getattr( store, girl + "2" ) ) )


# The main screen for the stats
screen stats():
  
    # The grid will position the data automatically.
    # I use a 6 entry example, because you gave only 4
    # names, and I need to explain something regarding
    # /grid/
    grid 3 2:
       # Proceed for all the girls
       for g in [ "Tiff", "Smi", "Joa", "Dar", None, None ]:
          # Either you display the data for the girl
          if not g is None:
              # By adding the 'girStat' screen inside this one
              # passing it the name of the actual girl.
              use girlStat( g )

          # Or you display an empty entry.
          # This is needed because /grid/ expect to have the exact
          # Number of entry. So here you need to fill to 6, which is
          # the reason why there's the two /None/ at the end of the
          # list above.
          else:
              null witdh 1
Like I said, I'm in hurry, so I wrote it totally on the fly. But minus typo that I can have made, it should give you the expected result, including the positioning of each element, without the need to explicitly give them a position.

Hi there,

I came across this thread while trying to figure out a good way to show a simple stats screen for my project. It looks like something I could use so I customized it a little bit and wanted to get your help/feedback on how to proceed...

I'm going to have possibly 14 LI's so i changed the grid to 4 by 4 and for the sake of organization, I will use a new girl ID system instead of their names. So that's the list for "g" that says "li1, li2, li3 ... etc". Instead of a star and heart, I have Love and Lust, so I made some simple placeholders for the portraits (200x200 px) and love and lust symbols (10x10 px) and beside each of those will be the point value for that stat.

Where I am getting a little over my head is using the Store. That's not something I really had experience with yet. Currently, in my code, I was tracking Love and Lust points for each LI by their own separate variables. So, for example, LI1's lust points might be li1_lust. This is going to be a fairly straight forward VN with various paths and endings, but no sandbox, so I was planning on increasing points using the normal means of $ li1_lust +=1 - that sort of basic training wheels Ren'py coding :)

How could I change this code to use the stats system I already have started?

As I said, I am planning on 14 LI's over the course of the VN, so a 4 x 4 grid should work good. I can see the benefit of a Store array, but I think I should keep it in the beginner's lane for right now, since I need to get this project moving and I have the renders done already.

Here's your code example with the minor edits I made, to reflect the new grid and the portrait names. (oh btw, I changed the format for the portraits to be "portrait_{girl}.png"

Python:
# The part of the screen for each girl
# Parameter is the girl to works with
screen girlStat( girl ):

     # The main block for the data
     # No need to position it, it will be automatic
     # You have two row.
     hbox:

        # The first row is the portrait for this girl.
        # The effective names are Tiffportrait.png, Smiportrait.png, ...
        # The name is computed in real time, depending of the
        # parameter given to the screen.
        add ( "images/stats/portrait_{}.png".format( girl ) )

        # The second row is the values.
        vbox:

            # The star, should be positionned
            add "gui/love.png"

            # Aerate a little, let 5 pixels
            null height 5

            # And the associated value
            # All variables are stored in an object named "store"
            # All variables can be addressed indirectly with
            # /getattr/. Build the name a the variable to get it
            # Here it's for Tiff1, Smi1, ...
            text ( "{}".format( getattr( store, girl + "1" ) ) )
            # If the values are in an object dedicated to this girl
            # use getattr( girl, "starValue" ) instead, assuming
            # that the objects are named 'Tiff', 'Smi', ...

            # Aerate a little, let 20 pixels this time
            null height 20

            # Repeat for the second value
            add "gui/lust.png"

            # Aerate a little, let 5 pixels
            null height 5

            text ( "{}".format( getattr( store, girl + "2" ) ) )


# The main screen for the stats
screen stats():

    # The grid will position the data automatically.
    # I use a 6 entry example, because you gave only 4
    # names, and I need to explain something regarding
    # /grid/
    grid 4 4:
       # Proceed for all the girls
       for g in [ "li1", "li2", "li3", "li4", "li5", "li6", "li7", "li8", "li9", "li10", "li11", "li12", "li13", "li14", None, None ]:
          # Either you display the data for the girl
          if not g is None:
              # By adding the 'girStat' screen inside this one
              # passing it the name of the actual girl.
              use girlStat( g )

          # Or you display an empty entry.
          # This is needed because /grid/ expect to have the exact
          # Number of entry. So here you need to fill to 6, which is
          # the reason why there's the two /None/ at the end of the
          # list above.
          else:
              null width 1
 

Bad Buster

Newbie
Oct 27, 2022
18
78
anne O'nymous

Not sure if you got a flag for this as I saw some moderation approval note for posting as a new account. Sorry for the necro on this thread, but the code looked perfect for what i needed, as long as it's not too out of date (Big possibility with Ren'py I imagine, lol)
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,234
Where I am getting a little over my head is using the Store. That's not something I really had experience with yet.
It's not too difficult. See the "store" as a shelf that would store all the variables.
In real life, if you ask someone to get you a book, you'll say "it's on the shelf". But there's times where it's obvious. You're in the entry of your room, there's nothing more than few coat hanger and a shelf with few books, the person you talk to will figure by itself that the book isn't on one of the coat hanger. But you can still give the location, it will not confuse this person.
The same apply with Ren'Py and the "store", when you ask for a variable, you'll say "it's on the store". Sometimes it's not necessary, adding this clarification will never hurt.


Currently, in my code, I was tracking Love and Lust points for each LI by their own separate variables. So, for example, LI1's lust points might be li1_lust. This is going to be a fairly straight forward VN with various paths and endings, but no sandbox, so I was planning on increasing points using the normal means of $ li1_lust +=1 - that sort of basic training wheels Ren'py coding :)
Then the construct to reach the variable would be: NAME_OF_THE_GIRL + "_lust"
What mean that, to get the value you'll need getattr( store, NAME_OF_THE_GIRL + "_lust" ), and to change the value you'll need setattr( store, NAME_OF_THE_GIRL + "_lust", NEW_VALUE ).
Ren'Py, can you please give me the variable on the store ? You can't confuse, the one I want have a name that starts with NAME_OF_THE_GIRL, and continue with "_lust".

Starting there, you can have all the construct that you want:
getattr( store, NAME_OF_THE_GIRL + "_" + NAME_OF_THE_STAT )
Ren'Py, can you please give me the variable on the store ? You can't confuse, the one I want have a name that starts with NAME_OF_THE_GIRL, and continue with "_", then end with NAME_OF_THE_STAT.
If NAME_OF_THE_GIRL is "sarah", and NAME_OF_THE_STAT is "lust", then Ren'Py will give you the variable "sarah_lust". But if NAME_OF_THE_STAT is "love", it will give you the variable "sarah_love".

And so on, there's not limits to the way you build the name of the variable. The only obligation is that, in the end, it correspond to a variable that exist.
 
  • Like
Reactions: Bad Buster

Bad Buster

Newbie
Oct 27, 2022
18
78
It's not too difficult. See the "store" as a shelf that would store all the variables.
In real life, if you ask someone to get you a book, you'll say "it's on the shelf". But there's times where it's obvious. You're in the entry of your room, there's nothing more than few coat hanger and a shelf with few books, the person you talk to will figure by itself that the book isn't on one of the coat hanger. But you can still give the location, it will not confuse this person.
The same apply with Ren'Py and the "store", when you ask for a variable, you'll say "it's on the store". Sometimes it's not necessary, adding this clarification will never hurt.




Then the construct to reach the variable would be: NAME_OF_THE_GIRL + "_lust"
What mean that, to get the value you'll need getattr( store, NAME_OF_THE_GIRL + "_lust" ), and to change the value you'll need setattr( store, NAME_OF_THE_GIRL + "_lust", NEW_VALUE ).
Ren'Py, can you please give me the variable on the store ? You can't confuse, the one I want have a name that starts with NAME_OF_THE_GIRL, and continue with "_lust".

Starting there, you can have all the construct that you want:
getattr( store, NAME_OF_THE_GIRL + "_" + NAME_OF_THE_STAT )
Ren'Py, can you please give me the variable on the store ? You can't confuse, the one I want have a name that starts with NAME_OF_THE_GIRL, and continue with "_", then end with NAME_OF_THE_STAT.
If NAME_OF_THE_GIRL is "sarah", and NAME_OF_THE_STAT is "lust", then Ren'Py will give you the variable "sarah_lust". But if NAME_OF_THE_STAT is "love", it will give you the variable "sarah_love".

And so on, there's not limits to the way you build the name of the variable. The only obligation is that, in the end, it correspond to a variable that exist.
OK, I think I have enough to get this sorted... gonna play with the code a little later today, after I complete this scene I am almost done with. I'll report back :)
 

The Rogue Trader

Active Member
Sep 12, 2021
510
756
Then the construct to reach the variable would be: NAME_OF_THE_GIRL + "_lust"
Sorry to intrude, but there are any particular reasons why you wouldn't recommend putting those variables into a class
Python:
    class Love_int:
        def __init__(self, character, love = 0, lust = 0, annoyance = 0, meet = False, portrait):
            self.c = character
            self.love = love
            self.lust = lust
            self.annoyance = annoyance
            # if the character has been already meet the MC
            self.meet = meet
            self.portrait = portrait
Then just defining each girl
alice = Love_int(Character('Alice', color="#A40000"), 0, 0, 0, False, "girls/portraits/alice_portrait.webp")
so to have variables that look like alice.love bea.lust carole.portrait
Yes, I know it's "not basic Renpy", but it still seems easier to manage and maintain to my eyes of cargo-cult programmer...
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,234
Sorry to intrude, but there are any particular reasons why you wouldn't recommend putting those variables into a class
Other that adjusting my answer to his level of knowledge ? No.

Effectively, I could have told him to rely on a class, then let him deal with it, not really knowing what he's doing, nor why he's doing it. Oh, of course, I could also have added a full course regarding what classes are, what is their interest, how they works, and all. But wouldn't have both been baffling, to him that don't have much knowledge in coding ?
There's a solution, relatively easy, to explain and to use, that will come handy in many other situation he can have to face. Why should I drown him with something that he don't effectively need to use right now ? One step after the other.


Yes, I know it's "not basic Renpy",
There's no such thing as "basic Ren'Py", and it there were, on F95zone I would be the one who stand the further from it.


but it still seems easier to manage and maintain to my eyes of cargo-cult programmer...
But you aren't the one that will use it. Plus, the cargo-cult concept is probably the worse possible one when it come to helping a novice, whatever the field.

I prefer passing some time teaching about fishing, that mouth feeding someone in need. Of course, while teaching I'll also provide some fishes, I don't want him to starve. But I also don't want him to later fill like an idiot, because he'll not know how to adapt something to his, similar but yet a bit different, next problem.
And I must said that this thread is the perfect illustration of this problem. The solution was right in front of his eyes. What was lacking wasn't the example, but the explanation regarding how it works ; an explanation that wasn't necessary for the initial poster.
 

Bad Buster

Newbie
Oct 27, 2022
18
78
Fuck it,

I had a wall of text written in response, but it's just not worth the effort.

I'll figure out a way to do a simple stats page, even if it means writing the same 16 blocks of "baby ren'py" over and over again. I don't care that much if it's elegant or if my script files get bloated a bit. All I care about is that it works and presents my story and my renders properly. And I am kinda tired about people's assumptions when we ask for help on this stuff, especially when we are asking on a game site and not a coding site. I only started learning Ren'py this year and I certainly know next to nothing about python, which the above Store example is part of, is it not? So forgive me if i have no time for ego's or assumptions or whatever.

I'll still get 'er done..
 

osanaiko

Engaged Member
Modder
Jul 4, 2017
2,553
4,637
Bad Buster

Ann'o'nonymous' answer is good for you. Rogue trader is also correct in how he is building on top of Anne'o's code but his way is more advanced and not needed while you are still getting a handle on renpython.

You are already very close: you are storing the love and lust values for each of your girls into renpy global variables.

Inside screen code anno is using getattr to access the the global variables which are inside the "store". getattr can take a string that is the name of the variable and return the variable value. so we need to build the correct string on top of the girl's variable name pattern

The part you would need to change is this line:

Code:
text ( "{}".format( getattr( store, girl + "2" ) ) )
The girl + "2" needs to become the correct variable name for your way of storing the love / lust value.

You are using "li1_lust" and "li1_love". So when you are passing into the girlStat screen "li1" etc, the getattr must change to be like this:

Code:
text ( "{}".format( getattr( store, girl + "_lust" ) ) )
That is what Anne explained above but it was kind of surrounded by lots of explanation so maybe it wasn't so clear.

Good luck and keep fighting!
 

Bad Buster

Newbie
Oct 27, 2022
18
78
osanaiko and The Rogue Trader

I appreciate the help and effort to try and explain things for me.

anne O'nymous

Sorry for being cranky. You don't get to be the only one who's grumpy on here, lol. I basically had problems because of a typo and some formatting issues I had when trying to make your code work. After I posted above, I ignored this project and worked on some other shit that needed to be done, then I came back fresh today and took another look and - lo and behold - it works! My project is near release and I have had some other issues and I was just in a stressed space last week.

So here's what I have and what i changed a bit.


The main block of code, pretty much how you showed it, except I am only setting up for 9 LI's for now. I won't need those last 7 for a couple of updates.

I also put it in a frame and added the formatting to make it centered on screen using a style prefix that I can edit easily. Right now I just have placeholder images, but eventually, I'll customize them and shine them up for release.

Python:
    screen girlStat( girl ):

         hbox:

            add ( "images/stats/portrait_{}.png".format( girl ) )

            vbox:

                add "gui/love.png"
                null height 5
                text ( "{}".format( getattr( store, girl + "_love" ) ) )
                null height 20

                add "gui/lust.png"
                null height 5
                text ( "{}".format( getattr( store, girl + "_lust" ) ) )

    screen stats():

        style_prefix "statsUI"
        frame:
            modal True
            xalign 0.5
            yalign 0.5
            xpadding 20
            ypadding 20
            hbox:
                grid 4 4:
                   for g in [ "li1", "li2", "li3", "li4", "li5", "li6", "li7", "li8", "li9", None, None, None, None, None, None, None ]:

                      if not g is None:
                          use girlStat( g )
                      else:
                          null width 1
To call the stat screen, I have a text link in my navigation area on the upper left of my game screens. The usual sorta thing with a time of day graphic, label for what time it is (Morning, Noon, etc) and the link for the stats. Here's the code for the screen call, so I can open and close the stats screen using the same link.

textbutton "STATS" action If(renpy.get_screen("stats"), Hide("stats"), Show("stats"))


Thanks again for the help!
 
  • Like
Reactions: osanaiko

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,234
Sorry for being cranky.
Don't worry about this.


textbutton "STATS" action If(renpy.get_screen("stats"), Hide("stats"), Show("stats"))
Here you can simplify drastically the action with the help of , that will do the same thing for you ; textbutton "STATS" action ToggleScreen( "stats" ).
 
  • Like
Reactions: Bad Buster

miketyson7584

New Member
Feb 17, 2018
8
2
I have a problem with Self-Voicing when i start it , it always read top stats first before dialogue and its very annoying anyone knows a way to get rid of that stat thingy or make Self-Voicing read only dialogue .
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
I have a problem with Self-Voicing when i start it , it always read top stats first before dialogue and its very annoying anyone knows a way to get rid of that stat thingy or make Self-Voicing read only dialogue .

Not without changing the script file(s). RenPy will voice any dialogue and anything within a screen that has a Text element. You can override the contents of the screen to mute specific things using the parameter.

You might want to check out this thread:
https://f95zone.to/threads/how-to-remove-this-from-script.67067/post-4603095

Which continued in this thread:
https://f95zone.to/threads/help-with-this-game-script.89956
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,234