Need a check if in friendly territory

So, I simplified things a bit. I am trying to add an exception to the following code so that the leader Kupe does not receive attrition damage on water tiles. Any ideas how to go about that?

Code:
local BaseRiverHeal = -10
local BaseAttMin,BaseAttMax = 2,10
local TerrainAttMul,CataChance,TerrainCataMul = 1,10,2
local TerrainAttMulLow,TerrainAttMulLowAvg,TerrainAttMulAvg,TerrainAttMulStrong,TerrainAttMulHuge = 5,8,12,20,40
local CataChanceLow,CataChanceAvg,CataChanceHighAvg,CataChanceStrong,CataChanceHuge = 100,125,250,500,800
local TerrainCataMulLow,TerrainCataMulLowAvg,TerrainCataMulAvg,TerrainCataMulStrong,TerrainCataMulHuge = 10,16,24,40,100



local TerrainDataTable = {     [GameInfo.Terrains["TERRAIN_GRASS"].Index] = {              TerrainAttMul = TerrainAttMulLow,
                                                                                        CataChance = CataChanceLow,         
                                                                                        TerrainCataMul = TerrainCataMulLow },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_GRASS_HILLS"].Index] = {          TerrainAttMul = TerrainAttMulLowAvg,
                                                                                        CataChance = CataChanceAvg,     
                                                                                        TerrainCataMul = TerrainCataMulLow },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_GRASS_MOUNTAIN"].Index] = {      TerrainAttMul = TerrainAttMulHuge,
                                                                                        CataChance = CataChanceHuge,   
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                            
                            [GameInfo.Terrains["TERRAIN_PLAINS"].Index] = {              TerrainAttMul = TerrainAttMulLow,
                                                                                        CataChance = CataChanceLow,         
                                                                                        TerrainCataMul = TerrainCataMulLow },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_PLAINS_HILLS"].Index] = {          TerrainAttMul = TerrainAttMulAvg,
                                                                                        CataChance = CataChanceAvg,     
                                                                                        TerrainCataMul = TerrainCataMulLow },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_PLAINS_MOUNTAIN"].Index] = {      TerrainAttMul = TerrainAttMulHuge,
                                                                                        CataChance = CataChanceHuge,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },

                            [GameInfo.Terrains["TERRAIN_DESERT"].Index] = {              TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceHuge,         
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_DESERT_HILLS"].Index] = {          TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceHuge,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_DESERT_MOUNTAIN"].Index] = {      TerrainAttMul = TerrainAttMulHuge,
                                                                                        CataChance = CataChanceHuge,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },

                            [GameInfo.Terrains["TERRAIN_SNOW"].Index] = {                  TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceStrong,         
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_SNOW_HILLS"].Index] = {          TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceStrong,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_SNOW_MOUNTAIN"].Index] = {      TerrainAttMul = TerrainAttMulHuge,
                                                                                        CataChance = CataChanceHuge,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },

                            [GameInfo.Terrains["TERRAIN_TUNDRA"].Index] = {              TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceAvg,         
                                                                                        TerrainCataMul = TerrainCataMulStrong },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_TUNDRA_HILLS"].Index] = {          TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceAvg,     
                                                                                        TerrainCataMul = TerrainCataMulStrong },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_TUNDRA_MOUNTAIN"].Index] = {      TerrainAttMul = TerrainAttMulHuge,
                                                                                        CataChance = CataChanceHuge,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },

                            [GameInfo.Terrains["TERRAIN_COAST"].Index] = {              TerrainAttMul = TerrainAttMulLow,
                                                                                        CataChance = CataChanceLow,         
                                                                                        TerrainCataMul = TerrainCataMulLow },
                                                                                        
                            [GameInfo.Terrains["TERRAIN_OCEAN"].Index] = {              TerrainAttMul = TerrainAttMulAvg,
                                                                                        CataChance = CataChanceStrong,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },
};



