1-- require "taskqueues" 2require "common" 3 4local DebugEnabled = false 5 6local function EchoDebug(inStr) 7 if DebugEnabled then 8 game:SendToConsole("AssistBehaviour: " .. inStr) 9 end 10end 11 12local CMD_GUARD = 25 13local CMD_PATROL = 15 14 15AssistBehaviour = class(Behaviour) 16 17function AssistBehaviour:DoIAssist() 18 if ai.nonAssistant[self.id] ~= true or self.isNanoTurret then 19 return true 20 else 21 return false 22 end 23end 24 25function AssistBehaviour:Init() 26 self.active = false 27 self.target = nil 28 -- keeping track of how many of each type of unit 29 local uname = self.unit:Internal():Name() 30 self.name = uname 31 if nanoTurretList[uname] then self.isNanoTurret = true end 32 if commanderList[uname] then self.isCommander = true end 33 self.id = self.unit:Internal():ID() 34 ai.assisthandler:AssignIDByName(self) 35 EchoDebug(uname .. " " .. ai.IDByName[self.id]) 36 EchoDebug("AssistBehaviour: added to unit "..uname) 37end 38 39function AssistBehaviour:UnitBuilt(unit) 40 if unit.engineID == self.unit.engineID then 41 if self.isNanoTurret then 42 -- set nano turrets to patrol 43 local upos = RandomAway(self.unit:Internal():GetPosition(), 50) 44 local floats = api.vectorFloat() 45 -- populate with x, y, z of the position 46 floats:push_back(upos.x) 47 floats:push_back(upos.y) 48 floats:push_back(upos.z) 49 self.unit:Internal():ExecuteCustomCommand(CMD_PATROL, floats) 50 end 51 end 52end 53 54function AssistBehaviour:UnitIdle(unit) 55 if unit.engineID == self.unit.engineID then 56 self.patroling = false 57 self.assisting = nil 58 end 59end 60 61function AssistBehaviour:Update() 62 -- nano turrets don't need updating, they already have a patrol order 63 if self.isNanoTurret then return end 64 65 local f = game:Frame() 66 67 if math.mod(f,180) == 0 then 68 local unit = self.unit:Internal() 69 local uname = self.name 70 if self.isCommander then 71 -- turn commander into build assister if you control more than half the mexes or if it's damaged 72 if ai.nonAssistant[self.id] then 73 if (IsSiegeEquipmentNeeded() or unit:GetHealth() < unit:GetMaxHealth() * 0.9) and ai.factories ~= 0 and ai.conCount > 2 then 74 ai.nonAssistant[self.id] = nil 75 self.unit:ElectBehaviour() 76 end 77 else 78 -- switch commander back to building 79 if (not IsSiegeEquipmentNeeded() and unit:GetHealth() >= unit:GetMaxHealth() * 0.9) or ai.factories == 0 or ai.conCount <= 2 then 80 ai.nonAssistant[self.id] = true 81 self.unit:ElectBehaviour() 82 end 83 end 84 else 85 -- fill empty spots after con units die 86 if ai.IDByName[self.id] > ai.nameCount[uname] then 87 EchoDebug("filling empty spots with " .. uname .. " " .. ai.IDByName[self.id]) 88 ai.assisthandler:AssignIDByName(self) 89 EchoDebug("ID now: " .. ai.IDByName[self.id]) 90 self.unit:ElectBehaviour() 91 end 92 end 93 end 94 95 if math.mod(f,60) == 0 then 96 if self.active then 97 if self.target ~= nil then 98 if self.assisting ~= self.target then 99 local floats = api.vectorFloat() 100 floats:push_back(self.target) 101 self.unit:Internal():ExecuteCustomCommand(CMD_GUARD, floats) 102 self.assisting = self.target 103 self.patroling = false 104 end 105 elseif not self.patroling then 106 local patrolPos = self.fallbackPos or self.unit:Internal():GetPosition() 107 local pos = RandomAway(patrolPos, 200) 108 local floats = api.vectorFloat() 109 -- populate with x, y, z of the position 110 floats:push_back(pos.x) 111 floats:push_back(pos.y) 112 floats:push_back(pos.z) 113 self.unit:Internal():ExecuteCustomCommand(CMD_PATROL, floats) 114 ai.assisthandler:AddFree(self) 115 self.patroling = true 116 end 117 end 118 end 119end 120 121function AssistBehaviour:Activate() 122 EchoDebug("AssistBehaviour: activated on unit "..self.name) 123 if self:DoIAssist() then 124 ai.assisthandler:Release(self.unit:Internal()) 125 ai.assisthandler:AddFree(self) 126 end 127 self.active = true 128 self.target = nil 129end 130 131function AssistBehaviour:Deactivate() 132 EchoDebug("AssistBehaviour: deactivated on unit "..self.name) 133 ai.assisthandler:RemoveWorking(self) 134 ai.assisthandler:RemoveFree(self) 135 self.active = false 136 self.target = nil 137 self.assisting = nil 138end 139 140function AssistBehaviour:Priority() 141 if self:DoIAssist() then 142 return 100 143 else 144 return 0 145 end 146end 147 148function AssistBehaviour:UnitDead(unit) 149 if unit.engineID == self.unit.engineID then 150 ai.assisthandler:RemoveAssistant(self) 151 end 152end 153 154function AssistBehaviour:Assign(builderID) 155 self.target = builderID 156 self.lastAssignFrame = game:Frame() 157end 158 159function AssistBehaviour:SetFallback(position) 160 self.fallbackPos = position 161end 162 163-- assign if not busy (used by factories to occupy idle assistants) 164function AssistBehaviour:SoftAssign(builderID) 165 if self.target == nil then 166 self.target = builderID 167 else 168 if self.lastAssignFrame == nil then 169 self.target = builderID 170 else 171 local f = game:Frame() 172 if f > self.lastAssignFrame + 900 then 173 self.target = builderID 174 end 175 end 176 end 177end