LUA code not triggering

DrNooooo

Warlord
Joined
May 12, 2015
Messages
129
I have tried absolutely everything but I cannot get this LUA code to, well, do anything. It prints "JFK LUA Loaded" and "JFK Ability Triggered" but nothing else happens or even prints. I know barely anything about LUA and am not a programmer so this is probably very bad, messy code but if anyone could help I'd appreciate it.

The goal of the code is to add a dummy building to all cities of the John F. Kennedy player provided that the John F. Kennedy player is at war with someone of a different government, and then to remove that building if John F. Kennedy is no longer at war with someone of a different government.

Here's the full code:

Code:
print ("JFK LUA Loaded")

-----------------------------------------------
-- FUNCTION C15_ValidTrait
-- Credits: Chrisy15
-----------------------------------------------

function C15_ValidTrait(sTrait)
    local tValid = {}
    for k, v in ipairs(PlayerManager.GetWasEverAliveIDs()) do
        local leaderType = PlayerConfigurations[v]:GetLeaderTypeName()
        for trait in GameInfo.LeaderTraits() do
            if trait.LeaderType == leaderType and trait.TraitType == sTrait then
                tValid[v] = true
            end;
        end
        if not tValid[v] then
            local civType = PlayerConfigurations[v]:GetCivilizationTypeName()
            for trait in GameInfo.CivilizationTraits() do
                if trait.CivilizationType == civType and trait.TraitType == sTrait then
                    tValid[v] = true
                end;
            end
        end
    end
    return tValid
end

local iDummy = GameInfo.Buildings["BUILDING_JFK_DIFFGOVWAR_DUMMY"].Index;
local sTrait = "TRAIT_LEADER_SNACK_JFK"
local tTraitPlayers = C15_ValidTrait(sTrait)

function JFK_DiffGovCheck(pAttacker, pDefender)
    print ("JFK Diff Gov Check starting");
        if (Players[pAttacker]:GetCulture():GetCurrentGovernment() ~= Players[pDefender]:GetCulture():GetCurrentGovernment()) and (pAttacker:GetDiplomacy():IsAtWarWith(pDefender) or  pAttacker:GetDiplomacy():IsAtWarWith(pDefender) ) then
            print ("JFK Diff Gov Check succeeded")
            return true;
            else
            return false;
        end
end

function JFKDiffGovWarAbility( eAttackingPlayerID, eDefendingPlayerID )
    print ("JFK Ability Triggered")
    local pAttacker    = Players[eAttackingPlayerID]
    local pDefender    = Players[eDefendingPlayerID]
    local pCities = pAttacker:GetCities()
    local pCity = pCities:FindID(cityID)
    local pCities2 = pDefender:GetCities()
    local pCity2 = pCities2:FindID(cityID)
    local pCityBuildings = pCity:GetBuildings()
    local pCity2Buildings = pCity2:GetBuildings()
    if tTraitPlayers[pAttacker] then
        print ("Attacker is JFK")
        if JFK_DiffGovCheck(pAttacker, pDefender) == true then
                print ("JFK Government + War Check is true")
                if pCityBuildings:HasBuilding(iDummy) ~= true then
                    local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                    --print("pPlot:", pPlot)
                    local iPlot = pPlot:GetIndex()
                    --print("iPlot:", iPlot)
                    pCity:GetBuildQueue():CreateIncompleteBuilding(iDummy, iPlot, 100)
                    print ("Dummy added")
                end
        end
    else
    if tTraitPlayers[pDefender] then
        print ("Defender is JFK")
        if JFK_DiffGovCheck(pAttacker, pDefender) == true then
                print ("JFK Government + War Check is true and JFK is defender")
                if pCity2Buildings:HasBuilding(iDummy) ~= true then
                    local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                    --print("pPlot:", pPlot)
                    local iPlot = pPlot:GetIndex()
                    --print("iPlot:", iPlot)
                    pCity:GetBuildQueue():CreateIncompleteBuilding(iDummy, iPlot, 100)
                    print ("Dummy added")
                end
        else
        if pCity2Buildings:HasBuilding(iDummy) == true then
            --print("pPlot:", pPlot)
            local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
            local iPlot = pPlot:GetIndex()
            --print("iPlot:", iPlot)
            pCityBuildings:RemoveBuilding(iDummy)
            print ("Dummy removed")
        else
            print ("All checks failed.")
        end
        end
    end
    end
