Giving random promotions to units

PawelS

Ancient Druid
Joined
Dec 11, 2003
Messages
2,811
Location
Poland
In my mod I'm going to implement a system where units can get random promotions from a pre-defined list when produced (something like in Battle for Wesnoth, where new units get two random traits). These can include small bonuses for normal units, bigger bonuses for heroes, and "mutations" for Demonic units. I'm not very good at LUA coding, so I need help from an expert.

It can be handled by a special promotion defined in Unit_FreePromotions that, when the unit is produced, gets replaced by a random set of promotions, or a special unit attribute defined as a new column in the Units table. As an example, I need code that gives the unit a promotion chosen randomly from these 3: PROMOTION_STRONG, PROMOTION_RESILIENT or PROMOTION_HEALTHY (in the mod it will be more complex than that, but I'll handle the details myself, I only need to know how to detect a new unit constructed, and grant it some random promotions).

Thanks in advance for any help :)
 
Hello.

The following should give one of those three promotions whenever an unit with the "MAGIC_PROMOTION" is created. Note that I am not sure that the free promotion has been granted at the moment the unit is created though. We would need to use another way if it does not.

Code:
local givenPromotions = 
{
    GameInfoTypes.PROMOTION_STRONG,
    GameInfoTypes.PROMOTION_RESILIENT,
    GameInfoTypes.PROMOTION_HEALTHY,
}
local triggerPromotion = GameInfoTypes.MAGIC_PROMOTION

function OnUnitCreated(playerID, unitID)
    local player = Players[playerID]
    local unit = player:GetUnitByID(unitID)

    -- Does it have the magic promotion?
    if not unit:IsHasPromotion(triggerPromotion) then return end
   unit:SetHasPromotion(triggerPromotion, false)

    -- Picks a random promotion
   local promotionID = givenPromotions[math.rand(#givenPromotions)]
   unit:SetHasPromotion(promotionID, true)
end
Events.SerialEventUnitCreated.Add(OnUnitCreated)
 
Remember that units are "deleted and created" when they are promoted, so the code above should also remove the GameInfoTypes.MAGIC_PROMOTION promotion after a random one has been assigned.

Edit: Or you could use "lost with upgrade", but the promotion will then show in the unit's list of promotions.
 
Upgrades can be a problem indeed, I don't want units to get another random promotion after upgrade (and the units will get the "magic promotion" after upgrade, because, when the higher tier units are produced, I want them to get that random promotion too). So maybe a better way to do it would be to give the unit a special promotion after it gets a random one to indicate that it shouldn't get any more. But then it would be good to hide that promotion in the interface.

Or perhaps there is a way to check the unit's age, so it only gets random promotions in the turn it's produced? But in this case, is there a way to distinguish between the situation when it's produced and when it's upgraded in the same turn as it was produced?

Another way would be checking if it already has any promotion from the list, but this can be time consuming if the list is long.

Also, I think I'll use similar code to give some promotion or extra XP to AI units on higher difficulty levels...
 
You can get the age of the unit, yes -> http://modiki.civfanatics.com/index.php/Unit.GetGameTurnCreated_(Civ5_API)

To prevent "double action" using reload or in the case when the unit could be created and embarked the same turn, Spatzimaus and Thalassicus are using a promotion to mark new units, and in my mod I'm using a table to track all units. I suppose their solution is much better for performance, but I need the table for other mechanisms, so that's not a problem in my case...
 
Another way would be checking if it already has any promotion from the list, but this can be time consuming if the list is long.
Not really because a unit is rarely created. Actually that would be the best solution since it does not require any extra promotion and since those ones are sparse. Do you need help to make that change?
 
I successfully implemented the code in the game (but math.rand doesn't work, Dr. Google told me that it should be math.random instead :))

I have a problem though: I want to give two promotions to units, and giving one should remove it from the list so the second one is different than the first, and in some cases it should also remove some other promotions, that shouldn't be used together with the first one. But I don't know how to do it, there is a way to remove an item from a specific position in the table (table.remove), but how to remove an item by its value?

Also, when I make changes to a table that is declared (as local) outside of the function, will it go back to its original form when the function is called again, or I need to make a copy of it before altering its content?
 
I successfully implemented the code in the game
:)

I have a problem though: I want to give two promotions to units, and giving one should remove it from the list so the second one is different than the first,
There are various ways to do this, but if you shuffle the table (see the MapmakerUtilities function GetShuffledCopyOfTable()) and give the unit the first two it makes some of what follows easier

and in some cases it should also remove some other promotions, that shouldn't be used together with the first one.
This can be done, but I'm off to work so can't give a sample.
Basically you'll need each item in your table to itself be a table(hash) with two entries - Promotion and PromotionGroup
Code:
table[1] = {Promotion="PROMOTION_MAGIC", Group=1}
You then give the unit the first entry in the shuffled table and the next entry which is not in the same group as the first entry

But I don't know how to do it, there is a way to remove an item from a specific position in the table (table.remove), but how to remove an item by its value?
If you're storing items by value you should be using keys(strings) as the "index", you can then remove them by name by setting them to nil

Also, when I make changes to a table that is declared (as local) outside of the function, will it go back to its original form when the function is called again, or I need to make a copy of it before altering its content?
Tables are passed by reference and not by value so yes, you'd need to make a copy of it. Using the shuffle utility method does this for you (although taking this approach, you don't need to delete anything from the original table anyway)

HTH

W
 
Back
Top Bottom