[BNW] Lua Hook for Expending Units (Like Missionaries or Settlers)

RoxyRiku94

Detective Agent
Joined
Jan 30, 2016
Messages
142
Location
Souzai Daigaku
Is there an existing Lua Hook when expending non-Great People units? I've looked within the GameEvents from Modiki, but to no avail (and making a Unique Missionary a Great Person just to use one function is also not a very good idea).
 
Nope, there is not (assuming you are not using a custom DLL mod). Judging from your post, I assume that you are (for example) trying to find a hook that fires when a missionary spreads its religion.

I wrote this piece of code for a collab 'Demak Sultanate'-civ, which causes missionaries to grant a small burst of culture (based on era) whenever they spread their religion. It is definitely not the cleanest code (and definitely not the most efficient as I already see multiple ways I could improve!), but it works in almost every case. There is just one bug where, if the player saves the game after he spreads religion with an Abangan (that has >1 Religion Spread), but before he presses next turn, then the bonus culture will not be granted. This could however be solved with tablesaverloader if someone feels like using that.

The basic idea of the code is the following:
-if a unit dies, check if it's an Abangan (missionary replacement) and check if it has 0 spreads. If that's the case, it died from spreading religion!
-every turn, compare the current spreads left of all Abangan units with the amount of spreads left last turn. If it's one less, then grant culture. (the amount of spreads left and the unit ID are stored in a table structured like this: {[unitID]=AMOUNTOFSPREADSLEFTHERE,[unitI2]=AMOUNTOFSPREADSLEFTHERE,etc.}. Then there is a table consisting of multiple variants of this table, one for each player: {[playerID]={[unitID]=3,[unitID2]=1},[playerID2]={[unitID]=2},etc.})
Spoiler :

Code:
-- AddWaliAndPesantrenBonuses
-- Author: Troller0001
-- DateCreated: 8/20/2016 6:01:16 PM
--------------------------------------------------------------

local iWali_Abangan = GameInfoTypes.UNIT_WALI_ABANGAN
local iWali_Putihan = GameInfoTypes.UNIT_WALI_PUTIHAN
local iPesantren = GameInfoTypes.BUILDING_PESANTREN
local tAbanganUnits = {}

local iWaliGarrison_25 = GameInfoTypes.BUILDING_DEMAK_DUMMY_RP_25
local iWaliGarrison_10 = GameInfoTypes.BUILDING_DEMAK_DUMMY_RP_10
local iWaliGarrison_culture = GameInfoTypes.BUILDING_DEMAK_DUMMY_CULTURE_5
local iPesantrenFaithPerPop = GameInfoTypes.BUILDING_DEMAK_DUMMY_FAITH_PER_POP
local iPesantrenSciencePerPop = GameInfoTypes.BUILDING_DEMAK_DUMMY_SCIENCE_PER_POP
local iWaliModifier = 2;
local iPopModifier = 1/3;

--Thanks to whoward for a post on Scaling with GameSpeeds
local fGameSpeedBoostCulture = (GameInfo.GameSpeeds[PreGame.GetGameSpeed()].TrainPercent)/100.0
local iStandardCulture = 2 --the base amount of culture from Abangan spreads
local iEraBoostCulture = 10 --+value for every era after ancient era




function CountAllAbangan(iPlayer,iUnit)
    local pPlayer = Players[iPlayer]
    local pUnit = pPlayer:GetUnitByID(iUnit)

    if pUnit:GetUnitType() == iWali_Abangan then
        print("Unit ID of this Wali (Abangan) is: "..iUnit)

        if tAbanganUnits[iPlayer][iUnit]==nil then
            print("This Wali (Abangan) has been added to the table")
            tAbanganUnits[iPlayer][iUnit]=  pUnit:GetSpreadsLeft()
        else
            print("This Wali (Abangan) was already present in the table")
        end
    end
end



