1require "common" 2 3 4local DebugEnabled = false 5 6local function EchoDebug(inStr) 7 if DebugEnabled then 8 game:SendToConsole("ScoutBehaviour: " .. inStr) 9 end 10end 11 12function IsScout(unit) 13 local unitName = unit:Internal():Name() 14 if scoutList[unitName] then 15 return true 16 else 17 return false 18 end 19end 20 21ScoutBehaviour = class(Behaviour) 22 23function ScoutBehaviour:Init() 24 self.evading = false 25 self.active = false 26 local mtype, network = ai.maphandler:MobilityOfUnit(self.unit:Internal()) 27 self.mtype = mtype 28 self.name = self.unit:Internal():Name() 29 self.armed = unitTable[self.name].isWeapon 30 self.keepYourDistance = unitTable[self.name].losRadius * 16 31 if mtype == "air" then 32 self.airDistance = unitTable[self.name].losRadius * 48 33 self.lastCircleFrame = game:Frame() 34 end 35 self.lastUpdateFrame = game:Frame() 36end 37 38function ScoutBehaviour:UnitBuilt(unit) 39 40end 41 42function ScoutBehaviour:UnitIdle(unit) 43 44end 45 46function ScoutBehaviour:Priority() 47 return 50 48end 49 50function ScoutBehaviour:Activate() 51 EchoDebug("activated on " .. self.name) 52 self.active = true 53end 54 55function ScoutBehaviour:Deactivate() 56 EchoDebug("deactivated on " .. self.name) 57 self.active = false 58 self.target = nil 59 self.evading = false 60 self.attacking = false 61end 62 63 64function ScoutBehaviour:Update() 65 if self.active then 66 local f = game:Frame() 67 if f > self.lastUpdateFrame + 30 then 68 local unit = self.unit:Internal() 69 -- reset target if it's in sight 70 if self.target ~= nil then 71 local los = ai.scouthandler:ScoutLos(self, self.target) 72 EchoDebug("target los: " .. los) 73 if los == 2 or los == 3 then 74 self.target = nil 75 end 76 end 77 -- attack small targets along the way if the scout is armed 78 local attackTarget 79 if self.armed then 80 if ai.targethandler:IsSafePosition(unit:GetPosition(), unit, 1) then 81 attackTarget = ai.targethandler:NearbyVulnerable(unit) 82 end 83 end 84 if attackTarget and not self.attacking then 85 CustomCommand(unit, CMD_ATTACK, {attackTarget.unitID}) 86 self.target = nil 87 self.evading = false 88 self.attacking = true 89 elseif self.target ~= nil then 90 -- evade enemies along the way if possible 91 local newPos, arrived = ai.targethandler:BestAdjacentPosition(unit, self.target) 92 if newPos then 93 unit:Move(newPos) 94 self.evading = true 95 self.attacking = false 96 elseif arrived then 97 -- if we're at the target, find a new target 98 self.target = nil 99 self.evading = false 100 elseif self.evading then 101 -- return to course to target after evading 102 unit:Move(self.target) 103 self.evading = false 104 self.attacking = false 105 end 106 end 107 -- find new scout spot if none and not attacking 108 if self.target == nil and attackTarget == nil then 109 local topos = ai.scouthandler:ClosestSpot(self) -- first look for closest metal/geo spot that hasn't been seen recently 110 if topos ~= nil then 111 EchoDebug("scouting spot at " .. topos.x .. "," .. topos.z) 112 self.target = RandomAway(topos, self.keepYourDistance) -- don't move directly onto the spot 113 unit:Move(self.target) 114 self.attacking = false 115 else 116 EchoDebug("nothing to scout!") 117 end 118 end 119 self.lastUpdateFrame = f 120 end 121 end 122 123 -- keep air units circling 124 if self.mtype == "air" and self.active then 125 local f = game:Frame() 126 if f > self.lastCircleFrame + 60 then 127 local unit = self.unit:Internal() 128 local upos = unit:GetPosition() 129 if self.target then 130 local dist = Distance(upos, self.target) 131 if dist < self.airDistance then 132 unit:Move(RandomAway(self.target, 100)) 133 end 134 else 135 unit:Move(RandomAway(upos, 500)) 136 end 137 self.lastCircleFrame = f 138 end 139 end 140end