Ren'Py Using Variables to pull data from array

SiddyJJ

Newbie
Apr 3, 2021
24
15
Hey Guys and Gals,

I am using a stats library that I got from somewhere, I cannot honestly remember :) Anyway it creates inventory and stats using a python class. The stats look something like this(taken from my game slightly)

default Amys = ModelStats("Amy", age='27', Fashion='Y', uWare = 'Y', Toys = 'Y', Glamour = 'Y', Video = 'N', Exp = 'Low', relation = 'No', Fash_Rate = 15, uWare_Rate = 20, Glam_Rate = 25, )

now to pull from or edit the values in my renpy code I can refer to the contents like this: pov " Amy Costs [amys.uWare_Rate] for Underwear"

What i want to do is use a variable sets so that I can re use the code for multiple girls. I have setup some defaults in my script file.

mod = Models name
mod_s = Models name with s added to end
sh_Levl = the Level rate they are shooting

so our examples would be:
mod = Amy
mod_s = amys
sh_Levl = uWare_Rate
I would like to do somethig like this: pov "[mod] charges £[mod_s.sh_Levl]"

However I get an error when calling the code:
Python:
in script
    b_mod "[mod_s] and [sh_Levl] [mod_s.sh_Levl]"
  File "renpy/common/00library.rpy", line 268, in say
    who(what, interact=interact, *args, **kwargs)
AttributeError: 'unicode' object has no attribute 'sh_Levl'
Am I not able to use Variables in this way? I'm sure I can bodge a way of making it work but I don't understand when it is not working when displaying the varibles individually they are correct.

Cheers
me
 

SiddyJJ

Newbie
Apr 3, 2021
24
15
Thanks, That didn't work either :( Same error message.

I have worked out a way around my issue. Not as nice as I would of liked but it will work for now, and I can play with the script to get it working properly.
 
Last edited:

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
If I'm reading it correctly, your basic problem is that you are trying to use a string as an object - rather than the object itself.

So you have:

default Amys = ModelStats("Amy", age='27', Fashion='Y', uWare = 'Y', Toys = 'Y', Glamour = 'Y', Video = 'N', Exp = 'Low', relation = 'No', Fash_Rate = 15, uWare_Rate = 20, Glam_Rate = 25, )

Which I guess references the class ModelStats().

So to access anything, you need Amys.Toys for example.

I'm no python expert. But I looked into things like lists, dictionaries and classes a while ago in order to try to learn it. In the process, I wrote an introductory guide here on the forums (included in my .sig).

What I was thinking was to have another variable as almost a wrapper around your ModelStats() class. In my guide, I think I referred to it as "lists within lists, within lists, within lists".
In this case, I think you want "a class within a dictionary".

I had a quick play around and came up with this code...

Python:
init python:

    class ModelStats():
        def __init__ (self, age=18, fashion=True, uwear=True, toys=True, glamour=True, video=False, exp=0, relation=False, fash_rate=15, uwear_rate=20, glam_rate=25):
            self.age = age
            self.fashion = fashion
            self.uwear = uwear
            self.toys = toys
            self.glamour = glamour
            self.video = video
            self.exp = exp
            self.relation = relation
            self.fash_rate = fash_rate
            self.uwear_rate = uwear_rate
            self.glam_rate = glam_rate

default girls = {
            "Amy": ModelStats(),
            "Betty": ModelStats(age=19, uwear=False, toys=False, glamour=False),
            "Carol": ModelStats(age=25, relation=True),
            "Debbie": ModelStats(fash_rate=10, uwear_rate=10, glam_rate=10)
        }

label start:

    scene black with fade
    "*** START ***"

    if girls["Amy"].age >= 18:
        "Today Amy is legal. She is [girls[Amy].age]."
    else:
        "Today Amy is jailbait."

    scene black with fade

    "*** THE END ***"
    return

I've used dictionaries here because of the need to refer to each character by name.

Note the difference between code and text substitution. Normally, [girls[Amy].age] would be coded as [girls["Amy"].age]. But I guess the text substitution doesn't really like double quotes within dialogue. I tried it with single quotes (which didn't work either). Why I thought to try it without any quote is anyone's guess... but it works (at least to a point).

I've also changed some of the variable types from strings ("Y") to boolean(True/False) as well as string("Low" to integers (zero). Plus corrected uWare (which I guess is UnderWear). But only because that's how I'd do it. It'll work equally well with your existing setup, even if it risks potential typos of case ("low" instead of "Low" or "y" instead of "Y" for example).

I don't think it solves all your problems. But it may help you avoid separate objects for each and every character.

Within your code, you'll be able to have separate variable to control which girls is currently active. But that flexibility only goes so far.

For example:

Python:
default girl_name = "Amy"

label start:

    scene black with fade
    "*** START ***"

    if girls[girl_name].age >= 18:
        "Today [girl_name] is legal. She is [girls[girl_name].age]."
    else:
        "Today [girl_name] is jailbait."

Whilst the name of the girl can be substituted for a variable in if girls[girl_name].age >= 18:...
"She is [girls[girl_name].age]." doesn't work. The text substitution that allows for dictionary use doesn't cope well with swapping Amy for girl_name in any combination I can figure out.
(Which isn't to say it's not possible... just that I can't figure out how).

I'm currently testing with RenPy 7.4.5. It's possible newer versions are better at it. (Unfortunately, I've somehow broken my copies of 7.4.8 and 7.4.11.

You could of course copy things to another (simpler) variable and use that within dialogue instead, as a workaround...

Python:
default girl_name = "Nobody"
default girl_data = None

label start:

    scene black with fade
    "*** START ***"

    $ girl_name = "Amy"
    $ girl_data = girls[girl_name]

    if girls[girl_name].age >= 18:
        "Today [girl_name] is legal. She is [girl_data.age]."
    else:
        "Today [girl_name] is jailbait."

That code deliberately mixes variables that could be simplified... mainly just to show the possibilities.
It is only necessary because of the way the text substitution works for spoken text. Oddly, its much easier to do as part of screen code, where you can use "She is {}.".format(girls[girl_name].age).

Also because $ girl_data = girls[girl_name] creates a reference (think "alias" or "shortcut") between girl_data and girls[girl_name], if you update girl_data.age, that immediately affects girls["Amy"].age. Creating references (as opposed to new objects) is an "object oriented programming" thing that is beyond the scope of this question - But I figured worth mentioning, because at some point you're going to want to increase the girl's rates or experience and knowing it works this way makes that easier to code.

Not quite sure if that helps. There is undoubtedly a better solution - but this seems to hit the majority of your requirements (I hope).
If none of that makes sense, perhaps read my dictionary guide. Or read the original details I found at .
 
Last edited:

SiddyJJ

Newbie
Apr 3, 2021
24
15
Thanks for such a detailed response! I'm going to play with your Dictionary, as it is lots smaller than that class I am using. I worked around my issue by setting up some temporary variables in the menu choice before they were needed, which owing to the nature of the models, I am going to have to have one of for each model, until I get better at coding.
 
Last edited: