Ren'Py Defining characters by trait [Solved]

Lou111

Active Member
Jun 2, 2018
538
680
Trying to make the speaker say something based on who is tagged by a variable.
More specifically, I have characters who will be assigned a random trait and I want whomever has these traits to speak.
For example: If there is an item and 30 possible characters could be holding it, I want that character to say "I'm the one holding it."

I've tried several different methods but the closest I got was using the .format function for the "who" and the side image doesn't show as a result.

Thank you for your time
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
I think any answer would be based on how you're currently storing the traits, the inventory and whatever method you're storing the "who could be holding it". So it might be helpful if you could post those sections of code from your script.

I don't think the answer is the screen who(). I'm thinking perhaps some sort of function that can return a string ("I'm the one holding it" or "" - an empty string) based on your existing stored data.

Then tie that in to the text filtering.
Historically, we've always used that for replacing words like "Landlady" with "Mother". But there's no reason it couldn't be used so replace a unique bit of text like "$itemheld$" with the string value returned from a some code that did some sort of item/person lookup.

Alternatively, you can do something similar with custom text tags tied into . Where you create a custom tag for string substitution... maybe something like "{itemflag}compass{/itemflag}", where {itemflag} is a custom text tag and compass is the name of the item that character could be holding (assuming you store the names of items... it could be an item number instead... or... well, lots of possibilities.
Or "{itemflag=mc}compass{/itemflag}", where the additional argument mc is the Character() object for the character you care about (then use something like arg.name within the function to access the name property of the mc object).

Example of say.menu_text_filter :
Example of custom_text_tags : https://f95zone.to/conversations/messages/307071/

Personally I find the text filtering easier to follow. But that's mainly because I find the tuples used by custom tags a concept my brain says "learn about that later"... and later never comes. The custom tags may be better solution, as it seems more flexible.
 
Last edited:
  • Love
Reactions: Lou111

Lou111

Active Member
Jun 2, 2018
538
680
I think any answer would be based on how you're currently storing the traits, the inventory and whatever method you're storing the "who could be holding it". So it might be helpful if you could post those sections of code from your script.
Thank you for your reply!
I just finished typing code for 14 hours. After work tomorrow I'll have to look at this and see if the solution is within it.

I thought the "item" example was a smart way to simplify my question but I was wrong.
I'm trying to build something where the NPCs are assigned random personalities and traits. In my side-project I'm testing it by allowing the player to select/choose personality traits to assign to NPCs. (i.e. She's the quiet one who is also materialistic)...
Then I want to add dialogue and have the "quiet one" speak the words rather than a specific character.
I'm still trying to figure out if this is the most efficient way to accomplish this but the most pressing concern is that I don't know how to get a character to speak based on whether a specific tag is assigned to them complete with their side images and stuff...
Long story short: I don't have the code to post yet cause I don't know where to start yet.
However! After reading the links you posted I'm sure I'll have a great idea, but this guy needs to put his head down.

Thanks again, friend! :D
 

guest1492

Member
Apr 28, 2018
322
272
I assume you have something like a variable holding a list of your randomized characters. Can't you just do something like this?

Python:
for x in list_of_characters:
    if x.has_trait("quiet"): # Just an example because I don't know how you implement your traits
        x "Say something"
 
  • Love
Reactions: Lou111

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,286
Then I want to add dialogue and have the "quiet one" speak the words rather than a specific character.
So 79flavors is right, this have nothing to do with the "say" screen and its who argument, and it totally depend of the way you store the traits. And the answer is near to what guest1492 said.

In the end, this is one of the many way to do what you want:
Python:
init python:

    # API to the name selection.
    class WhoByTraits( renpy.python.RevertableObject ):

        # [Internal] character selection code
        def _who( self, trait ):
            # For all the characters present in the current scene.
            for name in allCharactersInScene:
                # Get its traits
                charTraits = getattr( store, name+"Traits" )
                # If the character have the right trait...
                if getattr( charTraits, trait ):
                    # ... return its name.
                    return charTraits.who

            #  If no character have the expected trait, return the name of a
            # default character to not make Ren'py crash.
            return secureNet

        @property
        def quiet( self ):
            return self._who( "isQuiet" )

        @property
        def shy( self ):
            return self._who( "isShy" )

        @property
        def sad( self ):
            return self._who( "isSad" )

    # The object playing as interface don't need to be saved.
    byTraits = WhoByTraits()

    # Object where the traits are stored.
    class CharactersTraits( renpy.python.RevertableObject ):
        def __init__( self, who ):
            self.who = who
            self.isQuiet = False
            self.isShy = False
            self.isSad = False
            # [...]


# List of all the characters present in the current scene.
default allCharactersInScene = []

# The default character used to avoid crashes.
define secureNet = Character( "Voice in your head" )

# One character - don't need to be saved
define anna = Character( "Anna" )
# And its traits, that need to be saved
default annaTraits = CharactersTraits( anna )

define sarah = Character( "Sarah" )
default sarahTraits = CharactersTraits( sarah )

#  The generic characters corresponding to the expected trait. They take their
# name from the API object.
define quiet = Character( "[byTraits.quiet]" )
define shy = Character( "[byTraits.shy]" )
define sad = Character( "[byTraits.sad]" )


label start:

    # Generic traits assignation for the demonstration.
    $ annaTraits.isQuiet = True
    $ sarahTraits.isShy = True

    # Define what characters are present in the current scene.
    $ allCharactersInScene = [ "anna", "sarah" ]

    # The quiet character will say this.
    quiet "I'm the quiet character."
    # The shy character will say this.
    shy "And I'm the shy one."
    # It's not something definitive, the traits can change at anytime.
    $ annaTraits.isShy = True
    $ sarahTraits.isShy = False
    # Still said by the shy character, but not by the same girl.
    shy "No, I'm the shy character, at least now."
    # No one is sad, so this will be said by the security character.
    sad "And I'm the sad character..."
    "END"
    return
The approach by itself (relying on a character by trait) is probably the best one, because it make the dialog explicit. You know that it's the quiet character that will say this, whatever who this quiet character can be.
As for the traits "storage", it's better to have a external object for this, but if really you want the traits can be handled by the Character object ; it's no recommended, but it's possible.

You can also remove the security net character if you want. But in this case, you'll need to verify that a character correspond to the expected trait before using it:
Code:
label whatever:
    if not byTraits.shy is None:
        shy "Hello MC, what do you want ?"
        mc "To invite you for a coffee."
        shy "Me ?"
        mc "Yes."
    else:
        jump somewhere else
And finally you can also have full interaction with the given character like this:
Code:
label whatever:
    $ char = byTraits.shy
    if not char is secureNet:
        mc "[char] do you want to go see a movie with me ?"
        char "Me ? Really ?"
        mc "Yes [char], you."
        char "I... I accept."
        mc "Good, lets go."
        jump expression "movieDate_" + str( char )
    [...]

label movieDate_Sarah:
    [...]

label movieDate_Anna:
    [...]
 
  • Like
  • Yay, new update!
Reactions: DuniX and Lou111

Lou111

Active Member
Jun 2, 2018
538
680
anne O'nymous 79flavors guest1492

You guys are so freakin awesome!
I can't wait to get home from work and implement this! I don't know where I'd be without you guys...

I can always take your posts and make a day out of it, coming out a stronger writer. :D

Thank you for your time, I really appreciate it!