--[[ Copyright 2007-2020 The OpenRA Developers (see AUTHORS) This file is part of OpenRA, which is free software. It is made available to you under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. For more information, see COPYING. ]] AIPlayers = { } AIBarracks = { } AIDerricks = { } AIBaseLocation = { } IdlingAIActors = { } IdlingAISupportActors = { } AIOnDefense = { } -- It's good to start with 10 rifle man, one medic and 5 rocket soldiers InitialUnitsToBuild = { "e1", "e1", "e1", "e1", "e1", "medi", "e1", "e1", "e1", "e1", "e1", "e3", "e3", "e3", "e3", "e3" } UnitsToBuild = { "e1", "e1", "e1", "e1", "e1", "e3", "e3", "e3", "medi" } ActivateAI = function(player, id) AIPlayers[id] = player Trigger.AfterDelay(0, function() local barracks = player.GetActorsByType("tent") if #barracks > 0 then AIBarracks[id] = barracks[1] AIBaseLocation[id] = barracks[1].Location + CVec.New(2, 1) IdlingAIActors[id] = { } IdlingAISupportActors[id] = { } InitialInfantryProduction(id, InitialUnitsToBuild) DefendActor(id, barracks[1]) RepairBarracks(id) SellWalls(id) Trigger.AfterDelay(DateTime.Seconds(10), function() LookOutForCrates(id) end) end local derricks = player.GetActorsByType("oilb") if #derricks > 0 then AIDerricks[id] = derricks[1] DefendActor(id, derricks[1]) end end) end InitialInfantryProduction = function(id, units) local productionComplete = AIPlayers[id].Build(units, function(actors) InfantryProduction(id) end) Trigger.OnProduction(AIBarracks[id], function(producer, produced) BuildComplete(id, produced) end) end InfantryProduction = function(id) local productionComplete = AIPlayers[id].Build({ Utils.Random(UnitsToBuild) }, function(actors) Trigger.AfterDelay(0, function() InfantryProduction(id) end) end) if not productionComplete then Trigger.AfterDelay(0, function() InfantryProduction(id) end) end end BuildComplete = function(id, actor) if actor.Type == "medi" then local number = #IdlingAISupportActors[id] + 1 IdlingAISupportActors[id][number] = actor Trigger.OnKilled(actor, function() table.remove(IdlingAISupportActors[id], number) end) else local number = #IdlingAIActors[id] + 1 IdlingAIActors[id][number] = actor Trigger.OnKilled(actor, function() table.remove(IdlingAIActors[id], number) end) end Trigger.AfterDelay(0, function() DefendActor(id, actor) end) end AttackGroupSize = 5 SetupAttackGroup = function(id) local units = { } for i = 0, AttackGroupSize, 1 do if (#IdlingAIActors[id] == 0) then return units end local number = Utils.RandomInteger(0, #IdlingAIActors[id]) + 1 units[#units + 1] = IdlingAIActors[id][number] table.remove(IdlingAIActors[id], number) end return units end DefendActor = function(id, actorToDefend) if not actorToDefend or actorToDefend.IsDead or not actorToDefend.IsInWorld then return end Trigger.OnDamaged(actorToDefend, function(self, attacker) if AIOnDefense[id] or not attacker or attacker.IsDead then return end -- Don't try to kill something you can't kill if attacker.Type == "sniper.soviets" then return end AIOnDefense[id] = true local attackLoc = attacker.Location local defenders = SetupAttackGroup(id) if not defenders or #defenders == 0 then Trigger.AfterDelay(DateTime.Seconds(30), function() AIOnDefense[id] = false end) return end Utils.Do(defenders, function(unit) if unit.IsDead then return end unit.AttackMove(attackLoc) local home = AIBaseLocation[id] Trigger.OnIdle(unit, function() if unit.Location == home then IdlingAIActors[id][#IdlingAIActors[id] + 1] = unit Trigger.Clear(unit, "OnIdle") AIOnDefense[id] = false else unit.AttackMove(home) end end) end) end) end RepairBarracks = function(id) Trigger.OnDamaged(AIBarracks[id], function(self, attacker) self.StartBuildingRepairs(AIPlayers[id]) end) end SellWalls = function(id) Media.DisplayMessage("Lonestar AI " .. id .. " sold its walls for better combat experience.") local walls = AIPlayers[id].GetActorsByType("brik") Utils.Do(walls, function(wall) wall.Sell() end) end LookOutForCrates = function(id) Trigger.OnEnteredProximityTrigger(AIBarracks[id].CenterPosition, WDist.New(12 * 1024), function(actor) if actor.Type ~= "fortcrate" or #IdlingAIActors[id] == 0 then return end local unit = Utils.Random(IdlingAIActors[id]) local home = AIBaseLocation[id] local aim = actor.Location if unit.IsDead then return end unit.AttackMove(aim) Trigger.OnIdle(unit, function() if unit.Location == aim or not actor.IsInWorld then unit.AttackMove(home) Trigger.Clear(unit, "OnIdle") else unit.AttackMove(aim) end end) end) end