for loop over all exisiting players?

Serp

King
Joined
Apr 1, 2015
Messages
661
Hi :)

simple question:
how to make a for loop over all existing players? (one time with city states and one time without city states)

I already searched the wiki, but the only thing I found so far is
"Game.CountCivPlayersAlive()" .

But
Code:
for playerID = 0, Game.CountCivPlayersAlive()-1, 1 do
    print(Players[playerID]:GetName())
end
makes the game crash :D I think because city states have special player IDs?
 
The reason your version is crashing is because player IDs are static and since Game.CountCivPlayersAlive() gives the count of alive civs, the IDs you're looping through aren't necessarily the players that are still alive. For example, if playerID 2 is dead, but there are 4 remaining alive civs, you'll loop from 0-3, and when it gets to Players[2]:GetName(), player 2 is already dead and the game will crash. Use the following instead:

Code:
-- Major civs
for playerID = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
 local pPlayer = Players[playerID];
 if pPlayer:IsAlive() then
  print(pPlayer:GetName());
 end
end 

-- Minor civs
for playerID = GameDefines.MAX_MAJOR_CIVS, GameDefines.MAX_CIV_PLAYERS-1, 1 do
 local pPlayer = Players[playerID];
 if pPlayer:IsAlive() then
  print(pPlayer:GetName());
 end
end

Edited to add the GameDefines.MAX_CIV_PLAYERS-1 to the end of the second loop. Couldn't think of the exact name of it when I wrote it, so I had to look it up quick.
 
Ignore previous because I am stupid

--------------------------------------------------------------------------------------------------

This is actually appropo as part of a PlayerDoTurn because during PlayerDoTurn all players are processed sequentially as iPlayer so you have to sort out Barbs and City-States (Minor Civs) when they are taking the iPlayer "seat":
Code:
function EveryoneHatesEveryone(iPlayer)
	local pPlayer = Players[iPlayer]
	if not pPlayer:IsAlive() then return end
	if pPlayer:IsHuman() then return end
	[COLOR="blue"]if pPlayer:IsMinorCiv() then return end[/COLOR]
	local pPlayersTeam = pPlayer:GetTeam()
	for iMajPlayer = 0, GameDefines.MAX_MAJOR_CIVS - 1 do
		if Players[iMajPlayer] ~= pPlayer then
			local OtherPlayer = Players[iMajPlayer]
			[COLOR="red"]if not OtherPlayer:IsMinorCiv() then[/COLOR]
				if OtherPlayer:IsAlive() then
					local OtherPlayerTeam = OtherPlayer:GetTeam()
					if Teams[pPlayersTeam]:IsHasMet(OtherPlayerTeam) then
						if Teams[pPlayersTeam]:CanDeclareWar(OtherPlayerTeam) then
							Teams[pPlayersTeam]:DeclareWar(OtherPlayerTeam)
							Teams[pPlayersTeam]:SetPermanentWarPeace(OtherPlayerTeam, true)
						else print("Teams[pPlayersTeam]:CanDeclareWar(OtherPlayerTeam) returned false")
						end
					end
				end
			[COLOR="red"]end[/COLOR]
		end
	end
end
GameEvents.PlayerDoTurn.Add(EveryoneHatesEveryone)
The stuff in red isn't actually needed because, ya know, I am stupid at times. But you would need the blue part, or something like it. The reason this code does not concern itself with "iPlayer" being a Barbarian is that all players are already perpetually at war with the Barbarians.
 
Thanks for the answers :)
I will summarize it, to make sure I understood everything :)

"GameDefines.MAX_MAJOR_CIVS-1" gives the maximum ID number of all "major civs" , so no city states or barbarian, right?
If so, why LeeS wrote, that it will also run to some minor civs? I thougt it's something like this: number 0 to 21 are all major civs. 22 is barbarian I think. And from 22 to x are all city states (minor civs). So in this case "GameDefines.MAX_MAJOR_CIVS-1" would be equal to 21. So how is it possible it would run into minor civs?

And "GameDefines.MAX_CIV_PLAYERS-1" gives the maxmimum ID from all.

But there could still be missing numbers. To skip the missing players, I can check for "PreGame.GetSlotStatus(i)". But the IsAlive() check would also do it? I guess "PreGame.GetSlotStatus(i)" does not say, if the civ is still alive or not. I guess it acts more like IsEverAlive() ?
So for calling it during a game, IsAlive() would be the best way, right?

So the loop for all would be:
Code:
for playerID = 0, GameDefines.MAX_CIV_PLAYERS-1, 1 do
 local pPlayer = Players[playerID];
 if pPlayer:IsAlive() then
  print(pPlayer:GetName());
 end