--================So that the Abangan culture-from-spreading works after the game is reloaded (all tables are lost and thus need to be re-defined)===========================
print("The Game loaded/started")
for iPlayer = 0, GameDefines.MAX_PLAYERS-1, 1 do --in case Barbarians also gain access to a missionary and spread religion for some reason; Is that even possible?
    local pPlayer = Players[iPlayer];
    if pPlayer:IsAlive() then 
        if tAbanganUnits[iPlayer] == nil then --prepare the table for each civ (this is specifically here so that the UU will also function when gifted by a CS!)
            print("This (ID="..iPlayer..") civ was not yet present in the table")
            tAbanganUnits[iPlayer]={}     
        end
        for pUnit in pPlayer:Units() do
            local iUnit = pUnit:GetID();
            CountAllAbangan(iPlayer,iUnit)
        end
    end
end
--========================================================================================

function GrantCultureFromAbanganSpreads(iPlayer)
    for iUnit, iExpectedNumSpreadsLeft in pairs(tAbanganUnits[iPlayer]) do
        print(iUnit.." is the Unit ID of the unit in the table")

        local pPlayer = Players[iPlayer]
        local pUnit = pPlayer:GetUnitByID(iUnit)
        if pUnit == nil then
            print("This unit no longer exists! (It died or sth stupid)")
            tAbanganUnits[iPlayer][iUnit]=nil
        else
            local iNumSpreadsLeft = pUnit:GetSpreadsLeft()

            if iNumSpreadsLeft < iExpectedNumSpreadsLeft then
                print('A Wali (Abangan) spread its Religion!')
                GrantAbanganCulture(iPlayer) --The unit has less spreads than last turn, thus it must have used its spread religion-action!
                tAbanganUnits[iPlayer][iUnit] = iNumSpreadsLeft
            end
        end
 

    end
end


