Specifying a character object in a conditional

-CookieMonster666-

Devoted Member
Nov 20, 2018
11,321
16,534
I found an incest patch for a game that does a find-and-replace in text as you go along. Here is a small part of it; Julia would be the mother and Lucy the sister.
Python:
init 1040 python:
    def nameChange(txt):
        if "sJulia" in txt:
            sJulia.name = "Mom"
            return txt.replace("sJulia","sJulia")
        elif "Julia" in txt:
            return txt.replace("Julia","Mom")
        elif "sLucy" in txt:
            sLucy.name = "Sis"
            return txt.replace("sLucy","sLucy")
        elif "Lucy" in txt:
            return txt.replace("Lucy","Sis")
        else:
            return txt

    config.say_menu_text_filter = nameChange
The problem with this is that you end up with add instances of replacement that don't make sense:
  • A character related to neither the MC nor Julia will say "Mom", when "your Mom" or just "Julia" would make more sense. For example, a character named Isabella says, "I feel something special for Mom. I always took care of her." But she's not Isabella's mother.
  • An extended family member uses a term with his own wife that is really used for extended family (and someone in a higher position of respect within the family). For instance, a character referred to by the MC as "Aunt Emma" is getting called the same by her husband, Uncle Walter. Since she's Walter's wife, Walter would never refer to her as his aunt, but he does with the current text replacement code.
Is there a way to refer to characters such as Julia or Emma within a conditional, using their character objects? So basically to say:
  1. If Ren'Py finds that a character currently speaking refers to Julia and is either the MC or Lucy, have them use "Mom".
  2. If a character currently speaking is Walter, have him use "Emma" instead of "Aunt Emma".
This type of thing. Being able to identify who is speaking in a conditional would allow for much better character references when the patch is used.
 
  • Like
Reactions: Lgn332

pepette

Active Member
Game Developer
Feb 20, 2018
933
2,252
I don't use Ren'Py, but it's mainly a coding logic problem.

In the game code, the character's name should only be replaced in sentences about people in relationships. The rest of the time, the text should be "normal".
If you are not the dev of the game, it will involve making a MOD to change this.

To go further, you can consider at last 2 variables per character:
- 1 that changes the first name (used by people without a relationship)
- 1 that changes the relationship (sister / roommate...)
Then, you just have to call the right variable according to the context of the sentence.

Some games use this kind of question at the beginning of the game:
- her name is (name)
- she is your (sister / roommate)
- you call her (sis / surname / name)
 
  • Thinking Face
Reactions: -CookieMonster666-

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,391
15,307
The problem with this is that you end up with add instances of replacement that don't make sense:
Yeah, it's a problem I pointed many times. Text replacement is the less of two evil, but not necessarily the best approach.


Is there a way to refer to characters such as Julia or Emma within a conditional, using their character objects? So basically to say:
  1. If Ren'Py finds that a character currently speaking refers to Julia and is either the MC or Lucy, have them use "Mom".
  2. If a character currently speaking is Walter, have him use "Emma" instead of "Aunt Emma".
There's a way, but it would be a dirty hack. But anyway it wouldn't give better result than the unconditional replacement.
Imagine the MC talking about his mother to a friend. The line "It's my landlady, her name is Julia", would then become "It's my mother, her name is mom".
This approach could only works if you can also know to who the character is speaking, but it's an information that you can't have.

As modder, the only viable approach is to base the text replacement on the whole lines.
Code:
default replacementStrings = [ 
    "this line": "its new version",
    "that line": "yet another version",
    [...]
    ]

init 1040 python:

    def lineChange(txt):
        return replacementStrings[txt] if txt in replacementStrings else txt

    config.say_menu_text_filter = nameLine

    config.label_overrides["labelName"] = "labelNamePatch"
    config.label_overrides["labelNameReal"] = "labelName"
    config.label_overrides["labelName1"] = "labelName1Patch"
    config.label_overrides["labelName1Real"] = "labelName1"

 
label labelNamePatch:
    $ replacementStrings = [ 
    "this line from this label": "its new version",
    "that line from that label": "yet another version",
    [...]
    ]
    jump labelNameReal

label labelName1Patch:
   [...]

And as the coder, the approach is either to use custom tags:

Code:
label whatever:
    mc "This is my {myTag}landlady{/myTag} her name is Julia"
    mc "{myTag}Julia{/myTag}, I need to go to the mall with my friend, can I use your car ?"
The substitution apply during the tag processing, ensuring you that you'll only change the value when the change is significant.

or to rely on variables:
Code:
define impersonal = "Julia"
define personal = "Julia"
define title = "Landlady"

label whatever:
    mc "This is my [title] her name is [impersonal]"
    mc "[personal], I need to go to the mall with my friend, can I use your car ?"
Then you've this kind of patch:
Code:
define impersonal = "Julia"
define personal = "Mom"
define title = "Mother"
 
  • Like
Reactions: -CookieMonster666-

-CookieMonster666-

Devoted Member
Nov 20, 2018
11,321
16,534
Yeah, it's a problem I pointed many times. Text replacement is the less of two evil, but not necessarily the best approach.




There's a way, but it would be a dirty hack. But anyway it wouldn't give better result than the unconditional replacement.
Imagine the MC talking about his mother to a friend. The line "It's my landlady, her name is Julia", would then become "It's my mother, her name is mom".
This approach could only works if you can also know to who the character is speaking, but it's an information that you can't have.

As modder, the only viable approach is to base the text replacement on the whole lines.
Code:
default replacementStrings = [
    "this line": "its new version",
    "that line": "yet another version",
    [...]
    ]

init 1040 python:

    def lineChange(txt):
        return replacementStrings[txt] if txt in replacementStrings else txt

    config.say_menu_text_filter = nameLine

    config.label_overrides["labelName"] = "labelNamePatch"
    config.label_overrides["labelNameReal"] = "labelName"
    config.label_overrides["labelName1"] = "labelName1Patch"
    config.label_overrides["labelName1Real"] = "labelName1"


label labelNamePatch:
    $ replacementStrings = [
    "this line from this label": "its new version",
    "that line from that label": "yet another version",
    [...]
    ]
    jump labelNameReal

label labelName1Patch:
   [...]

And as the coder, the approach is either to use custom tags:

Code:
label whatever:
    mc "This is my {myTag}landlady{/myTag} her name is Julia"
    mc "{myTag}Julia{/myTag}, I need to go to the mall with my friend, can I use your car ?"
The substitution apply during the tag processing, ensuring you that you'll only change the value when the change is significant.

or to rely on variables:
Code:
define impersonal = "Julia"
define personal = "Julia"
define title = "Landlady"

label whatever:
    mc "This is my [title] her name is [impersonal]"
    mc "[personal], I need to go to the mall with my friend, can I use your car ?"
Then you've this kind of patch:
Code:
define impersonal = "Julia"
define personal = "Mom"
define title = "Mother"
Perhaps I could combine both approaches? I could use the dirty hack to which you referred, and then in instances where it doesn't work ("This is my mother. Her name is mom"), I could use line replacement. Or maybe there are unforeseen problems with this combined approach as well.
 
Nov 23, 2017
67
58
This approach could only works if you can also know to who the character is speaking, but it's an information that you can't have.
I also find it problematic, from a modder's perspective, when characters are speaking with each other rather than with the protagonist. But I would imagine knowing the "who" from the say statement would minimize this.
 

-CookieMonster666-

Devoted Member
Nov 20, 2018
11,321
16,534
I also find it problematic, from a modder's perspective, when characters are speaking with each other rather than with the protagonist. But I would imagine knowing the "who" from the say statement would minimize this.
Definitely. It's a shame that knowing what characters are interacting in a scene is an impossible (or at least monumentally cumbersome) task. Theoretically it might be possible to do so in any programming language, but it would be a hack at best. You might be able to take a current line of dialogue, look at the lines before that and after that, and (with a conditional to rule out a narrator or the same character using multiple lines) make assumptions that the character whose lines come before and/or after are part of the conversation.

This comes with all kinds of problems, though. What if the MC was talking to John and then turned to address Barbara, who had just walked up to the pair of them? Does the code assume Barbara's speech is John continuing to talk? What if the MC was talking to John, but then John left and the MC heard a pair of children playing in the background? There's literally no way to get all of those scenarios right, making any attempt to do so at best imperfect and at worst (the more likely result) extremely confusing and terrible to read.
 
