Choosing a Random City

DonStamos

Mobster Inc©
Joined
Sep 21, 2002
Messages
820
Location
United States
I've decided to try to do a different set of lua for another Civ, and I've got it all finished except for one part, where I need to choose a random city for an event. If the player selects one outcome, all cities celebrate WLTKD, but if the player chooses the second, the chosen city enters a few turns of resistance.

How would I write the lua to select a random city?

I know it starts:

local player:Cities{} --to make the table
local numCities = player:GetNumCities() --to determine what my range of integers will be

But I end up going nowhere past this.
 
Here:
Code:
local PlayerCitiesTb = {} -- creates an empty array

-- function to randomize an item in a table
function tablerandom(tbl)
	local keys = {}
	for k in pairs(tbl) do
		table.insert(keys, k)
	end
	local randIndex = math.random(#keys)
	local randKey = keys[randIndex]
	return tbl[randKey]
end

-- Snippet to insert all cities in a table and then get one at random
[...]
for pCityInsert in pPlayer:Cities() do
	table.insert(PlayerCitiesTb, pCityInsert)
end
local pCity = tablerandom(PlayerCitiesTb)
--do your code here with pCity
[...]
 
Thanks a ton, bane! :)
 
Because there is a Lua method to get the number of cities the player has, there is no need to create the table of cities to count them, so we can write a more efficient/faster function as

Code:
function GetRandomCity(pPlayer)
  -- iCity will be a number between 1 and the total number of cities the player has (inclusive)
  local iCity = math.random(pPlayer:GetNumCities())
  
  local i = 0
  for pCity in pPlayer:Cities() do
    i = i + 1
	
    if (i == iCity) then
      return pCity
    end
  end
  
  return nil
end

which doesn't need to create the temporary table, and only iterates the cities before the chosen one (so on average will only iterate half the cities)
 
I hope this isn't too stupid a question, but when I call back to the random city chosen in the function, do I use "iCity" or "pCity" (or is it a better option to use a separate tag to define it so I don't get wonky stuff when I go to manipulate cities later in the code)?

By the way, thank you guys a literal ton. I've finally managed to get some stuff to show up in-game, now I just gotta iron out some wrinkles with the events file (including this one).
 
Code:
-- set pPlayer to something, if you have the id (iPlayer) of the player (eg from a GameEvent) use pPlayer = Players[iPlayer]

-- Now get a random city for that player
local pRandomCity = GetRandomCity(pPlayer)

-- You can now use, eg
local sCityName = pRandomCity:GetName()
 
Thank you again, whoward! :D
 
One suggestion:

Code:
  local iCity = math.random(pPlayer:GetNumCities())

I'd recommend using the Game.Rand function rather than Lua's built-in math.random function. Game.Rand will use the game's random seed to calculate the number, granting it two benefits over math.random:

  • The result will be the same if the user reloads his or her game and tries the event again (unless the user manually chose the Random Seed game option)
  • The result will be the same for all clients in a multiplayer game, which will prevent desyncs
 
Back
Top Bottom