1require "common" 2 3local DebugEnabled = false 4 5local function EchoDebug(inStr) 6 if DebugEnabled then 7 game:SendToConsole("RaiderBehaviour: " .. inStr) 8 end 9end 10 11local CMD_IDLEMODE = 145 12local CMD_MOVE_STATE = 50 13local MOVESTATE_ROAM = 2 14 15function IsRaider(unit) 16 for i,name in ipairs(raiderList) do 17 if name == unit:Internal():Name() then 18 return true 19 end 20 end 21 return false 22end 23 24RaiderBehaviour = class(Behaviour) 25 26function RaiderBehaviour:Init() 27 local mtype, network = ai.maphandler:MobilityOfUnit(self.unit:Internal()) 28 self.mtype = mtype 29 self.name = self.unit:Internal():Name() 30 local utable = unitTable[self.name] 31 if self.mtype == "sub" then 32 self.range = utable.submergedRange 33 else 34 self.range = utable.groundRange 35 end 36 self.id = self.unit:Internal():ID() 37 self.disarmer = raiderDisarms[self.name] 38 if ai.raiderCount[mtype] == nil then 39 ai.raiderCount[mtype] = 1 40 else 41 ai.raiderCount[mtype] = ai.raiderCount[mtype] + 1 42 end 43end 44 45function RaiderBehaviour:UnitDead(unit) 46 if unit.engineID == self.unit.engineID then 47 -- game:SendToConsole("raider " .. self.name .. " died") 48 if self.target then 49 ai.targethandler:AddBadPosition(self.target, self.mtype) 50 end 51 ai.raidhandler:NeedLess(self.mtype) 52 ai.raiderCount[self.mtype] = ai.raiderCount[self.mtype] - 1 53 end 54end 55 56function RaiderBehaviour:UnitIdle(unit) 57 if unit.engineID == self.unit.engineID then 58 self.target = nil 59 self.evading = false 60 -- keep planes from landing (i'd rather set land state, but how?) 61 if self.mtype == "air" then 62 unit:Internal():Move(RandomAway(unit:Internal():GetPosition(), 500)) 63 end 64 self.unit:ElectBehaviour() 65 end 66end 67 68function RaiderBehaviour:RaidCell(cell) 69 EchoDebug(self.name .. " raiding cell...") 70 if self.unit == nil then 71 EchoDebug("no raider unit to raid cell with!") 72 -- ai.raidhandler:RemoveRecruit(self) 73 elseif self.unit:Internal() == nil then 74 EchoDebug("no raider unit internal to raid cell with!") 75 -- ai.raidhandler:RemoveRecruit(self) 76 else 77 if self.buildingIDs ~= nil then 78 ai.raidhandler:IDsWeAreNotRaiding(self.buildingIDs) 79 end 80 ai.raidhandler:IDsWeAreRaiding(cell.buildingIDs, self.mtype) 81 self.buildingIDs = cell.buildingIDs 82 self.target = RandomAway(cell.pos, self.range * 0.5) 83 if self.mtype == "air" then 84 if self.disarmer then 85 self.unitTarget = cell.disarmTarget 86 else 87 self.unitTarget = cell.targets.air.ground 88 end 89 EchoDebug("air raid target: " .. tostring(self.unitTarget.unitName)) 90 end 91 if self.active then 92 if self.mtype == "air" then 93 if self.unitTarget ~= nil then 94 CustomCommand(self.unit:Internal(), CMD_ATTACK, {self.unitTarget.unitID}) 95 end 96 else 97 self.unit:Internal():Move(self.target) 98 end 99 end 100 self.unit:ElectBehaviour() 101 end 102end 103 104function RaiderBehaviour:Priority() 105 if not self.target then 106 -- revert to scouting 107 return 0 108 else 109 return 100 110 end 111end 112 113function RaiderBehaviour:Activate() 114 EchoDebug(self.name .. " active") 115 self.active = true 116 if self.target then 117 if self.mtype == "air" then 118 if self.unitTarget ~= nil then 119 CustomCommand(self.unit:Internal(), CMD_ATTACK, {self.unitTarget.unitID}) 120 end 121 else 122 self.unit:Internal():Move(self.target) 123 end 124 end 125end 126 127function RaiderBehaviour:Deactivate() 128 EchoDebug(self.name .. " inactive") 129 self.active = false 130 self.target = nil 131end 132 133function RaiderBehaviour:Update() 134 local f = game:Frame() 135 136 if not self.active then 137 if math.mod(f, 89) == 0 then 138 local unit = self.unit:Internal() 139 local bestCell = ai.targethandler:GetBestRaidCell(unit) 140 ai.targethandler:RaiderHere(self) 141 EchoDebug(self.name .. " targetting...") 142 if bestCell then 143 EchoDebug(self.name .. " got target") 144 self:RaidCell(bestCell) 145 else 146 self.target = nil 147 self.unit:ElectBehaviour() 148 -- revert to scouting 149 end 150 end 151 else 152 if math.mod(f, 29) == 0 then 153 -- attack nearby vulnerables immediately 154 local unit = self.unit:Internal() 155 local attackTarget 156 if ai.targethandler:IsSafePosition(unit:GetPosition(), unit, 1) then 157 attackTarget = ai.targethandler:NearbyVulnerable(unit) 158 end 159 if attackTarget then 160 CustomCommand(unit, CMD_ATTACK, {attackTarget.unitID}) 161 else 162 -- evade enemies on the way to the target, if possible 163 if self.target ~= nil then 164 local newPos, arrived = ai.targethandler:BestAdjacentPosition(unit, self.target) 165 ai.targethandler:RaiderHere(self) 166 if newPos then 167 EchoDebug(self.name .. " evading") 168 unit:Move(newPos) 169 self.evading = true 170 elseif arrived then 171 EchoDebug(self.name .. " arrived") 172 -- if we're at the target 173 self.evading = false 174 elseif self.evading then 175 EchoDebug(self.name .. " setting course to taget") 176 -- return to course to target after evading 177 if self.mtype == "air" then 178 if self.unitTarget ~= nil then 179 CustomCommand(self.unit:Internal(), CMD_ATTACK, {self.unitTarget.unitID}) 180 end 181 else 182 self.unit:Internal():Move(self.target) 183 end 184 self.evading = false 185 end 186 end 187 end 188 end 189 end 190end 191 192-- set all raiders to roam 193function RaiderBehaviour:SetMoveState() 194 local thisUnit = self.unit 195 if thisUnit then 196 local floats = api.vectorFloat() 197 floats:push_back(MOVESTATE_ROAM) 198 thisUnit:Internal():ExecuteCustomCommand(CMD_MOVE_STATE, floats) 199 if self.mtype == "air" then 200 local floats = api.vectorFloat() 201 floats:push_back(1) 202 thisUnit:Internal():ExecuteCustomCommand(CMD_IDLEMODE, floats) 203 end 204 end 205end