end
       
Events.DiplomacyDeclareWar.Add(JFKDiffGovWarAbility)
Events.DiplomacyMakePeace.Add(JFKDiffGovWarAbility)
 
Your basic problem is a fundamental misunderstanding of the kind of lua data your code is attempting to manipulate.
  1. Table tTraitPlayers will hold player ID #s for all players who have the desired CivilizationTrait or LeaderTrait. But here you are translating a Player ID # into an lua PlayerObject variable, and then attempting to see if lua Table tTraitPlayers contains that PlayerObject variable in its list of valid lua player ID #s.
    Code:
        local pAttacker    = Players[eAttackingPlayerID]
    ...snipped lines...
     if tTraitPlayers[pAttacker] then
    This can never be true because a Player Object variable can never be the same as a Player Id #.

    The same basic mistake follows through for the "pDefender" variable. It is a Player Object variable and not a Player Id #. So it also can never be in the list held by lua Table tTraitPlayers.
  2. This
    Code:
        local pCities = pAttacker:GetCities()
        local pCity = pCities:FindID(cityID)
    and this
    Code:
        local pCities2 = pDefender:GetCities()
        local pCity2 = pCities2:FindID(cityID)
    will never succeed in valid data for City Object variables "pCity" and "pCity2" since there is no valid variable called "cityID" anywhere else in your code. So "pCity" and "pCity2" are in lua lingo "nil values".
  3. The remainder of the code within function JFKDiffGovWarAbility fails to execute because of these issues.
  4. Additionally to that, here you are "calling" function JFK_DiffGovCheck and passing the two Player Object variables for the attacking and defending player into that function:
    Code:
    if JFK_DiffGovCheck(pAttacker, pDefender) == true then
    So far as this goes in and of itself there is nothing wrong with this sort of coding. However, this too also fails because the code within function JFK_DiffGovCheck is not written to expect Player Object variables. It is written to expect a mishmash of Player Object variables and Player Id #s
    Code:
    function JFK_DiffGovCheck(pAttacker, pDefender)
        print ("JFK Diff Gov Check starting");
            if (Players[pAttacker]:GetCulture():GetCurrentGovernment() ~= Players[pDefender]:GetCulture():GetCurrentGovernment()) and (pAttacker:GetDiplomacy():IsAtWarWith(pDefender) or  pAttacker:GetDiplomacy():IsAtWarWith(pDefender) ) then
                print ("JFK Diff Gov Check succeeded")
                return true;
                else
                return false;
            end
    end
    • The argument of "pAttacker" here:
      Code:
      Players[pAttacker]
      is invalid because the pre-provided special lua "Players" table always needs a Player Id # and you are intstead giving it a Player Object variable. This will result in an lua nil value error.
    • The same is true here:
      Code:
      Players[pDefender]
    • This has issues as well, not the least of which is that both sides of the "or" are the same thing
      Code:
      (pAttacker:GetDiplomacy():IsAtWarWith(pDefender) or  pAttacker:GetDiplomacy():IsAtWarWith(pDefender)

      The IsAtWarWith method wants a Player ID # as an argument to give valid data as to whether the two players are at war. Here’s an example where Firaxis loops through all the other alive majors to determine whether "our" player is at war with anyone. The Player Object variable "pOurPlayer" is defined elsewhere in the code of the same file so it is already available to the function:
      Code:
      	function()
      		for i, pPlayer in ipairs(PlayerManager.GetAliveMajors()) do			
      			local iPlayer :number = pPlayer:GetID();
      			if pOurPlayer:GetDiplomacy():IsAtWarWith( iPlayer ) then
      				return true;		-- At war, let's raise this event!
      			end
      		end
      		return false;
      	end);
      They have to get an ID # for each of the possible other players before the IsAtWarWith method can be used to determine if "our" player is at war with the other player.

      What you have done is pass a Player Object variable to the IsAtWarWith method which can never execute correctly.
  5. I would never have written the code to use the same function when either of Events.DiplomacyDeclareWar or Events.DiplomacyMakePeace are triggered by the lua system.
    • When war is declared between two players we already know they are at war so there is no need to waste execution time checking whether they are at war. All we need to know is whether one of them is a player we are interested in and if the two warring players are using the same government or not. Then we need to add or remove the building as needed.
    • When peace is declared between two players we must first evaluate whether either of the two players is one of those we are interested in, and only then proceed to see if (a) they are still at war with another player of a different government, (b) the appropriate building is or is not in all of the cities owned by the player we are interested in.
    • When a player changes government it will be necessary to look at them and all other players, and determine whether the player(s) we are interested in are now at war with a player of a different government.
  6. If i were going to re-write the JFK_DiffGovCheck function I would do so as
    Code:
    function JFK_DiffGovCheck(iAttacker, iDefender)
    	print ("JFK Diff Gov Check starting");
    	if (Players[iAttacker]:GetCulture():GetCurrentGovernment() ~= Players[iDefender]:GetCulture():GetCurrentGovernment()) and Players[iAttacker]:GetDiplomacy():IsAtWarWith(iDefender) then
    		print ("JFK Diff Gov Check succeeded")
    		return true;
    	else
    		return false;
    	end
    end
    And then I would alter this line
    Code:
    if JFK_DiffGovCheck(pAttacker, pDefender) == true then
    to this in both places you are using it
    Code:
    if JFK_DiffGovCheck(eAttackingPlayerID, eDefendingPlayerID) == true then
  7. Executing through all of a player's cities is done like this
    Code:
    for i, pCity in Players[eAttackingPlayerID]:GetCities():Members() do
    	if pCity:GetBuildings():HasBuilding(iDummy) ~= true then
    		local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
    		--print("pPlot:", pPlot)
    		local iPlot = pPlot:GetIndex()
    		--print("iPlot:", iPlot)
    		pCity:GetBuildQueue():CreateIncompleteBuilding(iDummy, iPlot, 100)
    		print ("Dummy added")
    	end
    end
    Since neither of Events.DiplomacyDeclareWar or Events.DiplomacyMakePeace pass any argument data for a city ID # you cannot use the pCities:FindID(cityID) but must instead execute through all the players cities. This is not actually extra code you did not already need: in order to add a building, dummy or otherwise, to all of a player's cities via an lua script you have to execute through all the player's cities.
 
