Characters status

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
924
3,917
Hello, forum

Due to recent development, I stumbled on a question for which I don't seem to find an answer.
Does anyone know or can point out to a tutorial from which I can create character status like for example, relationship status or powers status?
I need to know how I can gather the points in one place and reflect it in the UI so that the player can see what the stats is.

Thank you in advance
 

Palanto

Active Member
Game Developer
Oct 4, 2017
964
1,839
Depends on how you want to do it.... you can either just create a variable for each stat, or you create a character class which holds all the stats a player character has in one place....

The later is "more advanced" and a little different to use. The first is simply defining variables like this:
Code:
default playerName = "Palanto"
default playerHealth = 100
default playerBallStatus = "Blue"
default MP = 120
and so on and so forth....

Of course, the "playerName" could/should be replaced in a renpy.input() just make sure you've set at least a default name ;)

Or in the class way:
Code:
init -100 python:
    # define the Character's class
    class Player(store.object):
        def __init__ (self, firstName = "", lastName = ""):

            # Name of the Player #
            self.name = firstName
            self.surname = lastName

            # Other Variables #
            self.hp = 100
            self.mp = 0
            self.inhib = 0
            self.exhib = 0

            self.lust = 0
            self.corruption = 0
            self.confidence = 0
            self.purity = 100
This would be a small "Player" class.
It stores a first name, a surname and a lot of "other variables" like the players health(hitpoints/hp), magic points(mp), inhibition, exhibition, lust, corruption, confidence and purity. You can add/remove whichever you need and rename them as much as you want, as long as you keep the variable names you use in the init the same as you use below.

i.e. changing self.name = firstName to self.name = whatEverYouWant means you have to change firstname to whatEverYouWant in the def __init__(self, whatEverYouWant = "", lastName = ""):
too.

Alright, and this is how you'd use the class:
Code:
default pl = Player("Phil", "Johnson") # would create an object of class player called "pl" with the first name "Phil" and the surname "Johnson"

label start:

python:
        name = renpy.input("What is your FIRST name?")
        name = name.strip()

        if not name:
            pass
        else:
            pl.name = name

        surname = renpy.input("What is your LAST name?")
        surname = surname.strip()

        if not surname:
            pass
        else:
            pl.surname = surname

    "This is a fascinating crap game... enjoy the shit!"
    $ pl.hp += 100
    "Your maximum health was raised by 100HP and you now have [pl.hp]!"
and so on and so forth.... try to google python classes, ren'py screens and ren'py screen actions.
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
924
3,917
Depends on how you want to do it.... you can either just create a variable for each stat, or you create a character class which holds all the stats a player character has in one place....

The later is "more advanced" and a little different to use. The first is simply defining variables like this:
Code:
default playerName = "Palanto"
default playerHealth = 100
default playerBallStatus = "Blue"
default MP = 120
and so on and so forth....

Of course, the "playerName" could/should be replaced in a renpy.input() just make sure you've set at least a default name ;)

Or in the class way:
Code:
init -100 python:
    # define the Character's class
    class Player(store.object):
        def __init__ (self, firstName = "", lastName = ""):

            # Name of the Player #
            self.name = firstName
            self.surname = lastName

            # Other Variables #
            self.hp = 100
            self.mp = 0
            self.inhib = 0
            self.exhib = 0

            self.lust = 0
            self.corruption = 0
            self.confidence = 0
            self.purity = 100
This would be a small "Player" class.
It stores a first name, a surname and a lot of "other variables" like the players health(hitpoints/hp), magic points(mp), inhibition, exhibition, lust, corruption, confidence and purity. You can add/remove whichever you need and rename them as much as you want, as long as you keep the variable names you use in the init the same as you use below.

i.e. changing self.name = firstName to self.name = whatEverYouWant means you have to change firstname to whatEverYouWant in the def __init__(self, whatEverYouWant = "", lastName = ""):
too.

Alright, and this is how you'd use the class:
Code:
default pl = Player("Phil", "Johnson") # would create an object of class player called "pl" with the first name "Phil" and the surname "Johnson"

label start:

