• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

Help LUA : infinit stack

Cat-du-fromage

Warlord
Joined
Nov 17, 2018
Messages
189
Hi,
Trying to rework a promotion from TCM's Austria-Hungary i had some problem when the bonus of +1 combat strenght stack every time i pick a promotion:

Zum Beispiel: Unit base combat strenght = 31,
Have Base 3 promotion
= Combat strenght = 34
Add 1 more promotion
= combat strenght = 38 WTH?????

In the base code, the strenght of the Unit was taken directly on [UNIT_TCM_GRENZER]

But now i try to use the ID to select the unit baseCombatStrength, since the promotion should not be lose on upgrade but it doesn't seem to work :undecide:

Code:
--------------------------------------------------------------
-- GE_Grenzer from TCM's Austria-Hungary
--------------------------------------------------------------
function GE_GetNumPromotions(unit)
        local numPromotions = 0
            if unit:IsHasPromotion(GameInfoTypes.PROMOTION_GRENZSCHUTZ) then
                for promotion in GameInfo.UnitPromotions() do
                        if unit:IsHasPromotion(promotion.ID) then
                            numPromotions = numPromotions + 1
                        end
                end
            end
        return numPromotions
end

local bonusPerPromotion = 1
local unitGrenzerID = GameInfoTypes["UNIT_TCM_GRENZER"]
local GEPromotion = GameInfoTypes["PROMOTION_GRENZSCHUTZ"]
local UnitGun = GameInfoTypes["UNITCOMBAT_GUN"]


function GE_Grenzer(playerID)
        local player = Players[playerID]
        if (player:GetCivilizationType() == civilisationID and player:IsEverAlive()) then
                for unit in player:Units() do
                        if unit:IsHasPromotion(GameInfoTypes.PROMOTION_GRENZSCHUTZ) then
                        local pUnit = unit:GetID() --Select Unit ID
                                local baseCombatStrength = pUnit:GetBaseCombatStrength() --Use Get base combat strenght from ID
                                if baseCombatStrength < (baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit)) then
                                    unit:SetBaseCombatStrength(baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit))
                                end
                              
                        end
                end
        end
end
    
if JFD_IsCivilisationActive(civilisationID) then
GameEvents.UnitPromoted.Add(GE_Grenzer)
GameEvents.UnitUpgraded.Add(GE_Grenzer)
        --GameEvents.PlayerDoTurn.Add(GE_Grenzer)
end

Note: the "pUnit:GetBaseCombatStrength()" doesn't work, it works only if i write "unit:GetBaseCombatStrength()"

Does someone see the error^^?
 
EDIT:
Code:
local bonusPerPromotion = 1
local unitGrenzerID = GameInfoTypes["UNIT_TCM_GRENZER"]
local unitGWIID = GameInfoTypes["UNIT_GREAT_WAR_INFANTRY"]
local unitInfantryID = GameInfoTypes["UNIT_INFANTRY"]
local unitMechInfantryID = GameInfoTypes["UNIT_MECHANIZED_INFANTRY"]
local GEPromotion = GameInfoTypes["PROMOTION_GRENZSCHUTZ"]
local UnitGun = GameInfoTypes["UNITCOMBAT_GUN"]


function GE_Grenzer(playerID, unitID)
        local player = Players[playerID]
        if (player:GetCivilizationType() == civilisationID and player:IsEverAlive()) then
                for unit in player:Units() do
                        if unit:GetUnitType() == unitGrenzerID then
                                local baseCombatStrength = GameInfo.Units["UNIT_TCM_GRENZER"].Combat
                                if baseCombatStrength < (baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit)) then
                                    unit:SetBaseCombatStrength(baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit))
                                    end
                            elseif unit:GetUnitType() == unitGWIID and unit:IsHasPromotion(GameInfoTypes.PROMOTION_GRENZSCHUTZ) then
                                    local baseCombatStrength = GameInfo.Units["UNIT_GREAT_WAR_INFANTRY"].Combat
                                    if baseCombatStrength < (baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit)) then
                                        unit:SetBaseCombatStrength(baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit))
                                        end
                                    elseif unit:GetUnitType() == unitInfantryID and unit:IsHasPromotion(GameInfoTypes.PROMOTION_GRENZSCHUTZ) then
                                    local baseCombatStrength = GameInfo.Units["UNIT_INFANTRY"].Combat
                                            if baseCombatStrength < (baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit)) then
                                                unit:SetBaseCombatStrength(baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit))
                                                end
                                                elseif unit:GetUnitType() == unitMechInfantryID and unit:IsHasPromotion(GameInfoTypes.PROMOTION_GRENZSCHUTZ) then
                                                    local baseCombatStrength = GameInfo.Units["UNIT_MECHANIZED_INFANTRY"].Combat
                                                        if baseCombatStrength < (baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit)) then
                                                        unit:SetBaseCombatStrength(baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit))
                                                        end
                             
                             
                        end
                end
            end
