Getting random character

Pilotus13

Newbie
Aug 14, 2018
32
26
Hi everyone,

I'm writing a content expansion for Lab Rats 2 ( ) and for one event that I plan to do, I need to get any random person from the entire gaming world (there are a lot of randomly generated people and I need to pick any of them). It seems that in this particular game there is no list of existing characters so I cannot just pick from the list.

Is there any global Ren'py function that allows to do that or it is strictly project dependent? If second option it is, could please anyone take a look at the game code and provide a solution?

Thanks in advance.
 

Trollden

Member
Aug 8, 2017
253
326
Hi everyone!

I'm writing another content expansion to make game even better (at least - in my eyes). But I have a problem with one event that I'm planning to do (yes, there will be additional events, not the expansion of old ones like my previous work).

For this particular one I need to get a random person from the whole world (so it is not limited to your employees or relatives, that are easy to get). But since I'm not any good with Ren'py, I miserably fail with this task.

Could anyone from the community, who is better with coding, provide the solution? The task is simple - I need to get any person (at random) that exists in your current game world.

Thanks in advance to Whoever-It-Will-Be.
I have no idea.
Have been looking through the scripts and there doesn't seem to be a builtin way listing all the characters in the world.

If you check the main script for "people_to_process" I think the answer is inside there somewhere as that contains a list of all the places and all the people within those places, but I could only make it return the Person (object).

Code:
python:
        people_to_process = [] #This is a master list of turns of need to process, stored as tuples [character,location]. Used to avoid modifying a list while we iterate over it, and to avoid repeat movements.
        for place in list_of_places:
            for people in place.people:
                people_to_process.append([people,place])
             
# This is the code inside the script after that I've been trying something like:

the_person = get_random_from_list(people_to_process)

# The problem with this is that it always returned a specific character and also had other oddeties
# Here is exactly what I did for that:
label person_in_world:
    python:
        people_in_world = []
        for place in list_of_places:
            for people in place.people:
                for person in place.people:
                    people_in_world.append([person])
        the_person = get_random_from_list(people_in_world)
After giving up on that I've been checking how the game determines spectators to the sex scenes, but that led pretty much nowhere as it draws from people in the location only, obviously.

Code:
#### Made a test label that I could call and it would randomize the_person to be from the location mc currently is in

label person_in_world:
        $ person_in_world = [person for person in mc.location.people]
        $ the_person = get_random_from_list(person_in_world)

# call person_in_world assigns the_person to someone in location
# Since I also don't know how to code I tried the next logical step to have it be
#"person for person not in mc.location.people"
# but that's sadly not a thing
My last attempt that I thought was a success is:
Code:
the_person = get_random_from_list(list_of_premade_characters)

# This assigns the_person to a random from the list of premade characters, but
# it does not seem that all characters in the world are contained in that list
Hope this helps you or points at where to look.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
Is there any global Ren'py function that allows to do that
No.


If second option it is, could please anyone take a look at the game code and provide a solution?
Don't have time, but one possible solution is :
Python:
init python:
    renpyCharacters = [ "_narrator", "nvl_narrator", "centered", "name_only", "adv", "vcentered", "nvl", "narrator" ]

    def allChar():
        return [ getattr( store, a ) for a in store.__dict__.keys() if isinstance( getattr( store, a ), renpy.character.ADVCharacter ) and not a in renpyCharacters ]
You pass all the store in revue and only keep variables that are a Character and that isn't one of the Characters defined by Ren'py. It's pretty fast and 100% accurate.
You can use the renpyCharacters list to discriminate more and remove characters like MC and other from the list.


the_person = get_random_from_list(people_to_process)

# The problem with this is that it always returned a specific character and also had other oddeties
I don't understand you. It's natural that you only have one character, since it's what you ask for.
I don't know how reliable it can be (because I don't have time to look at the code of the game), but apparently you already achieved to have the list of all the characters present at all the places, it's people_to_process. No need to go further in your process.
 

Pilotus13

Newbie
Aug 14, 2018
32
26
I have no idea.
Have been looking through the scripts and there doesn't seem to be a builtin way listing all the characters in the world.

If you check the main script for "people_to_process" I think the answer is inside there somewhere as that contains a list of all the places and all the people within those places, but I could only make it return the Person (object).

Code:
python:
        people_to_process = [] #This is a master list of turns of need to process, stored as tuples [character,location]. Used to avoid modifying a list while we iterate over it, and to avoid repeat movements.
        for place in list_of_places:
            for people in place.people:
                people_to_process.append([people,place])
            
# This is the code inside the script after that I've been trying something like:

the_person = get_random_from_list(people_to_process)

# The problem with this is that it always returned a specific character and also had other oddeties
# Here is exactly what I did for that:
label person_in_world:
    python:
        people_in_world = []
        for place in list_of_places:
            for people in place.people:
                for person in place.people:
                    people_in_world.append([person])
        the_person = get_random_from_list(people_in_world)
After giving up on that I've been checking how the game determines spectators to the sex scenes, but that led pretty much nowhere as it draws from people in the location only, obviously.

Code:
#### Made a test label that I could call and it would randomize the_person to be from the location mc currently is in

label person_in_world:
        $ person_in_world = [person for person in mc.location.people]
        $ the_person = get_random_from_list(person_in_world)

# call person_in_world assigns the_person to someone in location
# Since I also don't know how to code I tried the next logical step to have it be
#"person for person not in mc.location.people"
# but that's sadly not a thing
My last attempt that I thought was a success is:
Code:
the_person = get_random_from_list(list_of_premade_characters)

