Counting number of city state allies?

Countbuffalo

Chieftain
Joined
Aug 16, 2013
Messages
94
Hi, for a Civ I'm working on I want to create a dummy building for every city state ally, I've had a look at some sample code for something like this and I can't quite get my head around it, I've had a look at a few examples used in Vice Virtuoso's Mami Civ and in the Cocoa Civ I found on workshop which also creates a dummy building for having city state allies but makes use of pOtherPlayer and iOtherTeam which I've never seen before and don't know how to use.

Would someone mind showing me what a lua code to check city state allies would look like? I know I'd need to define pCapitalCity and use pCapitalCity:SetNumRealBuilding for the buildings. But the counting of city states is rather confusing.

Thanks
 
pOtherPlayer and iOtherTeam are just variables. I could as well have called them pILikeDogs, CatsAreStupid, or ThisIsAVariable. The letters (p and i) at the start of the variable names reference Hungarian Notation (it's not necessary to use this, though it does provide clarity in your code for yourself and for others who might be referencing it.) The p references a pointer. On these things we can use the Lua methods firaxis provided us. E.g. pPlayer:GetName(), pPlayer:GetCivilizationType() to name a few. In this case, pOtherPlayer is (as the name suggests) a pointer of another player. i on the other hand indicates an integer, which in many cases will be an ID (which is practically a number), In this case, iOtherTeam will contain the ID of another Team.
CivV works in Teams, which consists of a number of players. In standard games, each team consists of only one player.

---------


As you may know, here is the relevant code for the Cocoa civ:
Code:
--[..] snipped variable definitions. E.g. iBakeryCiv = GameInfoTypes.CIVILIZATION_BAKERY_COCOA_SOMETHING_SOMETHING

--Checks for allied city-states
function DiploBonusBakery(iPlayer)
    local paichnides = Players[iPlayer]
    if paichnides:GetCivilizationType() == iBakeryCiv then
        local philoi = 0
        local proteuousa = paichnides:GetCapitalCity()
        local iTeam = paichnides:GetTeam()
        local pTeam = Teams[iTeam]
        for jPlayer = GameDefines.MAX_MAJOR_CIVS, GameDefines.MAX_CIV_PLAYERS-1, 1 do
            local pOtherPlayer = Players[jPlayer]
            local iOtherTeam = pOtherPlayer:GetTeam()
            if iTeam ~= iOtherTeam and pOtherPlayer:IsAlive() then
                if pTeam:IsHasMet(iOtherTeam) and pOtherPlayer:IsMinorCiv() then
                    if pOtherPlayer:IsAllies(paichnides) then
                        philoi = philoi +1
                    end
                end
            end
        end

        if proteuousa ~= nil then
            proteuousa:SetNumRealBuilding(iDiploBonus, philoi)
        else
            print("WTF")
        end
    end
end
and
Code:
for iPlayer = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
    local paichnides = Players[iPlayer]
    if paichnides:GetCivilizationType() == iBakeryCiv then
        GameEvents.PlayerDoTurn.Add(DiploBonusBakery)
        --[..] snipped code
    end
end

In many cases, functions are executed through hooks. There are several of them, but the most used is PlayerDoTurn, which executes at the start of every turn for every player (incl city states and barbs).
In the second block, the author hooks his DiploBonusBakery function once for each Cocoa player. This is wrong, as the code will now fire multiple times for each player. E.g. if there are 2 cocoa's on the map, then the piece of code will fire twice for each civ. It however doesn't cause a direct problem in this case. I suspect that the author only wanted to hook to the event if the cocoa civ is active. A better way of doing this is using whoward's IsCivInPlay(...), or JFD's equivalent for that matter.
Neither did the author use consistent Hungarian Notation. E.g. local paichnides = Players[iPlayer] should be local pPaichnides = Players[iPlayer] for the sake of consistency. (NOTE: Not doing that does not provide problems, it just provides less clarity if your code gets bigger).

On to the first block of code:
Code:
if paichnides:GetCivilizationType() == iBakeryCiv then
--[..]snipped
end
This is only executed if the player is Cocoa.

Code:
local philoi = 0
local proteuousa = paichnides:GetCapitalCity()
local iTeam = paichnides:GetTeam()
local pTeam = Teams[iTeam]
I assume philoi is the name of the dummy building/trait of the cocoa civ. A better (more clear) name would've been: iNumPhiloiBuilding (or something in that direction)
proteuousa will contain the pointer of Cocoa's capital city. A better (and more clear) name would've been: pCocoaCapital or pBakeryCapital. (or pProteuousa assuming that the name of the capital is Proteuoasa)
iTeam contains the team ID of the cocoa player
pTeam contains the pointer of the team of the cocoa player. (It allows us to use the Lua methods!)

Code:
for jPlayer = GameDefines.MAX_MAJOR_CIVS, GameDefines.MAX_CIV_PLAYERS-1, 1 do
--[..]snipped
end
This for-loop loops through the IDs of all city states. GameDefines.MAX_MAJOR_CIVS is the maximum number of major civs (E.g. America, Germany, Netherlands, etc.) that may be active in a civ game, which equals 22. As IDs (of players) start at 0, Players[22] will be a minor civ. GameDefines.MAX_CIV_PLAYERS equals 63. We subtract 1 from this number so we exclude the Barbarian player (who has an ID of 63).
Again, bad naming was used. It would've been better to rename jPlayer to iMinor or iOtherPlayer (to keep it in his theme)

Code:
local pOtherPlayer = Players[jPlayer]
local iOtherTeam = pOtherPlayer:GetTeam()
Gets the pointer and teamID of the minor civ.

Code:
if iTeam ~= iOtherTeam and pOtherPlayer:IsAlive() then
--[..]snipped
end
This checks if the cocoa civ and the minor civ are not on the same team and if the minor civ is alive (I.e. it was not captured).
Normally, a major civ and a minor civ can never be on the same team, but I guess this just adds an extra checkup in case something weird happens.

Code:
  if pTeam:IsHasMet(iOtherTeam) and pOtherPlayer:IsMinorCiv() then
[..]snipped
end
This checks if the cocoa civ has met the minor civ, and if the minor civ is actually a minor civ.
As we only loop through minor civ IDs, the last check is not really necessary, though this probably just serves as an extra checkup in case something weird happens.

Code:
if pOtherPlayer:IsAllies(paichnides) then
     philoi = philoi +1
end
If the cocoa civ and the minor civ are allies, we add 1 to our dummy building count.

Code:
if proteuousa ~= nil then
            proteuousa:SetNumRealBuilding(iDiploBonus, philoi)
        else
            print("WTF")
        end
If the Cocoa civ has a capital city, then we give Cocoa the number of dummies we just counted in the capital.
If not, then the author shows his/her utter confusion by printing WTF in the Lua.log. I guess he/she has never played with CompleteKills enabled ;)


