1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Counting number of city state allies?

Discussion in 'Civ5 - Creation & Customization' started by Countbuffalo, Aug 3, 2017.

  1. Countbuffalo

    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
     
  2. Troller0001

    Troller0001 Not an actual Troll

    Joined:
    Mar 9, 2016
    Messages:
    739
    Gender:
    Male
    Location:
    The Netherlands
    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: Aug 4, 2017
  3. Countbuffalo

    Countbuffalo Chieftain

    Joined:
    Aug 16, 2013
    Messages:
    94
    Thanks for the help with this Troller, I'm writing it out now, Philoi seems to just be a numeric value since
    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
    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.
     

    Attached Files:

  4. Troller0001

    Troller0001 Not an actual Troll

    Joined:
    Mar 9, 2016
    Messages:
    739
    Gender:
    Male
    Location:
    The Netherlands
    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.
     
  5. Countbuffalo

    Countbuffalo Chieftain

    Joined:
    Aug 16, 2013
    Messages:
    94
    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.
     
    Troller0001 likes this.

Share This Page