LUA Function like when a forest is cleared, but when a unit dies

FieryCharizard7

Chieftain
Joined
Jul 8, 2016
Messages
62
Location
Chicaaago
Hello all,

I've been learning LUA for about a week now, and I think I have a handle on it, but I am unsure about making a LUA function. It will be an ability from a wonder that will increase a city's production on whatever it is currently constructing (whether a unit, building, wonder, etc.) and if a unit dies within 6 tiles of a city owned by the wonder owner, the city's production will be boosted by three times the combat strength of the unit.

I have written code below, and I am unsure which City methods should be used, as the names are somewhat vague and similar. Also, did I implement the unit pointer correctly? I wasn't 100% sure if this is the correct way to get the unit's plot.

Code:
-- After a unit death, checks the distance between the unit tile and the owner's cities, and if that is within 6 tiles
-- the cities' production will be increased by three times the combat strength of the unit
function ADVUnitDeathProdBoost(iPlayer)
    local pPlayer = Players[iPlayer]
    if pPlayer:GetBuildingClassCount(iArcoDellaVittoria) > 0 then
        local pPlot = Unit:GetPlot();
        local pPlayer = Players[iPlayer];
        local pCity = GetNearestCity(pPlot, pPlayer);
        if distanceBetween(pPlot,pCity:GetCityIndexPlot()) > 5 then
            -- next 4 lines get the higher of the ranged or melee combat strength
            local iCityProdBoost = Unit:GetBaseRangedCombatStrength() * 3;
            if iCityProdBoost < 1 then
                iCityProdBoost = Unit:GetBaseCombatStrength() * 3;
            end
            -- add code for boosting city production by the iUnitStrength
        end
    end
end
GameEventsEvents.UnitKilledInCombat.Add(ADVUnitDeathProdBoost);
 
Code:
function GetNearestCity(pPlot, pPlayer)
    local iShortestDistance = 6
    local pNearestCity = nil

    local iUnitX, iUnitY = pPlot:GetX(), pPlot:GetY()

    for pCity in pPlayer:Cities() do
        if not pCity:IsHasBuilding(iArcoDellaVittoria) then return end
        local iDist = Map.PlotDistance(pCity:GetX(), pCity:GetY(), iUnitX, iUnitY)
        if (iDist <= iShortestDistance) then
            iShortestDistance = iDist
            pNearestCity = pCity
        end
    end
    return pNearestCity
end --Suspiciously copied from bane? ;)

function ADVUnitDeathProdBoost (iOwner, iUnit, iUnitType, iX, iY, bDelay, iKiller)
    local pOwnerPlayer = Players[iOwner]
    local pUnitKilled = pOwnerPlayer:GetUnitByID(iUnit)
    if not pUnitKilled:IsCombatUnit() then return end
    if pOwnerPlayer:GetBuildingClassCount(iArcoDellaVittoria) > 0 then
        local pPlot = Map.GetPlot(iX, iY)
        local pCity = GetNearestCity(pPlot, pOwnerPlayer)
        if pCity == nil then return end
        if pUnitKilled:GetBaseRangedCombatStrength()*3 > 0 then
            pCity:ChangeProduction(pUnitKilled:GetBaseRangedCombatStrength()*3)
        else
            pCity:ChangeProduction(pUnitKilled:GetBaseCombatStrength()*3)
        end
    end
end
GameEvents.UnitPrekill.Add(ADVUnitDeathProdBoost);

I doubt it should work as intended however since I'm using and modifying a foreign function unknown to me, but the GameEvent should be correct.
 
Last edited:
Code:
function GetNearestCity(pPlot, pPlayer)
    local iShortestDistance = 6
    local pNearestCity = nil

    local iUnitX, iUnitY = pPlot:GetX(), pPlot:GetY()

    for pCity in pPlayer:Cities() do
        if not pCity:IsHasBuilding(iArcoDellaVittoria) then return end
        local iDist = Map.PlotDistance(pCity:GetX(), pCity:GetY(), iUnitX, iUnitY)
        if (iDist <= iShortestDistance) then
            iShortestDistance = iDist
            pNearestCity = pCity
        end
    end
    return pNearestCity
end --Suspiciously copied from bane? ;)

function ADVUnitDeathProdBoost (iOwner, iUnit, iUnitType, iX, iY, bDelay, iKiller)
    local pOwnerPlayer = Players[iOwner]
    local pUnitKilled = pOwnerPlayer:GetUnitByID(iUnit)
    if not pUnitKilled:IsCombatUnit() then return end
    if pOwnerPlayer:GetBuildingClassCount(iArcoDellaVittoria) > 0 then
        local pPlot = Map.GetPlot(iX, iY)
        local pCity = GetNearestCity(pPlot, pOwnerPlayer)
        if pCity == nil then return end
        if pUnitKilled:GetBaseRangedCombatStrength()*3 > 0 then
            pCity:ChangeProduction(pUnitKilled:GetBaseRangedCombatStrength()*3)
        else
            pCity:ChangeProduction(pUnitKilled:GetBaseCombatStrength()*3)
        end
    end
end
GameEvents.UnitPrekill.Add(ADVUnitDeathProdBoost);

I doubt it should work as intended however since I'm using and modifying a foreign function unknown to me, but the GameEvent should be correct.

For the record, I did write a credit in my code to Bane and link the forum page, so next time, I will copy my entire code (which is really what I should have done since there are some other things in that code snippit that were initialized earlier). The code does look right to me, but how does one know what variables are available to be passed into a function? And will the game automatically pass in the owner and the location of the unit?

Does the City:ChangeProduction method increment or decrement the city's production by that integer amount?

Is there a way to put a notification on screen (as well as added to the notification log) that will tell the user that production has been added, like what happens when a forest tile is cleared?
 
http://modiki.civfanatics.com/index.php?title=Lua_and_UI_Reference_(Civ5)
https://forums.civfanatics.com/threads/bnw-lua-api-reference.558353/

This line causes the function to terminate and return either nil or garbage info for the nearest city on the 1st city encountered that does not have the wonder in question:
Code:
if not pCity:IsHasBuilding(iArcoDellaVittoria) then return end
He wants the nearest city for the owner of the wonder, so long as that nearest city is within the 6 tile requirement.

UnitPreKill fires for every unit removal from the game, and it fires twice for any unit removed from the game as a result of combat. It also fires for units that are upgraded, units that are captured by barbarians, units that are rescued from barbarians, etc., etc.

UnitKilledInCombat is no good because no info is given for the individual unit that was defeated in combat. It only gives the ID # for Type of unit that was killed, ie, that the unit was a Warrior or an Archer, but not where the unit was or which individual Warrior unit that was previously on the map that was killed off.

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

Generally:

Code:
Something:ChangeAThing(iValue)
alters the specified "AThing" by whatever is currently in variable "iValue". So if "iValue" is positive, an addition occurs; if "iValue" is negative, a subtraction occurs.

Code:
Something:SetAThing(iValue)
alters the specified "AThing" by ignoring what is currently there and making the value whatever is currently in variable "iValue".
 
Last edited:
UnitPreKill fires for every unit removal from the game, and it fires twice for any unit removed from the game as a result of combat. It also fires for units that are upgraded, units that are captured by barbarians, units that are rescued from barbarians, etc., etc.
.

So does this mean that upgrading a unit would also give the production boost and fire twice for a unit getting killed?
 
yup. without additional logic within the function Enginseer posted to try to filter out these conditions you would get these 'false' extra additions.

So what sort of things would indicate that a unit has been upgraded, captured by barbarians, and only once upon death?
 
Back
Top Bottom