Thank you very much for the detailed help! Unfortunately, though, JFK_DiffGovCheck is still failing to work. Whenever it triggers, it returns "
function expected instead of nil" for the line "if (Players[iAttacker]:GetCulture():GetCurrentGovernment() ~= Players[iDefender]:GetCulture():GetCurrentGovernment()) and Players[iAttacker]:GetDiplomacy():IsAtWarWith(iDefender) then"

I also made the changes you suggested of making separate functions for war, peace, and governments changing, and the code now looks like this. Sorry again for the messy code, but can you tell me if anything else is wrong with this that needs fixing/changing?

Code:
function C15_ValidTrait(sTrait)
    local tValid = {}
    for k, v in ipairs(PlayerManager.GetWasEverAliveIDs()) do
        local leaderType = PlayerConfigurations[v]:GetLeaderTypeName()
        for trait in GameInfo.LeaderTraits() do
            if trait.LeaderType == leaderType and trait.TraitType == sTrait then
                tValid[v] = true
            end;
        end
        if not tValid[v] then
            local civType = PlayerConfigurations[v]:GetCivilizationTypeName()
            for trait in GameInfo.CivilizationTraits() do
                if trait.CivilizationType == civType and trait.TraitType == sTrait then
                    tValid[v] = true
                end;
            end
        end
    end
    return tValid
end

local iDummy = GameInfo.Buildings["BUILDING_JFK_DIFFGOVWAR_DUMMY"].Index;
local sTrait = "TRAIT_LEADER_SNACK_JFK"
local tTraitPlayers = C15_ValidTrait(sTrait)

function JFK_DiffGovCheck(iAttacker, iDefender)
    print ("JFK Diff Gov Check starting");
    if (Players[iAttacker]:GetCulture():GetCurrentGovernment() ~= Players[iDefender]:GetCulture():GetCurrentGovernment()) and Players[iAttacker]:GetDiplomacy():IsAtWarWith(iDefender) then
        print ("JFK Diff Gov Check succeeded")
        return true;
    else
        return false;
    end
end

function JFKDiffGovWarAbility( eAttackingPlayerID, eDefendingPlayerID )
    print ("JFK Ability Triggered")
    if tTraitPlayers[eAttackingPlayerID] then
        print ("Attacker is JFK")
        if JFK_DiffGovCheck(eAttackingPlayerID, eDefendingPlayerID) == true then
            print ("JFK Government + War Check is true")
            for i, pCity in Players[eAttackingPlayerID]:GetCities():Members() do
                if pCity:GetBuildings():HasBuilding(iDummy) ~= true then
                    local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                    --print("pPlot:", pPlot)
                    local iPlot = pPlot:GetIndex()
                    --print("iPlot:", iPlot)
                    pCity:GetBuildQueue():CreateIncompleteBuilding(iDummy, iPlot, 100)
                    print ("Dummy added")
                end
            end
        end
    else
    if tTraitPlayers[eDefendingPlayerID] then
        print ("Defender is JFK")
        if JFK_DiffGovCheck(eAttackingPlayerID, eDefendingPlayerID) == true then
            for i, pCity in Players[eDefendingPlayerID]:GetCities():Members() do
                if pCity:GetBuildings():HasBuilding(iDummy) ~= true then
                    local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                    --print("pPlot:", pPlot)
                    local iPlot = pPlot:GetIndex()
                    --print("iPlot:", iPlot)
                    pCity:GetBuildQueue():CreateIncompleteBuilding(iDummy, iPlot, 100)
                    print ("Dummy added")
                end
            end
        end
    end
    end
end

function JFKDiffGovPeaceDeclared (eAttackingPlayerID, eDefendingPlayerID)
    if tTraitPlayers[eAttackingPlayerID] then
        print ("Attacker is JFK")
        if JFK_DiffGovCheck(eAttackingPlayerID, eDefendingPlayerID) == true then
            print ("JFK Government Check is true")
            for i, pCity in Players[eAttackingPlayerID]:GetCities():Members() do
                if pCity:GetBuildings():HasBuilding(iDummy) == true then
                    local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                    --print("pPlot:", pPlot)
                    local iPlot = pPlot:GetIndex()
                    --print("iPlot:", iPlot)
                    pCity:RemoveBuilding(iDummy)
                    print ("Dummy removed")
                end
            end
        end
    else
    if tTraitPlayers[eDefendingPlayerID] then
        print ("Defender is JFK")
        if JFK_DiffGovCheck(eAttackingPlayerID, eDefendingPlayerID) == true then
            print ("JFK Government Check is true")
            for i, pCity in Players[eDefendingPlayerID]:GetCities():Members() do
                if pCity:GetBuildings():HasBuilding(iDummy) == true then
                    local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                    --print("pPlot:", pPlot)
                    local iPlot = pPlot:GetIndex()
                    --print("iPlot:", iPlot)
                    pCity:RemoveBuilding(iDummy)
                    print ("Dummy removed")
                end
            end
        end
    end
    end
end
        
function JFKGovernmentChanged(playerID)
    local pPlayer          = Players[playerID];
    local kPlayers     :table = PlayerManager.GetWasEverAlive();
    for _, pOtherPlayer in ipairs(kPlayers) do
        local otherPlayerID = pOtherPlayer:GetID();
        if otherPlayerID ~= playerID then
            local IsValidPlayer = true
            if (pOtherPlayer.IsFreeCities and pOtherPlayer:IsFreeCities()) or pOtherPlayer:IsBarbarian() or not pOtherPlayer:IsAlive()then
                IsValidPlayer = false
            end
            if IsValidPlayer and (pPlayer:GetDiplomacy():IsAtWarWith(pOtherPlayer) or  pOtherPlayer:GetDiplomacy():IsAtWarWith(pPlayer)) then
                if JFK_DiffGovCheck(playerID, otherPlayerID) ~= true then
                    print ("JFK Government + War Check is false")
                    if tTraitPlayers[playerID] == true then
                        for i, pCity in Players[playerID]:GetCities():Members() do
                            if pCity:GetBuildings():HasBuilding(iDummy) == true then
                            local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                            --print("pPlot:", pPlot)
                            local iPlot = pPlot:GetIndex()
                            --print("iPlot:", iPlot)
                            pCity:RemoveBuilding(iDummy)
                            print ("Dummy removed")
                            end
                        end
                    else
                    if tTraitPlayers[otherPlayerID] == true then
                        for i, pCity in Players[otherPlayerID]:GetCities():Members() do
                            if pCity:GetBuildings():HasBuilding(iDummy) == true then
                            local pPlot = Map.GetPlot(pCity:GetX(), pCity:GetY())
                            --print("pPlot:", pPlot)
                            local iPlot = pPlot:GetIndex()
                            --print("iPlot:", iPlot)
                            pCity:RemoveBuilding(iDummy)
                            print ("Dummy removed")
                            end
                        end
                    end
                    end
                end
            end
        end
    end
end
                        
Events.DiplomacyDeclareWar.Add(JFKDiffGovWarAbility)
Events.DiplomacyMakePeace.Add(JFKDiffGovPeaceDeclared)
Events.GovernmentChanged.Add(JFKGovernmentChanged)
 
You're getting the error because Player:GetCulture():GetCurrentGovernment() apparently is only valid in a User Interface script and is not valid in a Gameplay Script.

See this listing: https://docs.google.com/spreadsheet...D_xTTld4sFEyMxrDoPwX2NUFc/edit#gid=1205978888

Unfortunately there does not seem to be a function for this that is valid in a gameplay script.

So you'd have to rethink your code / UA effect based on what is available.
 
I don't really want to change that part of the UA because the basis of my John F. Kennedy mod was to simulate Cold War politics and events such as the Bay of Pigs invasion. Making different governments (i.e. Democracy vs. Communism) the basis for JFK's UA was the idea of the mod... I can't really think of any other equivalent.

Is there any hacky way to get a UI script and a gameplay script to communicate? Like, can I have the UI script give JFK's player/cities/whatever something that could then be read by the gameplay script? Alternately, what ways are there to rewrite the gameplay script to instead work as a UI script? There's also agenda requirements based on different governments (this is used by the Robespierre mod) - can anything be done with agendas or those requirements to perform the same check without using a UI script or any LUA at all?

In other words, if I wanted to keep the UA, is there any good way to do that or is it hopeless? Do I need to just throw away this part of his UA and give him something completely different?

ETA: I thought of a possibility for something different. What if instead JFK got Diplomatic Favor for making trade routes with Civs that are behind in civics or culture? Similar to how Russia's UA gives them bonus science/culture? If it also gave JFK himself some bonuses to the trade route to encourage the AI to do that, that could be a way of simulating JFK helping the "third world." Is something like that possible?
 
Last edited:
There are hacky methods you can use to make User Interface scripts communicate data to Gameplay Scripts, but they are a bit complicated.

I've been giving this a bit of thought this morning, and there is this hook event: Events.GovernmentChanged(playerID, governmentID)

The game engine passes the data for the Player ID # and the GovernmentType "Index" ID # to any lua function that is assigned to that hook event.

It should be possible to monitor Government Changes using this event, and then to record the data regarding which player changed to which Government so that it can be extracted and used later.

Let me do some more thinking about how best to use this this morning and I'll give you feedback later on how I'd proceed.
 
Well, I won't disagree on "hacky", but hey, surely Firaxis has created the ExposedMembers table for a reason :D
 
Code:
print ("JFK LUA Loaded")

-----------------------------------------------
-- FUNCTION C15_ValidTrait
-- Credits: Chrisy15
-----------------------------------------------

function C15_ValidTrait(sTrait)
	local tValid, bIsInPlay = {}, false
	for k, v in ipairs(PlayerManager.GetWasEverAliveIDs()) do
		local leaderType = PlayerConfigurations[v]:GetLeaderTypeName()
		for trait in GameInfo.LeaderTraits() do
			if trait.LeaderType == leaderType and trait.TraitType == sTrait then
				tValid[v] = true
				bIsInPlay = true
			end;
		end
		if not tValid[v] then
			local civType = PlayerConfigurations[v]:GetCivilizationTypeName()
			for trait in GameInfo.CivilizationTraits() do
				if trait.CivilizationType == civType and trait.TraitType == sTrait then
					tValid[v] = true
					bIsInPlay = true
				end;
			end
		end
	end
	return tValid, bIsInPlay
end

local iDummy = GameInfo.Buildings["BUILDING_JFK_DIFFGOVWAR_DUMMY"].Index;
local sTrait = "TRAIT_LEADER_SNACK_JFK"
local tTraitPlayers, bIsInPlay = C15_ValidTrait(sTrait)
local bGameLoadingComplete = false


function AddBuildingToAllPlayerCities(pPlayer, iBuildingIndex, bRepairPillaged)
	local bFixIfPillaged = ((bRepairPillaged ~= nil) and bRepairPillaged or false)
	for i, pCity in pPlayer:GetCities():Members() do
		if not pCity:GetBuildings():HasBuilding(iBuildingIndex) then
			local iCityPlotIndex = Map.GetPlot(pCity:GetX(), pCity:GetY()):GetIndex()
			pCity:GetBuildQueue():CreateIncompleteBuilding(iBuildingIndex, iCityPlotIndex, 100)
			print("Dummy added")
		else
			if (bFixIfPillaged == true) then
				if pCity:GetBuildings():IsPillaged(iBuildingIndex) then
					pCity:GetBuildings():SetPillaged(iBuildingIndex, false)
				end
			end
		end
	end
end
function RemoveBuildingFromAllPlayerCities(pPlayer, iBuildingIndex)
	for i, pCity in pPlayer:GetCities():Members() do
		if pCity:GetBuildings():HasBuilding(iBuildingIndex) then
			pCity:GetBuildings():RemoveBuilding(iBuildingIndex);
		end
	end
end
function CheckAllWarAndGovtStatuses()
	for k, v in ipairs(PlayerManager.GetWasEverAliveIDs()) do
		if tTraitPlayers[v] then
			local pLoopPlayer = Players[v]
			if pLoopPlayer:IsAlive() and pLoopPlayer:IsMajor() then
				local bGiveBuildings = false
				local iPlayerGovernmentIndex = pLoopPlayer:GetProperty("CurrentGovernment")
				for iPlayer = 0,62 do
					local pPlayer = Players[iPlayer]
					if (iPlayer ~= v) and pPlayer:IsAlive() and pPlayer:IsMajor() then
						if pPlayer:GetDiplomacy():IsAtWarWith(v) and (iPlayerGovernmentIndex ~= pPlayer:GetProperty("CurrentGovernment")) then
							bGiveBuildings = true
							break
						end
					end
				end
				if bGiveBuildings then
					AddBuildingToAllPlayerCities(pLoopPlayer, iDummy)
				else
					RemoveBuildingFromAllPlayerCities(pLoopPlayer, iDummy)
				end
			end
		end
	end
end   
function OnLoadScreenClose()
	bGameLoadingComplete = true
	CheckAllWarAndGovtStatuses()
end
function OnGovernmentChanged(playerID, governmentID)
	print("Events.GovernmentChanged with data playerID " .. playerID .. ", governmentID " .. governmentID)
	local pPlayer = Players[playerID]
	if pPlayer:IsMajor() then
		pPlayer:SetProperty("CurrentGovernment", governmentID)
	else
		pPlayer:SetProperty("CurrentGovernment", -1)
	end
	if bGameLoadingComplete then
		CheckAllWarAndGovtStatuses()
	end
end