end

This methode works BUT it seems very very heavy in term of performance, is there anyway to reduce the amount of calcul/check?
 
EDIT:

This methode works BUT it seems very very heavy in term of performance, is there anyway to reduce the amount of calcul/check?

There are several things that can indeed be optimised. First off are Database Accesses (I.e. GameInfo.SOMETHING/GameInfoTypes.SOMETHING), which are relatively slow.
An easy change is to replace all instances of "GameInfoTypes.PROMOTION_GRENZSCHUTZ" (in your function) with "GEPromotion". This way, we only ask for the promotionID once (when the code is initialised). This is called caching.
Code:
--this:
unit:IsHasPromotion(GameInfoTypes.PROMOTION_GRENZSCHUTZ)
--is replaced by this:
unit:IsHasPromotion(GEPromotion)

-----------

The other times you access the DB is when you call "GameInfo.Units["UNIT_SOMETHING"].Combat".
We can cache this information as well when the code initialises as follows:
Code:
local tCombatStrengths = {}
for row in DB.Query("SELECT ID, Combat FROM Units WHERE Combat > 0") do
    tCombatStrengths[row.ID] = row.Combat;
end
The table now stores the (melee) combat strength of each unit (that has such a combat strength), using the ID of the unit as a key and the combat strength as a value.
I.e. tCombatStrengths[12] = the combat strength of the unit with an ID of 12. (NB: This ID is the value that is returned by unit:GetUnitType() and NOT the one returned by unit:GetID();)

Code:
--we can replace this:
local baseCombatStrength = GameInfo.Units["UNIT_SOMETHING"].Combat
--by this:
local baseCombatStrength = tCombatStrengths[GameInfoTypes.UNIT_SOMETHING]
------------

But by the way we set up the code, we can make it work for any unitType!
So we can then modify your function and remove all unittype-specific checks (E.g. for UNIT_MECHANIZED_INFANTRY), and change hardcoded values by something else.
Code:
--replace this:
local baseCombatStrength = tCombatStrengths[GameInfoTypes.UNIT_SOMETHING]
--by this:
local baseCombatStrength = tCombatStrengths[unit:GetUnitType()]

--and remove all unit:GetUnitType()-checks and duplicate code

This also means that the promotion will work properly for any arbitrary upgrade path of your UU

-----------

Lastly, we know which unit earned a promotion (or which one upgraded), so we do not need to loop over all units. In other words, remove the for-loop over all of the player's units.
Code:
--replace this:
for unit in player:Units() do
end
--by this:
unit = player:GetUnitByID(unitID)

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

The modified code will look as follows:
Spoiler :

Code:
local bonusPerPromotion = 1
local GEPromotion = GameInfoTypes["PROMOTION_GRENZSCHUTZ"] --cache the ID of PROMOTION_GRENZSCHUTZ

local tCombatStrengths = {}
for row in DB.Query("SELECT ID, Combat FROM Units WHERE Combat > 0 AND Cost > 0") do
    tCombatStrengths[row.ID] = row.Combat;
end

--function GE_GetNumPromotions is defined here somewhere

function GE_Grenzer(playerID, unitID)
    local player = Players[playerID]
    --you could remove the following if-statement so that the promotion also works if another player obtains the promotion/your UU (E.g. by City State-gift/when spawned in using Lua by another mod)
    if (player:GetCivilizationType() == civilisationID and player:IsEverAlive()) then
        unit = player:GetUnitByID(unitID) --we know which unit is upgraded, so we remove the loop over all units
        if unit:IsHasPromotion(GEPromotion) then --any unit that has the promotion should get a bonus (since the unit can be an upgrade from the UU)
            local baseCombatStrength = tCombatStrengths[unit:GetUnitType()] --obtain the cached combat strength of the unit
            if baseCombatStrength then --if the unit is not in the table, then it doesn't have a (melee) combat strength
                --unit has a melee combat strength; set it to the maximum of its base combat strength and the buff provided by the promotion
                unit:SetBaseCombatStrength(math.max(baseCombatStrength, baseCombatStrength + bonusPerPromotion*GE_GetNumPromotions(unit)));
            end
        end
    --note that all elseif's (for UNIT_MECHANIZED_INFNATRY and such) are removed; this code will work for any unit.
    end --if you choose to remove the first if-statement, also remove this end
end

if JFD_IsCivilisationActive(civilisationID) then
    GameEvents.UnitPromoted.Add(GE_Grenzer)
    GameEvents.UnitUpgraded.Add(GE_Grenzer)
end
 
Last edited:
OH Thanks! gonna try this

EDIT: Didn't know about "row", i will do some reasearch about that
 
Last edited:
Back
Top Bottom