| function AIBiasCombo() | |
| local items = {} | |
| ForEachPreset("AIArchetype", function(item) | |
| for _, action in ipairs(item.SignatureActions) do | |
| local id = action.BiasId | |
| if id and id ~= "" then | |
| table.insert_unique(items, id) | |
| end | |
| end | |
| for _, behavior in ipairs(item.Behaviors) do | |
| local id = behavior.BiasId | |
| if id and id ~= "" then | |
| table.insert_unique(items, id) | |
| end | |
| for _, action in ipairs(behavior.SignatureActions) do | |
| local id = action.BiasId | |
| if id and id ~= "" then | |
| table.insert_unique(items, id) | |
| end | |
| end | |
| end | |
| end) | |
| return items | |
| end | |
| DefineClass.AIBiasModification = { | |
| __parents = { "PropertyObject" }, | |
| properties = { | |
| { id = "BiasId", editor = "choice", default = false, items = AIBiasCombo, }, | |
| { id = "Effect", editor = "choice", default = "modify", items = { "modify", "disable", "priority" }, }, | |
| { id = "Value", editor = "number", default = 0, no_edit = function(self) return self.Effect ~= "modify" end, }, | |
| { id = "Period", editor = "number", default = 1, help = "in turns", }, | |
| { id = "ApplyTo", editor = "choice", default = "Self", items = { "Self", "Team" }, }, | |
| }, | |
| } | |
| function AIBiasModification:GetEditorView() | |
| if self.BiasId and self.BiasId ~= "" then | |
| if self.Effect == "modify" then | |
| return string.format("%s %+d%% to %s for %d turns", self.BiasId, self.Value, self.ApplyTo, self.Period) | |
| elseif self.Effect == "priority" then | |
| return string.format("Make %s Priority to %s for %d turns", self.BiasId, self.ApplyTo, self.Period) | |
| elseif self.Effect == "disable" then | |
| return string.format("Disable %s for %s for %d turns", self.BiasId, self.ApplyTo, self.Period) | |
| end | |
| end | |
| return self.class | |
| end | |
| DefineClass.AIBiasObj = { | |
| __parents = { "PropertyObject" }, | |
| properties = { | |
| { id = "BiasId", name = "Bias Id", editor = "combo", default = false, items = AIBiasCombo }, | |
| { id = "Weight", editor = "number", default = 100, }, | |
| { id = "Priority", editor = "bool", default = false, }, | |
| { id = "OnActivationBiases", name = "OnActivation Biases", editor = "nested_list", default = false, base_class = "AIBiasModification", inclusive = true, }, | |
| }, | |
| } | |
| MapVar("g_AIBiases", {}) | |
| function AIBiasObj:OnActivate(unit) | |
| for _, mod in ipairs(self.OnActivationBiases or empty_table) do | |
| local id = mod.BiasId | |
| if id then | |
| local bias = g_AIBiases[id] or {} | |
| g_AIBiases[id] = bias | |
| local list | |
| if mod.ApplyTo == "Self" then | |
| list = bias[unit] or {} | |
| bias[unit] = list | |
| else | |
| list = bias[unit.team] or {} | |
| bias[unit.team] = list | |
| end | |
| list[#list + 1] = { | |
| end_turn = g_Combat.current_turn + mod.Period, | |
| value = mod.Value, | |
| disable = mod.Effect == "disable", | |
| priority = mod.Effect == "priority", | |
| } | |
| end | |
| end | |
| end | |
| function AIUpdateBiases() | |
| for id, item_mods in pairs(g_AIBiases) do | |
| for obj, mods in pairs(item_mods) do | |
| local total = 0 | |
| mods.disable = false | |
| mods.priority = false | |
| for i = #mods, 1, -1 do | |
| if mods[i].end_turn < g_Combat.current_turn then | |
| table.remove(mods, i) | |
| else | |
| total = total + mods[i].value | |
| mods.disable = mods.disable or mods[i].disable | |
| mods.priority = mods.priority or mods[i].priority | |
| end | |
| end | |
| mods.total = total | |
| end | |
| end | |
| end | |
| function AIGetBias(id, unit) | |
| local weight_mod, disable, priority = 100, false, false | |
| if id and id ~= "" then | |
| local mods = g_AIBiases[id] or empty_table | |
| if mods[unit] then | |
| weight_mod = weight_mod + mods[unit].total | |
| disable = disable or mods[unit].disable | |
| priority = priority or mods[unit].priority | |
| end | |
| if mods[unit.team] then | |
| weight_mod = weight_mod + mods[unit.team].total | |
| disable = disable or mods[unit.team].disable | |
| priority = priority or mods[unit.team].priority | |
| end | |
| end | |
| disable = disable or (weight_mod <= 0) | |
| return weight_mod, disable, priority | |
| end | |
| function AIAltArchetypeBelowHpPercent(unit, alt_archetype, threshold) | |
| local archetype = unit.archetype | |
| if MulDivRound(unit.HitPoints, 100, unit.MaxHitPoints) < threshold then | |
| archetype = alt_archetype | |
| end | |
| return archetype | |
| end | |
| function AIAltArchetypeOnAllyDeath(unit, alt_archetype, count) | |
| local archetype = unit.archetype | |
| local last_dead = unit:GetEffectValue("aa_num_team_dead") or 0 | |
| local dead = 0 | |
| count = count or 1 | |
| for _, other in ipairs(unit.team and unit.team.units) do | |
| dead = dead + 1 | |
| end | |
| if dead >= last_dead + count then | |
| unit:SetEffectValue("aa_num_team_dead", dead) | |
| archetype = alt_archetype | |
| end | |
| return archetype | |
| end | |
| function AIAltArchetypeOnNoEnemyDeath(unit, alt_archetype) | |
| local archetype = unit.archetype | |
| local last_dead = unit:GetEffectValue("aa_num_dead_enemies") or 0 | |
| local dead = 0 | |
| local unit_team = unit.team | |
| if unit_team then | |
| for _, team in ipairs(g_Teams) do | |
| if unit_team:IsEnemySide(team) then | |
| for _, other in ipairs(team.units) do | |
| if other:IsDead() then | |
| dead = dead + 1 | |
| end | |
| end | |
| end | |
| end | |
| end | |
| unit:SetEffectValue("aa_num_dead_enemies", dead) | |
| if dead == last_dead then | |
| archetype = alt_archetype | |
| end | |
| return archetype | |
| end |