function GrantCultureFromAbanganSpreads_Dead(iPlayer,iUnit,iUnitType,iX,iY,bDelay)
    if iUnitType == iWali_Abangan and not bDelay then
        local pPlayer = Players[iPlayer]
        local pUnit = pPlayer:GetUnitByID(iUnit)

        if pUnit:GetSpreadsLeft()==0 then --no need to check for a city here: A wali can only die from spreading its religion if its next to a city (except when you're a DIRTY CHEATER!)
            print("A Wali (Abangan) died from spreading its religion (0 spreads were left)")
            GrantAbanganCulture(iPlayer)
        end
     
    end
end

function GrantAbanganCulture(iPlayer) --Known Bug: If the player saves the game after he spreads religion with an Abangan (that has >1 Religion Spread), but before he presses next turn, then the bonus culture will not be granted.
    local pPlayer = Players[iPlayer]
 
    local iNumErasSinceAncient = GameInfo.Eras[pPlayer:GetCurrentEra()].ID --ID's already reflect the number of eras since ERA_ANCIENT so that's nice
    local iCultureToGrant = iStandardCulture * fGameSpeedBoostCulture + (iEraBoostCulture * iNumErasSinceAncient)
    print("The player is currently in "..GameInfo.Eras[pPlayer:GetCurrentEra()].Type);
 
    print(iCultureToGrant.." Total Culture to grant ("..iStandardCulture.." Base Culture; *"..fGameSpeedBoostCulture.." GameSpeed Bonus-Culture; +"..iEraBoostCulture * iNumErasSinceAncient.." Era Bonus Culture)")
    pPlayer:ChangeJONSCulture(iCultureToGrant)
    print('Culture was Granted')
end

[..snipped code..]



GameEvents.PlayerDoTurn.Add(GrantCultureFromAbanganSpreads)
Events.SerialEventUnitCreated.Add(CountAllAbangan)
GameEvents.UnitPrekill.Add(GrantCultureFromAbanganSpreads_Dead)
 
Last edited:
Nope, there is not (assuming you are not using a custom DLL mod). Judging from your post, I assume that you are (for example) trying to find a hook that fires when a missionary spreads its religion.

I wrote this piece of code for a collab 'Demak Sultanate'-civ, which causes missionaries to grant a small burst of culture (based on era) whenever they spread their religion. It is definitely not the cleanest code (and definitely not the most efficient as I already see multiple ways I could improve!), but it works in almost every case. There is just one bug where, if the player saves the game after he spreads religion with an Abangan (that has >1 Religion Spread), but before he presses next turn, then the bonus culture will not be granted. This could however be solved with tablesaverloader if someone feels like using that.

The basic idea of the code is the following:
-if a unit dies, check if it's an Abangan (missionary replacement) and check if it has 0 spreads. If that's the case, it died from spreading religion!
-every turn, compare the current spreads left of all Abangan units with the amount of spreads left last turn. If it's one less, then grant culture. (the amount of spreads left and the unit ID are stored in a table structured like this: {[unitID]=AMOUNTOFSPREADSLEFTHERE,[unitI2]=AMOUNTOFSPREADSLEFTHERE,etc.}. Then there is a table consisting of multiple variants of this table, one for each player: {[playerID]={[unitID]=3,[unitID2]=1},[playerID2]={[unitID]=2},etc.})
Spoiler :

Code:
-- AddWaliAndPesantrenBonuses
-- Author: Troller0001
-- DateCreated: 8/20/2016 6:01:16 PM
--------------------------------------------------------------

local iWali_Abangan = GameInfoTypes.UNIT_WALI_ABANGAN
local iWali_Putihan = GameInfoTypes.UNIT_WALI_PUTIHAN
local iPesantren = GameInfoTypes.BUILDING_PESANTREN
local tAbanganUnits = {}

local iWaliGarrison_25 = GameInfoTypes.BUILDING_DEMAK_DUMMY_RP_25
local iWaliGarrison_10 = GameInfoTypes.BUILDING_DEMAK_DUMMY_RP_10
local iWaliGarrison_culture = GameInfoTypes.BUILDING_DEMAK_DUMMY_CULTURE_5
local iPesantrenFaithPerPop = GameInfoTypes.BUILDING_DEMAK_DUMMY_FAITH_PER_POP
local iPesantrenSciencePerPop = GameInfoTypes.BUILDING_DEMAK_DUMMY_SCIENCE_PER_POP
local iWaliModifier = 2;
local iPopModifier = 1/3;

--Thanks to whoward for a post on Scaling with GameSpeeds
local fGameSpeedBoostCulture = (GameInfo.GameSpeeds[PreGame.GetGameSpeed()].TrainPercent)/100.0
local iStandardCulture = 2 --the base amount of culture from Abangan spreads
local iEraBoostCulture = 10 --+value for every era after ancient era




function CountAllAbangan(iPlayer,iUnit)
    local pPlayer = Players[iPlayer]
    local pUnit = pPlayer:GetUnitByID(iUnit)

    if pUnit:GetUnitType() == iWali_Abangan then
        print("Unit ID of this Wali (Abangan) is: "..iUnit)

        if tAbanganUnits[iPlayer][iUnit]==nil then
            print("This Wali (Abangan) has been added to the table")
            tAbanganUnits[iPlayer][iUnit]=  pUnit:GetSpreadsLeft()
        else
            print("This Wali (Abangan) was already present in the table")
        end
    end
end



--================So that the Abangan culture-from-spreading works after the game is reloaded (all tables are lost and thus need to be re-defined)===========================
print("The Game loaded/started")
for iPlayer = 0, GameDefines.MAX_PLAYERS-1, 1 do --in case Barbarians also gain access to a missionary and spread religion for some reason; Is that even possible?
    local pPlayer = Players[iPlayer];
    if pPlayer:IsAlive() then
        if tAbanganUnits[iPlayer] == nil then --prepare the table for each civ (this is specifically here so that the UU will also function when gifted by a CS!)
            print("This (ID="..iPlayer..") civ was not yet present in the table")
            tAbanganUnits[iPlayer]={}    
        end
        for pUnit in pPlayer:Units() do
            local iUnit = pUnit:GetID();
            CountAllAbangan(iPlayer,iUnit)
        end
    end
end
--========================================================================================

function GrantCultureFromAbanganSpreads(iPlayer)
    for iUnit, iExpectedNumSpreadsLeft in pairs(tAbanganUnits[iPlayer]) do
        print(iUnit.." is the Unit ID of the unit in the table")

        local pPlayer = Players[iPlayer]
        local pUnit = pPlayer:GetUnitByID(iUnit)
        if pUnit == nil then
            print("This unit no longer exists! (It died or sth stupid)")
            tAbanganUnits[iPlayer][iUnit]=nil
        else
            local iNumSpreadsLeft = pUnit:GetSpreadsLeft()

            if iNumSpreadsLeft < iExpectedNumSpreadsLeft then
                print('A Wali (Abangan) spread its Religion!')
                GrantAbanganCulture(iPlayer) --The unit has less spreads than last turn, thus it must have used its spread religion-action!
                tAbanganUnits[iPlayer][iUnit] = iNumSpreadsLeft
            end
        end
 

    end
end


function GrantCultureFromAbanganSpreads_Dead(iPlayer,iUnit,iUnitType,iX,iY,bDelay)
    if iUnitType == iWali_Abangan and not bDelay then
        local pPlayer = Players[iPlayer]
        local pUnit = pPlayer:GetUnitByID(iUnit)

        if pUnit:GetSpreadsLeft()==0 then --no need to check for a city here: A wali can only die from spreading its religion if its next to a city (except when you're a DIRTY CHEATER!)
            print("A Wali (Abangan) died from spreading its religion (0 spreads were left)")
            GrantAbanganCulture(iPlayer)
        end
    
    end
end

function GrantAbanganCulture(iPlayer) --Known Bug: If the player saves the game after he spreads religion with an Abangan (that has >1 Religion Spread), but before he presses next turn, then the bonus culture will not be granted.
    local pPlayer = Players[iPlayer]
 
    local iNumErasSinceAncient = GameInfo.Eras[pPlayer:GetCurrentEra()].ID --ID's already reflect the number of eras since ERA_ANCIENT so that's nice
    local iCultureToGrant = iStandardCulture * fGameSpeedBoostCulture + (iEraBoostCulture * iNumErasSinceAncient)
    print("The player is currently in "..GameInfo.Eras[pPlayer:GetCurrentEra()].Type);
 
    print(iCultureToGrant.." Total Culture to grant ("..iStandardCulture.." Base Culture; *"..fGameSpeedBoostCulture.." GameSpeed Bonus-Culture; +"..iEraBoostCulture * iNumErasSinceAncient.." Era Bonus Culture)")
    pPlayer:ChangeJONSCulture(iCultureToGrant)
    print('Culture was Granted')
end

[..snipped code..]



GameEvents.PlayerDoTurn.Add(GrantCultureFromAbanganSpreads)
Events.SerialEventUnitCreated.Add(CountAllAbangan)
GameEvents.UnitPrekill.Add(GrantCultureFromAbanganSpreads_Dead)

My custom civ I'm currently making requires TableSaverLoader and TSL Serializer anyway, so with those two TSL files, does this mean that I should replace the print snippets with MapModData.xxxxx.xxxxx or something like that to save the data? If that's the case, then it's exactly the function I'm looking for. I'll try to implement it as you suggested.
 
Code:
  <event name="UnitPrekill" type="Hook">
    <arg pos="1" type="PlayerTypes" name="ePlayer"/>
    <arg pos="2" type="int" name="iUnit"/>
    <arg pos="3" type="UnitTypes" name="eUnit"/>
    <arg pos="4" type="int" name="iPlotX"/>
    <arg pos="5" type="int" name="iPlotY"/>
    <arg pos="6" type="bool" name="bDelay"/>
    <arg pos="7" type="PlayerTypes" name="eByPlayer"/>
  </event>
It fires for the removal of any unit from the game for any reason. This also includes capturing by barbarians, Upgrading the Unit (like from a Musektman to a Rifleman), rescuing a settler from the barbs, etc. In the cases of rescuing, capturing, upgrading, the original unit is "killed" and then replaced by the game with a new unit.

It also fires once in the "pre-removal state" (ie, bDelay == true) and once in the "post-removal state" (ie, bDelay == false) for most units.

From what you seem to be looking for you would need to look at the event only when bDelay == true and then only when the eByPlayer == -1 or is the same as the ePlayer.

TableSaverLoader should not need to enter into consideration one way or another.

----------------------------------------------------------------------------------------------------------------

This is some data I got from running UnitPreKill quite some time ago but I no longer have the original code itself, just the data-dumping I saved at the time:
Spoiler :
Code:
--settler used to create a city
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 0
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 8192
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 0 (UNIT_SETTLER)
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 80
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 16
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: true
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 0
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 8192
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 0 (UNIT_SETTLER)
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 80
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 16
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: false
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1

--barb spearman killed with a crossbowman
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 204822
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 78 (UNIT_SPEARMAN)
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 81
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 19
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: true
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: 0
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 204822
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 78 (UNIT_SPEARMAN)
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 81
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 19
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: false
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1

--barb warrior killed with a mech infantry who occupied the tile
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 196630
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 85 (UNIT_BARBARIAN_WARRIOR)
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 82
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 15
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: true
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: 0
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 196630
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 85 (UNIT_BARBARIAN_WARRIOR)
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 82
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 15
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: false
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1
 
Last edited:
Code:
  <event name="UnitPrekill" type="Hook">
    <arg pos="1" type="PlayerTypes" name="ePlayer"/>
    <arg pos="2" type="int" name="iUnit"/>
    <arg pos="3" type="UnitTypes" name="eUnit"/>
    <arg pos="4" type="int" name="iPlotX"/>
    <arg pos="5" type="int" name="iPlotY"/>
    <arg pos="6" type="bool" name="bDelay"/>
    <arg pos="7" type="PlayerTypes" name="eByPlayer"/>
  </event>
It fires for the removal of any unit from the game for any reason. This also includes capturing by barbarians, Upgrading the Unit (like from a Musektman to a Rifleman), rescuing a settler from the barbs, etc. In the cases of rescuing, capturing, upgrading, the original unit is "killed" and then replaced by the game with a new unit.

It also fires once in the "pre-removal state" (ie, bDelay == true) and once in the "post-removal state" (ie, bDelay == false) for most units.

From what you seem to be looking for you would need to look at the event only when bDelay == true and then only when the eByPlayer == -1 or is the same as the ePlayer.

TableSaverLoader should not need to enter into consideration one way or another.

----------------------------------------------------------------------------------------------------------------

This is some data I got from running UnitPreKill quite some time ago but I no longer have the original code itself, just the data-dumping I saved at the time:
Spoiler :
Code:
--settler used to create a city
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 0
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 8192
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 0 (UNIT_SETTLER)
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 80
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 16
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: true
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 0
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 8192
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 0 (UNIT_SETTLER)
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 80
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 16
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: false
--[1913.281] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1

--barb spearman killed with a crossbowman
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 204822
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 78 (UNIT_SPEARMAN)
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 81
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 19
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: true
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: 0
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 204822
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 78 (UNIT_SPEARMAN)
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 81
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 19
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: false
--[2995.703] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1

--barb warrior killed with a mech infantry who occupied the tile
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 196630
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 85 (UNIT_BARBARIAN_WARRIOR)
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 82
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 15
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: true
--[2487.312] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: 0
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: prekillListener: Dumping data..
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: ePlayer: 63
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iUnit: 196630
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eUnit: 85 (UNIT_BARBARIAN_WARRIOR)
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iX: 82
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: iY: 15
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: bDelay: false
--[2487.375] \Users\Lee\Documents\My Games\Sid Meier's Civilization 5\MODS\LUA test (v 1)\Lua Script1: eByPlayer: -1

This is a little bit confusing, but to get it short, you need to add a requirement if eByPlayer is either -1 or the same as the ePlayer?

Not sure if it helps, but here's the code I wrote based of Troller0001's suggestion so far:
Code:
--RR94_Sanity_GetTherapist
function RR94_Sanity_GetTherapistID(iPlayer, iUnit)
   local pPlayer = Players[iPlayer]
   local pUnit = pPlayer:GetUnitByID(iUnit)
   if pUnit:GetUnitType() == RR94Therapist then
       print("Unit ID of this Therapist is: "..iUnit)

        if MapModData.RR94_Bullworth.TherapistUnit[iPlayer][iUnit] == nil then
            print("This Therapist has been added to the table")
            MapModData.RR94_Bullworth.TherapistUnit[iPlayer][iUnit] = pUnit:GetSpreadsLeft()
        else
            print("This Therapist was already present in the table")
        end
    end
end

--CountAllTherapists
print("Game Start")
for iPlayer = 0, GameDefines.MAX_PLAYERS-1, 1 do --in case Barbarians also gain access to a missionary and spread religion for some reason; Is that even possible?
    local pPlayer = Players[iPlayer]
    if pPlayer:IsAlive() then
        if MapModData.RR94_Bullworth.TherapistUnit[iPlayer] == nil then -- prepare the table for each civ (this is specifically here so that the UU will also function when gifted by a CS!)
            print("This (ID="..iPlayer..") civ was not yet present in the table")
            MapModData.RR94_Bullworth.TherapistUnit[iPlayer] = {}    
        end
        for pUnit in pPlayer:Units() do
            local iUnit = pUnit:GetID();
            CountAllTherapists(iPlayer, iUnit)
        end
    end
end

--RR94_Sanity_FromTherapistExpended
function RR94_Sanity_FromTherapistExpended(iPlayer)
    if iUnitType == RR94Therapist and bDelay == true then
        local pPlayer = Players[iPlayer]
        local pUnit = pPlayer:GetUnitByID(iUnit)
       if not pPlayer == civilizationID then return end -- Prevents the other Civs from receiving Sanity for no reason
       if pUnit:IsHasPromotion(RR94PortableMedicine) -- Must have exactly this promotion, otherwise it won't work
           if pUnit:GetSpreadsLeft() == 0 then --no need to check for a city here: Without dissolving a Therapist can only -- 1. dissolve after using the last charge or -- 2. get crushed by attrition -- 3. get captured
               print("Therapist was expended after using last spreading charge")
               local rewardSanity = 25
               pPlayer:ChangeSanity(rewardSanity)
           end
       else print("This Therapist is currently not eligible for raising Sanity - wait after your Piety recovers from Heretical State/Sanity recovers from Stir-Crazy State")
       end
   end
end
 
This is a little bit confusing, but to get it short, you need to add a requirement if eByPlayer is either -1 or the same as the ePlayer?
[..]
Normally, yes. However, in this case we know enough if :GetSpreadsLeft() == 0, since the only way that can happen is when the unit dies/is disbanded from using its last religion spread. When it is killed/disbanded/whatever from anything else, :GetSpreadsLeft() will return a value that is >0! Therefore, it is not entirely necessary to add it in this specific case.

Also, when I looked at your code I noticed that you are only interested in granting bonuses when the Therapist is killed/disbanded because it used up its last religious spread. If that is the case, you can omit all the table stuff and your function
RR94_Sanity_FromTherapistExpended should do all you actually need!
------

To further elaborate on the table-saver-loader I mentioned, I was only implying to fix the bug (where, if the player saves the game after he spreads religion with an Abangan (that has >1 Religion Spread), but before he presses next turn, then the bonus culture will not be granted). I would just store and load the main table (tAbanganUnits) using table-saver-loader so it would persist when reloading the game; that, and nothing else. (I could also remove small part of the code if I were to do that). I'm afraid that LeeS might've misunderstood what I wanted to do with table-saver-loader. (or I might overlook something myself)
 
If I wanted to use this code for the purpose of replacing the burst of Culture with a burst of Golden Age points, would it be as simple as replacing the culture value with a 'Golden Age points' value? Having no familiarity with Lua it is a bit daunting.
 
If I wanted to use this code for the purpose of replacing the burst of Culture with a burst of Golden Age points, would it be as simple as replacing the culture value with a 'Golden Age points' value? Having no familiarity with Lua it is a bit daunting.

Sure, just replace ChangeJONSCulture with ChangeGoldenAgeProgressMeter and you should be fine.
 
Top Bottom