--- **Functional** -- Send a truck to supply artillery groups. -- -- === -- -- **AMMOTRUCK** - Send a truck to supply artillery groups. -- -- === -- -- ## Missions: -- -- Demo missions can be found on [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Functional/AmmoTruck) -- -- === -- -- ### Author : **applevangelist** -- -- @module Functional.AmmoTruck -- @image Artillery.JPG -- -- Last update: July 2023 ------------------------------------------------------------------------- --- **AMMOTRUCK** class, extends Core.Fsm#FSM -- @type AMMOTRUCK -- @field #string ClassName Class Name -- @field #string lid Lid for log entries -- @field #string version Version string -- @field #string alias Alias name -- @field #boolean debug Debug flag -- @field #table trucklist List of (alive) #AMMOTRUCK.data trucks -- @field #table targetlist List of (alive) #AMMOTRUCK.data artillery -- @field #number coalition Coalition this is for -- @field Core.Set#SET_GROUP truckset SET of trucks -- @field Core.Set#SET_GROUP targetset SET of artillery -- @field #table remunitionqueue List of (alive) #AMMOTRUCK.data artillery to be reloaded -- @field #table waitingtargets List of (alive) #AMMOTRUCK.data artillery waiting -- @field #number ammothreshold Threshold (min) ammo before sending a truck -- @field #number remunidist Max distance trucks will go -- @field #number monitor Monitor interval in seconds -- @field #number unloadtime Unload time in seconds -- @field #number waitingtime Max waiting time in seconds -- @field #boolean routeonroad Route truck on road if true (default) -- @field #number reloads Number of reloads a single truck can do before he must return home -- @extends Core.Fsm#FSM --- *Amateurs talk about tactics, but professionals study logistics.* - General Robert H Barrow, USMC -- -- Simple Class to re-arm your artillery with trucks. -- -- #AMMOTRUCK -- -- * Controls a SET\_GROUP of trucks which will re-arm a SET\_GROUP of artillery groups when they run out of ammunition. -- -- ## 1 The AMMOTRUCK concept -- -- A SET\_GROUP of trucks which will re-arm a SET\_GROUP of artillery groups when they run out of ammunition. They will be based on a -- homebase and drive from there to the artillery groups and then back home. -- Trucks are the **only known in-game mechanic** to re-arm artillery and other units in DCS. Working units are e.g.: M-939 (blue), Ural-375 and ZIL-135 (both red). -- -- ## 2 Set-up -- -- Define a set of trucks and a set of artillery: -- -- local truckset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Ammo Truck"):FilterStart() -- local ariset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Artillery"):FilterStart() -- -- Create an AMMOTRUCK object to take care of the artillery using the trucks, with a homezone: -- -- local ammotruck = AMMOTRUCK:New(truckset,ariset,coalition.side.BLUE,"Logistics",ZONE:FindByName("HomeZone") -- -- ## 2 Options and their default values -- -- ammotruck.ammothreshold = 5 -- send a truck when down to this many rounds -- ammotruck.remunidist = 20000 -- 20km - send trucks max this far from home -- ammotruck.unloadtime = 600 -- 10 minutes - min time to unload ammunition -- ammotruck.waitingtime = 1800 -- 30 mintes - wait max this long until remunition is done -- ammotruck.monitor = -60 -- 1 minute - AMMOTRUCK checks run every one minute -- ammotruck.routeonroad = true -- Trucks will **try** to drive on roads -- ammotruck.usearmygroup = false -- If true, will make use of ARMYGROUP in the background (if used in DEV branch) -- ammotruck.reloads = 5 -- Maxn re-arms a truck can do before he needs to go home and restock. Set to -1 for unlimited -- -- ## 3 FSM Events to shape mission -- -- Truck has been sent off: -- -- function ammotruck:OnAfterRouteTruck(From, Event, To, Truckdata, Aridata) -- ... -- end -- -- Truck has arrived: -- -- function ammotruck:OnAfterTruckArrived(From, Event, To, Truckdata) -- ... -- end -- -- Truck is unloading: -- -- function ammotruck:OnAfterTruckUnloading(From, Event, To, Truckdata) -- ... -- end -- -- Truck is returning home: -- -- function ammotruck:OnAfterTruckReturning(From, Event, To, Truckdata) -- ... -- end -- -- Truck is arrived at home: -- -- function ammotruck:OnAfterTruckHome(From, Event, To, Truckdata) -- ... -- end -- -- @field #AMMOTRUCK AMMOTRUCK = { ClassName = "AMMOTRUCK", lid = "", version = "0.0.12", alias = "", debug = false, trucklist = {}, targetlist = {}, coalition = nil, truckset = nil, targetset = nil, remunitionqueue = {}, waitingtargets = {}, ammothreshold = 5, remunidist = 20000, monitor = -60, unloadtime = 600, waitingtime = 1800, routeonroad = true, reloads = 5, } --- -- @type AMMOTRUCK.State AMMOTRUCK.State = { IDLE = "idle", DRIVING = "driving", ARRIVED = "arrived", UNLOADING = "unloading", RETURNING = "returning", WAITING = "waiting", RELOADING = "reloading", OUTOFAMMO = "outofammo", REQUESTED = "requested", } --- --@type AMMOTRUCK.data --@field Wrapper.Group#GROUP group --@field #string name --@field #AMMOTRUCK.State statusquo --@field #number timestamp --@field #number ammo --@field Core.Point#COORDINATE coordinate --@field #string targetname --@field Wrapper.Group#GROUP targetgroup --@field Core.Point#COORDINATE targetcoordinate --@field #number reloads --- -- @param #AMMOTRUCK self -- @param Core.Set#SET_GROUP Truckset Set of truck groups -- @param Core.Set#SET_GROUP Targetset Set of artillery groups -- @param #number Coalition Coalition -- @param #string Alias Alias Name -- @param Core.Zone#ZONE Homezone Home, return zone for trucks -- @return #AMMOTRUCK self -- @usage -- Define a set of trucks and a set of artillery: -- local truckset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Ammo Truck"):FilterStart() -- local ariset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Artillery"):FilterStart() -- -- Create an AMMOTRUCK object to take care of the artillery using the trucks, with a homezone: -- local ammotruck = AMMOTRUCK:New(truckset,ariset,coalition.side.BLUE,"Logistics",ZONE:FindByName("HomeZone") function AMMOTRUCK:New(Truckset,Targetset,Coalition,Alias,Homezone) -- Inherit everything from BASE class. local self=BASE:Inherit(self, FSM:New()) -- #AMMOTRUCK self.truckset = Truckset -- Core.Set#SET_GROUP self.targetset = Targetset -- Core.Set#SET_GROUP self.coalition = Coalition -- #number self.alias = Alias -- #string self.debug = false self.remunitionqueue = {} self.trucklist = {} self.targetlist = {} self.ammothreshold = 5 self.remunidist = 20000 self.homezone = Homezone -- Core.Zone#ZONE self.waitingtime = 1800 self.usearmygroup = false self.hasarmygroup = false -- Log id. self.lid=string.format("AMMOTRUCK %s | %s | ", self.version, self.alias) self:SetStartState("Stopped") self:AddTransition("Stopped", "Start", "Running") self:AddTransition("*", "Monitor", "*") self:AddTransition("*", "RouteTruck", "*") self:AddTransition("*", "TruckArrived", "*") self:AddTransition("*", "TruckUnloading", "*") self:AddTransition("*", "TruckReturning", "*") self:AddTransition("*", "TruckHome", "*") self:AddTransition("*", "Stop", "Stopped") self:__Start(math.random(5,10)) self:I(self.lid .. "Started") ------------------------ --- Pseudo Functions --- ------------------------ --- Triggers the FSM event "Stop". Stops the AMMOTRUCK and all its event handlers. -- @function [parent=#AMMOTRUCK] Stop -- @param #AMMOTRUCK self --- Triggers the FSM event "Stop" after a delay. Stops the AMMOTRUCK and all its event handlers. -- @function [parent=#AMMOTRUCK] __Stop -- @param #AMMOTRUCK self -- @param #number delay Delay in seconds. --- On after "RouteTruck" event. -- @function [parent=#AMMOTRUCK] OnAfterRouteTruck -- @param #AMMOTRUCK self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #AMMOTRUCK.data Truck -- @param #AMMOTRUCK.data Artillery --- On after "TruckUnloading" event. -- @function [parent=#AMMOTRUCK] OnAfterTruckUnloading -- @param #AMMOTRUCK self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #AMMOTRUCK.data Truck --- On after "TruckReturning" event. -- @function [parent=#AMMOTRUCK] OnAfterTruckReturning -- @param #AMMOTRUCK self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #AMMOTRUCK.data Truck --- On after "RouteTruck" event. -- @function [parent=#AMMOTRUCK] OnAfterRouteTruck -- @param #AMMOTRUCK self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #AMMOTRUCK.data Truck --- On after "TruckHome" event. -- @function [parent=#AMMOTRUCK] OnAfterTruckHome -- @param #AMMOTRUCK self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #AMMOTRUCK.data Truck return self end --- -- @param #AMMOTRUCK self -- @param #table dataset table of #AMMOTRUCK.data entries -- @return #AMMOTRUCK self function AMMOTRUCK:CheckDrivingTrucks(dataset) self:T(self.lid .. " CheckDrivingTrucks") local data = dataset for _,_data in pairs (data) do local truck = _data -- #AMMOTRUCK.data -- see if we arrived at destination local coord = truck.group:GetCoordinate() local tgtcoord = truck.targetcoordinate local dist = coord:Get2DDistance(tgtcoord) if dist <= 150 then -- arrived truck.statusquo = AMMOTRUCK.State.ARRIVED truck.timestamp = timer.getAbsTime() truck.coordinate = coord self:__TruckArrived(1,truck) end -- still driving? local Tnow = timer.getAbsTime() if Tnow - truck.timestamp > 30 then local group = truck.group if self.usearmygroup then group = truck.group:GetGroup() end local currspeed = group:GetVelocityKMH() if truck.lastspeed then if truck.lastspeed == 0 and currspeed == 0 then self:T(truck.group:GetName().." Is not moving!") -- try and move it truck.timestamp = timer.getAbsTime() if self.routeonroad then group:RouteGroundOnRoad(truck.targetcoordinate,30,2,"Vee") else group:RouteGroundTo(truck.targetcoordinate,30,"Vee",2) end end truck.lastspeed = currspeed else truck.lastspeed = currspeed truck.timestamp = timer.getAbsTime() end self:I({truck=truck.group:GetName(),currspeed=currspeed,lastspeed=truck.lastspeed}) end end return self end --- -- @param #AMMOTRUCK self -- @param Wrapper.Group#GROUP Group -- @return #AMMOTRUCK self function AMMOTRUCK:GetAmmoStatus(Group) local ammotot, shells, rockets, bombs, missiles, narti = Group:GetAmmunition() return rockets+missiles+narti end --- -- @param #AMMOTRUCK self -- @param #table dataset table of #AMMOTRUCK.data entries -- @return #AMMOTRUCK self function AMMOTRUCK:CheckWaitingTargets(dataset) self:T(self.lid .. " CheckWaitingTargets") local data = dataset for _,_data in pairs (data) do local truck = _data -- #AMMOTRUCK.data -- see how long we're waiting - maybe ammo truck is dead? local Tnow = timer.getAbsTime() local Tdiff = Tnow - truck.timestamp if Tdiff > self.waitingtime then local hasammo = self:GetAmmoStatus(truck.group) if hasammo <= self.ammothreshold then truck.statusquo = AMMOTRUCK.State.OUTOFAMMO else truck.statusquo = AMMOTRUCK.State.IDLE end end end return self end --- -- @param #AMMOTRUCK self -- @param #table dataset table of #AMMOTRUCK.data entries -- @return #AMMOTRUCK self function AMMOTRUCK:CheckReturningTrucks(dataset) self:T(self.lid .. " CheckReturningTrucks") local data = dataset local tgtcoord = self.homezone:GetCoordinate() local radius = self.homezone:GetRadius() for _,_data in pairs (data) do local truck = _data -- #AMMOTRUCK.data -- see if we arrived at destination local coord = truck.group:GetCoordinate() local dist = coord:Get2DDistance(tgtcoord) self:T({name=truck.name,radius=radius,distance=dist}) if dist <= radius then -- arrived truck.statusquo = AMMOTRUCK.State.IDLE truck.timestamp = timer.getAbsTime() truck.coordinate = coord truck.reloads = self.reloads or 5 self:__TruckHome(1,truck) end end return self end --- -- @param #AMMOTRUCK self -- @param #string name Artillery group name to find -- @return #AMMOTRUCK.data Data function AMMOTRUCK:FindTarget(name) self:T(self.lid .. " FindTarget") local data = nil local dataset = self.targetlist for _,_entry in pairs(dataset) do local entry = _entry -- #AMMOTRUCK.data if entry.name == name then data = entry break end end return data end --- -- @param #AMMOTRUCK self -- @param #string name Truck group name to find -- @return #AMMOTRUCK.data Data function AMMOTRUCK:FindTruck(name) self:T(self.lid .. " FindTruck") local data = nil local dataset = self.trucklist for _,_entry in pairs(dataset) do local entry = _entry -- #AMMOTRUCK.data if entry.name == name then data = entry break end end return data end --- -- @param #AMMOTRUCK self -- @param #table dataset table of #AMMOTRUCK.data entries -- @return #AMMOTRUCK self function AMMOTRUCK:CheckArrivedTrucks(dataset) self:T(self.lid .. " CheckArrivedTrucks") local data = dataset for _,_data in pairs (data) do -- set to unloading local truck = _data -- #AMMOTRUCK.data truck.statusquo = AMMOTRUCK.State.UNLOADING truck.timestamp = timer.getAbsTime() self:__TruckUnloading(2,truck) -- set target to reloading local aridata = self:FindTarget(truck.targetname) -- #AMMOTRUCK.data if aridata then aridata.statusquo = AMMOTRUCK.State.RELOADING aridata.timestamp = timer.getAbsTime() end end return self end --- -- @param #AMMOTRUCK self -- @param #table dataset table of #AMMOTRUCK.data entries -- @return #AMMOTRUCK self function AMMOTRUCK:CheckUnloadingTrucks(dataset) self:T(self.lid .. " CheckUnloadingTrucks") local data = dataset for _,_data in pairs (data) do -- check timestamp local truck = _data -- #AMMOTRUCK.data local Tnow = timer.getAbsTime() local Tpassed = Tnow - truck.timestamp local hasammo = self:GetAmmoStatus(truck.targetgroup) if Tpassed > self.unloadtime and hasammo > self.ammothreshold then truck.statusquo = AMMOTRUCK.State.RETURNING truck.timestamp = timer.getAbsTime() self:__TruckReturning(2,truck) -- set target to reloaded local aridata = self:FindTarget(truck.targetname) -- #AMMOTRUCK.data if aridata then aridata.statusquo = AMMOTRUCK.State.IDLE aridata.timestamp = timer.getAbsTime() end end end return self end --- -- @param #AMMOTRUCK self -- @return #AMMOTRUCK self function AMMOTRUCK:CheckTargetsAlive() self:T(self.lid .. " CheckTargetsAlive") local arilist = self.targetlist for _,_ari in pairs(arilist) do local ari = _ari -- #AMMOTRUCK.data if ari.group and ari.group:IsAlive() then -- everything fine else -- ari dead self.targetlist[ari.name] = nil end end -- new arrivals? local aritable = self.targetset:GetSetObjects() --#table for _,_ari in pairs(aritable) do local ari = _ari -- Wrapper.Group#GROUP if ari and ari:IsAlive() and not self.targetlist[ari:GetName()] then local name = ari:GetName() local newari = {} -- #AMMOTRUCK.data newari.name = name newari.group = ari newari.statusquo = AMMOTRUCK.State.IDLE newari.timestamp = timer.getAbsTime() newari.coordinate = ari:GetCoordinate() local hasammo = self:GetAmmoStatus(ari) --newari.ammo = ari:GetAmmunition() newari.ammo = hasammo self.targetlist[name] = newari end end return self end --- -- @param #AMMOTRUCK self -- @return #AMMOTRUCK self function AMMOTRUCK:CheckTrucksAlive() self:T(self.lid .. " CheckTrucksAlive") local trucklist = self.trucklist for _,_truck in pairs(trucklist) do local truck = _truck -- #AMMOTRUCK.data if truck.group and truck.group:IsAlive() then -- everything fine else -- truck dead local tgtname = truck.targetname local targetdata = self:FindTarget(tgtname) -- #AMMOTRUCK.data if targetdata then if targetdata.statusquo ~= AMMOTRUCK.State.IDLE then targetdata.statusquo = AMMOTRUCK.State.IDLE end end self.trucklist[truck.name] = nil end end -- new arrivals? local trucktable = self.truckset:GetSetObjects() --#table for _,_truck in pairs(trucktable) do local truck = _truck -- Wrapper.Group#GROUP if truck and truck:IsAlive() and not self.trucklist[truck:GetName()] then local name = truck:GetName() local newtruck = {} -- #AMMOTRUCK.data newtruck.name = name newtruck.group = truck if self.hasarmygroup then -- is (not) already ARMYGROUP? if truck.ClassName and truck.ClassName == "GROUP" then local trucker = ARMYGROUP:New(truck) trucker:Activate() newtruck.group = trucker end end newtruck.statusquo = AMMOTRUCK.State.IDLE newtruck.timestamp = timer.getAbsTime() newtruck.coordinate = truck:GetCoordinate() newtruck.reloads = self.reloads or 5 self.trucklist[name] = newtruck end end return self end --- -- @param #AMMOTRUCK self -- @param #string From -- @param #string Event -- @param #string To -- @return #AMMOTRUCK self function AMMOTRUCK:onafterStart(From, Event, To) self:T({From, Event, To}) if ARMYGROUP and self.usearmygroup then self.hasarmygroup = true else self.hasarmygroup = false end if self.debug then BASE:TraceOn() BASE:TraceClass("AMMOTRUCK") end self:CheckTargetsAlive() self:CheckTrucksAlive() self:__Monitor(-30) return self end --- -- @param #AMMOTRUCK self -- @param #string From -- @param #string Event -- @param #string To -- @return #AMMOTRUCK self function AMMOTRUCK:onafterMonitor(From, Event, To) self:T({From, Event, To}) self:CheckTargetsAlive() self:CheckTrucksAlive() -- update ammo state local remunition = false local remunitionqueue = {} local waitingtargets = {} for _,_ari in pairs(self.targetlist) do local data = _ari -- #AMMOTRUCK.data if data.group and data.group:IsAlive() then data.ammo = self:GetAmmoStatus(data.group) data.timestamp = timer.getAbsTime() local text = string.format("Ari %s | Ammo %d | State %s",data.name,data.ammo,data.statusquo) self:T(text) if data.ammo <= self.ammothreshold and (data.statusquo == AMMOTRUCK.State.IDLE or data.statusquo == AMMOTRUCK.State.OUTOFAMMO) then -- add to remu queue data.statusquo = AMMOTRUCK.State.OUTOFAMMO remunitionqueue[#remunitionqueue+1] = data remunition = true elseif data.statusquo == AMMOTRUCK.State.WAITING then waitingtargets[#waitingtargets+1] = data end else self.targetlist[data.name] = nil end end -- sort trucks in buckets local idletrucks = {} local drivingtrucks = {} local unloadingtrucks = {} local arrivedtrucks = {} local returningtrucks = {} local found = false for _,_truckdata in pairs(self.trucklist) do local data = _truckdata -- #AMMOTRUCK.data if data.group and data.group:IsAlive() then -- check state local text = string.format("Truck %s | State %s",data.name,data.statusquo) self:T(text) if data.statusquo == AMMOTRUCK.State.IDLE then idletrucks[#idletrucks+1] = data found = true elseif data.statusquo == AMMOTRUCK.State.DRIVING then drivingtrucks[#drivingtrucks+1] = data elseif data.statusquo == AMMOTRUCK.State.ARRIVED then arrivedtrucks[#arrivedtrucks+1] = data elseif data.statusquo == AMMOTRUCK.State.UNLOADING then unloadingtrucks[#unloadingtrucks+1] = data elseif data.statusquo == AMMOTRUCK.State.RETURNING then returningtrucks[#returningtrucks+1] = data if data.reloads > 0 or data.reloads == -1 then idletrucks[#idletrucks+1] = data found = true end end else self.truckset[data.name] = nil end end -- see if we can/need route one local n=0 if found and remunition then -- match --local match = false for _,_truckdata in pairs(idletrucks) do local truckdata = _truckdata -- #AMMOTRUCK.data local truckcoord = truckdata.group:GetCoordinate() -- Core.Point#COORDINATE for _,_aridata in pairs(remunitionqueue) do local aridata = _aridata -- #AMMOTRUCK.data local aricoord = aridata.coordinate local distance = truckcoord:Get2DDistance(aricoord) if distance <= self.remunidist and aridata.statusquo == AMMOTRUCK.State.OUTOFAMMO and n <= #idletrucks then n = n + 1 aridata.statusquo = AMMOTRUCK.State.REQUESTED self:__RouteTruck(n*5,truckdata,aridata) break end end end end -- check driving trucks if #drivingtrucks > 0 then self:CheckDrivingTrucks(drivingtrucks) end -- check arrived trucks if #arrivedtrucks > 0 then self:CheckArrivedTrucks(arrivedtrucks) end -- check unloading trucks if #unloadingtrucks > 0 then self:CheckUnloadingTrucks(unloadingtrucks) end -- check returningtrucks trucks if #returningtrucks > 0 then self:CheckReturningTrucks(returningtrucks) end -- check waiting targets if #waitingtargets > 0 then self:CheckWaitingTargets(waitingtargets) end self:__Monitor(self.monitor) return self end --- -- @param #AMMOTRUCK self -- @param #string From -- @param #string Event -- @param #string To -- @param #AMMOTRUCK.data Truckdata -- @param #AMMOTRUCK.data Aridata -- @return #AMMOTRUCK self function AMMOTRUCK:onafterRouteTruck(From, Event, To, Truckdata, Aridata) self:T({From, Event, To, Truckdata.name, Aridata.name}) local truckdata = Truckdata -- #AMMOTRUCK.data local aridata = Aridata -- #AMMOTRUCK.data local tgtgrp = aridata.group local tgtzone = ZONE_GROUP:New(aridata.name,tgtgrp,30) local tgtcoord = tgtzone:GetRandomCoordinate(15) if self.hasarmygroup then local mission = AUFTRAG:NewONGUARD(tgtcoord) local oldmission = truckdata.group:GetMissionCurrent() if oldmission then oldmission:Cancel() end mission:SetTime(5) mission:SetTeleport(false) truckdata.group:AddMission(mission) elseif self.routeonroad then truckdata.group:RouteGroundOnRoad(tgtcoord,30) else truckdata.group:RouteGroundTo(tgtcoord,30) end truckdata.statusquo = AMMOTRUCK.State.DRIVING truckdata.targetgroup = tgtgrp truckdata.targetname = aridata.name truckdata.targetcoordinate = tgtcoord aridata.statusquo = AMMOTRUCK.State.WAITING aridata.timestamp = timer.getAbsTime() return self end --- -- @param #AMMOTRUCK self -- @param #string From -- @param #string Event -- @param #string To -- @param #AMMOTRUCK.data Truckdata -- @return #AMMOTRUCK self function AMMOTRUCK:onafterTruckUnloading(From, Event, To, Truckdata) local m = MESSAGE:New("Truck "..Truckdata.name.." unloading!",15,"AmmoTruck"):ToCoalitionIf(self.coalition,self.debug) local truck = Truckdata -- Functional.AmmoTruck#AMMOTRUCK.data local coord = truck.group:GetCoordinate() local heading = truck.group:GetHeading() heading = heading < 180 and (360-heading) or (heading - 180) local cid = self.coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA cid = self.coalition == coalition.side.NEUTRAL and country.id.UN_PEACEKEEPERS or cid local ammo = {} for i=1,5 do ammo[i] = SPAWNSTATIC:NewFromType("ammo_cargo","Cargos",cid) :InitCoordinate(coord:Translate((15+((i-1)*4)),heading)) :Spawn(0,"AmmoCrate-"..math.random(1,10000)) end local function destroyammo(ammo) for _,_crate in pairs(ammo) do _crate:Destroy(false) end end local scheduler = SCHEDULER:New(nil,destroyammo,{ammo},self.waitingtime) -- one reload less if truck.reloads ~= -1 then truck.reloads = truck.reloads - 1 end return self end --- -- @param #AMMOTRUCK self -- @param #string From -- @param #string Event -- @param #string To -- @param #AMMOTRUCK.data Truck -- @return #AMMOTRUCK self function AMMOTRUCK:onafterTruckReturning(From, Event, To, Truck) self:T({From, Event, To, Truck.name}) -- route home local truckdata = Truck -- #AMMOTRUCK.data local tgtzone = self.homezone local tgtcoord = tgtzone:GetRandomCoordinate() if self.hasarmygroup then local mission = AUFTRAG:NewONGUARD(tgtcoord) local oldmission = truckdata.group:GetMissionCurrent() if oldmission then oldmission:Cancel() end mission:SetTime(5) mission:SetTeleport(false) truckdata.group:AddMission(mission) elseif self.routeonroad then truckdata.group:RouteGroundOnRoad(tgtcoord,30,1,"Cone") else truckdata.group:RouteGroundTo(tgtcoord,30,"Cone",1) end return self end --- -- @param #AMMOTRUCK self -- @param #string From -- @param #string Event -- @param #string To -- @return #AMMOTRUCK self function AMMOTRUCK:onafterStop(From, Event, To) self:T({From, Event, To}) return self end