diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 5ce11f221..e2874853e 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -179,16 +179,20 @@ end -- @param #boolean force -- @return Wrapper.Unit#UNIT The added unit. function DATABASE:AddUnit( DCSUnitName, force ) - - if not self.UNITS[DCSUnitName] or force == true then + + local DCSunitName = DCSUnitName + + if type(DCSunitName) == "number" then DCSunitName = string.format("%d",DCSUnitName) end + + if not self.UNITS[DCSunitName] or force == true then -- Debug info. - self:T( { "Add UNIT:", DCSUnitName } ) + self:T( { "Add UNIT:", DCSunitName } ) -- Register unit - self.UNITS[DCSUnitName]=UNIT:Register(DCSUnitName) + self.UNITS[DCSunitName]=UNIT:Register(DCSunitName) end - return self.UNITS[DCSUnitName] + return self.UNITS[DCSunitName] end @@ -1451,7 +1455,7 @@ function DATABASE:_RegisterDynamicGroup(Groupname) -- Add unit. self:I(string.format("Register Unit: %s", tostring(DCSUnitName))) - self:AddUnit( DCSUnitName, true ) + self:AddUnit( tostring(DCSUnitName), true ) end else diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 3997fbdf5..4b993d7a4 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -1530,6 +1530,7 @@ function EVENT:onEvent( Event ) if Event.dynamiccargo then Event.IniDynamicCargo = Event.dynamiccargo Event.IniDynamicCargoName = Event.IniDynamicCargo.StaticName + Event.IniPlayerName = Event.IniDynamicCargo.Owner or string.match(Event.IniUnitName,"^(.+)|%d%d:%d%d|PKG%d+") end -- Zone object. diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 346e64c08..6959d908c 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -78,6 +78,7 @@ CTLD_CARGO = { -- @field #string REPAIR -- @field #string ENGINEERS -- @field #string STATIC + -- @field #string GCLOADABLE CTLD_CARGO.Enum = { VEHICLE = "Vehicle", -- #string vehicles TROOPS = "Troops", -- #string troops @@ -86,6 +87,7 @@ CTLD_CARGO = { REPAIR = "Repair", -- #string repair ENGINEERS = "Engineers", -- #string engineers STATIC = "Static", -- #string statics + GCLOADABLE = "GC_Loadable", -- #string dynamiccargo } --- Function to create new CTLD_CARGO object. @@ -770,7 +772,7 @@ do -- my_ctld.nobuildmenu = false -- if set to true effectively enforces to have engineers build/repair stuff for you. -- my_ctld.RadioSound = "beacon.ogg" -- -- this sound will be hearable if you tune in the beacon frequency. Add the sound file to your miz. -- my_ctld.RadioSoundFC3 = "beacon.ogg" -- this sound will be hearable by FC3 users (actually all UHF radios); change to something like "beaconsilent.ogg" and add the sound file to your miz if you don't want to annoy FC3 pilots. --- my_ctld.enableChinookGCLoading = true -- this will effectively suppress the crate load and drop menus for CTLD for the Chinook +-- my_ctld.enableChinookGCLoading = true -- this will effectively suppress the crate load and drop for CTLD_CARGO.Enum.STATIc types for CTLD for the Chinook -- -- ## 2.1 CH-47 Chinook support -- @@ -1203,6 +1205,7 @@ CTLD = { wpZones = {}, dropOffZones = {}, pickupZones = {}, + DynamicCargo = {}, } ------------------------------ @@ -1307,7 +1310,7 @@ CTLD.UnitTypeCapabilities = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.58" +CTLD.version="1.1.12" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1909,28 +1912,98 @@ function CTLD:_EventHandler(EventData) self.CtldUnits[unitname] = nil self.Loaded_Cargo[unitname] = nil self.MenusDone[unitname] = nil - elseif event.id == EVENTS.Birth and event.IniObjectCategory == 6 and string.match(event.IniUnitName,".+|%d%d:%d%d|PKG%d+") then - --UTILS.PrintTableToLog(event) + --elseif event.id == EVENTS.NewDynamicCargo and event.IniObjectCategory == 6 and string.match(event.IniUnitName,".+|%d%d:%d%d|PKG%d+") then + elseif event.id == EVENTS.NewDynamicCargo then + self:T(self.lid.."GC New Event "..event.IniDynamicCargoName) --------------- - -- New dynamic cargo system Handling + -- New dynamic cargo system Handling NEW -------------- - local function RegisterDynamicCargo() - local static = _DATABASE:AddStatic(event.IniUnitName) - if static then - static.DCSCargoObject = event.IniDCSUnit - local Mass = event.IniDCSUnit:getCargoWeight() - local country = event.IniDCSUnit:getCountry() - local template = _DATABASE:_GetGenericStaticCargoGroupTemplate(event.IniUnitName,event.IniTypeName,Mass,event.IniCoalition,country) - _DATABASE:_RegisterStaticTemplate(template,event.IniCoalition,"static",country) - self:I("**** Ground crew created static cargo added: "..event.IniUnitName .." | Weight in kgs: "..Mass) - local cargotype = self:AddStaticsCargo(event.IniUnitName,Mass,1,nil,true) - self.CrateCounter = self.CrateCounter + 1 - self.Spawned_Crates[self.CrateCounter] = static - cargotype.Positionable = static - table.insert(self.Spawned_Cargo, cargotype) + self.DynamicCargo[event.IniDynamicCargoName] = event.IniDynamicCargo + --------------- + -- End new dynamic cargo system Handling + -------------- + elseif event.id == EVENTS.DynamicCargoLoaded then + self:T(self.lid.."GC Loaded Event "..event.IniDynamicCargoName) + --------------- + -- New dynamic cargo system Handling LOADING + -------------- + local dcargo = event.IniDynamicCargo -- Wrapper.DynamicCargo#DYNAMICCARGO + -- get client/unit object + local client = CLIENT:FindByPlayerName(dcargo.Owner) + if client and client:IsAlive() then + -- add to unit load list + local unitname = client:GetName() or "none" + local loaded = {} + if self.Loaded_Cargo[unitname] then + loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo + else + loaded = {} -- #CTLD.LoadedCargo + loaded.Troopsloaded = 0 + loaded.Cratesloaded = 0 + loaded.Cargo = {} end + loaded.Cratesloaded = loaded.Cratesloaded+1 + table.insert(loaded.Cargo,dcargo) + self.Loaded_Cargo[unitname] = nil + self.Loaded_Cargo[unitname] = loaded + local Group = client:GetGroup() + self:_SendMessage(string.format("Crate %s loaded by ground crew!",event.IniDynamicCargoName), 10, false, Group) + self:__CratesPickedUp(1, Group, client, dcargo) end - --self:ScheduleOnce(0.5,RegisterDynamicCargo) + --------------- + -- End new dynamic cargo system Handling + -------------- + elseif event.id == EVENTS.DynamicCargoUnloaded then + self:T(self.lid.."GC Unload Event "..event.IniDynamicCargoName) + --------------- + -- New dynamic cargo system Handling UNLOADING + -------------- + local dcargo = event.IniDynamicCargo -- Wrapper.DynamicCargo#DYNAMICCARGO + -- get client/unit object + local client = CLIENT:FindByPlayerName(dcargo.Owner) + if client and client:IsAlive() then + -- add to unit load list + local unitname = client:GetName() or "none" + local loaded = {} + if self.Loaded_Cargo[unitname] then + loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo + loaded.Cratesloaded = loaded.Cratesloaded - 1 + if loaded.Cratesloaded < 0 then loaded.Cratesloaded = 0 end + -- TODO zap cargo from list + local Loaded = {} + for _,_item in pairs (loaded.Cargo or {}) do + self:T(self.lid.."UNLOAD checking: ".._item:GetName()) + self:T(self.lid.."UNLOAD state: ".. tostring(_item:WasDropped())) + if _item and _item:GetType() == CTLD_CARGO.Enum.GCLOADABLE and event.IniDynamicCargoName and event.IniDynamicCargoName ~= _item:GetName() and not _item:WasDropped() then + table.insert(Loaded,_item) + else + table.insert(Loaded,_item) + end + end + loaded.Cargo = nil + loaded.Cargo = Loaded + self.Loaded_Cargo[unitname] = nil + self.Loaded_Cargo[unitname] = loaded + else + loaded = {} -- #CTLD.LoadedCargo + loaded.Troopsloaded = 0 + loaded.Cratesloaded = 0 + loaded.Cargo = {} + self.Loaded_Cargo[unitname] = loaded + end + local Group = client:GetGroup() + self:_SendMessage(string.format("Crate %s unloaded by ground crew!",event.IniDynamicCargoName), 10, false, Group) + self:__CratesDropped(1,Group,client,{dcargo}) + end + --------------- + -- End new dynamic cargo system Handling + -------------- + elseif event.id == EVENTS.DynamicCargoRemoved then + self:T(self.lid.."GC Remove Event "..event.IniDynamicCargoName) + --------------- + -- New dynamic cargo system Handling REMOVE + -------------- + self.DynamicCargo[event.IniDynamicCargoName] = nil --------------- -- End new dynamic cargo system Handling -------------- @@ -2173,7 +2246,7 @@ end function CTLD:_FindRepairNearby(Group, Unit, Repairtype) self:T(self.lid .. " _FindRepairNearby") - --self:I({Group:GetName(),Unit:GetName(),Repairtype}) + --self:T({Group:GetName(),Unit:GetName(),Repairtype}) local unitcoord = Unit:GetCoordinate() -- find nearest group of deployed groups @@ -2191,7 +2264,7 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype) end end - --self:I("Distance: ".. nearestDistance) + --self:T("Distance: ".. nearestDistance) -- found one and matching distance? if nearestGroup == nil or nearestDistance > self.EngineerSearch then @@ -2225,7 +2298,7 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype) -- walk through generics and find matching type local Cargotype = nil for k,v in pairs(self.Cargo_Crates) do - --self:I({groupname,v.Templates,Repairtype}) + --self:T({groupname,v.Templates,Repairtype}) if matchstring(groupname,v.Templates) and matchstring(groupname,Repairtype) then Cargotype = v -- #CTLD_CARGO break @@ -2235,7 +2308,7 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype) if Cargotype == nil then return nil, nil else - --self:I({groupname,Cargotype}) + --self:T({groupname,Cargotype}) return nearestGroup, Cargotype end @@ -2713,7 +2786,7 @@ function CTLD:_ListCratesNearby( _group, _unit) end text:Add("------------------------------------------------------------") if indexgc > 0 then - text:Add("Probably ground crew loaded (F8)") + text:Add("Probably ground crew loadable (F8)") for _,_entry in pairs (loadedbygc) do local entry = _entry -- #CTLD_CARGO local name = entry:GetName() --#string @@ -2817,7 +2890,7 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight) local capabilities = {} local maxmass = 2000 local maxloadable = 2000 - local IsNoHook = not self:IsHook(_unit) + local IsHook = self:IsHook(_unit) if not _ignoreweight then maxloadable = self:_GetMaxLoadableMass(_unit) end @@ -2828,9 +2901,10 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight) local weight = cargo:GetMass() -- weight in kgs of this cargo local staticid = cargo:GetID() self:T(self.lid .. " Found cargo mass: " .. weight) - local cargoalive = false -- TODO dyn cargo spawn workaround - local dcsunit = nil - local dcsunitpos = nil + --local cargoalive = false -- TODO dyn cargo spawn workaround + --local dcsunit = nil + --local dcsunitpos = nil + --[[ if static and static.DCSCargoObject then dcsunit = Unit.getByName(static.StaticName) if dcsunit then @@ -2844,26 +2918,37 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight) end end end - if static and (static:IsAlive() or cargoalive) then - local staticpos = static:GetCoordinate() or dcsunitpos + --]] + if static and static:IsAlive() then --or cargoalive) then + local restricthooktononstatics = self.enableChinookGCLoading and IsHook + self:T(self.lid .. " restricthooktononstatics: " .. tostring(restricthooktononstatics)) + local cargoisstatic = cargo:GetType() == CTLD_CARGO.Enum.STATIC and true or false + self:T(self.lid .. " Cargo is static: " .. tostring(cargoisstatic)) + local restricted = cargoisstatic and restricthooktononstatics + self:T(self.lid .. " Loading restricted: " .. tostring(restricted)) + local staticpos = static:GetCoordinate() --or dcsunitpos + --[[ --- Testing local landheight = staticpos:GetLandHeight() local agl = staticpos.y-landheight agl = UTILS.Round(agl,2) local GCloaded = agl > 0 and true or false - if IsNoHook == true then GCloaded = false end + if IsNoHook == true then GCloaded = false end + --]] --- Testing local distance = self:_GetDistance(location,staticpos) - self:T({name=static:GetName(),IsNoHook=IsNoHook,agl=agl,GCloaded=GCloaded,distance=string.format("%.2f",distance or 0)}) - if (not GCloaded) and distance <= finddist and static and (weight <= maxloadable or _ignoreweight) then + --self:T({name=static:GetName(),IsHook=IsHook,agl=agl,GCloaded=GCloaded,distance=string.format("%.2f",distance or 0)}) + --if (not restricthooktononstatics) and distance <= finddist and static and (weight <= maxloadable or _ignoreweight) then + self:T(self.lid .. string.format("Dist %dm/%dm | weight %dkg | maxloadable %dkg",distance,finddist,weight,maxloadable)) + if distance <= finddist and (weight <= maxloadable or _ignoreweight) and restricted == false then index = index + 1 table.insert(found, staticid, cargo) maxloadable = maxloadable - weight + --elseif restricthooktononstatics and distance < 10 and static then + --indexg = indexg + 1 + --table.insert(LoadedbyGC,staticid, cargo) end - if GCloaded == true and distance < 10 and static then - indexg = indexg + 1 - table.insert(LoadedbyGC,staticid, cargo) - end + end end return found, index, LoadedbyGC, indexg @@ -2929,10 +3014,10 @@ function CTLD:_LoadCratesNearby(Group, Unit) if number == 0 and self.hoverautoloading then return self -- exit elseif number == 0 then - self:_SendMessage("Sorry no loadable crates nearby or max cargo weight reached!", 10, false, Group) + self:_SendMessage("Sorry, no loadable crates nearby or max cargo weight reached!", 10, false, Group) return self -- exit elseif numberonboard == cratelimit then - self:_SendMessage("Sorry no fully loaded!", 10, false, Group) + self:_SendMessage("Sorry, we are fully loaded!", 10, false, Group) return self -- exit else -- go through crates and load @@ -3024,9 +3109,13 @@ function CTLD:_GetUnitCargoMass(Unit) if (type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS) and not cargo:WasDropped() then loadedmass = loadedmass + (cargo.PerCrateMass * cargo:GetCratesNeeded()) end - if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and not cargo:WasDropped() then + if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then loadedmass = loadedmass + cargo.PerCrateMass end + if type == CTLD_CARGO.Enum.GCLOADABLE then + local mass = cargo:GetCargoWeight() + loadedmass = loadedmass+mass + end end end return loadedmass @@ -3073,8 +3162,8 @@ function CTLD:_ListCargo(Group, Unit) local loadedmass = self:_GetUnitCargoMass(Unit) -- #number local maxloadable = self:_GetMaxLoadableMass(Unit) local finddist = self.CrateDistance or 35 - local _,_,loadedgc,loadedno = self:_FindCratesNearby(Group,Unit,finddist,true) - if self.Loaded_Cargo[unitname] or loadedno > 0 then + --local _,_,loadedgc,loadedno = self:_FindCratesNearby(Group,Unit,finddist,true) + if self.Loaded_Cargo[unitname] then local no_troops = loadedcargo.Troopsloaded or 0 local no_crates = loadedcargo.Cratesloaded or 0 local cargotable = loadedcargo.Cargo or {} -- #table @@ -3099,17 +3188,22 @@ function CTLD:_ListCargo(Group, Unit) for _,_cargo in pairs(cargotable or {}) do local cargo = _cargo -- #CTLD_CARGO local type = cargo:GetType() -- #CTLD_CARGO.Enum - if (type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS) and (not cargo:WasDropped() or self.allowcratepickupagain) then + if (type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE) and (not cargo:WasDropped() or self.allowcratepickupagain) then report:Add(string.format("Crate: %s size 1",cargo:GetName())) cratecount = cratecount + 1 end + if type == CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then + report:Add(string.format("GC loaded Crate: %s size 1",cargo:GetName())) + cratecount = cratecount + 1 + end end if cratecount == 0 then report:Add(" N O N E") end + --[[ if loadedno > 0 then report:Add("------------------------------------------------------------") - report:Add(" -- CRATES loaded via F8 --") + report:Add(" -- CRATES loaded via Ground Crew --") for _,_cargo in pairs(loadedgc or {}) do local cargo = _cargo -- #CTLD_CARGO local type = cargo:GetType() -- #CTLD_CARGO.Enum @@ -3119,6 +3213,7 @@ function CTLD:_ListCargo(Group, Unit) end end end + --]] report:Add("------------------------------------------------------------") report:Add("Total Mass: ".. loadedmass .. " kg. Loadable: "..maxloadable.." kg.") local text = report:Text() @@ -3453,7 +3548,7 @@ function CTLD:_UnloadCrates(Group, Unit) for _,_cargo in pairs (cargotable) do local cargo = _cargo -- #CTLD_CARGO local type = cargo:GetType() -- #CTLD_CARGO.Enum - if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and (not cargo:WasDropped() or self.allowcratepickupagain) then + if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then -- unload crates self:_GetCrates(Group, Unit, cargo, 1, true) cargo:SetWasDropped(true) @@ -3474,6 +3569,10 @@ function CTLD:_UnloadCrates(Group, Unit) table.insert(loaded.Cargo,_cargo) loaded.Troopsloaded = loaded.Troopsloaded + size end + if type == CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then + table.insert(loaded.Cargo,_cargo) + loaded.Cratesloaded = loaded.Cratesloaded + size + end end self.Loaded_Cargo[unitname] = nil self.Loaded_Cargo[unitname] = loaded @@ -3906,7 +4005,8 @@ function CTLD:_RefreshF10Menus() local cantroops = capabilities.troops local cancrates = capabilities.crates local isHook = self:IsHook(_unit) - local nohookswitch = not (isHook and self.enableChinookGCLoading) + --local nohookswitch = not (isHook and self.enableChinookGCLoading) + local nohookswitch = true -- top menu local topmenu = MENU_GROUP:New(_group,"CTLD",nil) local toptroops = nil @@ -5537,7 +5637,11 @@ end self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler) self:HandleEvent(EVENTS.PlayerLeaveUnit, self._EventHandler) self:HandleEvent(EVENTS.UnitLost, self._EventHandler) - self:HandleEvent(EVENTS.Birth, self._EventHandler) + --self:HandleEvent(EVENTS.Birth, self._EventHandler) + self:HandleEvent(EVENTS.NewDynamicCargo, self._EventHandler) + self:HandleEvent(EVENTS.DynamicCargoLoaded, self._EventHandler) + self:HandleEvent(EVENTS.DynamicCargoUnloaded, self._EventHandler) + self:HandleEvent(EVENTS.DynamicCargoRemoved, self._EventHandler) self:__Status(-5) -- AutoSave @@ -5625,9 +5729,11 @@ end -- @return #CTLD self function CTLD:onafterStop(From, Event, To) self:T({From, Event, To}) - self:UnhandleEvent(EVENTS.PlayerEnterAircraft) - self:UnhandleEvent(EVENTS.PlayerEnterUnit) - self:UnhandleEvent(EVENTS.PlayerLeaveUnit) + self:UnHandleEvent(EVENTS.PlayerEnterAircraft) + self:UnHandleEvent(EVENTS.PlayerEnterUnit) + self:UnHandleEvent(EVENTS.PlayerLeaveUnit) + self:UnHandleEvent(EVENTS.UnitLost) + self:UnHandleEvent(EVENTS.Shot) return self end diff --git a/Moose Development/Moose/Wrapper/DynamicCargo.lua b/Moose Development/Moose/Wrapper/DynamicCargo.lua index 82b9074bb..6665f782e 100644 --- a/Moose Development/Moose/Wrapper/DynamicCargo.lua +++ b/Moose Development/Moose/Wrapper/DynamicCargo.lua @@ -30,6 +30,8 @@ -- @field #table DCS#Vec3 LastPosition. -- @field #number Interval Check Interval. 20 secs default. -- @field #boolean testing +-- @field Core.Timer#TIMER timer Timmer to run intervals +-- @field #string Owner The playername who has created, loaded or unloaded this cargo. Depends on state. -- @extends Wrapper.Positionable#POSITIONABLE --- *The capitalist cannot store labour-power in warehouses after he has bought it, as he may do with the raw material.* -- Karl Marx @@ -48,6 +50,8 @@ DYNAMICCARGO = { ClassName = "DYNAMICCARGO", verbose = 0, testing = true, + Interval = 10, + } --- Liquid types. @@ -109,17 +113,18 @@ DYNAMICCARGO.AircraftTypes = { --- Helo types possible. -- @type DYNAMICCARGO.AircraftDimensions DYNAMICCARGO.AircraftDimensions = { + -- CH-47 model start coordinate is quite exactly in the middle of the model, so half values here ["CH-47Fbl1"] = { - ["width"] = 8, + ["width"] = 4, ["height"] = 6, - ["length"] = 22, + ["length"] = 11, ["ropelength"] = 30, }, } --- DYNAMICCARGO class version. -- @field #string version -DYNAMICCARGO.version="0.0.1" +DYNAMICCARGO.version="0.0.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -137,7 +142,7 @@ DYNAMICCARGO.version="0.0.1" -- @return #DYNAMICCARGO self function DYNAMICCARGO:Register(CargoName) - -- Inherit everything from BASE class. + -- Inherit everything from a BASE class. local self=BASE:Inherit(self, POSITIONABLE:New(CargoName)) -- #DYNAMICCARGO self.StaticName = CargoName @@ -146,7 +151,7 @@ function DYNAMICCARGO:Register(CargoName) self.CargoState = DYNAMICCARGO.State.NEW - self.Interval = 10 + self.Interval = DYNAMICCARGO.Interval or 10 local DCSObject = self:GetDCSObject() @@ -157,7 +162,10 @@ function DYNAMICCARGO:Register(CargoName) self.lid = string.format("DYNAMICCARGO %s", CargoName) - self:ScheduleOnce(self.Interval,DYNAMICCARGO._UpdatePosition,self) + self.Owner = string.match(CargoName,"^(.+)|%d%d:%d%d|PKG%d+") or "None" + + self.timer = TIMER:New(DYNAMICCARGO._UpdatePosition,self) + self.timer:Start(self.Interval,self.Interval) if not _DYNAMICCARGO_HELOS then _DYNAMICCARGO_HELOS = SET_CLIENT:New():FilterAlive():FilterFunction(DYNAMICCARGO._FilterHeloTypes):FilterStart() @@ -181,6 +189,35 @@ end -- User API Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Get last know owner (player) name of this DYNAMICCARGO +-- @param #DYNAMICCARGO self +-- @return DCS#Vec3 Position in 3D space +function DYNAMICCARGO:GetLastPosition() + return self.Owner +end + +--- [CTLD] Get number of crates this DYNAMICCARGO consists of. Always one. +-- @param #DYNAMICCARGO self +-- @return #number crate number, always one +function DYNAMICCARGO:GetCratesNeeded() + return 1 +end + +--- [CTLD] Get this DYNAMICCARGO drop state. True if DYNAMICCARGO.State.UNLOADED +-- @param #DYNAMICCARGO self +-- @return #boolean Dropped +function DYNAMICCARGO:WasDropped() + return self.CargoState == DYNAMICCARGO.State.UNLOADED and true or false +end + +--- [CTLD] Get CTLD_CARGO.Enum type of this DYNAMICCARGO +-- @param #DYNAMICCARGO self +-- @return #string Type, only one at the moment is CTLD_CARGO.Enum.GCLOADABLE +function DYNAMICCARGO:GetType() + return CTLD_CARGO.Enum.GCLOADABLE +end + + --- Find last known position of this DYNAMICCARGO -- @param #DYNAMICCARGO self -- @return DCS#Vec3 Position in 3D space @@ -290,6 +327,51 @@ end -- Private Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- [Internal] _Get Possible Player Helo Nearby +-- @param #DYNAMICCARGO self +-- @param Core.Point#COORDINATE pos +-- @param #boolean loading If true measure distance for loading else for unloading +-- @return #boolean Success +-- @return Wrapper.Client#CLIENT Helo +-- @return #string PlayerName +function DYNAMICCARGO:_GetPossibleHeloNearby(pos,loading) + local set = _DYNAMICCARGO_HELOS:GetAliveSet() + local success = false + local Helo = nil + local Playername = nil + for _,_helo in pairs (set or {}) do + local helo = _helo -- Wrapper.Client#CLIENT + local name = helo:GetPlayerName() or "None" + self:T(self.lid.." Checking: "..name) + local hpos = helo:GetCoordinate() + -- TODO Unloading via sling load? + local inair = hpos.y-hpos:GetLandHeight() > 4 and true or false + local typename = helo:GetTypeName() + if hpos and typename and inair == false then + local dimensions = DYNAMICCARGO.AircraftDimensions[typename] + if dimensions then + local delta2D = hpos:Get2DDistance(pos) + local delta3D = hpos:Get3DDistance(pos) + if self.testing then + self:T(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D)) + self:T(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength)) + end + if loading~=true and delta2D > dimensions.length or delta2D > dimensions.width or delta3D > dimensions.ropelength then + success = true + Helo = helo + Playername = name + end + if loading == true and delta2D < dimensions.length or delta2D < dimensions.width or delta3D < dimensions.ropelength then + success = true + Helo = helo + Playername = name + end + end + end + end + return success,Helo,Playername +end + --- [Internal] Update internal states. -- @param #DYNAMICCARGO self -- @return #DYNAMICCARGO self @@ -298,15 +380,22 @@ function DYNAMICCARGO:_UpdatePosition() if self:IsAlive() then local pos = self:GetCoordinate() if self.testing then - self:I(string.format("Cargo position: x=%d, y=%d, z=%d",pos.x,pos.y,pos.z)) - self:I(string.format("Last position: x=%d, y=%d, z=%d",self.LastPosition.x,self.LastPosition.y,self.LastPosition.z)) + self:T(string.format("Cargo position: x=%d, y=%d, z=%d",pos.x,pos.y,pos.z)) + self:T(string.format("Last position: x=%d, y=%d, z=%d",self.LastPosition.x,self.LastPosition.y,self.LastPosition.z)) end if UTILS.Round(UTILS.VecDist3D(pos,self.LastPosition),2) > 0.5 then - -- moved + --------------- + -- LOAD Cargo + --------------- if self.CargoState == DYNAMICCARGO.State.NEW then - self:I(self.lid.." moved! NEW -> LOADED") + local isloaded, client, playername = self:_GetPossibleHeloNearby(pos,true) + self:T(self.lid.." moved! NEW -> LOADED by "..playername) self.CargoState = DYNAMICCARGO.State.LOADED + self.Owner = playername _DATABASE:CreateEventDynamicCargoLoaded(self) + --------------- + -- UNLOAD Cargo + --------------- elseif self.CargoState == DYNAMICCARGO.State.LOADED then -- TODO add checker if we are in flight somehow -- ensure not just the helo is moving @@ -317,49 +406,29 @@ function DYNAMICCARGO:_UpdatePosition() agl = UTILS.Round(agl,2) self:T(self.lid.." AGL: "..agl or -1) local isunloaded = true + local client + local playername if count > 0 and (agl > 0 or self.testing) then self:T(self.lid.." Possible alive helos: "..count or -1) if agl ~= 0 or self.testing then - isunloaded = false - local set = _DYNAMICCARGO_HELOS:GetAliveSet() - for _,_helo in pairs (set or {}) do - local helo = _helo -- Wrapper.Client#CLIENT - self:I(self.lid.." Checking: "..helo:GetPlayerName()) - local hpos = helo:GetCoordinate() - hpos:MarkToAll("Helo position",true,"helo") - pos:MarkToAll("Cargo position",true,"cargo") - local typename = helo:GetTypeName() - if hpos then - local dimensions = DYNAMICCARGO.AircraftDimensions[typename] - if dimensions then - hpos:SmokeOrange() - local delta2D = hpos:Get2DDistance(pos) - local delta3D = hpos:Get3DDistance(pos) - if self.testing then - self:I(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D)) - self:I(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength)) - end - if delta2D > dimensions.length or delta2D > dimensions.width or delta3D > dimensions.ropelength then - isunloaded = true - end - end - end - end + isunloaded, client, playername = self:_GetPossibleHeloNearby(pos,false) end if isunloaded then - self:I(self.lid.." moved! LOADED -> UNLOADED") + self:T(self.lid.." moved! LOADED -> UNLOADED by "..playername) self.CargoState = DYNAMICCARGO.State.UNLOADED + self.Owner = playername _DATABASE:CreateEventDynamicCargoUnloaded(self) end end end self.LastPosition = pos end - -- come back laters - self:ScheduleOnce(self.Interval,DYNAMICCARGO._UpdatePosition,self) else - -- we are dead - self:I(self.lid.." dead! " ..self.CargoState.."-> REMOVED") + --------------- + -- REMOVED Cargo + --------------- + if self.timer and self.timer:IsRunning() then self.timer:Stop() end + self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED") self.CargoState = DYNAMICCARGO.State.REMOVED _DATABASE:CreateEventDynamicCargoRemoved(self) end