I hope this was useful for you :D
GL
 
Last edited:
Thanks for the help with this Troller, I'm writing it out now, Philoi seems to just be a numeric value since
iDiploBonus
is the dummy building. I'm currently getting an error that I've seen with another piece of Lua I'm working on which is the following
[681113.828] Syntax Error: C:\Users\Alexander\Documents\My Games\Sid Meier's Civilization 5\MODS\Nogi Sonoko - The Taisha (v 1)\LUA/KagawaDiplomacy.lua:31: '<eof>' expected near 'end'
[681113.828] Runtime Error: Error loading C:\Users\Alexander\Documents\My Games\Sid Meier's Civilization 5\MODS\Nogi Sonoko - The Taisha (v 1)\LUA/KagawaDiplomacy.lua.

If I upload my LUA file it might help to figure it out, but I can't find a reference to <eof> on the LUA wiki or on these forums. Thanks again for your help.
 

Attachments

  • KagawaDiplomacy.rar
    656 bytes · Views: 49
Code:
--Check for City States
function SonokoDiplomacy(iPlayer)
    local pPlayer = Players[iPlayer] 
    if pPlayer:GetCivilizationType() == iSonoko then 
        local iFriends = 0
        local iSonokoCapital = pPlayer:GetCapitalCity()
        local iTeam = pPlayer:GetTeam()
        local pTeam = Teams[iTeam]
        for iMinor = GameDefines.MAX_MAJOR_CIVS, GameDefines.MAX_CIV_PLAYERS-1, 1 do
            local pOtherPlayer = Players[iMinor]
            local iOtherTeam = pOtherPlayer:GetTeam()
            if pTeam:IsHasMet(iOtherTeam) and pOtherPlayer:IsMinorCiv() then
                if pOtherPlayer:IsAllies(pPlayer) then
                    iFriends = iFriends +1
                    end --this one over here
                end
            end
        end
       
        if iSonokoCapital ~= nil then
            iSonokoCapital:SetNumRealBuilding(iInfluence, iFriends)
            print ("KAGAWA LIFE")
        end
    end
end
You have an 'end' too much below iFriends = iFriends + 1.

----------

Also, as I mentioned in the previous post, don't do this:
Code:
for iPlayer = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
    local pPlayer = Players[iPlayer]
    if pPlayer:GetCivilizationType() == iSonoko then
        GameEvents.PlayerDoTurn.Add(SonokoDiplomacy)
    end   
end
as it'll 'hook' the function for each copy of your civ.
E.g. If there are 2 civs, then the code will fire twice every turn for those civs. If there are 9 civs, then the code will fire 9 times every turn for those civs, etc.

Use a simple
Code:
--[..] rest of code

GameEvents.PlayerDoTurn.Add(SonokoDiplomacy)
instead.

Alternatively, you could use whoward's IsCivInPlay(..) (or JFD's equivalent) to reduce lag:
Code:
-- [..] rest of code

---- whoward's IsCivInPlay
function IsCivInPlay(iCivType)
  for iSlot = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
    local iSlotStatus = PreGame.GetSlotStatus(iSlot)
    if (iSlotStatus == SlotStatus.SS_TAKEN or iSlotStatus == SlotStatus.SS_COMPUTER) then
      if (PreGame.GetCivilization(iSlot) == iCivType) then
        return true
      end
    end
  end
 
  return false
end

if IsCivInPlay(iSonoko) then
     print("Sonoko is in play")
    GameEvents.PlayerDoTurn.Add(SonokoDiplomacy)
end

----

Seems I also made a typo in my previous post (oops). As pPlayer:GetCapitalCity() returns a pointer, the variable name should start with a p (for pointer) and not an i (for integer). I.e. iSonokoCapital should be pSonokoCapital.
 
Thanks a lot man, you showed up to help me out again and now it's working perfectly, I'm going to have to start keeping a list of every time you've fixed my LUA.
 
Top Bottom