python:
        name = renpy.input("What is your FIRST name?")
        name = name.strip()

        if not name:
            pass
        else:
            pl.name = name

        surname = renpy.input("What is your LAST name?")
        surname = surname.strip()

        if not surname:
            pass
        else:
            pl.surname = surname

    "This is a fascinating crap game... enjoy the shit!"
    $ pl.hp += 100
    "Your maximum health was raised by 100HP and you now have [pl.hp]!"
and so on and so forth.... try to google python classes, ren'py screens and ren'py screen actions.
Thanks mate!
 
  • Like
Reactions: Palanto

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,245
15,016
Er... To my eyes, it's a too opened question. There's so many different ways to handle both the points storing and their display, while managing the evolution of the values.

For the storing part, you can have:
  • Standalone variables
    You don't have permission to view the spoiler content. Log in or register now.
    It's the easiest way to do, and so what you see the most. No need to knowledge to works this way, but the more character you have, the more you increase the possibilities for errors. By example, in majority the variable start with the character initial, or the two firsts letters.
    It's great until you decide to name a character "Sarah" and the other "Sam". You end with a "s_love" and a "sa_love"... Good luck to avoid mixing them after some months of coding your game.
  • One dict to rule them all
    You don't have permission to view the spoiler content. Log in or register now.
    I show it (and worse), and present it because it's a possibility, but far to be the better.
    Because the name are split in many parts, people tend to use more significant (and longer) names.
    It present the advantage to simplify the display, but it's a pain in the ass to use in code.
  • An object by character
    You don't have permission to view the spoiler content. Log in or register now.
    Everything in a given place, and so many opening to simplify your work. But it need an average knowledge to use it correctly.


For the point evolution itself, there's also way too many possibilities. Among many other way, it can be done :

  • Directly, like in the examples gave above
    It's the simplest way to do, and so the most used.
  • With the help of a Ren'py label
    You don't have permission to view the spoiler content. Log in or register now.
    It help you limit the possibilities of errors. You write the assignation once, then forget about it, so no "var =+ 1" or "var -= 1" instead of "var += 1". It also do everything in a single place, like in my example notify the player of the change.
  • With the help of a Python function
    You don't have permission to view the spoiler content. Log in or register now.
    It works like the previous solution, but you can't really notify the player ; I mean, you can if you just use "renpy.notify" or some Python equivalent of Ren'py statement, but for this you need more than an average knowledge.
  • With the help of a method object
    You don't have permission to view the spoiler content. Log in or register now.
    It's the most advanced way to do it, and the one that need the most knowledge do be done correctly. But it's also the best way to really limit the possibilities of errors.
    In all the previous example, if you made a typo when writing the name/nickname of the character, it silently fail. Here, if you made a typo, Ren'py will crash, making you immediately know about it.

And for the display... Here it's the worse, not because it's difficult, but because there really tons of way to do it. Not only in terms of code, but also in terms of visual and design.
  • All character in one "full stats" display
    You don't have permission to view the spoiler content. Log in or register now.
  • Integrated to the User Interface
    You don't have permission to view the spoiler content. Log in or register now.
  • graphically
    You don't have permission to view the spoiler content. Log in or register now.

And that's just three examples for each case...

Edit: Well, @Palanto was faster than me this time ;)
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
924
3,917
Er... To my eyes, it's a too opened question. There's so many different ways to handle both the points storing and their display, while managing the evolution of the values.

For the storing part, you can have:
  • Standalone variables
    You don't have permission to view the spoiler content. Log in or register now.
    It's the easiest way to do, and so what you see the most. No need to knowledge to works this way, but the more character you have, the more you increase the possibilities for errors. By example, in majority the variable start with the character initial, or the two firsts letters.
    It's great until you decide to name a character "Sarah" and the other "Sam". You end with a "s_love" and a "sa_love"... Good luck to avoid mixing them after some months of coding your game.
  • One dict to rule them all
    You don't have permission to view the spoiler content. Log in or register now.
    I show it (and worse), and present it because it's a possibility, but far to be the better.
    Because the name are split in many parts, people tend to use more significant (and longer) names.
    It present the advantage to simplify the display, but it's a pain in the ass to use in code.
  • An object by character
    You don't have permission to view the spoiler content. Log in or register now.
    Everything in a given place, and so many opening to simplify your work. But it need an average knowledge to use it correctly.


