Reward when a unit dies in home territory

els4nt0

Chieftain
Joined
Jul 3, 2018
Messages
2
Hey all,

I'm trying to learn how to mod Civ 6, and I've been able to more or less work my way through the XML and SQL coding with trial and error. But I'm having a little more trouble with the LUA part.

I'm trying to make a leader trait where every time a unit by an enemy civ in friendly territory, the leader receives an envoy and a faith boost. I'm able to do the part where leader gets the rewards whenever a unit dies, but I can't seem to get the code to ONLY activate when the unit dies in friendly territory. It only seems to work anywhere, or nowhere at all.

Code:
function Els_Martin_UnitKilledInCombat(killedPlayerID, killedUnitID, playerID, unitID)
    local player = Players[killedPlayerID]
    local unitKilled = player:GetUnits():FindID(killedUnitID)
    local numCombat = math.floor(GameInfo.Units[unitKilled:GetType()].Combat)
    local unitPlot:table = Map.GetPlot(unitKilled:GetX(), unitKilled:GetY());
        if unitPlot:GetOwner() == killedPlayerID then
        player:GetReligion():ChangeFaithBalance(numCombat)
        player:GetInfluence():ChangeTokensToGive(1)
    end
end
Events.UnitKilledInCombat.Add(Els_Martin_UnitKilledInCombat)

I suspect it has something to do with the "Plot:GetOwner" part, but I just can't get it to work the way I want. Does anyone have any idea what the problem might be? Help would be greatly appreciated!
 
unitPlot is probably coming back as a nil value because generally by the time functions hooked into Events.UnitKilledInCombat fire, the unit is already dead and it's XY location is not usable. You get as I recall "-1" for both unitKilled:GetX() and unitKilled:GetY() so Map.GetPlot(args) returns a value of nil because of the negative plot-grid locations.

if you look in lua.log you will probably see an error message for attempting to index a nil value.
 
Lee is right. You should save the informations of all units of that civilization in a table before the units can die (e.g. every time when his turn begins or when initializing the game). Then your script will be able to check, whether the deceased unit was on a friendly territory.
 
Thanks for the replies! Hmm, creating that kind of table sounds like it would beyond my capabilities... Do you know of any resources that could help me learn how to do something like that? Or is there anything in the game's base files that performs a similar function I could look at?
 
It only requires basic Lua knowledge. I am doing something similar in my Free States City mod: Creating a table that contains the information of a free city, then destroy this city and finally create a new city state city with the informations saved in the table:

Spoiler :
In this code snippet you can see how the function GetCityDatas() stores the information of the old city in a table called "CityDataList", which contains informations like the city coordinates and its population.
Once the old city got destroyed my Lua script sets the population number in the new city using SetCityDatas().
Code:
local CityDataList = {}
function GetCityDatas ( pCity )
    local kCityDatas :table = {
        iTurn = Game.GetCurrentGameTurn(),
        iPosX = pCity:GetX(),
        iPosY = pCity:GetY(),
        iPop = pCity:GetPopulation()
    };
    table.insert(CityDataList, kCityDatas)
end

function SetCityPopulation( pCity, iPopulation )
    if ( pCity ) then
        while pCity:GetPopulation() < iPopulation do
            pCity:ChangePopulation(1); --increase pop by +1
        end
    end
end

function SetCityDatas() 
    for _, iCityStateID in ipairs(PlayerManager.GetAliveMinorIDs()) do
        local pCities = Players[iCityStateID]:GetCities();
        local pCity;
        for ii, pCity in pCities:Members() do     
            for i, kCityDatas in pairs(CityDataList) do                 
                if ( pCity:GetX() == kCityDatas.iPosX and pCity:GetY() == kCityDatas.iPosY ) then
                    SetCityPopulation( pCity, kCityDatas.iPop )
                end
                --table.remove(CityDataList, i) --dont remove items during loop!
            end
        end
    end
end

And yes, now I know that datas is the wrong plural of data. Maybe I am going to correct that typo one day. :D


Now you simply have to do something similar saving unit informations every time the game got initialized or when a new unit is created or when it has moved. For Initializing you use
Code:
function Initalize()
   ...
end
Initialize()
and for getting an event when a unit is created you use
Code:
function OnUnitAddedToMap( playerID:number, unitID:number )
   ...
Events.UnitAddedToMap.Add(OnUnitAddedToMap)
and for the event when a unit moves you use
Code:
function OnUnitMoveComplete(playerID, unitID, x, y, visibleToLocalPlayer, unitState)
   ...
end
Events.UnitMoveComplete.Add(  OnUnitMoveComplete );

If you are a total Lua beginner you should learn the basics first before you start doing this.
 
Last edited:
How do lua tables, like the one you posted, react with saved games? Does the information persist when saving and loading the game?
 
How do lua tables, like the one you posted, react with saved games? Does the information persist when saving and loading the game?
Only if you add a method to save and reload the table and its data within your lua code.

Many times, however, you do not actually need to use a "data-saving" method -- you can just recreate any info you need to track directly from the state of the game as the save reloads. For example, if you are tracking all units and their XY grid-locations, you do not really need to save any information when the human user exits the game. You just inspect all player units for all players when the game reloads from the save (or a new game is started), and then track the movements of the units from there on. If you use the UnitAddedToMap event hook, it will fire as I recall for every unit that is added back into the game from a save-file as the game places these units back onto the game map.

Whether or not you need to use a data persistence set-up like Gedemon uses depends entirely on what you are keeping track of.

Spoiler :
there are several threads on the civ6 forums as I recall pertaining to persisting lua-data across saving and reloading of a game, but I don't have any of the links handy
 
How do lua tables, like the one you posted, react with saved games? Does the information persist when saving and loading the game?

They will not be saved automatically. That is why you should use Initialize(), which will be triggered every time a new game is started or when a save file is loaded.
However, you could use Gedemon's table save loader code instead to save your tables in the save file. https://forums.civfanatics.com/threads/saving-loading-simple-tables-with-a-game.609397/
 
functions subscribed to Events.UnitAddedToMap do in fact fire when the game is reloaded from a save as each unit is re-added to the map as part of the game reloading process, so for a Events.UnitAddedToMap function it would not really be necessary to create an additional "Initialize()" function. All that would be necessary is just to subscribe your function to the event -- you would not need to do anything different with the code within the function between map "reload" firings and normal unit creations.

Events.UnitAddedToMap provides four arguments in the Vanilla expansion (I assume the same is true when running RaF):
Code:
(iPlayer, iUnitID, iUnitLocationX, iUnitLocationY)
 
Oh, that is good to know. Thx Lee!
Still he probably also needs the UnitMoveComplete Event to keep track on the locations of moved units.
Yes, he would need that as well for tracking the units as they start moving around the map.
 
Back
Top Bottom