diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 6a76b5349..42e8d61cb 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -4220,7 +4220,7 @@ function WAREHOUSE:_AssetItemInfo(asset) text=text..string.format("Cargo bay max = %5.2f kg\n", asset.cargobaymax) text=text..string.format("Load radius = %s m\n", tostring(asset.loadradius)) text=text..string.format("Skill = %s\n", tostring(asset.skill)) - text=text..string.format("Livery = %s", tostring(asset.livery)) + text=text..string.format("Livery = %s", tostring(asset.livery)) self:I(self.lid..text) self:T({DCSdesc=asset.DCSdesc}) self:T3({Template=asset.template}) diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 8e330e9f8..98d2992a2 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -896,10 +896,13 @@ function ARMYGROUP:onafterSpawned(From, Event, To) -- Will be set in update route. --self.option.Formation=self.optionDefault.Formation end + + -- Number of waypoints. + local Nwp=#self.waypoints -- Update route. - if #self.waypoints>1 then - self:T(self.lid.."Got waypoints on spawn ==> Cruise in -0.1 sec!") + if Nwp>1 and self.isMobile then + self:T(self.lid..string.format("Got %d waypoints on spawn ==> Cruise in -1.0 sec!", Nwp)) self:__Cruise(-1, nil, self.option.Formation) else self:T(self.lid.."No waypoints on spawn ==> Full Stop!") @@ -920,8 +923,13 @@ end -- @param #number Speed Speed in knots. Default cruise speed. -- @param #number Formation Formation of the group. function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation) + + -- Is transition allowed? We assume yes until proven otherwise. + local allowed=true + local trepeat=nil + if self:IsWaiting() then - self:T(self.lid.."Update route denied. Group is WAIRING!") + self:T(self.lid.."Update route denied. Group is WAITING!") return false elseif self:IsInUtero() then self:T(self.lid.."Update route denied. Group is INUTERO!") @@ -936,7 +944,54 @@ function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation) self:T(self.lid.."Update route denied. Group is holding position!") return false end - return true + + -- Check for a current task. + if self.taskcurrent>0 then + + -- Get the current task. Must not be executing already. + local task=self:GetTaskByID(self.taskcurrent) + + if task then + if task.dcstask.id=="PatrolZone" then + -- For patrol zone, we need to allow the update as we insert new waypoints. + self:T2(self.lid.."Allowing update route for Task: PatrolZone") + elseif task.dcstask.id=="ReconMission" then + -- For recon missions, we need to allow the update as we insert new waypoints. + self:T2(self.lid.."Allowing update route for Task: ReconMission") + elseif task.dcstask.id==AUFTRAG.SpecialTask.RELOCATECOHORT then + -- For relocate + self:T2(self.lid.."Allowing update route for Task: Relocate Cohort") + else + local taskname=task and task.description or "No description" + self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname))) + allowed=false + end + else + -- Now this can happen, if we directly use TaskExecute as the task is not in the task queue and cannot be removed. Therefore, also directly executed tasks should be added to the queue! + self:T(self.lid..string.format("WARNING: before update route taskcurrent=%d (>0!) but no task?!", self.taskcurrent)) + -- Anyhow, a task is running so we do not allow to update the route! + allowed=false + end + end + + -- Not good, because mission will never start. Better only check if there is a current task! + --if self.currentmission then + --end + + -- Only AI flights. + if not self.isAI then + allowed=false + end + + -- Debug info. + self:T2(self.lid..string.format("Onbefore Updateroute in state %s: allowed=%s (repeat in %s)", self:GetState(), tostring(allowed), tostring(trepeat))) + + -- Try again? + if trepeat then + self:__UpdateRoute(trepeat, n) + end + + return allowed end --- On after "UpdateRoute" event. @@ -1239,6 +1294,33 @@ function ARMYGROUP:onafterRearmed(From, Event, To) self:_CheckGroupDone(1) end +--- On before "RTZ" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Core.Zone#ZONE Zone The zone to return to. +-- @param #number Formation Formation of the group. +function ARMYGROUP:onbeforeRTZ(From, Event, To, Zone, Formation) + + -- Zone. + local zone=Zone or self.homezone + + if zone then + + if (not self.isMobile) and (not self:IsInZone(zone)) then + self:Teleport(zone:GetCoordinate(), 0, true) + self:__RTZ(-1, Zone, Formation) + return false + end + + else + return false + end + + return true +end + --- On after "RTZ" event. -- @param #ARMYGROUP self -- @param #string From From state. @@ -1618,8 +1700,12 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation) -- Not waiting anymore. self.Twaiting=nil self.dTwait=nil + + -- Debug info. + self:T(self.lid.."Cruise ==> Update route in 0.01 sec") - self:__UpdateRoute(-0.1, nil, nil, Speed, Formation) + -- Update route. + self:__UpdateRoute(-0.01, nil, nil, Speed, Formation) end @@ -1712,6 +1798,13 @@ function ARMYGROUP:_InitGroup(Template) -- Max speed in km/h. self.speedMax=self.group:GetSpeedMax() + -- Is group mobile? + if self.speedMax>3.6 then + self.isMobile=true + else + self.isMobile=false + end + -- Cruise speed in km/h self.speedCruise=self.speedMax*0.7 diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 6cc77618f..35276066f 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -3097,6 +3097,13 @@ function FLIGHTGROUP:_InitGroup(Template) -- Max speed in km/h. self.speedMax=group:GetSpeedMax() + + -- Is group mobile? + if self.speedMax>3.6 then + self.isMobile=true + else + self.isMobile=false + end -- Cruise speed limit 350 kts for fixed and 80 knots for rotary wings. local speedCruiseLimit=self.isHelo and UTILS.KnotsToKmph(80) or UTILS.KnotsToKmph(350) diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index e32952ab9..a94a6568f 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -145,7 +145,7 @@ INTEL = { --- Contact or cluster type. -- @type INTEL.Ctype --- @field #string GROUND Ground. +-- @field #string GROUND Ground. -- @field #string NAVAL Ship. -- @field #string AIRCRAFT Airpane or helicopter. -- @field #string STRUCTURE Static structure. @@ -349,7 +349,7 @@ function INTEL:New(DetectionSet, Coalition, Alias) -- @param #INTEL self -- @param #number delay Delay in seconds. -- @param #INTEL.Cluster Cluster Detected cluster. - + --- On After "NewCluster" event. -- @function [parent=#INTEL] OnAfterNewCluster -- @param #INTEL self @@ -753,10 +753,10 @@ function INTEL:UpdateIntel() -- Set of all detected units. local DetectedUnits={} - + -- Set of which units was detected by which recce local RecceDetecting = {} - + -- Loop over all units providing intel. for _,_group in pairs(self.detectionset.Set or {}) do local group=_group --Wrapper.Group#GROUP @@ -863,8 +863,8 @@ function INTEL:UpdateIntel() if self.clusteranalysis then self:PaintPicture() end - - return self + + return self end --- Update an #INTEL.Contact item. @@ -874,11 +874,11 @@ end function INTEL:_UpdateContact(Contact) if Contact.isStatic then - + -- Statics don't need to be updated. - + else - + if Contact.group and Contact.group:IsAlive() then Contact.Tdetected=timer.getAbsTime() @@ -899,7 +899,7 @@ function INTEL:_UpdateContact(Contact) end end end - + end return self end @@ -915,11 +915,11 @@ function INTEL:_CreateContact(Positionable, RecceName) -- Create new contact. local item={} --#INTEL.Contact - + if Positionable:IsInstanceOf("GROUP") then - + local group=Positionable --Wrapper.Group#GROUP - + item.groupname=group:GetName() item.group=group item.Tdetected=timer.getAbsTime() @@ -952,13 +952,13 @@ function INTEL:_CreateContact(Positionable, RecceName) elseif item.category==Group.Category.SHIP then item.ctype=INTEL.Ctype.NAVAL end - + return item - + elseif Positionable:IsInstanceOf("STATIC") then - + local static=Positionable --Wrapper.Static#STATIC - + item.groupname=static:GetName() item.group=static item.Tdetected=timer.getAbsTime() @@ -973,14 +973,14 @@ function INTEL:_CreateContact(Positionable, RecceName) item.recce=RecceName item.isground = true item.isship = false - item.isStatic=true + item.isStatic=true item.ctype=INTEL.Ctype.STRUCTURE - - return item + + return item else self:E(self.lid..string.format("ERROR: object needs to be a GROUP or STATIC!")) end - + end return nil @@ -1005,7 +1005,7 @@ function INTEL:CreateDetectedItems(DetectedGroups, DetectedStatics, RecceDetecti self:KnowObject(group, RecceDetecting[groupname]) end - + -- Loop over statics. for staticname,_static in pairs(DetectedStatics) do local static=_static --Wrapper.Static#STATIC @@ -1105,7 +1105,7 @@ function INTEL:onafterNewContact(From, Event, To, Contact) -- Debug text. self:F(self.lid..string.format("NEW contact %s", Contact.groupname)) - + -- Add to table of unknown contacts. table.insert(self.ContactsUnknown, Contact) return self @@ -1121,7 +1121,7 @@ function INTEL:onafterLostContact(From, Event, To, Contact) -- Debug text. self:F(self.lid..string.format("LOST contact %s", Contact.groupname)) - + -- Add to table of lost contacts. table.insert(self.ContactsLost, Contact) return self @@ -1134,10 +1134,10 @@ end -- @param #string To To state. -- @param #INTEL.Cluster Cluster Detected cluster. function INTEL:onafterNewCluster(From, Event, To, Cluster) - + -- Debug text. self:F(self.lid..string.format("NEW cluster #%d [%s] of size %d", Cluster.index, Cluster.ctype, Cluster.size)) - + -- Add cluster to table. self:_AddCluster(Cluster) return self @@ -1154,12 +1154,12 @@ function INTEL:onafterLostCluster(From, Event, To, Cluster, Mission) -- Debug text. local text = self.lid..string.format("LOST cluster #%d [%s]", Cluster.index, Cluster.ctype) - + if Mission then local mission=Mission --Ops.Auftrag#AUFTRAG text=text..string.format(" mission name=%s type=%s target=%s", mission.name, mission.type, mission:GetTargetName() or "unknown") end - + self:T(text) return self end @@ -1178,47 +1178,47 @@ function INTEL:KnowObject(Positionable, RecceName, Tdetected) local Tnow=timer.getAbsTime() Tdetected=Tdetected or Tnow - + if Positionable and Positionable:IsAlive() then if Tdetected>Tnow then -- Delay call. self:ScheduleOnce(Tdetected-Tnow, self.KnowObject, self, Positionable, RecceName) else - + -- Name of the object. local name=Positionable:GetName() - + -- Try to get the contact by name. local contact=self:GetContactByName(name) - + if contact then - + -- Update contact info. self:_UpdateContact(contact) - + else - + -- Create new contact. contact=self:_CreateContact(Positionable, RecceName) - + if contact then - + -- Debug info. self:T(string.format("%s contact detected by %s", contact.groupname, RecceName or "unknown")) - + -- Add contact to table. self:AddContact(contact) - + -- Trigger new contact event. self:NewContact(contact) - + end - + end end end - + return self end @@ -1268,7 +1268,7 @@ function INTEL:AddContact(Contact) self:T(self.lid..string.format("Adding new Contact %s to table", tostring(Contact.groupname))) table.insert(self.Contacts, Contact) end - + return self end @@ -1298,7 +1298,7 @@ function INTEL:_CheckContactLost(Contact) if Contact.group==nil or not Contact.group:IsAlive() then return true end - + -- We never forget statics as they don't move. if Contact.isStatic then return false @@ -1308,7 +1308,7 @@ function INTEL:_CheckContactLost(Contact) local dT=timer.getAbsTime()-Contact.Tdetected local dTforget=nil - + if Contact.category==Group.Category.GROUND then dTforget=60*60*2 -- 2 hours elseif Contact.category==Group.Category.AIRPLANE then @@ -1341,80 +1341,80 @@ function INTEL:PaintPicture() -- First remove all lost contacts from clusters. for _,_contact in pairs(self.ContactsLost) do local contact=_contact --#INTEL.Contact - + -- Get cluster this contact belongs to (if any). local cluster=self:GetClusterOfContact(contact) - + if cluster then self:RemoveContactFromCluster(contact, cluster) end end - + -- Clean up cluster table. local ClusterSet = {} - + -- Now check if whole clusters were lost. for _i,_cluster in pairs(self.Clusters) do local cluster=_cluster --#INTEL.Cluster - + if cluster.size>0 and self:ClusterCountUnits(cluster)>0 then -- This one has size>0 and units>0 table.insert(ClusterSet,_cluster) else - + -- This cluster is gone. - -- Remove marker. + -- Remove marker. if cluster.marker then cluster.marker:Remove() end - + -- Marker of the arrow. if cluster.markerID then COORDINATE:RemoveMark(cluster.markerID) end - + -- Lost cluster. self:LostCluster(cluster, cluster.mission) end end - + -- Set Clusters. self.Clusters = ClusterSet -- Update positions. self:_UpdateClusterPositions() - + for _,_contact in pairs(self.Contacts) do local contact=_contact --#INTEL.Contact - + -- Debug info. self:T(string.format("Paint Picture: checking for %s",contact.groupname)) -- Get the current cluster (if any) this contact belongs to. local currentcluster=self:GetClusterOfContact(contact) - if currentcluster then + if currentcluster then --- -- Contact is currently part of a cluster. --- -- Check if the contact is still connected to the cluster. local isconnected=self:IsContactConnectedToCluster(contact, currentcluster) - + if isconnected then - + else - + --- Not connected to current cluster any more. - + -- Remove from current cluster. self:RemoveContactFromCluster(contact, currentcluster) - + -- Find new cluster. local cluster=self:_GetClosestClusterOfContact(contact) - + if cluster then -- Add contact to cluster. self:AddContactToCluster(contact, cluster) @@ -1422,11 +1422,11 @@ function INTEL:PaintPicture() -- Create a new cluster. local newcluster=self:_CreateClusterFromContact(contact) - + -- Trigger new cluster event. self:NewCluster(newcluster) end - + end else @@ -1434,26 +1434,26 @@ function INTEL:PaintPicture() --- -- Contact is not in any cluster yet. --- - + -- Debug info. self:T(self.lid..string.format("Paint Picture: contact %s has NO current cluster", contact.groupname)) - + -- Get the closest existing cluster of this contact. local cluster=self:_GetClosestClusterOfContact(contact) if cluster then - + -- Debug info. self:T(self.lid..string.format("Paint Picture: contact %s has closest cluster #%d",contact.groupname, cluster.index)) - + -- Add contact to this cluster. self:AddContactToCluster(contact, cluster) - + else -- Create a brand new cluster. local newcluster=self:_CreateClusterFromContact(contact) - + -- Trigger event for a new cluster. self:NewCluster(newcluster) end @@ -1470,19 +1470,19 @@ function INTEL:PaintPicture() for _,_cluster in pairs(self.Clusters) do local cluster=_cluster --#INTEL.Cluster --local coordinate=self:GetClusterCoordinate(cluster) - + -- Update F10 marker. MESSAGE:New("Updating cluster marker and future position", 10):ToAll() - + -- Update cluster markers. self:UpdateClusterMarker(cluster) - + -- Extrapolate future position of the cluster. self:CalcClusterFuturePosition(cluster, 300) - + end end - + return self end @@ -1515,15 +1515,15 @@ end function INTEL:_CreateClusterFromContact(Contact) local cluster=self:_CreateCluster() - + self:T(self.lid..string.format("Created NEW cluster #%d with first contact %s", cluster.index, Contact.groupname)) cluster.coordinate:UpdateFromCoordinate(Contact.position) cluster.ctype=Contact.ctype - + self:AddContactToCluster(Contact, cluster) - + return cluster end @@ -1536,7 +1536,7 @@ function INTEL:_AddCluster(Cluster) -- Add cluster. table.insert(self.Clusters, Cluster) - + return self end @@ -1547,7 +1547,7 @@ end function INTEL:AddContactToCluster(contact, cluster) if contact and cluster then - + -- Add neighbour to cluster contacts. table.insert(cluster.Contacts, contact) @@ -1556,14 +1556,14 @@ function INTEL:AddContactToCluster(contact, cluster) -- Increase size. cluster.size=cluster.size+1 - + -- alt self:GetClusterAltitude(cluster,true) - + -- Debug info. self:T(self.lid..string.format("Adding contact %s to cluster #%d [%s] ==> New size=%d", contact.groupname, cluster.index, cluster.ctype, cluster.size)) end - + return self end @@ -1582,7 +1582,7 @@ function INTEL:RemoveContactFromCluster(contact, cluster) -- Remove threat level sum. cluster.threatlevelSum=cluster.threatlevelSum-contact.threatlevel - + -- Decrease cluster size. cluster.size=cluster.size-1 @@ -1662,13 +1662,13 @@ function INTEL:CalcClusterDirection(cluster) local n=0 for _,_contact in pairs(cluster.Contacts) do local contact=_contact --#INTEL.Contact - + if (not contact.isStatic) and contact.group:IsAlive() then direction = direction + contact.group:GetHeading() n=n+1 end end - + --TODO: This calculation is WRONG! -- Simple example for two groups: -- First group is going West, i.e. heading 090 @@ -1677,7 +1677,7 @@ function INTEL:CalcClusterDirection(cluster) -- It should not go anywhere as the two movements cancel each other. -- Correct, edge case for N=2^x, but when 2 pairs of groups drive in exact opposite directions, the cluster will split at some point? -- maybe add the speed as weight to get a factor - + if n==0 then return 0 else @@ -1694,17 +1694,17 @@ function INTEL:CalcClusterSpeed(cluster) local velocity = 0 ; local n=0 for _,_contact in pairs(cluster.Contacts) do local contact=_contact --#INTEL.Contact - + if (not contact.isStatic) and contact.group:IsAlive() then velocity = velocity + contact.group:GetVelocityMPS() n=n+1 end - + end - + if n==0 then return 0 - else + else return math.floor(velocity / n) end end @@ -1716,10 +1716,10 @@ end function INTEL:CalcClusterVelocityVec3(cluster) local v={x=0, y=0, z=0} --DCS#Vec3 - + for _,_contact in pairs(cluster.Contacts) do local contact=_contact --#INTEL.Contact - + if (not contact.isStatic) and contact.group:IsAlive() then local vec=contact.group:GetVelocityVec3() v.x=v.x+vec.x @@ -1727,7 +1727,7 @@ function INTEL:CalcClusterVelocityVec3(cluster) v.z=v.y+vec.z end end - + return v end @@ -1737,22 +1737,22 @@ end -- @param #number seconds Time interval in seconds. Default is `self.prediction`. -- @return Core.Point#COORDINATE Calculated future position of the cluster. function INTEL:CalcClusterFuturePosition(cluster, seconds) - + -- Get current position of the cluster. local p=self:GetClusterCoordinate(cluster) - + -- Velocity vector in m/s. local v=self:CalcClusterVelocityVec3(cluster) - + -- Time in seconds. local t=seconds or self.prediction - -- Extrapolated vec3. + -- Extrapolated vec3. local Vec3={x=p.x+v.x*t, y=p.y+v.y*t, z=p.z+v.z*t} - + -- Future position. local futureposition=COORDINATE:NewFromVec3(Vec3) - + -- Create an arrow pointing in the direction of the movement. if self.clustermarkers and self.verbose>1 then if cluster.markerID then @@ -1760,7 +1760,7 @@ function INTEL:CalcClusterFuturePosition(cluster, seconds) end cluster.markerID = p:ArrowToAll(futureposition, self.coalition, {1,0,0}, 1, {1,1,0}, 0.5, 2, true, "Position Calc") end - + return futureposition end @@ -1798,7 +1798,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster) if contact.ctype~=cluster.ctype then return false, math.huge end - + for _,_contact in pairs(cluster.Contacts) do local Contact=_contact --#INTEL.Contact @@ -1807,7 +1807,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster) --local dist=Contact.position:Get2DDistance(contact.position) local dist=Contact.position:DistanceFromPointVec2(contact.position) - + -- AIR - check for spatial proximity local airprox = false if contact.ctype == INTEL.Ctype.AIRCRAFT then @@ -1817,7 +1817,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster) airprox = true end end - + if dist0 then avgalt = newalt/n end - + -- Update cluster coordinate. Cluster.altitude = avgalt - + self:T(string.format("Updating Cluster Altitude: %d",Cluster.altitude)) - + return Cluster.altitude end @@ -1982,35 +1982,44 @@ function INTEL:GetClusterCoordinate(Cluster, Update) -- Init. local x=0 ; local y=0 ; local z=0 ; local n=0 - + -- Loop over all contacts. for _,_contact in pairs(Cluster.Contacts) do local contact=_contact --#INTEL.Contact - + local vec3=nil --DCS#Vec3 - - if Update and contact.group:IsAlive() then + + if Update and contact.group and contact.group:IsAlive() then vec3 = contact.group:GetVec3() - else - vec3 = contact.position end - - -- Sum up posits. + + if not vec3 then + vec3=contact.position + end + if vec3 then + + -- Sum up posits. x=x+vec3.x y=y+vec3.y z=z+vec3.z - + -- Increase counter. n=n+1 + end + end - -- Average. - local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3 - - -- Update cluster coordinate. - Cluster.coordinate:UpdateFromVec3(Vec3) + if n>0 then + + -- Average. + local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3 + + -- Update cluster coordinate. + Cluster.coordinate:UpdateFromVec3(Vec3) + + end return Cluster.coordinate end @@ -2024,7 +2033,7 @@ end function INTEL:_CheckClusterCoordinateChanged(Cluster, Coordinate, Threshold) Threshold=Threshold or 100 - + Coordinate=Coordinate or Cluster.coordinate -- Positions of cluster. @@ -2046,11 +2055,11 @@ end function INTEL:_UpdateClusterPositions() for _,_cluster in pairs (self.Clusters) do local cluster=_cluster --#INTEL.Cluster - + -- Update cluster coordinate. local coord = self:GetClusterCoordinate(cluster, true) local alt = self:GetClusterAltitude(cluster,true) - + -- Debug info. self:T(self.lid..string.format("Updating Cluster position size: %s", cluster.size)) end @@ -2070,7 +2079,7 @@ function INTEL:ContactCountUnits(Contact) end else if Contact.group then - local n=Contact.group:CountAliveUnits() + local n=Contact.group:CountAliveUnits() return n else return 0 @@ -2084,7 +2093,7 @@ end -- @return #number unitcount function INTEL:ClusterCountUnits(Cluster) local unitcount = 0 - for _,_contact in pairs (Cluster.Contacts) do + for _,_contact in pairs (Cluster.Contacts) do local contact=_contact --#INTEL.Contact unitcount = unitcount + self:ContactCountUnits(contact) end @@ -2102,10 +2111,10 @@ function INTEL:UpdateClusterMarker(cluster) local text=string.format("Cluster #%d: %s\nSize %d\nUnits %d\nTLsum=%d", cluster.index, cluster.ctype, cluster.size, unitcount, cluster.threatlevelSum) if not cluster.marker then - + -- First time ==> need to create a new marker object. cluster.marker=MARKER:New(cluster.coordinate, text):ToCoalition(self.coalition) - + else -- Need to refresh? @@ -2118,7 +2127,7 @@ function INTEL:UpdateClusterMarker(cluster) end -- Check if coordinate changed. - local coordchange=self:_CheckClusterCoordinateChanged(cluster, cluster.marker.coordinate) + local coordchange=self:_CheckClusterCoordinateChanged(cluster, cluster.marker.coordinate) if coordchange then cluster.marker.coordinate:UpdateFromCoordinate(cluster.coordinate) refresh=true @@ -2197,22 +2206,22 @@ INTEL_DLINK.version = "0.0.1" -- Contact duplicates are removed. Clusters might contain duplicates (Might fix that later, WIP). -- -- Basic setup: --- +-- -- local datalink = INTEL_DLINK:New({myintel1,myintel2}), "FSB", 20, 300) -- datalink:__Start(2) -- -- Add an Intel while running: --- +-- -- datalink:AddIntel(myintel3) -- -- Gather the data: --- +-- -- datalink:GetContactTable() -- #table of #INTEL.Contact contacts. -- datalink:GetClusterTable() -- #table of #INTEL.Cluster clusters. -- datalink:GetDetectedItemCoordinates() -- #table of contact coordinates, to be compatible with @{Functional.Detection#DETECTION}. -- -- Gather data with the event function: --- +-- -- function datalink:OnAfterCollected(From, Event, To, Contacts, Clusters) -- ... ... -- end diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 5479e94f2..2acd1c706 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -83,7 +83,6 @@ function LEGION:New(WarehouseName, LegionName) self.lid=string.format("LEGION %s | ", self.alias) -- Defaults: - -- TODO: What? self:SetMarker(false) -- Dead and crash events are handled via opsgroups. diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index a770297b0..5c1cd9781 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -1021,23 +1021,75 @@ end -- @param #number Speed Speed in knots to the next waypoint. -- @param #number Depth Depth in meters to the next waypoint. function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth) + -- Is transition allowed? We assume yes until proven otherwise. + local allowed=true + local trepeat=nil + if self:IsWaiting() then - self:E(self.lid.."Update route denied. Group is WAITING!") + self:T(self.lid.."Update route denied. Group is WAITING!") return false elseif self:IsInUtero() then - self:E(self.lid.."Update route denied. Group is INUTERO!") + self:T(self.lid.."Update route denied. Group is INUTERO!") return false elseif self:IsDead() then - self:E(self.lid.."Update route denied. Group is DEAD!") + self:T(self.lid.."Update route denied. Group is DEAD!") return false elseif self:IsStopped() then - self:E(self.lid.."Update route denied. Group is STOPPED!") + self:T(self.lid.."Update route denied. Group is STOPPED!") return false elseif self:IsHolding() then self:T(self.lid.."Update route denied. Group is holding position!") - return false + return false end - return true + + -- Check for a current task. + if self.taskcurrent>0 then + + -- Get the current task. Must not be executing already. + local task=self:GetTaskByID(self.taskcurrent) + + if task then + if task.dcstask.id=="PatrolZone" then + -- For patrol zone, we need to allow the update as we insert new waypoints. + self:T2(self.lid.."Allowing update route for Task: PatrolZone") + elseif task.dcstask.id=="ReconMission" then + -- For recon missions, we need to allow the update as we insert new waypoints. + self:T2(self.lid.."Allowing update route for Task: ReconMission") + elseif task.dcstask.id==AUFTRAG.SpecialTask.RELOCATECOHORT then + -- For relocate + self:T2(self.lid.."Allowing update route for Task: Relocate Cohort") + else + local taskname=task and task.description or "No description" + self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname))) + allowed=false + end + else + -- Now this can happen, if we directly use TaskExecute as the task is not in the task queue and cannot be removed. Therefore, also directly executed tasks should be added to the queue! + self:T(self.lid..string.format("WARNING: before update route taskcurrent=%d (>0!) but no task?!", self.taskcurrent)) + -- Anyhow, a task is running so we do not allow to update the route! + allowed=false + end + end + + -- Not good, because mission will never start. Better only check if there is a current task! + --if self.currentmission then + --end + + -- Only AI flights. + if not self.isAI then + allowed=false + end + + -- Debug info. + self:T2(self.lid..string.format("Onbefore Updateroute in state %s: allowed=%s (repeat in %s)", self:GetState(), tostring(allowed), tostring(trepeat))) + + -- Try again? + if trepeat then + self:__UpdateRoute(trepeat, n) + end + + return allowed + end --- On after "UpdateRoute" event. @@ -1712,6 +1764,13 @@ function NAVYGROUP:_InitGroup(Template) -- Max speed in km/h. self.speedMax=self.group:GetSpeedMax() + -- Is group mobile? + if self.speedMax>3.6 then + self.isMobile=true + else + self.isMobile=false + end + -- Cruise speed: 70% of max speed. self.speedCruise=self.speedMax*0.7 diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index cbaff0512..c95c7ecea 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -4144,8 +4144,18 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task) -- Debug info. self:T(self.lid..string.format("Fire at point with nshots=%d of %d", nShots, nAmmo)) - -- Only fire number of avail shots. - nShots=math.min(nShots, nAmmo) + if nShots==-1 then + -- The -1 is for using all available ammo. + nShots=nAmmo + self:T(self.lid..string.format("Fire at point taking max amount of ammo = %d", nShots)) + elseif nShots<1 then + local p=nShots + nShots=UTILS.Round(p*nAmmo, 0) + self:T(self.lid..string.format("Fire at point taking %.1f percent amount of ammo = %d", p, nShots)) + else + -- Fire nShots but at most nAmmo. + nShots=math.min(nShots, nAmmo) + end -- Set quantity of task. DCSTask.params.expendQty=nShots