For the point evolution itself, there's also way too many possibilities. Among many other way, it can be done :

  • Directly, like in the examples gave above
    It's the simplest way to do, and so the most used.
  • With the help of a Ren'py label
    You don't have permission to view the spoiler content. Log in or register now.
    It help you limit the possibilities of errors. You write the assignation once, then forget about it, so no "var =+ 1" or "var -= 1" instead of "var += 1". It also do everything in a single place, like in my example notify the player of the change.
  • With the help of a Python function
    You don't have permission to view the spoiler content. Log in or register now.
    It works like the previous solution, but you can't really notify the player ; I mean, you can if you just use "renpy.notify" or some Python equivalent of Ren'py statement, but for this you need more than an average knowledge.
  • With the help of a method object
    You don't have permission to view the spoiler content. Log in or register now.
    It's the most advanced way to do it, and the one that need the most knowledge do be done correctly. But it's also the best way to really limit the possibilities of errors.
    In all the previous example, if you made a typo when writing the name/nickname of the character, it silently fail. Here, if you made a typo, Ren'py will crash, making you immediately know about it.

And for the display... Here it's the worse, not because it's difficult, but because there really tons of way to do it. Not only in terms of code, but also in terms of visual and design.
  • All character in one "full stats" display
    You don't have permission to view the spoiler content. Log in or register now.
  • Integrated to the User Interface
    You don't have permission to view the spoiler content. Log in or register now.
  • graphically
    You don't have permission to view the spoiler content. Log in or register now.

And that's just three examples for each case...

Edit: Well, @Palanto was faster than me this time ;)
Thank you @anne O'nymous! Your knowledge never ceases to amaze me :)
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
924
3,917
Er... To my eyes, it's a too opened question. There's so many different ways to handle both the points storing and their display, while managing the evolution of the values.

For the storing part, you can have:
  • Standalone variables
    You don't have permission to view the spoiler content. Log in or register now.
    It's the easiest way to do, and so what you see the most. No need to knowledge to works this way, but the more character you have, the more you increase the possibilities for errors. By example, in majority the variable start with the character initial, or the two firsts letters.
    It's great until you decide to name a character "Sarah" and the other "Sam". You end with a "s_love" and a "sa_love"... Good luck to avoid mixing them after some months of coding your game.
  • One dict to rule them all
    You don't have permission to view the spoiler content. Log in or register now.
    I show it (and worse), and present it because it's a possibility, but far to be the better.
    Because the name are split in many parts, people tend to use more significant (and longer) names.
    It present the advantage to simplify the display, but it's a pain in the ass to use in code.
  • An object by character
    You don't have permission to view the spoiler content. Log in or register now.
    Everything in a given place, and so many opening to simplify your work. But it need an average knowledge to use it correctly.


For the point evolution itself, there's also way too many possibilities. Among many other way, it can be done :

  • Directly, like in the examples gave above
    It's the simplest way to do, and so the most used.
  • With the help of a Ren'py label
    You don't have permission to view the spoiler content. Log in or register now.
    It help you limit the possibilities of errors. You write the assignation once, then forget about it, so no "var =+ 1" or "var -= 1" instead of "var += 1". It also do everything in a single place, like in my example notify the player of the change.
  • With the help of a Python function
    You don't have permission to view the spoiler content. Log in or register now.
    It works like the previous solution, but you can't really notify the player ; I mean, you can if you just use "renpy.notify" or some Python equivalent of Ren'py statement, but for this you need more than an average knowledge.
  • With the help of a method object
    You don't have permission to view the spoiler content. Log in or register now.
    It's the most advanced way to do it, and the one that need the most knowledge do be done correctly. But it's also the best way to really limit the possibilities of errors.
    In all the previous example, if you made a typo when writing the name/nickname of the character, it silently fail. Here, if you made a typo, Ren'py will crash, making you immediately know about it.