end

@ LeeS:
Can you explain why this could fail ?
 
@ LeeS:
Can you explain why this could fail ?
Because I am stupid and didn't look closely enough at the code shown. For some reason I kept seeing it as a PlayerDoTurn kind of thing, rather than just a loop through.

---------------------------------------------------------------------------------

63 is always the Barbarian player in lua. Unfortunately, because of the dreadful way they did WorldBuilder, Barbarians are always 22 (or 23 ?) in Worldbuilder, so we have that nice consistency going for us

----------------------------------------------------------------------------------

IsAlive() is better because it tells whether the player is still currently part of the game. IsEverAlive() will be true if the player in question was ever part of the current game.

-----------------------------------------------------------------------------------

This method:
Code:
gQActiveCivPlayerNames = {}

for i = 0, GameDefines.MAX_MAJOR_CIVS - 1 do
	local iSlot = PreGame.GetSlotStatus(i)
	if iSlot == SlotStatus.SS_TAKEN or iSlot == SlotStatus.SS_COMPUTER then
		local playerCivilizationID = Players[i]:GetCivilizationType()
		local playerCivilizationName = GameInfo.Civilizations{ID=playerCivilizationID}().Type
		table.insert(gQActiveCivPlayerNames, playerCivilizationName)
	end
end
is an example not only of how to loop through the major players and only process the ones that are or were in-game, but also shows an example of how to "store" some critical piece of info in an lua-table to access it again later. This is much faster processing-wise than looking up the same data from the game's XML-tables every time you need to refer to that data. You wouldn't necessarily want the "Type" data, for example, but you might want some other piece of info, such as, say, the ArtStyle.

In my case I was interested in all the "CIVILIZATION_AMERICA", "CIVILIZATION_ARABIA", etc., names for civs that had at one point been active in the game, because I followed the loop shown with searching through an altered <Unit_UniqueNames> XML-table that as a result of my mod now had 800+ names to sort through, each of which was assigned to a specific civilization.
 
Sorry, I'm always bad at explaining the reasoning behind what I write. That's probably why I'm not a teacher.

In the base game:
0-21 == Major Civs
MAX_MAJOR_CIVS == 22, so you'd use MAX_MAJOR_CIVS-1 in a for loop
22-62 == Minor Civs
MAX_CIV_PLAYERS == 63, so you'd use MAX_CIV_PLAYERS-1 in a for loop
Barbarians == 63
Like LeeS said though, WorldBuilder wonderfully mixes that up.

One of the reasons you'd want to use the GameDefines instead of hardcoding the values is for compatibility with other mods like YNAEMP that change the amount of Major Civs. Also, like LeeS pointed out, if what you're trying to do is going to be hooked into an event like PlayerDoTurn, you'll already be processing through the player IDs without having to explicitly loop through them. But there are definitely times when you might need to loop through players on your own, which is where my code would be useful.
 
Sorry, I'm always bad at explaining the reasoning behind what I write. That's probably why I'm not a teacher.

In the base game:
0-21 == Major Civs
MAX_MAJOR_CIVS == 22, so you'd use MAX_MAJOR_CIVS-1 in a for loop
22-62 == Minor Civs
MAX_CIV_PLAYERS == 63, so you'd use MAX_CIV_PLAYERS-1 in a for loop
Barbarians == 63
Like LeeS said though, WorldBuilder wonderfully mixes that up.

One of the reasons you'd want to use the GameDefines instead of hardcoding the values is for compatibility with other mods like YNAEMP that change the amount of Major Civs. Also, like LeeS pointed out, if what you're trying to do is going to be hooked into an event like PlayerDoTurn, you'll already be processing through the player IDs without having to explicitly loop through them. But there are definitely times when you might need to loop through players on your own, which is where my code would be useful.
It was as much me creating confusion because of my "Teh Dreadful Stupid" this morning. Hopefully, my corrects and edits have clarified, and been of some help.
 
In general, because Firaxis is oh-so-consistent to the point where not even their XML stays consistent between tables, the less hard-coding you do, the better. It's almost always better to simply query the game for its defines.
 
In general, because Firaxis is oh-so-consistent to the point where not even their XML stays consistent between tables, the less hard-coding you do, the better. It's almost always better to simply query the game for its defines.

I don't know if you've looked in the DLLs much, and I don't know the history behind it, but some of the comments in some of the classes leads me to believe that they either had a lot of people working on it at the same time or switched lead programmers at some point. Every once in a while there will be a comment that's something like -- Why is this like this? or -- ??????? and then someone's initials. It's pretty funny.
 
Top Bottom