Ren'Py how to show character in a certain pose by using this code

rayminator

Engaged Member
Respected User
Sep 26, 2018
3,040
3,135
how to show character in a certain pose by using this code


just want to know if it is possible to do it this way or leave at is

so far the code works fine but I want to add pose or timeofday like morning,afternoon,evening,night

screenshot0007.png

I have tried to put something like pose inside of the code that you have gave me error or no image at all

so what I'm trying to have is

anna_Library_afternoon_pose1.png
anna_Library_afternoon_pose2.png
anna_Library_afternoon_pose3.png
anna_Library_evening_pose1.png
anna_Library_evening_pose2.png
anna_Library_evening_pose3.png
anna_Library_Night_pose1.png
anna_Library_Night_pose2.png
anna_Library_Night_pose3.png

for now I have it

anna_Library.png


it's that I don't want to have the same pose through out the hole day long

how can I modify it so it will show anna_Library_Night_pose_1.png or anna_Library_pose_1.png

example:
Code:
self.fmt_str = "avatar/{name}/{name}_{{}}_{timeofday}_{pose}.png".format(name=name)
or

Code:
self.fmt_str = "avatar/{name}/{name}_{{}}_{pose}.png".format(name=name)

and this is how I am changing the $ time = 0 variable

it's in a loop for now
Python:
if dn >= 0 and dn <= 5:
                $ dn +=  1
                #$ time += 1
            elif dn >= 6 and dn <= 9:
                $ dn +=  1
                if dn == 9:
                    $ time += 1
            elif dn >= 10 and dn <= 12:
                $ dn +=  1
                if dn == 12:
                    $ time += 1
            elif dn >= 13 and dn <= 16:
                $ dn +=  1
                if dn == 16:
                    $ time += 1
            elif dn >= 17 and dn <= 18:
                $ dn +=  1
                if dn == 18:
                    $ time += 1
            elif dn >= 19 and dn <= 21:
                $ dn +=  1
                if dn == 21:
                    $ time += 1
            elif dn >= 22:
                $ dn +=  1
                if dn == 23:
                    $ time += 1



            if dn >= 24:
                $ dn = 0
            if dn == 6:
                $ time = 0


Python:
"""
npc_schedule is a dict { (time: int, location: str): (npc_name: str, lbt: str} }
npcs is a dict { npc_name: NPC } used to get an NPC by its name.
"""
default npc_schedule = {}
default npcs = {}
init python:
    class NPC:
        @classmethod
        def create(cls, name, nice_name, schedule):
            """
            schedule: a dict {(time: int, location: str): lbt: str}
                value will be converted to tuple (name, lbt) during creation
            """
            npcs[name] = NPC(name, nice_name, NPC.__key)
            for key, value in schedule.iteritems():
                if key not in npc_schedule:
                    npc_schedule[key] = [ ]
                npc_schedule[key].append( (name, value) )

        __key = object() # To disallow accidental creation
        def __init__(self, name, nice_name, key):
            assert(create_key == NPC.__key)
            self.nice_name = nice_name
            self.fmt_str = "avatar/{name}/{name}_{{}}.png".format(name=name)

        @property
        def avatar(self):
            global location
            avtr = self.fmt_str.format(location)
            if renpy.loadable(avtr):
                return avtr
            else:
                return Crop((100, 100, 100, 100), Solid("#0F0"))  #"images/avatar/empty.png"

default location = "ryan"
default time = 0

screen character_screen():
    $ npc_present = npc_schedule.get( (time, location), [ ] )

    vbox:
        for name, lbt in npc_present:
            $ npc = npcs[name]
            hbox:
                imagebutton:
                    idle npc.avatar
                    hover npc.avatar
                    focus_mask True
                    action Call(lbt)
                text "[npc.nice_name]: [lbt]"

label start:

    show screen character_screen
    ' . . .' # Nothing is shown, because no schedule is set
    $ NPC.create("mom", nice_name="Mom", schedule={
            (0, "ryan"):       "sally_kitchen_talk",
            (1, "parent"):     "sally_parent_talk",
            (2, "bathroom"):   "sally_bathroom_talk",
            (3, "livingroom"): "sally_livingroom_talk",
    })
    " . . . " # Now we see Mom
    $ time = 1
    ' . . . ' # We changed time, but not location. There no one here
    $ location = "parent"
    ' . . . ' # We caught up to Mom again
    return
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
I have tried to put something like pose inside of the code that you have gave me error or no image at all
What error did it give you ?


so what I'm trying to have is

anna_Library_afternoon_pose1.png
So, in "code language", {name}_{location}_[time}_{pose}, what is exactly this:

example:
Code:
self.fmt_str = "avatar/{name}/{name}_{{}}_{timeofday}_{pose}.png".format(name=name)
Except that:
and this is how I am changing the $ time = 0 variable
So you don't have timeofday value. You need to compute it (at the end of you time changing loop):
Code:
    if time < 2:
        $ timeofday = "night"
   elif time < 4:
        $ timeofday = "morning"
   elif time < 6:
        $ timeofday = "noon"
   elif time < 8:
        $ timeofday = "afternoon"
   elif time < 10:
        $ timeofday = "evening"
   else:
        $ timeofday = "night"
Python:
    [...]
    class NPC:
        def __init__(self, name, nice_name, key):
            assert(create_key == NPC.__key)
            self.nice_name = nice_name
           # self.fmt_str = "avatar/{name}/{name}_{{}}.png".format(name=name)
           self.fmt_str = "avatar/{name}/{name}_{{}}_{{}}_{{}}.png".format(name=name)

        @property
        def avatar(self):
            global location
            #avtr = self.fmt_str.format(location)
            avtr = self.fmt_str.format(location, timeofday, pose )
    [...]
Obviously, you need to give a value to pose at some moment in your label:
Python:
label library:
    $ location = "library"
    $ pose = "pose1"
    anna "Hello MC, how are you."
    mc "Good, thanks. You look marvelous dressed like than."
    $ pose = "pose2"
    anna "Oh, you'll make me blush..."
Normally it should works.


This being said, I'm not really a fan of this method, because it's too rigid. Characters have to be where they are expected, and can not be somewhere else.
A better approach would be similar to what is done in Super Powered, something like:
/!\ This is wrote on the fly /!\
Python:
# How the images path+name are formed.
define imageMask = "images/girls/{}/{}/{}/{}.jpg"
#  You need to have at least an image "images/girls/NAME_OF_THE_GIRL/void/noon/idle.jpg" 
# it will act as default image in case of error.
# Default location for all sprites.
define defaultLocation = "void"
# Default time of the day for all sprites.
define defaultTOD = "noon"
# Default pose for all sprites.
define defaultPose = "idle"


# The sprite image for Anna.
# Having a variable by girl complicate a bit the code, but offer a good security against missing images.
image anna = "girls/anna/[annaLocation]/[annaTOD]/[annaPose].jpg"
# Set the variables to their default values.
default annaLocation = defaultLocation
default annaTOD = defaultTOD
default annaPose = defaultPose

# Same for the mother.
image sally = "girls/sally/[sallyLocation]/[sallyTOD]/[sallyPose].jpg"
default sallyLocation = defaultLocation
default sallyTOD = defaultTOD
default sallyPose = defaultPose

# The game start in MC's room
default location = "MC room"

init python:
    #  Validate that an image exist, else find the most accurate one. In the same time, update the variables
    # that will define the image to display.
    def validateImage( who, pose ):
        # The image exist, update the variables for this girl
        if renpy.loadable( imageMask.format( who, store.location, store.timeofday, pose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.timeofday )
            setattr( store, who+"pose", pose  )
            return

        # The image do not exist, try to find the most accurate one.

        # Starting by the default pose.
        if renpy.loadable( imageMask.format( who, store.location, store.timeofday, store.defaultPose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.timeofday )
            setattr( store, who+"pose", store.defaultPose )
            return

        # The default time of the day with the asked pose.
        if renpy.loadable( imageMask.format( who, store.location, store.defaultTOD, store.pose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", pose  )
            return

        # The default time of the day with the default pose.
        if renpy.loadable( imageMask.format( who, store.location, store.defaultTOD, store.defaultPose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", store.defaultPose  )
            return

        # The default location with the actual time of the day and asked the pose.
        if renpy.loadable( imageMask.format( who, store.defaultLocation, store.timeofday, pose ):
            setattr( store, who+"Location", store.defaultLocation )
            setattr( store, who+"TOD", store.timeofday )
            setattr( store, who+"pose", pose  )
            return

        # The default location with the default time of the day and asked the pose.
        if renpy.loadable( imageMask.format( who, store.defaultLocation, store.defaultTOD, pose ):
            setattr( store, who+"Location", store.defaultLocation )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", pose  )
            return

        # Everything with the default values, this one exist we are sure.
        if renpy.loadable( imageMask.format( who, store.defaultLocation, store.defaultTOD, store.defaultPose ):
            setattr( store, who+"Location", store.defaultLocation )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", store.defaultPose  )


# Used to add a girl on the screen.
# Arguments: 
#   who -> Name of the girl
#  pose -> [optional] pose for this girl
label showGirl( who, pose="idle" ):
    # Validate that the image effectively exist.
    $ validateImage( who, pose )
    # Then show the image. It will be automatically updated by Ren'Py when the variables' value change.
    show expression who
    return

# Used to remove a girl from the screen
label hideGirl( who ):
    hide expression who
    return

# Used to change the pose.
label setPose( who, pose ):
    # Validate that the image effectively exist,
    $ validateImage( who, pose )
    #  Nothing more to do. The variables for this girl are updated to match an existing image,
    # and Ren'Py will update the sprite automatically.
    return
Then you use it like that:
Python:
label library:
    $ location = "library"
    # Ask for the sprite of Anna, in her 'idle' pose. 
   # While show her in her 'idle' pose, as she is in the library at this time of the day.
    call showGirl( "anna" )
    mc "Hello Anna, you are beautiful today"
    # Update the pose, asking for the 'blush' sprite. Still as it is in the library at this time of the day.
    call setPose( "anna", "blush" )
    anna "Oh, [MC.name], not so loud, your mother is here."
    # Ask for the sprite for the mother, in her 'curious' pose.
    call showGirl( "sally", "curious" )
    # Anna return to her 'idle' pose
    call setPose( "anna", "idle" )
    mom "Yes ? You called me ? Oh, hello son, how are you ?"
    anna "No, you should have misheard."
    mc "I'm fine."
    mom "Ok, then I return where I was, don't mind me."
    # Remove the sprite for the mother.
    call hideGirl( "sally" )
As I said, I wrote it on the fly, but normally it should works.
It imply a bit more works than the code you presented, but also offer you more freedom since the girls can be anywhere you want, as long as you have a sprite for this location. And if you don't have a sprite, the code will search the closest one to what you asked for.

Plus, if you choose wisely, the default sprites can still be used for unusual locations. By example, MC can go to a lingerie store with Anna. Since it will happen only once in the whole game, there's no need to have specific sprites for the basic poses:
Python:
label lingerieWithAnna:
    $ location = "lingerieShop"
    #  There's no image "images/anna/lingerieShop/afternoon/idle.jpg",
    # Ren'Py will display "images/anna/void/noon/idle.jpg"
    call showGirl( "anna" )
    mc "Oh, look at this, I'm sure you'll be beautiful wearing it."
    #  There's no image "images/anna/lingerieShop/afternoon/blush.jpg",
    # Ren'Py will display "images/anna/void/noon/blush.jpg"
    call setPose( "anna", "blush" )
    anna "Naughty boy. You really want to see me wearing this ?"
    mc "Of course."
    anna "Ok, I'll go try it."
    # Remove Anna, she's on the dressing room.
    hide showGirl( "anna" )
    anna "Hmmm, you're right, I look good in this."
    mc "You said that you'll show me."
    anna "Oh, really, I said this ? Hmm, OK."
    #  Here, you've an image "images/anna/lingerieShop/afternoon/naughtyLingerie.jpg",
    # Ren'Py will display it
    call showGirl( "anna", "naughtyLingerie" )
    mc "Wow... You're even more beautiful than I imagined it."
 

rayminator

Engaged Member
Respected User
Sep 26, 2018
3,040
3,135
What error did it give you ?




So, in "code language", {name}_{location}_[time}_{pose}, what is exactly this:



Except that:


So you don't have timeofday value. You need to compute it (at the end of you time changing loop):
Code:
    if time < 2:
        $ timeofday = "night"
   elif time < 4:
        $ timeofday = "morning"
   elif time < 6:
        $ timeofday = "noon"
   elif time < 8:
        $ timeofday = "afternoon"
   elif time < 10:
        $ timeofday = "evening"
   else:
        $ timeofday = "night"
Python:
    [...]
    class NPC:
        def __init__(self, name, nice_name, key):
            assert(create_key == NPC.__key)
            self.nice_name = nice_name
           # self.fmt_str = "avatar/{name}/{name}_{{}}.png".format(name=name)
           self.fmt_str = "avatar/{name}/{name}_{{}}_{{}}_{{}}.png".format(name=name)

        @property
        def avatar(self):
            global location
            #avtr = self.fmt_str.format(location)
            avtr = self.fmt_str.format(location, timeofday, pose )
    [...]
Obviously, you need to give a value to pose at some moment in your label:
Python:
label library:
    $ location = "library"
    $ pose = "pose1"
    anna "Hello MC, how are you."
    mc "Good, thanks. You look marvelous dressed like than."
    $ pose = "pose2"
    anna "Oh, you'll make me blush..."
Normally it should works.


This being said, I'm not really a fan of this method, because it's too rigid. Characters have to be where they are expected, and can not be somewhere else.
A better approach would be similar to what is done in Super Powered, something like:
/!\ This is wrote on the fly /!\
Python:
# How the images path+name are formed.
define imageMask = "images/girls/{}/{}/{}/{}.jpg"
#  You need to have at least an image "images/girls/NAME_OF_THE_GIRL/void/noon/idle.jpg"
# it will act as default image in case of error.
# Default location for all sprites.
define defaultLocation = "void"
# Default time of the day for all sprites.
define defaultTOD = "noon"
# Default pose for all sprites.
define defaultPose = "idle"


# The sprite image for Anna.
# Having a variable by girl complicate a bit the code, but offer a good security against missing images.
image anna = "girls/anna/[annaLocation]/[annaTOD]/[annaPose].jpg"
# Set the variables to their default values.
default annaLocation = defaultLocation
default annaTOD = defaultTOD
default annaPose = defaultPose

# Same for the mother.
image sally = "girls/sally/[sallyLocation]/[sallyTOD]/[sallyPose].jpg"
default sallyLocation = defaultLocation
default sallyTOD = defaultTOD
default sallyPose = defaultPose

# The game start in MC's room
default location = "MC room"

init python:
    #  Validate that an image exist, else find the most accurate one. In the same time, update the variables
    # that will define the image to display.
    def validateImage( who, pose ):
        # The image exist, update the variables for this girl
        if renpy.loadable( imageMask.format( who, store.location, store.timeofday, pose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.timeofday )
            setattr( store, who+"pose", pose  )
            return

        # The image do not exist, try to find the most accurate one.

        # Starting by the default pose.
        if renpy.loadable( imageMask.format( who, store.location, store.timeofday, store.defaultPose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.timeofday )
            setattr( store, who+"pose", store.defaultPose )
            return

        # The default time of the day with the asked pose.
        if renpy.loadable( imageMask.format( who, store.location, store.defaultTOD, store.pose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", pose  )
            return

        # The default time of the day with the default pose.
        if renpy.loadable( imageMask.format( who, store.location, store.defaultTOD, store.defaultPose ):
            setattr( store, who+"Location", store.location )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", store.defaultPose  )
            return

        # The default location with the actual time of the day and asked the pose.
        if renpy.loadable( imageMask.format( who, store.defaultLocation, store.timeofday, pose ):
            setattr( store, who+"Location", store.defaultLocation )
            setattr( store, who+"TOD", store.timeofday )
            setattr( store, who+"pose", pose  )
            return

        # The default location with the default time of the day and asked the pose.
        if renpy.loadable( imageMask.format( who, store.defaultLocation, store.defaultTOD, pose ):
            setattr( store, who+"Location", store.defaultLocation )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", pose  )
            return

        # Everything with the default values, this one exist we are sure.
        if renpy.loadable( imageMask.format( who, store.defaultLocation, store.defaultTOD, store.defaultPose ):
            setattr( store, who+"Location", store.defaultLocation )
            setattr( store, who+"TOD", store.defaultTOD )
            setattr( store, who+"pose", store.defaultPose  )


# Used to add a girl on the screen.
# Arguments:
#   who -> Name of the girl
#  pose -> [optional] pose for this girl
label showGirl( who, pose="idle" ):
    # Validate that the image effectively exist.
    $ validateImage( who, pose )
    # Then show the image. It will be automatically updated by Ren'Py when the variables' value change.
    show expression who
    return

# Used to remove a girl from the screen
label hideGirl( who ):
    hide expression who
    return

# Used to change the pose.
label setPose( who, pose ):
    # Validate that the image effectively exist,
    $ validateImage( who, pose )
    #  Nothing more to do. The variables for this girl are updated to match an existing image,
    # and Ren'Py will update the sprite automatically.
    return
Then you use it like that:
Python:
label library:
    $ location = "library"
    # Ask for the sprite of Anna, in her 'idle' pose.
   # While show her in her 'idle' pose, as she is in the library at this time of the day.
    call showGirl( "anna" )
    mc "Hello Anna, you are beautiful today"
    # Update the pose, asking for the 'blush' sprite. Still as it is in the library at this time of the day.
    call setPose( "anna", "blush" )
    anna "Oh, [MC.name], not so loud, your mother is here."
    # Ask for the sprite for the mother, in her 'curious' pose.
    call showGirl( "sally", "curious" )
    # Anna return to her 'idle' pose
    call setPose( "anna", "idle" )
    mom "Yes ? You called me ? Oh, hello son, how are you ?"
    anna "No, you should have misheard."
    mc "I'm fine."
    mom "Ok, then I return where I was, don't mind me."
    # Remove the sprite for the mother.
    call hideGirl( "sally" )
As I said, I wrote it on the fly, but normally it should works.
It imply a bit more works than the code you presented, but also offer you more freedom since the girls can be anywhere you want, as long as you have a sprite for this location. And if you don't have a sprite, the code will search the closest one to what you asked for.

Plus, if you choose wisely, the default sprites can still be used for unusual locations. By example, MC can go to a lingerie store with Anna. Since it will happen only once in the whole game, there's no need to have specific sprites for the basic poses:
Python:
label lingerieWithAnna:
    $ location = "lingerieShop"
    #  There's no image "images/anna/lingerieShop/afternoon/idle.jpg",
    # Ren'Py will display "images/anna/void/noon/idle.jpg"
    call showGirl( "anna" )
    mc "Oh, look at this, I'm sure you'll be beautiful wearing it."
    #  There's no image "images/anna/lingerieShop/afternoon/blush.jpg",
    # Ren'Py will display "images/anna/void/noon/blush.jpg"
    call setPose( "anna", "blush" )
    anna "Naughty boy. You really want to see me wearing this ?"
    mc "Of course."
    anna "Ok, I'll go try it."
    # Remove Anna, she's on the dressing room.
    hide showGirl( "anna" )
    anna "Hmmm, you're right, I look good in this."
    mc "You said that you'll show me."
    anna "Oh, really, I said this ? Hmm, OK."
    #  Here, you've an image "images/anna/lingerieShop/afternoon/naughtyLingerie.jpg",
    # Ren'Py will display it
    call showGirl( "anna", "naughtyLingerie" )
    mc "Wow... You're even more beautiful than I imagined it."
thanks for the info I got the solution from a member from renpy forums

user said:
This is relatively easy. First of all, you need to prepare format string:
Code:
self.fmt_str = "avatar/{name}/{name}_{{location}}_{{timeofday}}_{{pose}}.png".format(name=name)
Doubling braces escapes them, so they would not be considered part of replacement this time.

Then you change [c]avatar[/c] function to take time of day and pose globally, in addition to location and pass it to format function:
Code:
        @property
        def avatar(self):
            global location
            global TimeOfDay
            global pose
            avtr = self.fmt_str.format(location=location, timeofday=TimeOfDay, pose=pose)
            if renpy.loadable(avtr):
                return avtr
            else:
                return Crop((100, 100, 100, 100), Solid("#0F0"))  #"images/avatar/empty.png"
You can simplify time-keeping code drastically:

Code:
label advance_time:
    python:
        dn += 1
        if dn >= 24:
            dn = 0
        if dn == 6
            time = 0
        if dn in (9, 12, 16, 18, 21, 23): # if dn is one of the hours when time slice should change
            time += 1
    return

# Or even:
label advance_time:
    python:
        dn += 1
        if dn >= 24:
            dn = 0
        time = {6:0, 9:1, 12:2 16:3, 18:4, 21:5, 23:6}.get(dn, time)
        return
Edit: the changes that I have didn't work and for anne O'nymous way wouldn't work because my game is based on screen basis the image I post is made with screen not labels
 
Last edited: