[BNW] How to change a detected improvement with another one

jarcast2

King
Joined
Jan 10, 2018
Messages
641
Location
Terra Incognita
Hi everyone, does anyone know if there is a way to switch an improvement with another one when the former is finished?
My code look like this:

Code:
local DummyPolicy = GameInfo.Policies["POLICY_DUMMY"].ID
local pasture = GameInfo.Improvements.IMPROVEMENT_PASTURE.ID
local camp = GameInfo.Improvements.IMPROVEMENT_CAMP.ID
local pastureS = GameInfo.Improvements.IMPROVEMENT_PASTURE_S.ID
local campS = GameInfo.Improvements.IMPROVEMENT_CAMP_S.ID

function DummyPolicy(playerID, plotX, plotY, improvementID)
    local pPlot = Map.GetPlot(plotX, plotY)
    local pPlayer = Players[playerID]
    --local pPlayer = Players[pPlot:GetOwner()]
    if pPlayer:GetCivilizationType() == iCiv and pPlayer:HasPolicy(DummyPolicy) then
        if improvementID == pasture then
            "change pasture with pastureS"
        elseif improvementID == camp then
            "change camp with campS"
        else
        end
    end
end
if JFD_IsCivilisationActive(iCiv) then GameEvents.BuildFinished.Add(DummyPolicy) end

Thanks in advance.
 
Simply use plotX and plotY to get the plot and call Plot:SetImprovementType(type) where needed.

Keep in mind that the player might be able to build the default improvement over the dummy one once it's been replaced. It's mostly cosmetic, as the cycle will just repeat, but something to consider.
 
I see, just imagining the AI workers that will just stay there replacing the dummy improvement with the default one over and over gives me shivers.

My intentions with the dummy improvement is to give +2 culture when the improvement is on a road (similar to trading posts with vox Populi). Is there a way to tell the workers to not build anymore the default improvement and build the dummy instead? Something like making unit.CanBuild from true to false just for the specified civ and after adopting the dummy policy.

Actually this solution is a remedy for an issue regarding a Decision (i.e. Sukritact's Events and Decisions) I made for my civ. In my original code I gave the dummy policy and also the +2 culture on the eligible tiles (pasture or camps on road), then I used Events.SerialEventRoadCreated (to add the +2 culture when a road is created over a pasture or camp) in tandem with GameEvents.BuildFinished (to add +2 culture when a pasture or camp is built on an existing road).
However, I found out that every time I load a saved game inexpicably the amount of culture on the selected tiles increases by 2 reaching ridicolously high yields by the end of the game. That's why I thought that trying the way of the dummy improvement may solve the issue.
In addition, is there a reason why GameEvents.BuildFinished fires twice giving double the intended yield when a single improvement is finished?

Spoiler Original Decision code :
Code:
local Decisions_SamnitesTratturi = {}
    Decisions_SamnitesTratturi.Name = "TXT_KEY_DECISIONS_TRATTURI"
   Decisions_SamnitesTratturi.Desc = "TXT_KEY_DECISIONS_TRATTURI_DESC"
   HookDecisionCivilizationIcon(Decisions_SamnitesTratturi, "CIVILIZATION_SAMNITES")
   Decisions_SamnitesTratturi.CanFunc = (
   function(pPlayer)
       if pPlayer:GetCivilizationType() ~= GameInfoTypes.CIVILIZATION_SAMNITES then return false, false end
       if load(pPlayer, "Decisions_SamnitesTratturi") == true then
           Decisions_SamnitesTratturi.Desc = Locale.ConvertTextKey("TXT_KEY_DECISIONS_TRATTURI_ENACTED_DESC")
           return false, false, true
       end
       local iCost = math.ceil(250*iMod)
       Decisions_SamnitesTratturi.Desc = Locale.ConvertTextKey("TXT_KEY_DECISIONS_TRATTURI_DESC", iCost)
       if (Teams[pPlayer:GetTeam()]:IsHasTech(GameInfoTypes.TECH_ENGINEERING)) and (pPlayer:GetJONSCulture() >= iCost) then
           return true, true
       else
           return true, false
       end
       if (pPlayer:GetNumResourceAvailable(iMagistrate, false) < 2) then return true, false end
       
       
       return true, true
   end
   )
   
   Decisions_SamnitesTratturi.DoFunc = (
   function(pPlayer)
       local iCost = math.ceil(250*iMod)
       pPlayer:ChangeNumResourceTotal(iMagistrate, -2)
       pPlayer:ChangeJONSCulture(-iCost)
       pPlayer:SetNumFreePolicies(1)
       pPlayer:SetNumFreePolicies(0)
       pPlayer:SetHasPolicy(GameInfoTypes.POLICY_DECISIONS_TRATTURI, true)
       pPlayer:GetCapitalCity():SetNumRealBuilding(GameInfoTypes["BUILDING_DECISIONS_TRATTURI"], 1)
       save(pPlayer, "Decisions_SamnitesTratturi", true)
       
       -- Give +2 Culture on pasture and camps with road on them
       local pasture = GameInfo.Improvements.IMPROVEMENT_PASTURE.ID
       local camp = GameInfo.Improvements.IMPROVEMENT_CAMP.ID
       local road = GameInfo.Routes.ROUTE_ROAD.ID
       local railroad = GameInfo.Routes.ROUTE_RAILROAD.ID
       local iCulture = GameInfo.Yields.YIELD_CULTURE.ID
       for pCity in pPlayer:Cities() do
           for adjacentPlot in PlotAreaSweepIterator(pCity:Plot(), 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
           x = adjacentPlot:GetX()
           y = adjacentPlot:GetY()
               if adjacentPlot:GetImprovementType() == pasture or adjacentPlot:GetImprovementType() == camp then
                   if adjacentPlot:GetRouteType() == road then
                       print("Decision Tratturi activated")
                       if adjacentPlot:GetWorkingCity() == pCity then
                           Game.SetPlotExtraYield(adjacentPlot:GetX(), adjacentPlot:GetY(), iCulture, 2)
                       else
                       end
                   end
               end
           end
       end
       
   end
   )
   
Decisions_AddCivilisationSpecific(GameInfoTypes.CIVILIZATION_SAMNITES, "Decisions_SamnitesTratturi", Decisions_SamnitesTratturi)

Spoiler Follow-up Code :

Code:
local pasture = GameInfo.Improvements.IMPROVEMENT_PASTURE.ID
local camp = GameInfo.Improvements.IMPROVEMENT_CAMP.ID
local road = GameInfo.Routes.ROUTE_ROAD.ID
local railroad = GameInfo.Routes.ROUTE_RAILROAD.ID

-- When road is built, check pasture or camp
function TratturiCulture(iHexX, iHexY, iPlayer, iRouteType)
    local pPlot = Map.GetPlot(ToGridFromHex(iHexX, iHexY))
    local pPlayer = Players[iPlayer]
    if pPlayer:GetCivilizationType() == iCiv and pPlayer:HasPolicy(GameInfo.Policies["POLICY_DECISIONS_TRATTURI"].ID) then
        if iRouteType == road or pPlot:GetRouteType() == railroad then
            if pPlot:GetImprovementType() == pasture or pPlot:GetImprovementType() == camp then
                print("EnD addons TratturiCulture road built")
               Game.SetPlotExtraYield(pPlot:GetX(), pPlot:GetY(), iCulture, 2)
            end
        end
    end
end

if JFD_IsCivilisationActive(iCiv) then Events.SerialEventRoadCreated.Add(TratturiCulture) end;

-- When pasture or camp is built check road
function TratturiCulture2(playerID, plotX, plotY, improvementID)
    local pPlot = Map.GetPlot(plotX, plotY)
    local pPlayer = Players[playerID]
    --local pPlayer = Players[pPlot:GetOwner()]
    if pPlayer:GetCivilizationType() == iCiv and pPlayer:HasPolicy(GameInfo.Policies["POLICY_DECISIONS_TRATTURI"].ID) then
        if improvementID == pasture or improvementID == camp then
            if pPlot:GetRouteType() == road then
              Game.SetPlotExtraYield(pPlot:GetX(), pPlot:GetY(), iCulture, 1) -- it fires twice don't know why
              print("EnD addons TratturiCulture improvement built")
            end
        end
    end
end

if JFD_IsCivilisationActive(iCiv) then GameEvents.BuildFinished.Add(TratturiCulture2) end


In the meantime I have discovered the monitors function and corrected the decision code in this way (eliminating also any railroad reference)

Spoiler New Decision code :
Code:
local pasture = GameInfo.Improvements.IMPROVEMENT_PASTURE.ID
local camp = GameInfo.Improvements.IMPROVEMENT_CAMP.ID
local road = GameInfo.Routes.ROUTE_ROAD.ID

local Decisions_SamnitesTratturi = {}
    Decisions_SamnitesTratturi.Name = "TXT_KEY_DECISIONS_TRATTURI"
   Decisions_SamnitesTratturi.Desc = "TXT_KEY_DECISIONS_TRATTURI_DESC"
   HookDecisionCivilizationIcon(Decisions_SamnitesTratturi, "CIVILIZATION_SAMNITES")
   Decisions_SamnitesTratturi.CanFunc = (
   function(pPlayer)
       if pPlayer:GetCivilizationType() ~= GameInfoTypes.CIVILIZATION_SAMNITES then return false, false end
       if load(pPlayer, "Decisions_SamnitesTratturi") == true then
           Decisions_SamnitesTratturi.Desc = Locale.ConvertTextKey("TXT_KEY_DECISIONS_TRATTURI_ENACTED_DESC")
           return false, false, true
       end
       local iCost = math.ceil(250*iMod)
       Decisions_SamnitesTratturi.Desc = Locale.ConvertTextKey("TXT_KEY_DECISIONS_TRATTURI_DESC", iCost)
       if (Teams[pPlayer:GetTeam()]:IsHasTech(GameInfoTypes.TECH_ENGINEERING)) and (pPlayer:GetJONSCulture() >= iCost) then
           return true, true
       else
           return true, false
       end
       if (pPlayer:GetNumResourceAvailable(iMagistrate, false) < 2) then return true, false end
       
       
       return true, true
   end
   )
   
   Decisions_SamnitesTratturi.DoFunc = (
   function(pPlayer)
       local iCost = math.ceil(250*iMod)
       pPlayer:ChangeNumResourceTotal(iMagistrate, -2)
       pPlayer:ChangeJONSCulture(-iCost)
       pPlayer:SetNumFreePolicies(1)
       pPlayer:SetNumFreePolicies(0)
       pPlayer:SetHasPolicy(GameInfoTypes.POLICY_DECISIONS_TRATTURI, true)
       pPlayer:GetCapitalCity():SetNumRealBuilding(GameInfoTypes["BUILDING_DECISIONS_TRATTURI"], 1)
       
       -- Give +2 Culture on pasture and camps with road on them
       local iCulture = GameInfo.Yields.YIELD_CULTURE.ID
       for pCity in pPlayer:Cities() do
           for adjacentPlot in PlotAreaSweepIterator(pCity:Plot(), 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
           x = adjacentPlot:GetX()
           y = adjacentPlot:GetY()
               if adjacentPlot:GetImprovementType() == pasture or adjacentPlot:GetImprovementType() == camp then
                   if adjacentPlot:GetRouteType() == road then
                       print("Decision Tratturi activated")
                       if adjacentPlot:GetWorkingCity() == pCity then
                           Game.SetPlotExtraYield(adjacentPlot:GetX(), adjacentPlot:GetY(), iCulture, 2)
                       else
                       end
                   end
               end
           end
       end
       save(pPlayer, "Decisions_SamnitesTratturi", true)
   end
   )
   
   Decisions_SamnitesTratturi.Monitors = {}
   Decisions_SamnitesTratturi.Monitors[Events.SerialEventRoadCreated] = (   
   function(iHexX, iHexY, iPlayer, iRouteType)
       local pPlot = Map.GetPlot(ToGridFromHex(iHexX, iHexY))
       local pPlayer = Players[iPlayer]
       if load(pPlayer, "Decisions_SamnitesTratturi") == true then
           if iRouteType == road then
               if pPlot:GetImprovementType() == pasture or pPlot:GetImprovementType() == camp then
                   print("EnD addons TratturiCulture road built")
                  Game.SetPlotExtraYield(pPlot:GetX(), pPlot:GetY(), iCulture, 2)
               end
           end
       end
   end
   )
   
   Decisions_SamnitesTratturi.Monitors[GameEvents.BuildFinished] = (   
   function(playerID, plotX, plotY, improvementID)
       local pPlot = Map.GetPlot(plotX, plotY)
       local pPlayer = Players[playerID]
       if load(pPlayer, "Decisions_SamnitesTratturi") == true then
           if improvementID == pasture or improvementID == camp then
               if pPlot:GetRouteType() == road then
                  Game.SetPlotExtraYield(pPlot:GetX(), pPlot:GetY(), iCulture, 1) -- it fires twice don't know why
                   print("EnD addons TratturiCulture improvement built")
               end
           end
       end
   end
   )
   
Decisions_AddCivilisationSpecific(GameInfoTypes.CIVILIZATION_SAMNITES, "Decisions_SamnitesTratturi", Decisions_SamnitesTratturi)

What am I still missing?
 
Something like making unit.CanBuild from true to false just for the specified civ and after adopting the dummy policy.
If you're dependant on a modded DLL, you can use the PlayerCanBuild event. Let the worker build the improvement, switch it to the other improvement, then use the event to ban workers replacing it.

then I used Events.SerialEventRoadCreated
Test carefully, some/most/all SerialEvents (I forget the details) only trigger if the active human player can see the tile in question (so may not fire for an AI worker completing a road in the FoW)

However, I found out that every time I load a saved game inexpicably the amount of culture on the selected tiles increases by 2
Because every time the game loads, all the roads are added back to the base map, and the event triggers again

In addition, is there a reason why GameEvents.BuildFinished fires twice giving double the intended yield when a single improvement is finished?
It's a bug in the DLL
 
Back
Top Bottom