And for the display... Here it's the worse, not because it's difficult, but because there really tons of way to do it. Not only in terms of code, but also in terms of visual and design.
  • All character in one "full stats" display
    You don't have permission to view the spoiler content. Log in or register now.
  • Integrated to the User Interface
    You don't have permission to view the spoiler content. Log in or register now.
  • graphically
    You don't have permission to view the spoiler content. Log in or register now.

And that's just three examples for each case...

Edit: Well, @Palanto was faster than me this time ;)

And with the risk of becoming persona non grata on this forum :)), how can I link a button that is in-game, with the code you gave
screen stats:

default page = "mother"

hbox:
textbutton "mother" action SetScreenVariable( "page", "mother" )
textbutton "aunt" action SetScreenVariable( "page", "aunt" )
textbutton "sister" action SetScreenVariable( "page", "sister" )
null width 30
textbutton "close" action Hide( "stats" )

if page == "mother":
vbox:
text "love [mo_love]"
text "lust [mo_lust]"
text "corruption [mo_corruption]"
elif page == "aunt":
vbox:
text "love [au_love]"
text "lust [au_lust]"
text "corruption [au_corruption]"
elif page == "sister":
vbox:
text "love [si_love]"
text "lust [si_lust]"
text "corruption [si_corruption]"
?
I have for the button, the following code:
screen button:
vbox xalign 1.0 yalign 1.0:

imagebutton:
idle "button_idle.png"
hover "button_hover.png"
action ui.callsinnewcontext("aff_screen_label")

In Screens.rpy
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,245
15,016
how can I link a button that is in-game, with the code you gave
The simplest way is to use a code like this :
Code:
init python:
    config.overlay_screens.append( "myButton" )

default activeStats = True

screen myButton:

    if activeStats is True:
        textbutton "stats":
            action Show( "stats" )

screen stats:
    modal True

   [whatever you want]
    textbutton "close":
        action Hide( "stats" )
It offer you all the flexibility you can need.
  1. It's an overlay.
    By adding the name in , you made the screen independent of any hide, show, scene, whatever Ren'py statement. As long as "store.suppress_overlay" (undocumented) is True, the overlays will always be added to what is displayed.
    So, putting the User Interface as overlay can be a good idea ; it obviously depend of the main design. This let you show/hide all the elements of the said UI with a single line :
    Code:
        $ suppress_overlay = True  # The User Interface is shown
        $ suppress_overlay = False  # The User Interface is hidden
    Overlays are also context dependent. It mean that when you use things like , the overlays automatically disappear in this new context, to automatically reappear when you'll return to the main context. It's not the better way to hide/show them, but it imply that they'll never be seen when you have a Ren'py screen (like "preference", "save", etc.).
  2. You also have an individual control over this part of the User Interface
    Note the "if activeStats is True" that start the screen. At anytime you can continue to have the User Interface shown as overlay, while not having this button shown. It works in the same way than above, except that this time it's not with the help of a mysterious Ren'py variable:
    Code:
        $ activeStats = True  # The button is shown
        $ activeStats = False  # The button is hidden
  3. When displayed, the stats prevent the player do click anywhere
    It's a flaw that is recurrent when someone use large screens. They display it on top of the actual content... but the player can continue to interact with what's behind the shown screen. It mean that you can look at the stats, and in the same time click on the button that will change your location. Obviously it's not a great thing and it can break the game if, instead of changing location the player decide to interact with an object that will open a screen. They will stack on the screen and most of the time the result is weird and unusable.
    That's why the "stats" screen starts with "modal True". is a screen property and, when set at True, it will make everything except this screen insensible. So, you'll still have all the interactive part of the actual scene the player was in before asking for the stats but, as long as the "stats" screen is displayed he can't interact with them.
    Obviously, this is to use only if the screen is really big. When it's a small screen like this one by example :
    Code:
    screen stats:
      vbox: 
         text "mother [mo_love]"
         text "aunt [au_love]"
         text "sister [si_love]"
    It don't really interfere with the main screen and can be let like this. In fact, it's even better to let it like this in this case. It's like any kind of game where you can show/hide some parts of the User Interface to keep track of something while still playing the game.