function OnWarDeclared(iPlayerOne, iPlayerTwo)
	if tTraitPlayers[iPlayerOne] or tTraitPlayers[iPlayerTwo] then
		local pPlayerOne = Players[iPlayerOne]
		local pPlayerTwo = Players[iPlayerTwo]
		if pPlayerOne:IsMajor() and pPlayerTwo:IsMajor() then
			if (pPlayerOne:GetProperty("CurrentGovernment") ~= pPlayerTwo:GetProperty("CurrentGovernment")) then
				if tTraitPlayers[iPlayerOne] then
					AddBuildingToAllPlayerCities(pPlayerOne, iDummy)
				end
				if tTraitPlayers[iPlayerTwo] then
					AddBuildingToAllPlayerCities(pPlayerTwo, iDummy)
				end
			end
		end
	end
end
function OnPeaceDeclared(iPlayerOne, iPlayerTwo)
	if tTraitPlayers[iPlayerOne] or tTraitPlayers[iPlayerTwo] then
		local pPlayerOne = Players[iPlayerOne]
		local pPlayerTwo = Players[iPlayerTwo]
		if pPlayerOne:IsMajor() and pPlayerTwo:IsMajor() then
			CheckAllWarAndGovtStatuses()
		end
	end
end
function OnCityFoundedOrCaptured(iPlayer, iCityID)
	if tTraitPlayers[iPlayer] then
		CheckAllWarAndGovtStatuses()
	else
		local pCity = Players[iPlayer]:GetCities():FindID(iCityID)
		if pCity:GetBuildings():HasBuilding(iDummy) then
			pCity:GetBuildings():RemoveBuilding(iDummy);
		end
	end
end
if bIsInPlay then
	Events.GovernmentChanged.Add(OnGovernmentChanged)
	Events.DiplomacyDeclareWar.Add(OnWarDeclared)
	Events.DiplomacyMakePeace.Add(OnPeaceDeclared)
	Events.LoadScreenClose.Add(OnLoadScreenClose)
	Events.CityInitialized.Add(OnCityFoundedOrCaptured)
end
Don't believe I've made any coding or logic errors, but you will need to verify to be sure.

I've made the code not add the dummy building when one of the players at war is not a major civ -- otherwise City States and Free Cities will probably nearly always cause the dummy building to be added.

Events.GovernmentChanged.Add(OnGovernmentChanged) fires for each player in turn when a game is first started, but not when reloaded (because the players already have governments selected when reloading, but not when the game is originally being "built")

I've also altered Chrisy15's function to return whether or not any player has the trait as a direct boolean in addition to the table of all players who have the trait. This makes it a little more easy to understand the code that only activates the main hook functions when at least one player who has the trait is part of the game. When no players have the trait there is no reason for the code to ever execute.
 
First off, thank you LeeS! Your code worked perfectly, which is great. I need to test it more, but it at least gave the building to all cities without returning errors.

However, I have a new problem - the building itself isn't doing anything. There must be something wrong with my SQL but I'm not sure what. I've uploaded the SQL file to Google Drive - can you take a look at it and tell me what's wrong? (Note that some of the SQL file's values are temporary, like his agenda, which I haven't programmed yet).

https://drive.google.com/file/d/1SGEHiy_N9obU5FW8-MO5mqWzlrprxmtY/view?usp=sharing
 
Without looking any further into it, you have a mismatch between what you are adding in table DynamicModifiers and what your are stating as ModifierType in table Modifiers.

DynamicModifiers ModifierType = MODIFIER_SNACK_DIFFGOVWAR_ADJUSTUNITPRODUCTION
Modifiers ModifierType = MODIFIER_SNACK_JFK_DIFFGOVWAR_UNITPRODUCTION

File Database.log ought to be reporting an invalid reference. If it is not, then there almost certainly has to be a syntax error between table Buildings and table Modifiers in your file. In which case the syntax error should be reported in Database.log
 
Last edited:
Database.log didn't report anything, but you were correct - when I changed the ModifierType, it worked.

That should be everything - I just need to put in his agenda and write his Civlopedia pages. Thank you so, so much, you've been a huge help!

ETA: Oh, wait, one more thing - how do I remove dummy buildings from the city list? Is that not possible?
 
You mean from showing in the list of buildings a city has?

It's possible but requires a re-write of the CityPanelOverview.lua file, you then have to set your custom version of this file under an ImportFiles Action-type in modbuddy, and then your mod will be incompatible with any other mod that also has a custom version of the same User Interface lua file.
 
Back
Top Bottom