local FeatureDataTable = {     [GameInfo.Features["FEATURE_ICE"].Index] = {                  TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceHuge,         
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                                                                                        
                            [GameInfo.Features["FEATURE_MARSH"].Index] = {              TerrainAttMul = TerrainAttMulStrong,
                                                                                        CataChance = CataChanceHuge,     
                                                                                        TerrainCataMul = TerrainCataMulAvg },
                                                                                        
                            [GameInfo.Features["FEATURE_BARRIER_REEF"].Index] = {          TerrainAttMul = TerrainAttMulLow,
                                                                                        CataChance = CataChanceStrong,   
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                            
                            [GameInfo.Features["FEATURE_JUNGLE"].Index] = {              TerrainAttMul = TerrainAttMulAvg,
                                                                                        CataChance = CataChanceStrong,         
                                                                                        TerrainCataMul = TerrainCataMulHuge },
                                                                                        
                            [GameInfo.Features["FEATURE_FOREST"].Index] = {              TerrainAttMul = TerrainAttMulLowAvg,
                                                                                        CataChance = CataChanceAvg,     
                                                                                        TerrainCataMul = TerrainCataMulStrong },
                                                                                        
                            [GameInfo.Features["FEATURE_OASIS"].Index] = {              TerrainAttMul = 0,
                                                                                        CataChance = CataChanceAvg,     
                                                                                        TerrainCataMul = TerrainCataMulHuge },

                            
};


function GetPlotFeature (pUnitPlot)
    if (pUnitPlot ~= nil) then
         local fFeatureType = pUnitPlot:GetFeatureType()
         if (fFeatureType ~= -1) and (fFeatureType ~= nil) then
              --the plot has a FeatureType registered within xml table <Features>
              fFeature = GameInfo.Features[fFeatureType].FeatureType
              isFeatureWonder = GameInfo.Features[fFeatureType].NaturalWonder
         else
              fFeature = "FEATURE_NONE"
              isFeatureWonder = "FEATURE_NONE"
         end
         return fFeature, isWonder
    end
end



function damageAndDestroyUnit(pPlayer,iUnit,minDam,maxDam)
    local tKillUnits = {}
    local pPlayerToCheck = Players[pPlayer]
    local pUnits = pPlayerToCheck:GetUnits()
    local pUnit = pUnits:FindID(iUnit)
    local pPlayerEra = pPlayerToCheck:GetEra()+1
    if (pUnit ~= nil) and (pUnit:IsDead() == false) and (pUnit:IsDelayedDeath() == false) then
        local UnitPlot = Map.GetPlot(pUnit:GetX(), pUnit:GetY())
        local UnitPlotOwner = UnitPlot:GetOwner()
        if (UnitPlot ~= nil) and (UnitPlotOwner ~= pPlayer) then
            local unitDamage = math.random(minDam,maxDam)
            if (pUnit:GetDamage() + unitDamage) >= 150 then
                table.insert(tKillUnits, pUnit)
            else
                pUnit:ChangeDamage(unitDamage)
                print("inflicted "..unitDamage.." to unit")
            end
        end
    end
    --now we've completed the iteration through table pUnits:Members() and can safely delete units listed as members
    for k,pUnit in ipairs(tKillUnits) do
        pUnits:Destroy(pUnit)
        print("a unit was destroyed because of attrition")
    end       
end








function IdleDamage()
    local players = Game.GetPlayers()
    for k, pPlayer in ipairs (players) do
        local pUnits = pPlayer:GetUnits()
        for i, pUnit in pUnits:Members() do
            if (pUnit ~= nil) and (pUnit:IsDead() == false) and (pUnit:IsDelayedDeath() == false) then   
                local pUnitID = pUnit:GetID()
                local pUnitPlot = Map.GetPlot(pUnit:GetX(), pUnit:GetY())
                
                --Check for attrition exceptions NOTE: need to add diplomatic exceptoins and for Maoi civ, barbarians have attrition reduced
                local pUnitOwnerID = pPlayer:GetID()
                local pUnitOwnerName = GameInfo.Leaders[pUnitOwnerID].LeaderType
                local pUnitPlotOwner = pUnitPlot:GetOwner()
                local IsFreshWaterAdj = pUnitPlot:IsFreshWater()
                local tTerrain = GameInfo.Terrains[pUnitPlot:GetTerrainType()].TerrainType
                local TerrainAttMul,CataChance,TerrainCataMul = 0, 0, 0
                GetPlotFeature(pUnitPlot)
                local pUnitOwnerDiplo = pPlayer:GetAi_Diplomacy():GetDiplomaticState(pUnitPlotOwner)
                if    pUnitOwnerDiplo == nil then
                    pUnitOwnerDiplo = "NONE"
                end
                if    (pUnitOwner == pUnitPlotOwner) or
                    string.match(pUnitOwnerDiplo, "FRIENDLY") or
                    string.match(pUnitOwnerDiplo, "ALLIANCE") or
                    (isFeatureWonder == true ) then
                elseif    IsFreshWaterAdj == true then
                    pUnit:ChangeDamage(BaseRiverHeal)
                else   
                    --Damage mulitpliers
                    local PlotTerrainDamages = TerrainDataTable[pUnitPlot:GetTerrainType()]
                    if (fFeature ~= "FEATURE_NONE") then
                        --Get damage multipliers from feature
                         TerrainAttMul,CataChance,TerrainCataMul = PlotFeatureDamages.TerrainAttMul,  PlotFeatureDamages.CataChance,  PlotFeatureDamages.TerrainCataMul
                    else
                        --Get damage mulitpliers from terrain
                         TerrainAttMul,CataChance,TerrainCataMul = PlotTerrainDamages.TerrainAttMul,  PlotTerrainDamages.CataChance,  PlotTerrainDamages.TerrainCataMul
                    end
                local FinalAttMin = (BaseAttMin*TerrainAttMul)/2
                local FinalAttMax = (BaseAttMax*TerrainAttMul)/2
                damageAndDestroyUnit(pUnitOwnerID,pUnitID,FinalAttMin,FinalAttMax)
                end
                
                print("-----------------------------")
                print("-----------------------------")
                print("----------UNIT INFO----------")
                print("Unit Owner:")
                print(pUnitOwnerName)
                print("Unit relations to plot owner:")
                print(pUnitOwnerDiplo)
                print("Unit ID:")
                print(pUnitID)
                print("Unit plot:")
                print(pUnitPlotIndex)
                print("----------PLOT INFO----------")
                print("Plot Owner:")
                print(pUnitPlotOwner)
                print("Terrain type")
                print(tTerrain)
                print("Feature type")
                print(fFeature)
                print("Is river:")
                print(IsFreshWaterAdj)
                print("Is feature wonder:")
                print(isFeatureWonder)
                print("-----------------------------")
                print("-----------------------------")
            end
        end
    end
end
 
Code:
local pUnitOwnerID = pPlayer:GetID()
"pUnitOwnerID" will be the ID number of the player from the lua special table "Players" and will never conform to any ID or Index number from any database table, therefore this cannot be done:
Code:
local pUnitOwnerID = pPlayer:GetID()
local pUnitOwnerName = GameInfo.Leaders[pUnitOwnerID].LeaderType
If the Player being processed is the human player in a Single Player game, the lua ID # of that player is always 0 and so you would always get "LEADER_DEFAULT" regardless of which leader is being used by the human player. Lua Player #1 would always get LEADER_BARBAROSSA, lua Player #2 would always get LEADER_CATHERINE_DE_MEDICI. This is because of the order these leaders appear in table "Leaders", and the Index numbers of these leaders is the SQL row number - 1.

Code:
for iLoopPlayer = 1, 62 do	--altered to check all players other than the human and the barb
			local pLoopPlayer = Players[iLoopPlayer]
			if pLoopPlayer:IsAlive() then
				local sPlayerCivName = PlayerConfigurations[iLoopPlayer]:GetCivilizationTypeName()
				local sPlayerLeaderName = PlayerConfigurations[iLoopPlayer]:GetLeaderTypeName()
"sPlayerCivName" will be a CivilizationType from table <Civilizations> such as "CIVILIZATION_GREECE" and "sPlayerLeaderName" will be a LeaderType from table <Leaders> such as "LEADER_GORGO" or "LEADER_PERICLES" in the case of Greece.

Code:
GetPlotFeature(pUnitPlot)
Nope.

Because you need a set of variables for the "return" of the function to send its data. Otherwise you are just running the function and then discarding the gathered data from the function. This will have the result that this line will always be evaluated as a "true" statement:
Code:
if (fFeature ~= "FEATURE_NONE") then
Because fFeature will always be a nil value and therefore not equal to "FEATURE_NONE".

You need
Code:
local fFeature, isFeatureWonder = GetPlotFeature(pUnitPlot)
 
Last edited:
You have logical errors in function GetPlotFeature, however:
Code:
function GetPlotFeature(pUnitPlot)
    if (pUnitPlot ~= nil) then
         local fFeatureType = pUnitPlot:GetFeatureType()
         if (fFeatureType ~= -1) and (fFeatureType ~= nil) then
              --the plot has a FeatureType registered within xml table <Features>
              fFeature = GameInfo.Features[fFeatureType].FeatureType
              isFeatureWonder = GameInfo.Features[fFeatureType].NaturalWonder
         else
              fFeature = "FEATURE_NONE"
              isFeatureWonder = "FEATURE_NONE"
         end
         return fFeature, isWonder
    end
end
  1. "isFeatureWonder" is not the same as "isWonder" so "isWonder" will always be 'boolean' nil.
  2. Variables "fFeature" and "isFeatureWonder" are being treated as global variables, which is why the code seems to work except for item #1 above. Allowing variables to be used as globals in this manner is always code-dangerous and slower in process execution. It is code dangerous because the last established value persists for the remainder of the game-session and often leads to unanticipated results, usually in the form of difficult bugs to eliminate.
  3. You should rewrite as advised and also cure the issue with not capturing the "return" as noted in the previous post.
Code:
function GetPlotFeature(pUnitPlot)
	if (pUnitPlot ~= nil) then
		local tFeatureDetails = GameInfo.Features[pUnitPlot:GetFeatureType()]
		if (tFeatureDetails ~= nil) then
			--the plot has a FeatureType registered within xml table <Features>
			return tFeatureDetails.FeatureType, tFeatureDetails.NaturalWonder
		end
	end
	return "FEATURE_NONE", false
end
This also cures the "return" data issues in the corner-case wherein pUnitPlot might be a nil value, which the original code was not handling.
 
Also, nothing is coded to happen in this case
Code:
if    (pUnitOwner == pUnitPlotOwner) or
                    string.match(pUnitOwnerDiplo, "FRIENDLY") or
                    string.match(pUnitOwnerDiplo, "ALLIANCE") or
                    (isFeatureWonder == true ) then
Which appears to be on purpose but is a result of clumbsy code.
Code:
if (pUnitOwner ~= pUnitPlotOwner) and (string.match(pUnitOwnerDiplo, "FRIENDLY") == false)
	and (string.match(pUnitOwnerDiplo, "ALLIANCE") == false) and (isFeatureWonder == false) then

	if (IsFreshWaterAdj == true) then
		pUnit:ChangeDamage(BaseRiverHeal)
	else   
		--Damage mulitpliers
		local PlotTerrainDamages = TerrainDataTable[pUnitPlot:GetTerrainType()]
		if (fFeature ~= "FEATURE_NONE") then
			--Get damage multipliers from feature
			TerrainAttMul,CataChance,TerrainCataMul = PlotFeatureDamages.TerrainAttMul,  PlotFeatureDamages.CataChance,  PlotFeatureDamages.TerrainCataMul
		else
			--Get damage mulitpliers from terrain
			TerrainAttMul,CataChance,TerrainCataMul = PlotTerrainDamages.TerrainAttMul,  PlotTerrainDamages.CataChance,  PlotTerrainDamages.TerrainCataMul
		end
		local FinalAttMin = (BaseAttMin*TerrainAttMul)/2
		local FinalAttMax = (BaseAttMax*TerrainAttMul)/2
		damageAndDestroyUnit(pUnitOwnerID,pUnitID,FinalAttMin,FinalAttMax)
	end
end
 
Hi Lee,

Thank you for the feedback. I'm not sure how to implement the loop you suggested below

Code:
for iLoopPlayer = 1, 62 do    --altered to check all players other than the human and the barb
            local pLoopPlayer = Players[iLoopPlayer]
            if pLoopPlayer:IsAlive() then
                local sPlayerCivName = PlayerConfigurations[iLoopPlayer]:GetCivilizationTypeName()
                local sPlayerLeaderName = PlayerConfigurations[iLoopPlayer]:GetLeaderTypeName()
 
I posted that to show the correct way to get the CivilizationTypeName and LeaderTypeName. You want to use
Code:
PlayerConfigurations[PlayerID#]:GetLeaderTypeName()
to get a LeaderType Name such as "LEADER_CATHERINE" instead of
Code:
local pUnitOwnerID = pPlayer:GetID()
                local pUnitOwnerName = GameInfo.Leaders[pUnitOwnerID].LeaderType
Because the code you were using will not get what you thought it was.

In the method to loop through players that you were using you want as:
Code:
for k, pPlayer in ipairs (players) do
	local pUnits = pPlayer:GetUnits()
	local pUnitOwnerID = pPlayer:GetID()
	local pUnitOwnerName = PlayerConfigurations[pUnitOwnerID]:GetLeaderTypeName()
	for i, pUnit in pUnits:Members() do
		if (pUnit ~= nil) and (pUnit:IsDead() == false) and (pUnit:IsDelayedDeath() == false) then   
			local pUnitID = pUnit:GetID()
			local pUnitPlot = Map.GetPlot(pUnit:GetX(), pUnit:GetY())
                
			--Check for attrition exceptions NOTE: need to add diplomatic exceptoins and for Maoi civ, barbarians have attrition reduced

                                ...etc...
Notice that I moved the code to get the player ID and leader name above the loop through pUnits:Members()

This is because all those units are going to belong to the same player (pPlayer:GetID()). There cannot be units within a player's pUnits:Members() that belong to a different player, so you may as well grab that data once for each of the players in your loop rather than doing so for every unit belonging to that player.

Because of scoping rules on local variables, when done the way I've shown, the data assigned to "pUnitOwnerID" and "pUnitOwnerName" for each player will still be available when your code loops through that player's pUnits:Members().
 
Back
Top Bottom