This said, well, like before, it's just one way to do it. You can replace "textbutton" by an "imagebutton". You can put the button inside a single User Interface screen, with or without the "activeStats" part. And there's more possible variations. But it's also the example that show the most possibilities by itself. Starting with this, you can come to most of the possible variations.
 

Palanto

Active Member
Game Developer
Oct 4, 2017
964
1,839
And with the risk of becoming persona non grata on this forum :)), how can I link a button that is in-game, with the code you gave
screen stats:

default page = "mother"

hbox:
textbutton "mother" action SetScreenVariable( "page", "mother" )
textbutton "aunt" action SetScreenVariable( "page", "aunt" )
textbutton "sister" action SetScreenVariable( "page", "sister" )
null width 30
textbutton "close" action Hide( "stats" )

if page == "mother":
vbox:
text "love [mo_love]"
text "lust [mo_lust]"
text "corruption [mo_corruption]"
elif page == "aunt":
vbox:
text "love [au_love]"
text "lust [au_lust]"
text "corruption [au_corruption]"
elif page == "sister":
vbox:
text "love [si_love]"
text "lust [si_lust]"
text "corruption [si_corruption]"
?
I have for the button, the following code:
screen button:
vbox xalign 1.0 yalign 1.0:

imagebutton:
idle "button_idle.png"
hover "button_hover.png"
action ui.callsinnewcontext("aff_screen_label")

In Screens.rpy
btw. just saw this:
imagebutton:
idle "button_idle.png"
hover "button_hover.png"
action ui.callsinnewcontext("aff_screen_label")

why don't you use auto buttons there? :) "if" the image has the same name with _state.png then just use
Code:
imagebutton:
    auto "button_%s.png"
    action ui.callsinnewcontext("aff_screen_label")
auto replaces %s with "idle" "hover" and all other possible states, but the only two "mandatory" are idle and hover to make it work ;)
 
  • Like
Reactions: anne O'nymous

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,245
15,016
auto replaces %s with "idle" "hover" and all other possible states, but the only two "mandatory" are idle and hover to make it work ;)
If I remember it correctly, you can even forget the "hover". It's a little weird to works this way, but it can come handy when you use the imagebutton only for its hovered or tooltip property.
 

Palanto

Active Member
Game Developer
Oct 4, 2017
964
1,839
True, forgot about that even though I already used it once or twice X_x Somehow I still remember reading in the docs that you "must have" those two but it was never there :D
 

Deleted member 416612

The 'landlord'
Donor
Game Developer
Feb 2, 2018
924
3,917
btw. just saw this:
imagebutton:
idle "button_idle.png"
hover "button_hover.png"
action ui.callsinnewcontext("aff_screen_label")

why don't you use auto buttons there? :) "if" the image has the same name with _state.png then just use
Code:
imagebutton:
    auto "button_%s.png"
    action ui.callsinnewcontext("aff_screen_label")
auto replaces %s with "idle" "hover" and all other possible states, but the only two "mandatory" are idle and hover to make it work ;)
So this work somehow like a class
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,245
15,016
Hmmm it's more like string interpolation (replacement)
I'll even say that it's purely "string interpolation", he even kept the "%s".
This let me wonder if we'll have to adapt once the version 8 will be a reality. This interpolation use a method that is obsolete in Python 2.7 and (if I remember correctly) have even been removed from Python 3.3. Not that it will be more difficult, but we will have to relearn many things in this case.
 

Palanto

Active Member
Game Developer
Oct 4, 2017
964
1,839
I'll even say that it's purely "string interpolation", he even kept the "%s".
This let me wonder if we'll have to adapt once the version 8 will be a reality. This interpolation use a method that is obsolete in Python 2.7 and (if I remember correctly) have even been removed from Python 3.3. Not that it will be more difficult, but we will have to relearn many things in this case.
Well it's still working in python 3.7 (just tried, cause I couldn't find anything about it being removed, just being unrecommended)
But yeah, str.format() and the other interpolation methods are obviously the better things to use ;)

still working.png