Best Way to Get Random Citizen?

I’m trying to get a random citizen of my own population. I’ve come up with some code to do it, but I’m not sure if it’s the best way to go about doing so. Here’s the code:

local pop = stonehearth.population:get_population(player_id) local citizens = pop:get_citizens() local random_int = rng:get_int(0, pop:get_citizen_count()) local i = 0 for _, citizen in citizens:each() do if random_int == i and citizen and citizen:is_valid() then self._sv._random_citizen = citizen break else i = i + 1 end end

If anyone knows a more performant way to grab a random citizen, I hope they’ll share :smiley: If not, this can be used as a reference by anyone who is wondering how to do so. I know that there is a function “citizens:get(citizen_id)” that might eliminate having to iterate through citizens:each(), but then I’d need some way to easily get a random citizen’s id, which I don’t :frowning:. Perhaps @sdee or @yshan would be so kind to give their opinions :slight_smile:

Uhm…
Maybe
citizens[rng:get_int(1, pop:get_citizen_count())]

1 Like

I tried that and sadly I had no luck working with citizens as an array. Decoda says it’s a numbermap so I’m guessing it’s a bit different.

Oh, that rng that you used will eventually break, I think. you are randomizing 0 to count, while it should be 1 to count or 0 to count -1.

I don’t think you can address citizens[] at all (using squared brackets). I always get nil values returned. Also, when you call citizens:get(citizen_id), citizen_id is actually the entity id (so usually a four digit number). Sadly, I have no idea where to find the functions that citizens has so I can’t check what can be called, passed, or returned either :frowning:

I found those functions at /stonehearth/services/server/population/

Population does not store the functions for the numbermap citizens, notice the line:

self._sv.citizens = _radiant.sim.alloc_number_map()

so when you call citizens:get() or citizens:each(), that is not found in population_faction.lua or population_service.lua, it must be within the c++ engine.

This should get you in the right direction.

function Commands:add_citizen_command(session, response, entity, job)
   local player_id = session.player_id
   local pop = stonehearth.population:get_population(player_id)
   local citizen = pop:create_new_citizen()

   citizen:add_component('stonehearth:job')
               :promote_to('stonehearth:jobs:worker')

   local explored_region = stonehearth.terrain:get_visible_region(player_id):get()
   local centroid = _radiant.csg.get_region_centroid(explored_region):to_closest_int()
   local town_center = radiant.terrain.get_point_on_terrain(Point3(centroid.x, 0, centroid.y))

   local spawn_point = radiant.terrain.find_placement_point(town_center, 20, 30)
   radiant.terrain.place_entity(citizen, spawn_point)

   return true
end
1 Like

That’s definitely very useful for getting a new citizen, but I was more thinking of getting a random existing citizen :slight_smile:

Lol. In my head it was bouncing around as create a new citizen with random attributes. I’ll see myself out.

@Wharp I think there exists a radiant function for converting maps to arrays:

...
local target_entities = radiant.map_to_array(ctx.entity_registration_paths)
for i, entity_name in ipairs(target_entities) do 
...

I believe this array can be used with square brackets, but I’m not sure if this code would work with the numbermap you mention.

Maybe the hearthling therapist can give a hint on how to access citizens. :confused: