Q: Adjusting a Random Variable [Renpy]

WickedCadrach

New Member
Jul 9, 2020
6
1
I'm fairly new to Renpy and coding in general so I apologize for the 'new guy' question', but I've been stuck on this for a while.

I'd like to set my script to pull a random variable from a list and then modify it. For instance, if I have a list of skills for a character and they get a bonus to a random skill, how do I put that through?

An abbreviated version of my current code is below. I'm fairly certain I know why this doesn't work, but I'm unsure what it should look like instead. Any help is greatly appreciated. Thank you!

Code:
$ skill_list = [fight, wits, lore]

$ skill_boost = 5

$ selectedSkill = renpy.random.choice(skill_list)

$ selectedSkill += skill_boost
 

K.T.L.

Keeping Families Together
Donor
Mar 5, 2019
555
1,079
Ok, edited because you evidently want to use a list. I'd use a dictionary for that but you could try:
Code:
$ skill_list[selectedSkill] += skill_boost

And I wouldn't use random.choice for that. try:
Code:
 $ selectedSkill =  renpy.random.randint(1, len(skill_list) )

So your code would look like:
Code:
$ skill_list = [fight, wits, lore]
$ skill_boost = 5
$ selectedSkill =  renpy.random.randint(0, len(skill_list)-1)
$ skill_list[selectedSkill] += skill_boost
Using randint to return an integer to access the list, from 0 (first item in the list) to len(skill_list)-1 the last item in the list. len() returns the 'length' of the object but because python indexes start at 0, we have to subtract 1 from the length to get the last index value. Hope that makes sense.
 
Last edited:
  • Like
Reactions: WickedCadrach

K.T.L.

Keeping Families Together
Donor
Mar 5, 2019
555
1,079
Apologies for all the edits on this one, hope it didn't cause too much confusion. There's a lesson there I think - Guinness and coding don't mix :whistle:
 
  • Like
Reactions: 79flavors

WickedCadrach

New Member
Jul 9, 2020
6
1
That does make sense when I read it. I gave it a try, but the boost still doesn't seem to transfer over to the skill variable.

I'm pretty new still, so you may be right that a dictionary is a better tool and I may just need to do my homework on that before I can do this.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,225
There might be a clever way to do it... but the simple way would be something like...

Python:
default fight = 0
default wits = 0
default lore = 0

default skill_boost = 0

label start:

    $ selectedSkill = renpy.random.randint(1, 3)
    $ skill_boost = 5

    if selectedSkill == 1:
        $ fight += skill_boost
    elif selectedSkill == 2:
        $ wits += skill_boost
    elif selectedSkill == 3:
        $ lore += skill_boost

    "*** THE END ***"

    return

If you were storing the stats in a , you could probably do something like:

Python:
default stats = {
        "fight": 0,
        "wits": 0,
        "lore": 0,
    }

default skill_boost = 0

label start:

    $ selectedSkill = renpy.random.choice("fight", "wits", "lore")
    $ skill_boost = 5

    $ stats[selectedSkill] += skill_boost

    "*** THE END ***"

    return

The first method has the advantage of being simple. The second method requires a basic understanding of , especially dictionaries in this case.

You don't strictly need the extra variable in the second example, but...
$ stats[renpy.random.choice("fight", "wits", "lore")] += skill_boost is both correct and somewhat unwieldy.

Honestly, I'd do it the first way... because I prefer simple to understand.

I'm certain there's a way of addressing the variable names as a variable itself. Probably by directly doing something with the object, or doing some sort of clever evaluate or expression statement or something. But it's also not common knowledge... and that sort of "clever" can be a bit of clever too far sometimes.

Edit: Found it. Apparently there's something called setattr(). You might be looking for:

Python:
default fight = 0
default wits = 0
default lore = 0

default skill_boost = 0

label start:

    $ selectedSkill = renpy.random.choice("fight", "wits", "lore")
    $ skill_boost = 5

    $ setattr(renpy.store, selectedSkill, getattr(renpy.store, selectedSkill) + skill_boost)

    "*** THE END ***"

    return

Where you are effectively doing setattr ( renpy.store, "fight", fight + 5 ) or something similar.
Needless to say, I hate it. :whistle:
 
Last edited:

WickedCadrach

New Member
Jul 9, 2020
6
1
This is awesome! Thank you!
I tried it using the dictionary method you described and did a bit of reading and it seems to be working well.

The setattr() looks interesting, but I agree that it seems a bit much.

Thanks again!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,225
The setattr() looks interesting, but I agree that it seems a bit much.

Honestly, I think I'd pick setattr() over dictionaries. But mainly because it retains the simplicity of having separate variables for each of the stats - which is what you'd normally see in a game created by a new VN developer.

But as with any solution... if it works and you understand it... it's fine.
... and RenPy is flexible enough that there's a dozen solutions to any problem.

Though I should also qualify all that by saying I've been bitten in the ass by dictionaries recently - so I am somewhat biased.
 

K.T.L.

Keeping Families Together
Donor
Mar 5, 2019
555
1,079
Readability is important. If you have trouble understanding something you've coded today, you'll really struggle with it in a couple of months time when you come back to it and have to work out what on earth you were thinking when you coded it. If in doubt, comment everything!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,225
Readability is important.

I couldn't agree more - and it's the reason I will always favor simple code over complex code.

If in doubt, comment everything!

I couldn't agree less. :giggle:
Comment nothing. If your code needs comments to understand it... then find a simpler way to write the code.

Again, I am somewhat biased. I've worked on WAY too many large systems where a programmer will update the code and not update the comments. A 3rd programmer comes along years later, reads the comments... believes them... and before long, I'm getting called in at 2am to fix something that everyone is convinced should work. I like my sleep too much to believe comments - and if they can't be trusted, they shouldn't be there. :p

Okay, okay... probably unnecessary advice for a hobbyist AVN project - but I have my principles, and I like my sleep.
 

WickedCadrach

New Member
Jul 9, 2020
6
1
Fair points!
I'm very much still learning and trying to dissect a lot of Renpy games right now to figure out how all this works. The creators that commented their files are goddamn saints in my book.
 
  • Like
Reactions: 79flavors

bernie1066

New Member
Jun 9, 2020
1
0
apologies for necro'ing this thread, was just reading through and thought I'd share another way of doing this that's kind of fun.

Code:
skills={"fight":10,"wits":10,"lore":10}
skill_boost = 5
selected_skill = renpy.random.choice(list(skills))
skills[selected_skill] += skill_boost
the skills are stored in a dictionary. list(skills) returns a list of the dictionary keys: ["fight", "wits","lore"].
random.choice() picks a key from that list, and then we use that to select the value in the skills dictionary to change.

pro's and cons:

with the setattr() / getattr() method, the skills are just regular properties so easier to reference later.

but, if you add more skills or change the names of any of them, you have to remember to change the code wherever else they are referenced. The dictionary method takes care of some of that for you.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,292
Code:
selected_skill = renpy.random.choice(list(skills))
It's useless to pass through a list for that. Due to it following paradigm, Python is pretty good at iteration, and can iterate almost anything.

Therefore this :
Code:
selected_skill = renpy.random.choice(skills.keys())
and even that :
Code:
selected_skill = renpy.random.choice(skills)
would do exactly the same, without the need to firstly transform the dictionary into a list.