# This assigns the_person to a random from the list of premade characters, but
# it does not seem that all characters in the world are contained in that list
Hope this helps you or points at where to look.
We are following each other steps, but on reverse - the first thing I tried was "not in mc.location".

Tried the part with people_to_process - not working, it returns something else. At least when I tried to pick someone from the list, it didn't have character attributes.

For second part you are wrong - premade character list is not the list of all the people, somewhere down the code there is a replacement of them for randomly generated persons. I think it may be a leftover of earlier code...

Will try the way anne O'nymous proposed. Will inform on the results.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
Tried the part with people_to_process - not working, it returns something else. At least when I tried to pick someone from the list, it didn't have character attributes.
Because in fact the game don't directly works with ADVCharacter objects.

Python:
init python:
    def allChars():
        # Premade characters for random encounters
        all = list_of_premade_characters
        # Plus the list of each people in each places
        for place in list_of_places:
            for people in place.people:
                # Only if not already in the list.
                if not people in all: all.append( people)
        #  Then the special characters, those that
        # effectively can be found in the /store/.
        for people in store.__dict__.keys():
            people = getattr( store, people )
            if isinstance( people, store.Person ) and not people in all: all.append( people )
        return all
Then if you want to address the ADVCharacter object, it's people.char that you need to use.
So for the list of the names of all the characters, by example, it's names = [ p.char.name for p in allChar() ].
You'll note that many names come twice, but they really are different Person objects.


For second part you are wrong - premade character list is not the list of all the people, somewhere down the code there is a replacement of them for randomly generated persons. I think it may be a leftover of earlier code...
It's not replacement, the list is defined as a list of random characters, in "random_lists.rpy". And it's the only file where the list appear. At least literally ; it perhaps appear somewhere as a built name and so a grep can't find it.
 
  • Like
Reactions: Trollden

Pilotus13

Newbie
Aug 14, 2018
32
26
No.




Don't have time, but one possible solution is :
Python:
init python:
    renpyCharacters = [ "_narrator", "nvl_narrator", "centered", "name_only", "adv", "vcentered", "nvl", "narrator" ]

    def allChar():
        return [ getattr( store, a ) for a in store.__dict__.keys() if isinstance( getattr( store, a ), renpy.character.ADVCharacter ) and not a in renpyCharacters ]
You pass all the store in revue and only keep variables that are a Character and that isn't one of the Characters defined by Ren'py. It's pretty fast and 100% accurate.
You can use the renpyCharacters list to discriminate more and remove characters like MC and other from the list.




I don't understand you. It's natural that you only have one character, since it's what you ask for.
I don't know how reliable it can be (because I don't have time to look at the code of the game), but apparently you already achieved to have the list of all the characters present at all the places, it's people_to_process. No need to go further in your process.
Well, finnaly had time to try it. But it doesn't seem to work, as when I try to get a single person from renpyCharacters list, I get this error message:

Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 7466, in script call
    python:
  File "game/script.rpy", line 8441, in script call
    call advance_time from _call_advance_time_5
  File "game/script.rpy", line 8900, in script call
    $ the_crisis.call_action()
  File "game/crises.rpy", line 5233, in script
    "While walking around the town, you see that the window in [the_person.name]'s house is open and something is hapenning there."
AttributeError: 'unicode' object has no attribute 'name'
 

Rich

Old Fart
Modder
Donor
Respected User
Game Developer
Jun 25, 2017
2,486
7,007
This likely indicates that you didn't get the type of object that you expected. The nature of the error suggests that "the_person" is a string, not a Person or ADVCharacter. Use the Ren'py console to determine what you actually got and to debug your code.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
But it doesn't seem to work,[...]
I tested the code before giving it, so I can assure you that it works.


Code:
I'm sorry, but an uncaught exception occurred.
AttributeError: 'unicode' object has no attribute 'name'
Like @Rich said, you've got the wrong type of value.
I assume that you works with a list of names instead of a list of objects, so did you understand that names = [ p.char.name for p in allChar() ] is an quick example of use (precisely the way to build a list with all the names), and not the way to have the list of all the characters ?
It's the allChar function itself that gave this list.

This said, perhaps that you should start modding with a more simple game. I don't say this to belittle you or to be rude, but because Lab Rat 2 is really a complex game that use advanced code. It's far to be something easy to mod, even for someone with a strong knowledge regarding Ren'py and Python ; definitively not the right game for a first mod.
 
  • Like
Reactions: Rich

Pilotus13

Newbie
Aug 14, 2018
32
26
I tested the code before giving it, so I can assure you that it works.




Like @Rich said, you've got the wrong type of value.
I assume that you works with a list of names instead of a list of objects, so did you understand that names = [ p.char.name for p in allChar() ] is an quick example of use (precisely the way to build a list with all the names), and not the way to have the list of all the characters ?
It's the allChar function itself that gave this list.

This said, perhaps that you should start modding with a more simple game. I don't say this to belittle you or to be rude, but because Lab Rat 2 is really a complex game that use advanced code. It's far to be something easy to mod, even for someone with a strong knowledge regarding Ren'py and Python ; definitively not the right game for a first mod.
Yes, I guess my ambitions went way ahead of my abilities. Will try something easier. Thanks for help, anyway. I will still save the code, maybe one day I will be able to use it properly:)