Nov 23, 2017
67
58
Definitely. It's a shame that knowing what characters are interacting in a scene is an impossible (or at least monumentally cumbersome) task. Theoretically it might be possible to do so in any programming language, but it would be a hack at best. You might be able to take a current line of dialogue, look at the lines before that and after that, and (with a conditional to rule out a narrator or the same character using multiple lines) make assumptions that the character whose lines come before and/or after are part of the conversation.
I don't know about all the characters participating in the conversation, but I can confirm that you can access the character currently speaking by shamelessly monkey patching renpy.exports.say and modifying the text inside it, rather than using config.say_menu_text_filter (no idea what would be the side effects of that).

This comes with all kinds of problems, though. What if the MC was talking to John and then turned to address Barbara, who had just walked up to the pair of them? Does the code assume Barbara's speech is John continuing to talk? What if the MC was talking to John, but then John left and the MC heard a pair of children playing in the background? There's literally no way to get all of those scenarios right, making any attempt to do so at best imperfect and at worst (the more likely result) extremely confusing and terrible to read.
Yeah, that would be a nightmare. You might be better off doing some kind of general replacement (perharps using regular expressions) and in those edge cases where things get weird, you replace the whole line.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,391
15,307
Perhaps I could combine both approaches? I could use the dirty hack to which you referred, and then in instances where it doesn't work ("This is my mother. Her name is mom"), I could use line replacement.
A dirty hack is never the solution when you can avoid it.
Anyway, how your idea to combine the two would works ?

If the MC say "This is my landlady, her name is Julia" to a friend, how do you'll tell to the dirty hack that he must not change the line ? If it's for having the dirty hack change the line, then to have the text replacement restore it, what's the interest ?


Definitely. It's a shame that knowing what characters are interacting in a scene is an impossible (or at least monumentally cumbersome) task.
My bad, I haven't been explicit enough. The dirty hack was referring to the question as you asked it ; a child of Character to handle differently the text replacement for some characters. I should have been more explicit.

Because strictly speaking, knowing who is speaking need only one line:
Code:
screen say( who, what ):
    if who == mc.name:
        [...]
What imply that you can perfectly have this:
Code:
init python:

   def nameChange(txt):
        if "Julia" in txt:
            return txt.replace("Julia","Mom")
        else:
            return txt

screen say( who, what ):
    if who in [mc.name, sis.name]:
        $ what = nameChange( what )
And since screens can be overwrote without problem (the last one declared will be the one used), it's something really basic.

But as I said, this will still lead to too many unwanted changes. And the only way to make this works without them is to know to whom the character is speaking, what isn't possible as it...



Theoretically it might be possible to do so in any programming language, [...] This comes with all kinds of problems, though. What if the MC was talking to John and then turned to address Barbara, who had just walked up to the pair of them?
Exactly.

Code:
label whatever:
   [Whole dialog between MC and his friend]
   [They move to the living-room, where the mother is]
   mc "This is my landlady her name is Julia"
   mc "Julia, I need to go to the mall with my friend, can I use your car ?"
   [The mother exit the scene]
   friend "You don't need to do that, I'll take the bus."
   mc "I insist, it's late, and it's because I've been too talkative."
   [the mother come back on the scene]
   mother "Here's the key [mc.name]."
How do you want to know that the second dialog line was the MC talking to his mother ?


The only way to know to whom the character is speaking is to explicitly provide the information:
Code:
init python:

   def nameChange(txt):
        if "Julia" in txt:
            return txt.replace("Julia","Mom")
        else:
            return txt

screen say( who, what, whom=None ):
    if whom in [ "mother", "sister", "son"] and who in [mc.name, sis.name]:
        $ what = nameChange( what )

label whatever:
    mc "This is my landlady her name is Julia"
    mc "Julia, I need to go to the mall with my friend, can I use your car ?" ( whom="mother" )
But obviously this works only if you're the game author. As I said, the only effectively reliable method for modders is to perform a text replacement based on a dictionary.



[...] I can confirm that you can access the character currently speaking by shamelessly monkey patching renpy.exports.say and modifying the text inside it, [...]
What an over complicated way to do something trivial (see above).