Renpy - assigning a variable to equal a character ??

TDoddery

Member
Apr 28, 2020
175
167
Despite reading a lot of Ren'Py stuff I'm afraid I'm still struggling with this.

So here's the thing - I define a character in the usual way - let's say they are defined as "X".

That all works fine.

Then I want to tag character X for some special purpose (Let's call the special purpose "A").

So I define A as a variable, and then the relevant code goes - $ A = X

Now if I write a Ren'Py "say" statement like "Mr [A] went into town." It works fine and I get text saying "Mr <The name of the character X> went into town."

But here's what I don't get - if I try a conditional statement like: if A == X :

Then it comes up false. Even though Ren'Py has obviously recognized A as being equal to X.

WTF ............ anybody ?
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
Not sure.

My first thought was that X is a Character() and A might be a string (since the name of the character is the default value returned when used - which is why [X] works as a string when you use it in dialogue).

But I just tried the following code, and my if A == X: type check came back True.

Python:
define e = Character("Emily", color="#04B486")

label start:

    scene black with fade
    "Start:.... "

    $ e_var = e

    if e_var == e:
        "they are the same"
    else:
        "NOT the same"

    "*** THE END ***"

    return

Not sure why I'm seeing different results than you. I can only conclude something else is going on.

But if I open the developer console (shift+D) after the variables have been assigned and then go into the Variable Viewer... it tells me that e_var is a Character() - which if I'm honest, I was a bit surprised at.

My best guess is that because a Character() object is more than just the character's name - some other value/property of the Character() object could have altered as your code continues - but my code is too simple and/or close to the change of value to see the same results.

What I think you maybe want, is the actual name of the character stored as a string.

Python:
define e = Character("Emily", color="#04B486")
default e_var = ""

label start:

    scene black with fade
    "Start:.... "

    $ e_var = e.name

    if e_var == e.name:
        "they are the same"
    else:
        "NOT the same"

    "*** THE END ***"

    return

Now e_var is a simple string, with a value of "Emily" (store in unicode - which is the u' before the string value you may see in specific places).

A full list of the can be found in the documentation. But "name" sounds like the right choice here - assuming my assumptions are correct.

Variables containing strings seems right to me. Variables as Character() objects causes a nervous twitch in my eye. It might be fine. That could just be because I like to play things safe when coding.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,191
But here's what I don't get - if I try a conditional statement like: if A == X :

Then it comes up false. Even though Ren'Py has obviously recognized A as being equal to X.
Hmm ?

Code:
default mc = Character( "MC" )

label start:
    $ a = mc
    $ equality = a == mc
    "Is 'a' equal to 'mc' ? [equality]"
    if a == mc:
        "They really are equal."
        if a is mc:
            "I mean really, really equal."
        if id( a ) == id( mc ):
            "Like in 'it's strictly the same object'."
    else:
        "They aren't equal"
    "END"
    return
Return the expected :
  • Is 'a' equal to 'mc' ? True
  • They really are equal.
  • I mean really, really equal.
  • Like in 'it's strictly the same object'.
  • END

There's something in your code that isn't shown in your explanation, or the value of A is changed before the if.


My first thought was that X is a Character() and A might be a string (since the name of the character is the default value returned when used - which is why [X] works as a string when you use it in dialogue).
Yes but no.

Ren'py define the magic methods __str__, __unicode__ that return the "printable string representation" of the object, and __format__ that do the same, but for the format() string method. That's why when you've something like sayer "this is [mc]" or text ( "Name: {}".format( mc ) ) you effectively get the name of the character ; I assume that it's even the reason why those methods are defined.
To this add the __repr__ that do the same but when the repr() function is called. What permit to see "<Character: MC>" when using at the variable viewer by example. It's a debug helper.

But when you do an assignation like A = X then "A" and "X" now point to the same object. So there's no reason for an if a == x to fail, like shown by my example above ; and like it's Python, it's not because there's a missing =, since it would have thrown an error.
The assignation make them not only equal, but also strictly identical.

Some words regarding the difference between "equal" and "strictly identical", because it's something to know, even if it's rarely used :
Code:
label start:
    $ a = "abc"
    $ b = "abc"
    $ iA = id( a )
    $ iB = id( b )
    "Id of 'a' : [iA]\nId of 'b' : [iB]"
    if a == b:
        "'a' is equal to 'b'."
    if a is b:  # could have been an /if not/ but more understandable this way.
        "..."
    else:
        "'a' isn't strictly identical to 'b'."
    $ b = a
    $ iA = id( a )
    $ iB = id( b )
    "Id of 'a' : [iA]\nId of 'b' : [iB]"
    if a is b:
        "Now they are strictly identical."
    "END"
Despite a and b having the same value from the start, and so being always equal, they become identical only when you finally assign a to b. Before this, they were only two different string objects that happened to have the same value.
 

TDoddery

Member
Apr 28, 2020
175
167
Thank you both very much. I'm responding on my 'phone at the moment so I can't test anything out, but that last bit makes me wonder if the problem might be due to X having been defined in the strict sense (ie. define X = Character(..... etc.) whereas the variable "A" was created as a default (default A = 0) and then got changed in-game through $ A = X.

So I guess they cannot be regarded as identical because theoretically A could change again but X can't. Maybe ?

I'm sure nothing else happens to A because $ A = X is the result of a menu outcome whereby A can be equated to one of several characters, but that can only happen once.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,191
So I guess they cannot be regarded as identical because theoretically A could change again but X can't. Maybe ?
No, it's not that. Whatever the way you create them, they'll still be variables and have the same behavior. It's only when the time come to save the game, that the use of default and define will make a difference.


I'm sure nothing else happens to A because $ A = X is the result of a menu outcome whereby A can be equated to one of several characters, but that can only happen once.
Still there's something. Not that I doubt your words, just that I know for sure that, as you presented it, it can't works differently than what I said ; and as you can see, both 79flavors and me came to the same conclusion, and both our tests said that what you get isn't the correct behavior.

Even something like this lead to an equality :
Code:
default mc = Character( "MC" )
default a = None

label start:
    $ renpy.call_in_new_context( "called" )
    $ rA = repr( a )
    if a == mc:
        "They are equal, a is [rA]"
    else:
        "They aren't equal because a is [a]"
    "END"
    return

label called:
    $ a = mc
    return
So either the assignation isn't done, or the value of A is changed after it.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
Or to put it another way...

It works exactly how you originally expected it to work.

The fact that it's doing something else "probably" means you're not actually doing what you think you're doing. Either there's some extra code in there you've forgotten or there's a typo that you've stared at for so long - you still don't see it for what it really is.

That's the problem with simplifying things to post here on the forums - you end up with code that you know should be more or less the same - but isn't.
 

TDoddery

Member
Apr 28, 2020
175
167
Well I am of course grateful to you both for your time and knowledge. However, today I tried simply changing the define of the character to a default instead and ..... everything worked !?

But given AON has kindly reminded me that "It's only when the time come to save the game, that the use of default and define will make a difference.", I'm now thinking maybe when I was having the problem I was running it from an inappropriate save point and that might have been the problem. After I changed the character define to a default I re-started the game from scratch. So maybe that's why it started working, although it was still recognizing that the A had acquired the character's name, so the save either included the $ A = X event or I had continued through it.