From fac7a5fdc6b816e07d43d4df33325d56ff0ad0eb Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:40:38 +0100 Subject: [PATCH 01/32] Update CTLD.lua (#2058) Add Remove Crates option --- Moose Development/Moose/Ops/CTLD.lua | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 9f0d780bd..07f15ad9d 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -2561,6 +2561,40 @@ function CTLD:_ListCratesNearby( _group, _unit) return self end +-- (Internal) Function to find and Remove nearby crates. +-- @param #CTLD self +-- @param Wrapper.Group#GROUP Group +-- @param Wrapper.Unit#UNIT Unit +-- @return #CTLD self +function CTLD:_RemoveCratesNearby( _group, _unit) + self:T(self.lid .. " _RemoveCratesNearby") + local finddist = self.CrateDistance or 35 + local crates,number = self:_FindCratesNearby(_group,_unit, finddist,true) -- #table + if number > 0 then + local text = REPORT:New("Removing Crates Found Nearby:") + text:Add("------------------------------------------------------------") + for _,_entry in pairs (crates) do + local entry = _entry -- #CTLD_CARGO + local name = entry:GetName() --#string + local dropped = entry:WasDropped() + if dropped then + text:Add(string.format("Crate for %s, %dkg removed",name, entry.PerCrateMass)) + else + text:Add(string.format("Crate for %s, %dkg removed",name, entry.PerCrateMass)) + end + entry:GetPositionable():Destroy(false) + end + if text:GetCount() == 1 then + text:Add(" N O N E") + end + text:Add("------------------------------------------------------------") + self:_SendMessage(text:Text(), 30, true, _group) + else + self:_SendMessage(string.format("No (loadable) crates within %d meters!",finddist), 10, false, _group) + end + return self +end + --- (Internal) Return distance in meters between two coordinates. -- @param #CTLD self -- @param Core.Point#COORDINATE _point1 Coordinate one @@ -3672,6 +3706,7 @@ function CTLD:_RefreshF10Menus() end end listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit) + listmenu = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",topcrates, self._RemoveCratesNearby, self, _group, _unit) local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit) if not self.nobuildmenu then local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit) From bc3a5271dc8ac91304862a21f55b5a4fb574b0ff Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 4 Dec 2023 22:19:31 +0100 Subject: [PATCH 02/32] Update OpsGroup.lua - Fixed group returning to legion when told not to --- Moose Development/Moose/Ops/OpsGroup.lua | 28 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index b5eb4079c..d7cbe4ab6 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -3472,10 +3472,9 @@ function OPSGROUP:RemoveWaypoint(wpindex) -- Could be that the waypoint we are currently moving to was the LAST waypoint. Then we now passed the final waypoint. if (self.adinfinitum or istemp) then - self:_PassedFinalWaypoint(false, "Removed PASSED temporary waypoint ") - end - - + self:_PassedFinalWaypoint(false, "Removed PASSED temporary waypoint") + end + end end @@ -5801,6 +5800,27 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) end end + if self.legion and self.legionReturn==false and self.waypoints and #self.waypoints==1 then + --- + -- This is the case where a group was send on a mission (which is over now), has no addional + -- waypoints or tasks and should NOT return to its legion. + -- We create a new waypoint at the current position and let it hold here. + --- + + local Coordinate=self:GetCoordinate() + + if self.isArmygroup then + ARMYGROUP.AddWaypoint(self, Coordinate, 0, nil, nil, false) + elseif self.isNavygroup then + NAVYGROUP.AddWaypoint(self,Coordinate, 0, nil, nil, false) + end + + -- Remove original waypoint. + self:RemoveWaypoint(1) + + self:_PassedFinalWaypoint(true, "Passed final waypoint as group is done with mission but should NOT return to its legion") + end + -- Check if group is done. self:_CheckGroupDone(delay) From f789fbac709d5127e068ac09b8f52433f062c57a Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 5 Dec 2023 17:48:34 +0100 Subject: [PATCH 03/32] Update Zone.lua - Fixed ZONE_POLYGON:New called without initial points --- Moose Development/Moose/Core/Zone.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 229356455..26a164c83 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -2380,13 +2380,13 @@ function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) self._.Polygon[i].y = PointsArray[i].y end + -- triangulate the polygon so we can work with it + self._Triangles = self:_Triangulate() + -- set the polygon's surface area + self.SurfaceArea = self:_CalculateSurfaceArea() + end - -- triangulate the polygon so we can work with it - self._Triangles = self:_Triangulate() - -- set the polygon's surface area - self.SurfaceArea = self:_CalculateSurfaceArea() - return self end From e078e488531e5d6e5d62276da17c2d293e4843f2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 6 Dec 2023 08:42:07 +0100 Subject: [PATCH 04/32] #SPAWN * Fix for a Link16 flight having a non-NATO callsign as number --- Moose Development/Moose/Core/Spawn.lua | 31 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index e562bfbf5..388b9aafe 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -3321,10 +3321,10 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 SpawnTemplate.units[UnitID].callsign[2] = UnitID SpawnTemplate.units[UnitID].callsign[3] = "1" SpawnTemplate.units[UnitID].callsign["name"] = tostring(callsignname)..tostring(UnitID).."1" - -- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].callsign,1) + -- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].callsign,1) end else - -- Ruskis + -- Russkis for UnitID = 1, #SpawnTemplate.units do SpawnTemplate.units[UnitID].callsign = math.random(1,999) end @@ -3335,7 +3335,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 local Callsign = SpawnTemplate.units[UnitID].callsign if Callsign then if type( Callsign ) ~= "number" then -- blue callsign - --UTILS.PrintTableToLog(Callsign,1) + -- UTILS.PrintTableToLog(Callsign,1) Callsign[2] = ((SpawnIndex - 1) % 10) + 1 local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string CallsignName = string.match(CallsignName,"^(%a+)") -- 2.8 - only the part w/o numbers @@ -3377,11 +3377,11 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 end end -- VoiceCallsignNumber - if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber then + if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber and type( Callsign ) ~= "number" then SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber = SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3] end -- VoiceCallsignLabel - if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel then + if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel and type( Callsign ) ~= "number" then local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string CallsignName = string.match(CallsignName,"^(%a+)") -- 2.8 - only the part w/o numbers local label = "NY" -- Navy One exception @@ -3390,7 +3390,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 end SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel = label end - -- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].AddPropAircraft,1) + -- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].AddPropAircraft,1) -- FlightLead if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.Link16 and SpawnTemplate.units[UnitID].datalinks.Link16.settings then SpawnTemplate.units[UnitID].datalinks.Link16.settings.flightLead = UnitID == 1 and true or false @@ -3399,11 +3399,28 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.SADL and SpawnTemplate.units[UnitID].datalinks.SADL.settings then SpawnTemplate.units[UnitID].datalinks.SADL.settings.flightLead = UnitID == 1 and true or false end - --UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].datalinks,1) + -- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].datalinks,1) + end + end + -- Link16 team members + for UnitID = 1, #SpawnTemplate.units do + if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.Link16 and SpawnTemplate.units[UnitID].datalinks.Link16.network then + local team = {} + local isF16 = string.find(SpawnTemplate.units[UnitID].type,"F-16",1,true) and true or false + for ID = 1, #SpawnTemplate.units do + local member = {} + member.missionUnitId = ID + if isF16 then + member.TDOA = true + end + table.insert(team,member) + end + SpawnTemplate.units[UnitID].datalinks.Link16.network.teamMembers = team end end self:T3( { "Template:", SpawnTemplate } ) + --UTILS.PrintTableToLog(SpawnTemplate,1) return SpawnTemplate end From 88e1bbd60d9c03e32a48c2ad8c49fda63930a1af Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Dec 2023 11:20:43 +0100 Subject: [PATCH 05/32] #SET * Repaired SET_UNIT:GetCoordinate() --- Moose Development/Moose/Core/Set.lua | 41 ++++++++++++++++------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index fec517906..c9cbc9f3a 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -419,7 +419,11 @@ do -- SET_BASE -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetRandom() - local tablemax = table.maxn(self.Index) + local tablemax = 0 + for _,_ind in pairs(self.Index) do + tablemax = tablemax + 1 + end + --local tablemax = table.maxn(self.Index) local RandomItem = self.Set[self.Index[math.random(1,tablemax)]] self:T3( { RandomItem } ) return RandomItem @@ -561,10 +565,12 @@ do -- SET_BASE return self end - --- Iterate the SET_BASE while identifying the nearest object from a @{Core.Point#POINT_VEC2}. + --- Iterate the SET_BASE while identifying the nearest object in the set from a @{Core.Point#POINT_VEC2}. -- @param #SET_BASE self - -- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest object in the set. + -- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#COORDINATE} or @{Core.Point#POINT_VEC2} object (but **not** a simple DCS#Vec2!) from where to evaluate the closest object in the set. -- @return Core.Base#BASE The closest object. + -- @usage + -- myset:FindNearestObjectFromPointVec2( ZONE:New("Test Zone"):GetCoordinate() ) function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ) self:F2( PointVec2 ) @@ -2849,15 +2855,14 @@ do -- SET_UNIT function SET_UNIT:GetCoordinate() local Coordinate = nil - local unit = self:GetRandom() + local unit = self:GetFirst() if self:Count() == 1 and unit then return unit:GetCoordinate() end if unit then - local Coordinate = unit:GetCoordinate() - --self:F({Coordinate:GetVec3()}) - - + Coordinate = unit:GetCoordinate() + self:T2(UTILS.PrintTableToLog(Coordinate:GetVec3())) + local x1 = Coordinate.x local x2 = Coordinate.x local y1 = Coordinate.y @@ -2868,19 +2873,19 @@ do -- SET_UNIT local AvgHeading = nil local MovingCount = 0 - for UnitName, UnitData in pairs( self:GetAliveSet() ) do + for UnitName, UnitData in pairs( self.Set) do local Unit = UnitData -- Wrapper.Unit#UNIT - local Coordinate = Unit:GetCoordinate() + local Coord = Unit:GetCoordinate() - x1 = (Coordinate.x < x1) and Coordinate.x or x1 - x2 = (Coordinate.x > x2) and Coordinate.x or x2 - y1 = (Coordinate.y < y1) and Coordinate.y or y1 - y2 = (Coordinate.y > y2) and Coordinate.y or y2 - z1 = (Coordinate.y < z1) and Coordinate.z or z1 - z2 = (Coordinate.y > z2) and Coordinate.z or z2 + x1 = (Coord.x < x1) and Coord.x or x1 + x2 = (Coord.x > x2) and Coord.x or x2 + y1 = (Coord.y < y1) and Coord.y or y1 + y2 = (Coord.y > y2) and Coord.y or y2 + z1 = (Coord.y < z1) and Coord.z or z1 + z2 = (Coord.y > z2) and Coord.z or z2 - local Velocity = Coordinate:GetVelocity() + local Velocity = Coord:GetVelocity() if Velocity ~= 0 then MaxVelocity = (MaxVelocity < Velocity) and Velocity or MaxVelocity local Heading = Coordinate:GetHeading() @@ -2897,7 +2902,7 @@ do -- SET_UNIT Coordinate:SetHeading( AvgHeading ) Coordinate:SetVelocity( MaxVelocity ) - self:F( { Coordinate = Coordinate } ) + self:T2(UTILS.PrintTableToLog(Coordinate:GetVec3())) end return Coordinate From fe9d841af5ebda6ac44d856ad645dc5acac87ec4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Dec 2023 11:21:52 +0100 Subject: [PATCH 06/32] #PLAYERRECCE * Fixed visual targets not being smoked * Added option to smoke an average coordinate of targets instead of all * Defaulted self-smoking of player to false --- Moose Development/Moose/Ops/PlayerRecce.lua | 79 +++++++++++++-------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index ec3a57954..9c1cb9eb6 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -79,6 +79,7 @@ -- @field Utilities.FiFo#FIFO TargetCache -- @field #boolean smokeownposition -- @field #table SmokeOwn +-- @field #boolean smokeaveragetargetpos -- @extends Core.Fsm#FSM --- @@ -104,7 +105,7 @@ PLAYERRECCE = { ClassName = "PLAYERRECCE", verbose = true, lid = nil, - version = "0.0.22", + version = "0.1.23", ViewZone = {}, ViewZoneVisual = {}, ViewZoneLaser = {}, @@ -130,8 +131,9 @@ PLAYERRECCE = { ReferencePoint = nil, TForget = 600, TargetCache = nil, - smokeownposition = true, + smokeownposition = false, SmokeOwn = {}, + smokeaveragetargetpos = false, } --- @@ -1109,9 +1111,8 @@ function PLAYERRECCE:_SmokeTargets(client,group,playername) self:T(self.lid.."_SmokeTargets") local cameraset = self:_GetTargetSet(client,true) -- Core.Set#SET_UNIT local visualset = self:_GetTargetSet(client,false) -- Core.Set#SET_UNIT - cameraset:AddSet(visualset) - if cameraset:CountAlive() > 0 then + if cameraset:CountAlive() > 0 or visualset:CountAlive() > 0 then self:__TargetsSmoked(-1,client,playername,cameraset) else return self @@ -1126,29 +1127,31 @@ function PLAYERRECCE:_SmokeTargets(client,group,playername) -- laser targer gets extra smoke if laser and laser.Target and laser.Target:IsAlive() then laser.Target:GetCoordinate():Smoke(lasersmoke) - if cameraset:IsInSet(laser.Target) then - cameraset:Remove(laser.Target:GetName(),true) + end + + local coord = visualset:GetCoordinate() + if coord and self.smokeaveragetargetpos then + coord:SetAtLandheight() + coord:Smoke(medsmoke) + else + -- smoke everything + for _,_unit in pairs(visualset.Set) do + local unit = _unit --Wrapper.Unit#UNIT + if unit and unit:IsAlive() then + local coord = unit:GetCoordinate() + local threat = unit:GetThreatLevel() + if coord then + local color = lowsmoke + if threat > 7 then + color = highsmoke + elseif threat > 2 then + color = medsmoke + end + coord:Smoke(color) + end + end end end - - local coordinate = nil - local setthreat = 0 - -- smoke everything else - if cameraset:CountAlive() > 1 then - local coordinate = cameraset:GetCoordinate() - local setthreat = cameraset:CalculateThreatLevelA2G() - end - - if coordinate then - local color = lowsmoke - if setthreat > 7 then - color = medsmoke - elseif setthreat > 2 then - color = lowsmoke - end - coordinate:Smoke(color) - end - if self.SmokeOwn[playername] then local cc = client:GetVec2() -- don't smoke mid-air @@ -1189,15 +1192,15 @@ function PLAYERRECCE:_FlareTargets(client,group,playername) -- smoke everything else for _,_unit in pairs(cameraset.Set) do local unit = _unit --Wrapper.Unit#UNIT - if unit then + if unit and unit:IsAlive() then local coord = unit:GetCoordinate() local threat = unit:GetThreatLevel() if coord then local color = lowsmoke if threat > 7 then - color = medsmoke + color = highsmoke elseif threat > 2 then - color = lowsmoke + color = medsmoke end coord:Flare(color) end @@ -1546,7 +1549,7 @@ end -- @param #PLAYERRECCE self -- @return #PLAYERRECCE self function PLAYERRECCE:EnableSmokeOwnPosition() - self:T(self.lid.."ENableSmokeOwnPosition") + self:T(self.lid.."EnableSmokeOwnPosition") self.smokeownposition = true return self end @@ -1560,6 +1563,24 @@ function PLAYERRECCE:DisableSmokeOwnPosition() return self end +--- [User] Enable smoking of average target positions, instead of all targets visible. Loses smoke per threatlevel -- each is med threat. Default is - smoke all positions. +-- @param #PLAYERRECCE self +-- @return #PLAYERRECCE self +function PLAYERRECCE:EnableSmokeAverageTargetPosition() + self:T(self.lid.."ENableSmokeOwnPosition") + self.smokeaveragetargetpos = true + return self +end + +--- [User] Disable smoking of average target positions, instead of all targets visible. Default is - smoke all positions. +-- @param #PLAYERRECCE self +-- @return #PLAYERRECCE +function PLAYERRECCE:DisableSmokeAverageTargetPosition() + self:T(self.lid.."DisableSmokeAverageTargetPosition") + self.smokeaveragetargetpos = false + return self +end + --- [Internal] Get text for text-to-speech. -- Numbers are spaced out, e.g. "Heading 180" becomes "Heading 1 8 0 ". -- @param #PLAYERRECCE self From dd37a42470bff96230cd7257f141fc71f11460ff Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:12:19 +0100 Subject: [PATCH 07/32] Update CTLD.lua (#2060) Changes from @Rey --- Moose Development/Moose/Ops/CTLD.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 07f15ad9d..fac6173bf 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -3671,6 +3671,7 @@ function CTLD:_RefreshF10Menus() local loadmenu = MENU_GROUP_COMMAND:New(_group,"Load crates",topcrates, self._LoadCratesNearby, self, _group, _unit) local cratesmenu = MENU_GROUP:New(_group,"Get Crates",topcrates) local packmenu = MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) + local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates) if self.usesubcats then local subcatmenus = {} @@ -3706,7 +3707,7 @@ function CTLD:_RefreshF10Menus() end end listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit) - listmenu = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",topcrates, self._RemoveCratesNearby, self, _group, _unit) + removecrates = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu, self._RemoveCratesNearby, self, _group, _unit) local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit) if not self.nobuildmenu then local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit) From 6f473faa924942d2509b27ce5014952c7b87b9f7 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:14:59 +0100 Subject: [PATCH 08/32] Update Message.lua #2059 fixed --- Moose Development/Moose/Core/Message.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 0feeecd2b..8b6da3cdd 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -98,7 +98,7 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen self.MessageType = nil - -- When no MessageCategory is given, we don't show it as a title... + -- When no MessageCategory is given, we don't show it as a title... if MessageCategory and MessageCategory ~= "" then if MessageCategory:sub( -1 ) ~= "\n" then self.MessageCategory = MessageCategory .. ": " @@ -368,7 +368,7 @@ function MESSAGE:ToCoalition( CoalitionSide, Settings ) if CoalitionSide then if self.MessageDuration ~= 0 then self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration ) - trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen ) + trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen ) end end From 9ce1d360d6c921ad072bd3b077d3f89a772a9c37 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Dec 2023 13:31:40 +0100 Subject: [PATCH 09/32] #CTLD * Spawn dropped troops in a nice circle 5m (hover: 1.5m) left of the he --- Moose Development/Moose/Ops/CTLD.lua | 54 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index fac6173bf..095eb28de 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -24,7 +24,7 @@ -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Last Update November 2023 +-- Last Update December 2023 do @@ -1228,7 +1228,7 @@ CTLD.UnitTypeCapabilities = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.43" +CTLD.version="1.0.44" --- Instantiate a new CTLD. -- @param #CTLD self @@ -3010,6 +3010,35 @@ function CTLD:IsHercules(Unit) end end + +--- (Internal) Function to set troops positions of a template to a nice circle +-- @param #CTLD self +-- @param Core.Point#COORDINATE Coordinate Start coordinate to use +-- @param #number Radius Radius to be used +-- @param #number Heading Heading starting with +-- @param #string Template The group template name +-- @return #table Positions The positions table +function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template) + local Positions = {} + local template = _DATABASE:GetGroupTemplate(Template) + UTILS.PrintTableToLog(template) + local numbertroops = #template.units + local newcenter = Coordinate:Translate(Radius,((Heading+270)%360)) + for i=1,360,math.floor(360/numbertroops) do + local phead = ((Heading+270+i)%360) + local post = newcenter:Translate(Radius,phead) + local pos1 = post:GetVec2() + local p1t = { + x = pos1.x, + y = pos1.y, + heading = phead, + } + table.insert(Positions,p1t) + end + UTILS.PrintTableToLog(Positions) + return Positions +end + --- (Internal) Function to unload troops from heli. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group @@ -3061,14 +3090,29 @@ function CTLD:_UnloadTroops(Group, Unit) zoneradius = Unit:GetVelocityMPS() or 100 end local zone = ZONE_GROUP:New(string.format("Unload zone-%s",unitname),Group,zoneradius*factor) - local randomcoord = zone:GetRandomCoordinate(10,30*factor):GetVec2() + local randomcoord = zone:GetRandomCoordinate(10,30*factor) --:GetVec2() + local heading = Group:GetHeading() or 0 + -- Spawn troops left from us, closer when hovering, further off when landed + if hoverunload or grounded then + randomcoord = Group:GetCoordinate() + -- slightly left from us + local Angle = (heading+270)%360 + local offset = hoverunload and 1.5 or 5 + randomcoord:Translate(offset,Angle,nil,true) + end + local tempcount = 0 for _,_template in pairs(temptable) do self.TroopCounter = self.TroopCounter + 1 + tempcount = tempcount+1 local alias = string.format("%s-%d", _template, math.random(1,100000)) + local rad = 2.5+tempcount + local Positions = self:_GetUnitPositions(randomcoord,rad,heading,_template) self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) - :InitRandomizeUnits(true,20,2) + --:InitRandomizeUnits(true,20,2) + --:InitHeading(heading) :InitDelayOff() - :SpawnFromVec2(randomcoord) + :InitSetUnitAbsolutePositions(Positions) + :SpawnFromVec2(randomcoord:GetVec2()) self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter],type) end -- template loop cargo:SetWasDropped(true) From c770f4cb680c546fd984e7ca72e16f756c4654a8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Dec 2023 13:46:32 +0100 Subject: [PATCH 10/32] #ZONE Docu fixes --- Moose Development/Moose/Core/Zone.lua | 32 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index cb2648d0d..ab2f23949 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -10,7 +10,7 @@ -- * Create moving zones around a unit. -- * Create moving zones around a group. -- * Provide the zone behavior. Some zones are static, while others are moveable. --- * Enquiry if a coordinate is within a zone. +-- * Enquire if a coordinate is within a zone. -- * Smoke zones. -- * Set a zone probability to control zone selection. -- * Get zone coordinates. @@ -42,7 +42,7 @@ -- * @{#ZONE_UNIT}: The ZONE_UNIT class defines by a zone around a @{Wrapper.Unit#UNIT} with a radius. -- * @{#ZONE_GROUP}: The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. -- * @{#ZONE_POLYGON}: The ZONE_POLYGON class defines by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- * @{#ZONE_OVAL}: The ZONE_OVAL class isdefined by a center point, major axis, minor axis, and angle. +-- * @{#ZONE_OVAL}: The ZONE_OVAL class is defined by a center point, major axis, minor axis, and angle. -- -- === -- @@ -2232,7 +2232,14 @@ end --- ZONE_POLYGON to accurately find a point inside a polygon; as well as getting the correct surface area of --- a polygon. -- @type _ZONE_TRIANGLE --- @extends #BASE +-- @extends Core.Zone#ZONE_BASE + +--- ## _ZONE_TRIANGLE class, extends @{#ZONE_BASE} +-- +-- _ZONE_TRIANGLE class is a helper class for ZONE_POLYGON +-- This class implements the inherited functions from @{#ZONE_BASE} taking into account the own zone format and properties. +-- +-- @field #_ZONE_TRIANGLE _ZONE_TRIANGLE = { ClassName="ZONE_TRIANGLE", Points={}, @@ -2241,7 +2248,12 @@ _ZONE_TRIANGLE = { SurfaceArea=0, DrawIDs={} } - +--- +-- @param #_ZONE_TRIANGLE self +-- @param DCS#Vec p1 +-- @param DCS#Vec p2 +-- @param DCS#Vec p3 +-- @return #_ZONE_TRIANGLE self function _ZONE_TRIANGLE:New(p1, p2, p3) local self = BASE:Inherit(self, ZONE_BASE:New()) self.Points = {p1, p2, p3} @@ -2260,6 +2272,7 @@ function _ZONE_TRIANGLE:New(p1, p2, p3) end --- Checks if a point is contained within the triangle. +-- @param #_ZONE_TRIANGLE self -- @param #table pt The point to check -- @param #table points (optional) The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it -- @return #bool True if the point is contained, false otherwise @@ -2281,6 +2294,7 @@ function _ZONE_TRIANGLE:ContainsPoint(pt, points) end --- Returns a random Vec2 within the triangle. +-- @param #_ZONE_TRIANGLE self -- @param #table points The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it -- @return #table The random Vec2 function _ZONE_TRIANGLE:GetRandomVec2(points) @@ -2296,6 +2310,8 @@ function _ZONE_TRIANGLE:GetRandomVec2(points) end --- Draw the triangle +-- @param #_ZONE_TRIANGLE self +-- @return #table of draw IDs function _ZONE_TRIANGLE:Draw(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly) Coalition=Coalition or -1 @@ -2390,7 +2406,8 @@ end --- Triangulates the polygon. --- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Polygon.lua --- @return #table The #_TRIANGLE list that make up +-- @param #ZONE_POLYGON_BASE self +-- @return #table The #_ZONE_TRIANGLE list that makes up the polygon function ZONE_POLYGON_BASE:_Triangulate() local points = self._.Polygon local triangles = {} @@ -2519,6 +2536,7 @@ end --- Calculates the surface area of the polygon. The surface area is the sum of the areas of the triangles that make up the polygon. --- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Polygon.lua +-- @param #ZONE_POLYGON_BASE self -- @return #number The surface area of the polygon function ZONE_POLYGON_BASE:_CalculateSurfaceArea() local area = 0 @@ -3590,7 +3608,8 @@ end do -- ZONE_ELASTIC - + + --- -- @type ZONE_ELASTIC -- @field #table points Points in 2D. -- @field #table setGroups Set of GROUPs. @@ -3791,6 +3810,7 @@ end do -- ZONE_AIRBASE + --- -- @type ZONE_AIRBASE -- @field #boolean isShip If `true`, airbase is a ship. -- @field #boolean isHelipad If `true`, airbase is a helipad. From ff6704f123ca0517c6ea524607c883cc2a2f2012 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Dec 2023 15:11:53 +0100 Subject: [PATCH 11/32] #ZONE docu fixes --- Moose Development/Moose/Core/Zone.lua | 485 +++++++++++++------------- 1 file changed, 246 insertions(+), 239 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index ab2f23949..09ef67c2f 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -480,12 +480,14 @@ function ZONE_BASE:UndrawZone(Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, ZONE_BASE.UndrawZone, self) else - if self.DrawID and type(self.DrawID) ~= "table" then - UTILS.RemoveMark(self.DrawID) - else -- DrawID is a table with a collections of mark ids, as used in ZONE_POLYGON + if self.DrawID then + if type(self.DrawID) ~= "table" then + UTILS.RemoveMark(self.DrawID) + else -- DrawID is a table with a collections of mark ids, as used in ZONE_POLYGON for _, mark_id in pairs(self.DrawID) do - UTILS.RemoveMark(mark_id) + UTILS.RemoveMark(mark_id) end + end end end return self @@ -1999,234 +2001,6 @@ function ZONE_GROUP:GetRandomPointVec2( inner, outer ) end ---- ZONE_OVAL created from a center point, major axis, minor axis, and angle. --- Ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua --- @type ZONE_OVAL --- @extends Core.Zone#ZONE_BASE - ---- ## ZONE_OVAL class, extends @{#ZONE_BASE} --- --- The ZONE_OVAL class is defined by a center point, major axis, minor axis, and angle. --- This class implements the inherited functions from @{#ZONE_BASE} taking into account the own zone format and properties. --- --- @field #ZONE_OVAL -ZONE_OVAL = { - ClassName = "OVAL", - ZoneName="", - MajorAxis = nil, - MinorAxis = nil, - Angle = 0, - DrawPoly = nil -- let's just use a ZONE_POLYGON to draw the ZONE_OVAL on the map -} - ---- Creates a new ZONE_OVAL from a center point, major axis, minor axis, and angle. ---- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua --- @param #table vec2 The center point of the oval --- @param #number major_axis The major axis of the oval --- @param #number minor_axis The minor axis of the oval --- @param #number angle The angle of the oval --- @return #ZONE_OVAL The new oval -function ZONE_OVAL:New(name, vec2, major_axis, minor_axis, angle) - self = BASE:Inherit(self, ZONE_BASE:New()) - self.ZoneName = name - self.CenterVec2 = vec2 - self.MajorAxis = major_axis - self.MinorAxis = minor_axis - self.Angle = angle or 0 - - _DATABASE:AddZone(name, self) - - return self -end - ---- Constructor to create a ZONE_OVAL instance, taking the name of a drawing made with the draw tool in the Mission Editor. ---- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua --- @param #ZONE_OVAL self --- @param #string DrawingName The name of the drawing in the Mission Editor --- @return #ZONE_OVAL self -function ZONE_OVAL:NewFromDrawing(DrawingName) - self = BASE:Inherit(self, ZONE_BASE:New(DrawingName)) - for _, layer in pairs(env.mission.drawings.layers) do - for _, object in pairs(layer["objects"]) do - if string.find(object["name"], DrawingName, 1, true) then - if object["polygonMode"] == "oval" then - self.CenterVec2 = { x = object["mapX"], y = object["mapY"] } - self.MajorAxis = object["r1"] - self.MinorAxis = object["r2"] - self.Angle = object["angle"] - - end - end - end - end - - _DATABASE:AddZone(DrawingName, self) - - return self -end - ---- Gets the major axis of the oval. --- @param #ZONE_OVAL self --- @return #number The major axis of the oval -function ZONE_OVAL:GetMajorAxis() - return self.MajorAxis -end - ---- Gets the minor axis of the oval. --- @param #ZONE_OVAL self --- @return #number The minor axis of the oval -function ZONE_OVAL:GetMinorAxis() - return self.MinorAxis -end - ---- Gets the angle of the oval. --- @param #ZONE_OVAL self --- @return #number The angle of the oval -function ZONE_OVAL:GetAngle() - return self.Angle -end - ---- Returns a the center point of the oval --- @param #ZONE_OVAL self --- @return #table The center Vec2 -function ZONE_OVAL:GetVec2() - return self.CenterVec2 -end - ---- Checks if a point is contained within the oval. --- @param #ZONE_OVAL self --- @param #table point The point to check --- @return #bool True if the point is contained, false otherwise -function ZONE_OVAL:IsVec2InZone(vec2) - local cos, sin = math.cos, math.sin - local dx = vec2.x - self.CenterVec2.x - local dy = vec2.y - self.CenterVec2.y - local rx = dx * cos(self.Angle) + dy * sin(self.Angle) - local ry = -dx * sin(self.Angle) + dy * cos(self.Angle) - return rx * rx / (self.MajorAxis * self.MajorAxis) + ry * ry / (self.MinorAxis * self.MinorAxis) <= 1 -end - ---- Calculates the bounding box of the oval. The bounding box is the smallest rectangle that contains the oval. --- @param #ZONE_OVAL self --- @return #table The bounding box of the oval -function ZONE_OVAL:GetBoundingSquare() - local min_x = self.CenterVec2.x - self.MajorAxis - local min_y = self.CenterVec2.y - self.MinorAxis - local max_x = self.CenterVec2.x + self.MajorAxis - local max_y = self.CenterVec2.y + self.MinorAxis - - return { - {x=min_x, y=min_x}, {x=max_x, y=min_y}, {x=max_x, y=max_y}, {x=min_x, y=max_y} - } -end - ---- Find points on the edge of the oval --- @param #ZONE_OVAL self --- @param #number num_points How many points should be found. More = smoother shape --- @return #table Points on he edge -function ZONE_OVAL:PointsOnEdge(num_points) - num_points = num_points or 40 - local points = {} - local dtheta = 2 * math.pi / num_points - - for i = 0, num_points - 1 do - local theta = i * dtheta - local x = self.CenterVec2.x + self.MajorAxis * math.cos(theta) * math.cos(self.Angle) - self.MinorAxis * math.sin(theta) * math.sin(self.Angle) - local y = self.CenterVec2.y + self.MajorAxis * math.cos(theta) * math.sin(self.Angle) + self.MinorAxis * math.sin(theta) * math.cos(self.Angle) - table.insert(points, {x = x, y = y}) - end - - return points -end - ---- Returns a random Vec2 within the oval. --- @param #ZONE_OVAL self --- @return #table The random Vec2 -function ZONE_OVAL:GetRandomVec2() - local theta = math.rad(self.Angle) - - local random_point = math.sqrt(math.random()) --> uniformly - --local random_point = math.random() --> more clumped around center - local phi = math.random() * 2 * math.pi - local x_c = random_point * math.cos(phi) - local y_c = random_point * math.sin(phi) - local x_e = x_c * self.MajorAxis - local y_e = y_c * self.MinorAxis - local rx = (x_e * math.cos(theta) - y_e * math.sin(theta)) + self.CenterVec2.x - local ry = (x_e * math.sin(theta) + y_e * math.cos(theta)) + self.CenterVec2.y - - return {x=rx, y=ry} -end - ---- Define a random @{Core.Point#POINT_VEC2} within the zone. --- @param #ZONE_OVAL self --- @return Core.Point#POINT_VEC2 The PointVec2 coordinates. -function ZONE_OVAL:GetRandomPointVec2() - return POINT_VEC2:NewFromVec2(self:GetRandomVec2()) -end - ---- Define a random @{Core.Point#POINT_VEC2} within the zone. --- @param #ZONE_OVAL self --- @return Core.Point#POINT_VEC2 The PointVec2 coordinates. -function ZONE_OVAL:GetRandomPointVec3() - return POINT_VEC2:NewFromVec3(self:GetRandomVec2()) -end - ---- Draw the zone on the F10 map. ---- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua --- @param #ZONE_OVAL self --- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. --- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red. --- @param #number Alpha Transparency [0,1]. Default 1. --- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- doesn't seem to work --- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- doesn't seem to work --- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. --- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. --- @return #ZONE_OVAL self -function ZONE_OVAL:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType) - Coalition = Coalition or self:GetDrawCoalition() - - -- Set draw coalition. - self:SetDrawCoalition(Coalition) - - Color = Color or self:GetColorRGB() - Alpha = Alpha or 1 - - -- Set color. - self:SetColor(Color, Alpha) - - FillColor = FillColor or self:GetFillColorRGB() - if not FillColor then - UTILS.DeepCopy(Color) - end - FillAlpha = FillAlpha or self:GetFillColorAlpha() - if not FillAlpha then - FillAlpha = 0.15 - end - - LineType = LineType or 1 - - -- Set fill color -----------> has fill color worked in recent versions of DCS? - -- doing something like - -- - -- trigger.action.markupToAll(7, -1, 501, p.Coords[1]:GetVec3(), p.Coords[2]:GetVec3(),p.Coords[3]:GetVec3(),p.Coords[4]:GetVec3(),{1,0,0, 1}, {1,0,0, 1}, 4, false, Text or "") - -- - -- doesn't seem to fill in the shape for an n-sided polygon - self:SetFillColor(FillColor, FillAlpha) - - self.DrawPoly = ZONE_POLYGON:NewFromPointsArray(self.ZoneName, self:PointsOnEdge(80)) - self.DrawPoly:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType) -end - ---- Remove drawing from F10 map --- @param #ZONE_OVAL self -function ZONE_OVAL:UndrawZone() - if self.DrawPoly then - self.DrawPoly:UndrawZone() - end -end - - --- Ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Triangle.lua --- This triangle "zone" is not really to be used on its own, it only serves as building blocks for --- ZONE_POLYGON to accurately find a point inside a polygon; as well as getting the correct surface area of @@ -2394,13 +2168,13 @@ function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) self._.Polygon[i].y = PointsArray[i].y end + -- triangulate the polygon so we can work with it + self._Triangles = self:_Triangulate() + -- set the polygon's surface area + self.SurfaceArea = self:_CalculateSurfaceArea() + end - -- triangulate the polygon so we can work with it - self._Triangles = self:_Triangulate() - -- set the polygon's surface area - self.SurfaceArea = self:_CalculateSurfaceArea() - return self end @@ -3106,9 +2880,13 @@ function ZONE_POLYGON_BASE:Boundary(Coalition, Color, Radius, Alpha, Segments, C return self end +do -- Zone_Polygon + + --- -- @type ZONE_POLYGON -- @extends #ZONE_POLYGON_BASE +-- @extends #ZONE_BASE --- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon, OR by drawings made with the Draw tool @@ -3140,8 +2918,7 @@ end -- -- This class has been updated to use a accurate way of generating random points inside the polygon without having to use trial and error guesses. -- You can also get the surface area of the polygon now, handy if you want measure which coalition has the largest captured area, for example. - - +-- -- @field #ZONE_POLYGON ZONE_POLYGON = { ClassName="ZONE_POLYGON", @@ -3606,6 +3383,7 @@ function ZONE_POLYGON:IsNoneInZone() return self:CountScannedCoalitions() == 0 end +end do -- ZONE_ELASTIC @@ -3808,6 +3586,235 @@ do -- ZONE_ELASTIC end + + +--- ZONE_OVAL created from a center point, major axis, minor axis, and angle. +-- Ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua +-- @type ZONE_OVAL +-- @extends Core.Zone#ZONE_BASE + +--- ## ZONE_OVAL class, extends @{#ZONE_BASE} +-- +-- The ZONE_OVAL class is defined by a center point, major axis, minor axis, and angle. +-- This class implements the inherited functions from @{#ZONE_BASE} taking into account the own zone format and properties. +-- +-- @field #ZONE_OVAL +ZONE_OVAL = { + ClassName = "OVAL", + ZoneName="", + MajorAxis = nil, + MinorAxis = nil, + Angle = 0, + DrawPoly = nil -- let's just use a ZONE_POLYGON to draw the ZONE_OVAL on the map +} + +--- Creates a new ZONE_OVAL from a center point, major axis, minor axis, and angle. +--- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua +-- @param #table vec2 The center point of the oval +-- @param #number major_axis The major axis of the oval +-- @param #number minor_axis The minor axis of the oval +-- @param #number angle The angle of the oval +-- @return #ZONE_OVAL The new oval +function ZONE_OVAL:New(name, vec2, major_axis, minor_axis, angle) + self = BASE:Inherit(self, ZONE_BASE:New()) + self.ZoneName = name + self.CenterVec2 = vec2 + self.MajorAxis = major_axis + self.MinorAxis = minor_axis + self.Angle = angle or 0 + + _DATABASE:AddZone(name, self) + + return self +end + +--- Constructor to create a ZONE_OVAL instance, taking the name of a drawing made with the draw tool in the Mission Editor. +--- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua +-- @param #ZONE_OVAL self +-- @param #string DrawingName The name of the drawing in the Mission Editor +-- @return #ZONE_OVAL self +function ZONE_OVAL:NewFromDrawing(DrawingName) + self = BASE:Inherit(self, ZONE_BASE:New(DrawingName)) + for _, layer in pairs(env.mission.drawings.layers) do + for _, object in pairs(layer["objects"]) do + if string.find(object["name"], DrawingName, 1, true) then + if object["polygonMode"] == "oval" then + self.CenterVec2 = { x = object["mapX"], y = object["mapY"] } + self.MajorAxis = object["r1"] + self.MinorAxis = object["r2"] + self.Angle = object["angle"] + + end + end + end + end + + _DATABASE:AddZone(DrawingName, self) + + return self +end + +--- Gets the major axis of the oval. +-- @param #ZONE_OVAL self +-- @return #number The major axis of the oval +function ZONE_OVAL:GetMajorAxis() + return self.MajorAxis +end + +--- Gets the minor axis of the oval. +-- @param #ZONE_OVAL self +-- @return #number The minor axis of the oval +function ZONE_OVAL:GetMinorAxis() + return self.MinorAxis +end + +--- Gets the angle of the oval. +-- @param #ZONE_OVAL self +-- @return #number The angle of the oval +function ZONE_OVAL:GetAngle() + return self.Angle +end + +--- Returns a the center point of the oval +-- @param #ZONE_OVAL self +-- @return #table The center Vec2 +function ZONE_OVAL:GetVec2() + return self.CenterVec2 +end + +--- Checks if a point is contained within the oval. +-- @param #ZONE_OVAL self +-- @param #table point The point to check +-- @return #bool True if the point is contained, false otherwise +function ZONE_OVAL:IsVec2InZone(vec2) + local cos, sin = math.cos, math.sin + local dx = vec2.x - self.CenterVec2.x + local dy = vec2.y - self.CenterVec2.y + local rx = dx * cos(self.Angle) + dy * sin(self.Angle) + local ry = -dx * sin(self.Angle) + dy * cos(self.Angle) + return rx * rx / (self.MajorAxis * self.MajorAxis) + ry * ry / (self.MinorAxis * self.MinorAxis) <= 1 +end + +--- Calculates the bounding box of the oval. The bounding box is the smallest rectangle that contains the oval. +-- @param #ZONE_OVAL self +-- @return #table The bounding box of the oval +function ZONE_OVAL:GetBoundingSquare() + local min_x = self.CenterVec2.x - self.MajorAxis + local min_y = self.CenterVec2.y - self.MinorAxis + local max_x = self.CenterVec2.x + self.MajorAxis + local max_y = self.CenterVec2.y + self.MinorAxis + + return { + {x=min_x, y=min_x}, {x=max_x, y=min_y}, {x=max_x, y=max_y}, {x=min_x, y=max_y} + } +end + +--- Find points on the edge of the oval +-- @param #ZONE_OVAL self +-- @param #number num_points How many points should be found. More = smoother shape +-- @return #table Points on he edge +function ZONE_OVAL:PointsOnEdge(num_points) + num_points = num_points or 40 + local points = {} + local dtheta = 2 * math.pi / num_points + + for i = 0, num_points - 1 do + local theta = i * dtheta + local x = self.CenterVec2.x + self.MajorAxis * math.cos(theta) * math.cos(self.Angle) - self.MinorAxis * math.sin(theta) * math.sin(self.Angle) + local y = self.CenterVec2.y + self.MajorAxis * math.cos(theta) * math.sin(self.Angle) + self.MinorAxis * math.sin(theta) * math.cos(self.Angle) + table.insert(points, {x = x, y = y}) + end + + return points +end + +--- Returns a random Vec2 within the oval. +-- @param #ZONE_OVAL self +-- @return #table The random Vec2 +function ZONE_OVAL:GetRandomVec2() + local theta = math.rad(self.Angle) + + local random_point = math.sqrt(math.random()) --> uniformly + --local random_point = math.random() --> more clumped around center + local phi = math.random() * 2 * math.pi + local x_c = random_point * math.cos(phi) + local y_c = random_point * math.sin(phi) + local x_e = x_c * self.MajorAxis + local y_e = y_c * self.MinorAxis + local rx = (x_e * math.cos(theta) - y_e * math.sin(theta)) + self.CenterVec2.x + local ry = (x_e * math.sin(theta) + y_e * math.cos(theta)) + self.CenterVec2.y + + return {x=rx, y=ry} +end + +--- Define a random @{Core.Point#POINT_VEC2} within the zone. +-- @param #ZONE_OVAL self +-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates. +function ZONE_OVAL:GetRandomPointVec2() + return POINT_VEC2:NewFromVec2(self:GetRandomVec2()) +end + +--- Define a random @{Core.Point#POINT_VEC2} within the zone. +-- @param #ZONE_OVAL self +-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates. +function ZONE_OVAL:GetRandomPointVec3() + return POINT_VEC2:NewFromVec3(self:GetRandomVec2()) +end + +--- Draw the zone on the F10 map. +--- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua +-- @param #ZONE_OVAL self +-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. +-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red. +-- @param #number Alpha Transparency [0,1]. Default 1. +-- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- doesn't seem to work +-- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- doesn't seem to work +-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. +-- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. +-- @return #ZONE_OVAL self +function ZONE_OVAL:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType) + Coalition = Coalition or self:GetDrawCoalition() + + -- Set draw coalition. + self:SetDrawCoalition(Coalition) + + Color = Color or self:GetColorRGB() + Alpha = Alpha or 1 + + -- Set color. + self:SetColor(Color, Alpha) + + FillColor = FillColor or self:GetFillColorRGB() + if not FillColor then + UTILS.DeepCopy(Color) + end + FillAlpha = FillAlpha or self:GetFillColorAlpha() + if not FillAlpha then + FillAlpha = 0.15 + end + + LineType = LineType or 1 + + -- Set fill color -----------> has fill color worked in recent versions of DCS? + -- doing something like + -- + -- trigger.action.markupToAll(7, -1, 501, p.Coords[1]:GetVec3(), p.Coords[2]:GetVec3(),p.Coords[3]:GetVec3(),p.Coords[4]:GetVec3(),{1,0,0, 1}, {1,0,0, 1}, 4, false, Text or "") + -- + -- doesn't seem to fill in the shape for an n-sided polygon + self:SetFillColor(FillColor, FillAlpha) + + self.DrawPoly = ZONE_POLYGON:NewFromPointsArray(self.ZoneName, self:PointsOnEdge(80)) + self.DrawPoly:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType) +end + +--- Remove drawing from F10 map +-- @param #ZONE_OVAL self +function ZONE_OVAL:UndrawZone() + if self.DrawPoly then + self.DrawPoly:UndrawZone() + end +end + do -- ZONE_AIRBASE --- From 6903e252d2461b7827a5b07df2bfff5937044f52 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 7 Dec 2023 16:08:47 +0100 Subject: [PATCH 12/32] #UTILS * Nicer PrintTableToLog() --- Moose Development/Moose/Utilities/Utils.lua | 23 ++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index f8fbfe2eb..9fe3d9823 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -443,22 +443,35 @@ end --- Print a table to log in a nice format -- @param #table table The table to print --- @param #number indent Number of idents +-- @param #number indent Number of indents +-- @return #string text Text created on the fly of the log output function UTILS.PrintTableToLog(table, indent) + local text = "\n" if not table then env.warning("No table passed!") - return + return nil end if not indent then indent = 0 end for k, v in pairs(table) do + if string.find(k," ") then k='"'..k..'"'end if type(v) == "table" then env.info(string.rep(" ", indent) .. tostring(k) .. " = {") - UTILS.PrintTableToLog(v, indent + 1) - env.info(string.rep(" ", indent) .. "}") + text = text ..string.rep(" ", indent) .. tostring(k) .. " = {\n" + text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1)).."\n" + env.info(string.rep(" ", indent) .. "},") + text = text .. string.rep(" ", indent) .. "},\n" else - env.info(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(v)) + local value + if tostring(v) == "true" or tostring(v) == "false" or tonumber(v) ~= nil then + value=v + else + value = '"'..tostring(v)..'"' + end + env.info(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n") + text = text .. string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n" end end + return text end --- Returns table in a easy readable string representation. From b3a006096ce2a83a467697026251489437a2b3a6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 9 Dec 2023 13:03:34 +0100 Subject: [PATCH 13/32] fixes --- Moose Development/Moose/Core/Set.lua | 88 +++++++++++------------ Moose Development/Moose/Wrapper/Group.lua | 1 + 2 files changed, 41 insertions(+), 48 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index c9cbc9f3a..43fbd8fce 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -2854,58 +2854,50 @@ do -- SET_UNIT -- @return Core.Point#COORDINATE The center coordinate of all the units in the set, including heading in degrees and speed in mps in case of moving units. function SET_UNIT:GetCoordinate() - local Coordinate = nil - local unit = self:GetFirst() - if self:Count() == 1 and unit then - return unit:GetCoordinate() - end - if unit then - Coordinate = unit:GetCoordinate() - self:T2(UTILS.PrintTableToLog(Coordinate:GetVec3())) - - local x1 = Coordinate.x - local x2 = Coordinate.x - local y1 = Coordinate.y - local y2 = Coordinate.y - local z1 = Coordinate.z - local z2 = Coordinate.z - local MaxVelocity = 0 - local AvgHeading = nil - local MovingCount = 0 - - for UnitName, UnitData in pairs( self.Set) do - - local Unit = UnitData -- Wrapper.Unit#UNIT - local Coord = Unit:GetCoordinate() - - x1 = (Coord.x < x1) and Coord.x or x1 - x2 = (Coord.x > x2) and Coord.x or x2 - y1 = (Coord.y < y1) and Coord.y or y1 - y2 = (Coord.y > y2) and Coord.y or y2 - z1 = (Coord.y < z1) and Coord.z or z1 - z2 = (Coord.y > z2) and Coord.z or z2 - - local Velocity = Coord:GetVelocity() - if Velocity ~= 0 then - MaxVelocity = (MaxVelocity < Velocity) and Velocity or MaxVelocity - local Heading = Coordinate:GetHeading() - AvgHeading = AvgHeading and (AvgHeading + Heading) or Heading - MovingCount = MovingCount + 1 + local function GetSetVec3(units) + -- Init. + local x=0 + local y=0 + local z=0 + local n=0 + -- Loop over all units. + for _,unit in pairs(units) do + local vec3=nil --DCS#Vec3 + if unit and unit:IsAlive() then + vec3 = unit:GetVec3() + 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 - - AvgHeading = AvgHeading and (AvgHeading / MovingCount) - - Coordinate.x = (x2 - x1) / 2 + x1 - Coordinate.y = (y2 - y1) / 2 + y1 - Coordinate.z = (z2 - z1) / 2 + z1 - Coordinate:SetHeading( AvgHeading ) - Coordinate:SetVelocity( MaxVelocity ) - - self:T2(UTILS.PrintTableToLog(Coordinate:GetVec3())) + if n>0 then + -- Average. + local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3 + return Vec3 + end + return nil + end + + local Coordinate = nil + local Vec3 = GetSetVec3(self.Set) + if Vec3 then + Coordinate = COORDINATE:NewFromVec3(Vec3) end - return Coordinate + if Coordinate then + local heading = self:GetHeading() or 0 + local velocity = self:GetVelocity() or 0 + Coordinate:SetHeading( heading ) + Coordinate:SetVelocity( velocity ) + self:I(UTILS.PrintTableToLog(Coordinate)) + end + + return Coordinate end --- Get the maximum velocity of the SET_UNIT. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 9ee2d2c21..fe0833189 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -1157,6 +1157,7 @@ function GROUP:GetAverageCoordinate() local coord = COORDINATE:NewFromVec3(vec3) local Heading = self:GetHeading() coord.Heading = Heading + return coord else BASE:E( { "Cannot GetAverageCoordinate", Group = self, Alive = self:IsAlive() } ) return nil From 6b270916c4b192b9d671801ad3e0abd324e83cd5 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 9 Dec 2023 13:53:27 +0100 Subject: [PATCH 14/32] # DETECTION_BASE * Added `SetRadarBlur(minheight,thresheight,thresblur)` --- .../Moose/Functional/Detection.lua | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 9fc086cd9..2ec01a349 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -39,7 +39,7 @@ do -- DETECTION_BASE - --- @type DETECTION_BASE + -- @type DETECTION_BASE -- @field Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role. -- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected. -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. @@ -269,10 +269,10 @@ do -- DETECTION_BASE DetectedItemsByIndex = {}, } - --- @type DETECTION_BASE.DetectedObjects + -- @type DETECTION_BASE.DetectedObjects -- @list <#DETECTION_BASE.DetectedObject> - --- @type DETECTION_BASE.DetectedObject + -- @type DETECTION_BASE.DetectedObject -- @field #string Name -- @field #boolean IsVisible -- @field #boolean KnowType @@ -284,7 +284,7 @@ do -- DETECTION_BASE -- @field #boolean LastPos -- @field #number LastVelocity - --- @type DETECTION_BASE.DetectedItems + -- @type DETECTION_BASE.DetectedItems -- @list <#DETECTION_BASE.DetectedItem> --- Detected item data structure. @@ -522,7 +522,7 @@ do -- DETECTION_BASE do -- State Transition Handling - --- @param #DETECTION_BASE self + -- @param #DETECTION_BASE self -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. @@ -530,7 +530,7 @@ do -- DETECTION_BASE self:__Detect( 1 ) end - --- @param #DETECTION_BASE self + -- @param #DETECTION_BASE self -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. @@ -570,7 +570,7 @@ do -- DETECTION_BASE end - --- @param #DETECTION_BASE self + -- @param #DETECTION_BASE self -- @param #number The amount of alive recce. function DETECTION_BASE:CountAliveRecce() @@ -578,7 +578,7 @@ do -- DETECTION_BASE end - --- @param #DETECTION_BASE self + -- @param #DETECTION_BASE self function DETECTION_BASE:ForEachAliveRecce( IteratorFunction, ... ) self:F2( arg ) @@ -587,7 +587,7 @@ do -- DETECTION_BASE return self end - --- @param #DETECTION_BASE self + -- @param #DETECTION_BASE self -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. @@ -712,6 +712,22 @@ do -- DETECTION_BASE end end + -- Calculate radar blue probability + + if self.RadarBlur then + local minheight = self.RadarBlurMinHeight or 250 -- meters + local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group + local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall + local fheight = math.floor(math.random(1,10000)/100) + local fblur = math.floor(math.random(1,10000)/100) + local unit = UNIT:FindByName(DetectedObjectName) + if unit and unit:IsAlive() then + local AGL = unit:GetAltitude(true) + if AGL <= minheight and fheight > thresheight then DetectionAccepted = false end + if fblur > thresblur then DetectionAccepted = false end + end + end + -- Calculate additional probabilities if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then @@ -1011,7 +1027,21 @@ do -- DETECTION_BASE return self end - + + --- Method to make the radar detection less accurate, e.g. for WWII scenarios. + -- @param #DETECTION_BASE self + -- @param #number minheight Minimum flight height to be detected, in meters AGL (above ground) + -- @param #number thresheight Threshold to escape the radar if flying below minheight, defaults to 90 (90% escape chance) + -- @param #number thresblur Threshold to be detected by the radar overall, defaults to 85 (85% chance to be found) + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur) + self.RadarBlur = true + self.RadarBlurMinHeight = minheight or 250 -- meters + self.RadarBlurThresHeight = thresheight or 90 -- 10% chance to find a low flying group + self.RadarBlurThresBlur = thresblur or 85 -- 25% chance to escape the radar overall + return self + end + end do @@ -1354,7 +1384,7 @@ do -- DETECTION_BASE } } - --- @param DCS#Unit FoundDCSUnit + -- @param DCS#Unit FoundDCSUnit -- @param Wrapper.Group#GROUP ReportGroup -- @param Core.Set#SET_GROUP ReportSetGroup local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) @@ -1419,7 +1449,7 @@ do -- DETECTION_BASE DetectedItem.PlayersNearBy = nil _DATABASE:ForEachPlayer( - --- @param Wrapper.Unit#UNIT PlayerUnit + -- @param Wrapper.Unit#UNIT PlayerUnit function( PlayerUnitName ) local PlayerUnit = UNIT:FindByName( PlayerUnitName ) @@ -1975,8 +2005,9 @@ do -- DETECTION_BASE end do -- DETECTION_UNITS - - --- @type DETECTION_UNITS + + --- + -- @type DETECTION_UNITS -- @field DCS#Distance DetectionRange The range till which targets are detected. -- @extends Functional.Detection#DETECTION_BASE @@ -2232,7 +2263,7 @@ end do -- DETECTION_TYPES - --- @type DETECTION_TYPES + -- @type DETECTION_TYPES -- @extends Functional.Detection#DETECTION_BASE --- Will detect units within the battle zone. @@ -2434,8 +2465,9 @@ do -- DETECTION_TYPES end do -- DETECTION_AREAS - - --- @type DETECTION_AREAS + + --- + -- @type DETECTION_AREAS -- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. -- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. -- @extends Functional.Detection#DETECTION_BASE @@ -2961,7 +2993,7 @@ do -- DETECTION_AREAS -- DetectedSet:Flush( self ) - DetectedSet:ForEachUnit( --- @param Wrapper.Unit#UNIT DetectedUnit + DetectedSet:ForEachUnit( -- @param Wrapper.Unit#UNIT DetectedUnit function( DetectedUnit ) if DetectedUnit:IsAlive() then -- self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() ) From 0f4162a9a96750c5c1f3c6298ecaabaaa76104dc Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 9 Dec 2023 14:34:41 +0100 Subject: [PATCH 15/32] * fixes --- .../Moose/Functional/Detection.lua | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 2ec01a349..4ddf6ff9c 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -38,7 +38,8 @@ -- @image Detection.JPG do -- DETECTION_BASE - + + --- -- @type DETECTION_BASE -- @field Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role. -- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected. @@ -91,6 +92,11 @@ do -- DETECTION_BASE -- -- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) -- + -- + -- ## Radar Blur - use to make the radar less exact, e.g. for WWII scenarios + -- + -- * @{DETECTION_BASE.SetRadarBlur}(): Set the radar blur to be used. + -- -- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list -- -- DETECTION_BASE derived classes build a list called DetectedItems[], which is essentially a first later @@ -268,10 +274,12 @@ do -- DETECTION_BASE DetectedItems = {}, DetectedItemsByIndex = {}, } - + + --- -- @type DETECTION_BASE.DetectedObjects -- @list <#DETECTION_BASE.DetectedObject> + --- -- @type DETECTION_BASE.DetectedObject -- @field #string Name -- @field #boolean IsVisible @@ -283,7 +291,8 @@ do -- DETECTION_BASE -- @field #number LastTime -- @field #boolean LastPos -- @field #number LastVelocity - + + --- -- @type DETECTION_BASE.DetectedItems -- @list <#DETECTION_BASE.DetectedItem> @@ -723,7 +732,7 @@ do -- DETECTION_BASE local unit = UNIT:FindByName(DetectedObjectName) if unit and unit:IsAlive() then local AGL = unit:GetAltitude(true) - if AGL <= minheight and fheight > thresheight then DetectionAccepted = false end + if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end if fblur > thresblur then DetectionAccepted = false end end end @@ -2262,7 +2271,8 @@ do -- DETECTION_UNITS end do -- DETECTION_TYPES - + + --- -- @type DETECTION_TYPES -- @extends Functional.Detection#DETECTION_BASE From bc3f9ed7c0ac72560b83a054d2c6a7f7d5b4fe8a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 9 Dec 2023 15:51:35 +0100 Subject: [PATCH 16/32] #SPAWN * Added SPAWN:InitCallSign(ID,Name,Minor,Major) --- Moose Development/Moose/Core/Spawn.lua | 33 ++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 388b9aafe..df588f14a 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1108,6 +1108,22 @@ function SPAWN:InitRandomizeCallsign() return self end +--- [BLUE AIR only!] This method sets a specific callsign for a spawned group. Use for a group with one unit only! +-- @param #SPAWN self +-- @param #number ID ID of the callsign enumerator, e.g. CALLSIGN.Tanker.Texaco - - resulting in e.g. Texaco-2-1 +-- @param #string Name Name of this callsign as it cannot be determined from the ID because of the dependency on the task type of the plane, and the plane type. E.g. "Texaco" +-- @param #number Minor Minor number, i.e. the unit number within the group, e.g 2 - resulting in e.g. Texaco-2-1 +-- @param #number Major Major number, i.e. the group number of this name, e.g. 1 - resulting in e.g. Texaco-2-1 +-- @return #SPAWN self +function SPAWN:InitCallSign(ID,Name,Minor,Major) + self.SpawnInitCallSign = true + self.SpawnInitCallSignID = ID or 1 + self.SpawnInitCallSignMinor = Minor or 1 + self.SpawnInitCallSignMajor = Major or 1 + self.SpawnInitCallSignName = string.lower(Name) or "enfield" + return self +end + --- This method sets a spawn position for the group that is different from the location of the template. -- @param #SPAWN self -- @param Core.Point#COORDINATE Coordinate The position to spawn from @@ -3331,10 +3347,23 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 end end + if self.SpawnInitCallSign then + for UnitID = 1, #SpawnTemplate.units do + local Callsign = SpawnTemplate.units[UnitID].callsign + if Callsign and type( Callsign ) ~= "number" then + SpawnTemplate.units[UnitID].callsign[1] = self.SpawnInitCallSignID + SpawnTemplate.units[UnitID].callsign[2] = self.SpawnInitCallSignMinor + SpawnTemplate.units[UnitID].callsign[3] = self.SpawnInitCallSignMajor + SpawnTemplate.units[UnitID].callsign["name"] = string.format("%s%d%d",self.SpawnInitCallSignName,self.SpawnInitCallSignMinor,self.SpawnInitCallSignMajor) + --UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].callsign,1) + end + end + end + for UnitID = 1, #SpawnTemplate.units do local Callsign = SpawnTemplate.units[UnitID].callsign if Callsign then - if type( Callsign ) ~= "number" then -- blue callsign + if type( Callsign ) ~= "number" and not self.SpawnInitCallSign then -- blue callsign -- UTILS.PrintTableToLog(Callsign,1) Callsign[2] = ((SpawnIndex - 1) % 10) + 1 local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string @@ -3342,7 +3371,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2 local CallsignLen = CallsignName:len() SpawnTemplate.units[UnitID].callsign[2] = UnitID SpawnTemplate.units[UnitID].callsign["name"] = CallsignName:sub( 1, CallsignLen ) .. SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3] - else + elseif type( Callsign ) == "number" then SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex end end From d2d6fac7df3d3bf5b205fc3dfa90ddffca1fa5bc Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 9 Dec 2023 18:16:29 +0100 Subject: [PATCH 17/32] # DETECTION, logic fix --- Moose Development/Moose/Functional/Detection.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 4ddf6ff9c..a33e7f7b0 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -724,6 +724,7 @@ do -- DETECTION_BASE -- Calculate radar blue probability if self.RadarBlur then + BASE:I("RadarBlur") local minheight = self.RadarBlurMinHeight or 250 -- meters local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall @@ -732,8 +733,11 @@ do -- DETECTION_BASE local unit = UNIT:FindByName(DetectedObjectName) if unit and unit:IsAlive() then local AGL = unit:GetAltitude(true) - if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end + BASE:I("Unit "..DetectedObjectName.." is at "..AGL.."m.") + BASE:I(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur)) if fblur > thresblur then DetectionAccepted = false end + if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end + BASE:I("Detection Accepted = "..tostring(DetectionAccepted)) end end From 87f1a5ed0d303a4a128abec56fc694e8f35c2d8f Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 10 Dec 2023 11:58:19 +0100 Subject: [PATCH 18/32] # DETECTION * Option to make Radar Blue decision visible in logs (self.debug) and/or screen (self.verbose) --- Moose Development/Moose/Functional/Detection.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index a33e7f7b0..09ad78104 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -46,6 +46,8 @@ do -- DETECTION_BASE -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. -- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. -- @field #number DetectionRun + -- @field #boolean debug + -- @field #boolean verbose -- @extends Core.Fsm#FSM --- Defines the core functions to administer detected objects. @@ -273,6 +275,8 @@ do -- DETECTION_BASE DetectedObjectsIdentified = {}, DetectedItems = {}, DetectedItemsByIndex = {}, + debug = false, + verbose = false, } --- @@ -721,10 +725,10 @@ do -- DETECTION_BASE end end - -- Calculate radar blue probability + -- Calculate radar blur probability if self.RadarBlur then - BASE:I("RadarBlur") + MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose) local minheight = self.RadarBlurMinHeight or 250 -- meters local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall @@ -733,11 +737,11 @@ do -- DETECTION_BASE local unit = UNIT:FindByName(DetectedObjectName) if unit and unit:IsAlive() then local AGL = unit:GetAltitude(true) - BASE:I("Unit "..DetectedObjectName.." is at "..AGL.."m.") - BASE:I(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur)) + MESSAGE:New("Unit "..DetectedObjectName.." is at "..math.floor(AGL).."m.",10):ToLogIf(self.debug):ToAllIf(self.verbose) + MESSAGE:New(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur),10):ToLogIf(self.debug):ToAllIf(self.verbose) if fblur > thresblur then DetectionAccepted = false end - if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end - BASE:I("Detection Accepted = "..tostring(DetectionAccepted)) + if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end + MESSAGE:New("Detection Accepted = "..tostring(DetectionAccepted),10):ToLogIf(self.debug):ToAllIf(self.verbose) end end From c089e56060974539e58a346665f7536a2898c4cf Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 10 Dec 2023 14:37:41 +0100 Subject: [PATCH 19/32] # DETECTION * Make the radar blur less effective when under 20km distance --- Moose Development/Moose/Functional/Detection.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 09ad78104..1acd82ad2 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -46,8 +46,6 @@ do -- DETECTION_BASE -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. -- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. -- @field #number DetectionRun - -- @field #boolean debug - -- @field #boolean verbose -- @extends Core.Fsm#FSM --- Defines the core functions to administer detected objects. @@ -275,8 +273,6 @@ do -- DETECTION_BASE DetectedObjectsIdentified = {}, DetectedItems = {}, DetectedItemsByIndex = {}, - debug = false, - verbose = false, } --- @@ -725,19 +721,24 @@ do -- DETECTION_BASE end end - -- Calculate radar blur probability + -- Calculate radar blue probability if self.RadarBlur then MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose) local minheight = self.RadarBlurMinHeight or 250 -- meters local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall + local dist = math.floor(Distance) + if dist <= 20 then + thresheight = (((dist*dist)/400)*thresheight) + thresblur = (((dist*dist)/400)*thresblur) + end local fheight = math.floor(math.random(1,10000)/100) local fblur = math.floor(math.random(1,10000)/100) local unit = UNIT:FindByName(DetectedObjectName) if unit and unit:IsAlive() then local AGL = unit:GetAltitude(true) - MESSAGE:New("Unit "..DetectedObjectName.." is at "..math.floor(AGL).."m.",10):ToLogIf(self.debug):ToAllIf(self.verbose) + MESSAGE:New("Unit "..DetectedObjectName.." is at "..math.floor(AGL).."m. Distance "..math.floor(Distance).."km.",10):ToLogIf(self.debug):ToAllIf(self.verbose) MESSAGE:New(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur),10):ToLogIf(self.debug):ToAllIf(self.verbose) if fblur > thresblur then DetectionAccepted = false end if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end From 230d9d82bfe1ba3cc6f57c2ab1a689d98eb53b0f Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:04:35 +0100 Subject: [PATCH 20/32] Update Detection.lua (#2063) # RadarBlur - make burn-through limit configureable --- Moose Development/Moose/Functional/Detection.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 1acd82ad2..a71e194ed 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -721,7 +721,7 @@ do -- DETECTION_BASE end end - -- Calculate radar blue probability + -- Calculate radar blur probability if self.RadarBlur then MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose) @@ -729,9 +729,9 @@ do -- DETECTION_BASE local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall local dist = math.floor(Distance) - if dist <= 20 then - thresheight = (((dist*dist)/400)*thresheight) - thresblur = (((dist*dist)/400)*thresblur) + if dist <= self.RadarBlurClosing then + thresheight = (((dist*dist)/self.RadarBlurClosingSquare)*thresheight) + thresblur = (((dist*dist)/self.RadarBlurClosingSquare)*thresblur) end local fheight = math.floor(math.random(1,10000)/100) local fblur = math.floor(math.random(1,10000)/100) @@ -1051,12 +1051,15 @@ do -- DETECTION_BASE -- @param #number minheight Minimum flight height to be detected, in meters AGL (above ground) -- @param #number thresheight Threshold to escape the radar if flying below minheight, defaults to 90 (90% escape chance) -- @param #number thresblur Threshold to be detected by the radar overall, defaults to 85 (85% chance to be found) + -- @param #number closing Closing-in in km - the limit of km from which on it becomes increasingly difficult to escape radar detection if flying towards the radar position. Should be about 1/3 of the radar detection radius in kilometers, defaults to 20. -- @return #DETECTION_BASE self - function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur) + function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur,closing) self.RadarBlur = true self.RadarBlurMinHeight = minheight or 250 -- meters self.RadarBlurThresHeight = thresheight or 90 -- 10% chance to find a low flying group self.RadarBlurThresBlur = thresblur or 85 -- 25% chance to escape the radar overall + self.RadarBlurClosing = closing or 20 -- 20km + self.RadarBlurClosingSquare = self.RadarBlurClosing * self.RadarBlurClosing return self end From b8d44643c1e2b87f0af3cf29fb4178973d63d5da Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:49:00 +0100 Subject: [PATCH 21/32] Update Detection.lua (#2063) (#2064) # RadarBlur - make burn-through limit configureable --- Moose Development/Moose/Functional/Detection.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 1acd82ad2..a71e194ed 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -721,7 +721,7 @@ do -- DETECTION_BASE end end - -- Calculate radar blue probability + -- Calculate radar blur probability if self.RadarBlur then MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose) @@ -729,9 +729,9 @@ do -- DETECTION_BASE local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall local dist = math.floor(Distance) - if dist <= 20 then - thresheight = (((dist*dist)/400)*thresheight) - thresblur = (((dist*dist)/400)*thresblur) + if dist <= self.RadarBlurClosing then + thresheight = (((dist*dist)/self.RadarBlurClosingSquare)*thresheight) + thresblur = (((dist*dist)/self.RadarBlurClosingSquare)*thresblur) end local fheight = math.floor(math.random(1,10000)/100) local fblur = math.floor(math.random(1,10000)/100) @@ -1051,12 +1051,15 @@ do -- DETECTION_BASE -- @param #number minheight Minimum flight height to be detected, in meters AGL (above ground) -- @param #number thresheight Threshold to escape the radar if flying below minheight, defaults to 90 (90% escape chance) -- @param #number thresblur Threshold to be detected by the radar overall, defaults to 85 (85% chance to be found) + -- @param #number closing Closing-in in km - the limit of km from which on it becomes increasingly difficult to escape radar detection if flying towards the radar position. Should be about 1/3 of the radar detection radius in kilometers, defaults to 20. -- @return #DETECTION_BASE self - function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur) + function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur,closing) self.RadarBlur = true self.RadarBlurMinHeight = minheight or 250 -- meters self.RadarBlurThresHeight = thresheight or 90 -- 10% chance to find a low flying group self.RadarBlurThresBlur = thresblur or 85 -- 25% chance to escape the radar overall + self.RadarBlurClosing = closing or 20 -- 20km + self.RadarBlurClosingSquare = self.RadarBlurClosing * self.RadarBlurClosing return self end From cd4fb0c6c5723deceba69dfb26826508bfca35de Mon Sep 17 00:00:00 2001 From: ttrebuchon Date: Mon, 11 Dec 2023 05:50:09 -0500 Subject: [PATCH 22/32] Add missing files to Moose.files: (#2062) Utilities/Socket.lua Core/Astar.lua Core/MarkerOps_Base.lua Functional/ZoneGoalCargo.lua Ops/OpsZone.lua Ops/ArmyGroup.lua Ops/OpsTransport.lua Ops/Target.lua --- Moose Setup/Moose.files | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index eb513c320..90a6e761d 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -5,6 +5,7 @@ Utilities/Profiler.lua Utilities/Templates.lua Utilities/STTS.lua Utilities/FiFo.lua +Utilities/Socket.lua Core/Base.lua Core/Beacon.lua @@ -32,6 +33,8 @@ Core/TextAndSound.lua Core/Condition.lua Core/Pathline.lua Core/ClientMenu.lua +Core/Astar.lua +Core/MarkerOps_Base.lua Wrapper/Object.lua Wrapper/Identifiable.lua @@ -79,6 +82,7 @@ Functional/Shorad.lua Functional/Autolase.lua Functional/AICSAR.lua Functional/AmmoTruck.lua +Functional/ZoneGoalCargo.lua Ops/Airboss.lua Ops/RecoveryTanker.lua @@ -107,6 +111,10 @@ Ops/FlightControl.lua Ops/PlayerTask.lua Ops/PlayerRecce.lua Ops/EasyGCICAP.lua +Ops/OpsZone.lua +Ops/ArmyGroup.lua +Ops/OpsTransport.lua +Ops/Target.lua AI/AI_Balancer.lua AI/AI_Air.lua From f837e9dec7522605ce60b31bbccfcb092c839b8b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 12 Dec 2023 10:53:37 +0100 Subject: [PATCH 23/32] #COORDINATE * Added functions to create a COORDINATE from MGRS --- Moose Development/Moose/Core/Point.lua | 52 ++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 3911a52f3..9cf13ba3e 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -25,7 +25,7 @@ do -- COORDINATE - --- @type COORDINATE + -- @type COORDINATE -- @field #string ClassName Name of the class -- @field #number x Component of the 3D vector. -- @field #number y Component of the 3D vector. @@ -2551,7 +2551,7 @@ do -- COORDINATE Offset=Offset or 2 - -- Measurement of visibility should not be from the ground, so Adding a hypotethical 2 meters to each Coordinate. + -- Measurement of visibility should not be from the ground, so Adding a hypothetical 2 meters to each Coordinate. local FromVec3 = self:GetVec3() FromVec3.y = FromVec3.y + Offset @@ -2952,10 +2952,10 @@ do -- COORDINATE end -- corrected Track to be direction of travel of bogey (self in this case) - local track = "Maneuver" - - if self.Heading then - track = UTILS.BearingToCardinal(self.Heading) or "North" + local track = "Maneuver" + + if self.Heading then + track = UTILS.BearingToCardinal(self.Heading) or "North" end if rangeNM > 3 then @@ -3100,6 +3100,44 @@ do -- COORDINATE local MGRS = coord.LLtoMGRS( lat, lon ) return "MGRS " .. UTILS.tostringMGRS( MGRS, MGRS_Accuracy ) end + + --- Provides a COORDINATE from an MGRS String + -- @param #COORDINATE self + -- @param #string MGRSString MGRS String, e.g. "MGRS 37T DK 12345 12345" + -- @return #COORDINATE self + function COORDINATE:NewFromMGRSString( MGRSString ) + local myparts = UTILS.Split(MGRSString," ") + UTILS.PrintTableToLog(myparts,1) + local MGRS = { + UTMZone = myparts[2], + MGRSDigraph = myparts[3], + Easting = tonumber(myparts[4]), + Northing = tonumber(myparts[5]), + } + local lat, lon = coord.MGRStoLL(MGRS) + local point = coord.LLtoLO(lat, lon, 0) + local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z}) + return coord + end + + --- Provides a COORDINATE from an MGRS Coordinate + -- @param #COORDINATE self + -- @param #string UTMZone UTM Zone, e.g. "37T" + -- @param #string MGRSDigraph Digraph, e.g. "DK" + -- @param #number Easting Meters easting + -- @param #number Northing Meters northing + -- @return #COORDINATE self + function COORDINATE:NewFromMGRS( UTMZone, MGRSDigraph, Easting, Northing ) + local MGRS = { + UTMZone = UTMZone, + MGRSDigraph = MGRSDigraph, + Easting = Easting, + Northing = Northing, + } + local lat, lon = coord.MGRStoLL(MGRS) + local point = coord.LLtoLO(lat, lon, 0) + local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z}) + end --- Provides a coordinate string of the point, based on a coordinate format system: -- * Uses default settings in COORDINATE. @@ -3613,7 +3651,7 @@ end do -- POINT_VEC2 - --- @type POINT_VEC2 + -- @type POINT_VEC2 -- @field DCS#Distance x The x coordinate in meters. -- @field DCS#Distance y the y coordinate in meters. -- @extends Core.Point#COORDINATE From 2a7213c1b74da5d8cbca9db153a05e1ccf061c76 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 12 Dec 2023 10:54:16 +0100 Subject: [PATCH 24/32] xxx --- Moose Development/Moose/Ops/Intelligence.lua | 132 +++++++++++++++++-- 1 file changed, 119 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index 0f71a234e..6e900790f 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -26,6 +26,7 @@ -- @field #table filterCategoryGroup Filter for group categories. -- @field Core.Set#SET_ZONE acceptzoneset Set of accept zones. If defined, only contacts in these zones are considered. -- @field Core.Set#SET_ZONE rejectzoneset Set of reject zones. Contacts in these zones are not considered, even if they are in accept zones. +-- @field Core.Set#SET_ZONE conflictzoneset Set of conflict zones. Contacts in these zones are considered, even if they are not in accept zones or if they are in reject zones. -- @field #table Contacts Table of detected items. -- @field #table ContactsLost Table of lost detected items. -- @field #table ContactsUnknown Table of new detected items. @@ -159,13 +160,12 @@ INTEL.Ctype={ --- INTEL class version. -- @field #string version -INTEL.version="0.3.5" +INTEL.version="0.3.6" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: Make forget times user input. Currently these are hard coded. -- TODO: Add min cluster size. Only create new clusters if they have a certain group size. -- TODO: process detected set asynchroniously for better performance. -- DONE: Add statics. @@ -266,6 +266,7 @@ function INTEL:New(DetectionSet, Coalition, Alias) self:SetForgetTime() self:SetAcceptZones() self:SetRejectZones() + self:SetConflictZones() ------------------------ --- Pseudo Functions --- @@ -416,7 +417,7 @@ function INTEL:RemoveAcceptZone(AcceptZone) end --- Set reject zones. Contacts detected in this/these zone(s) are rejected and not reported by the detection. --- Note that reject zones overrule accept zones, i.e. if a unit is inside and accept zone and inside a reject zone, it is rejected. +-- Note that reject zones overrule accept zones, i.e. if a unit is inside an accept zone and inside a reject zone, it is rejected. -- @param #INTEL self -- @param Core.Set#SET_ZONE RejectZoneSet Set of reject zone(s). -- @return #INTEL self @@ -426,7 +427,7 @@ function INTEL:SetRejectZones(RejectZoneSet) end --- Add a reject zone. Contacts detected in this zone are rejected and not reported by the detection. --- Note that reject zones overrule accept zones, i.e. if a unit is inside and accept zone and inside a reject zone, it is rejected. +-- Note that reject zones overrule accept zones, i.e. if a unit is inside an accept zone and inside a reject zone, it is rejected. -- @param #INTEL self -- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set. -- @return #INTEL self @@ -444,6 +445,36 @@ function INTEL:RemoveRejectZone(RejectZone) return self end +--- Set conflict zones. Contacts detected in this/these zone(s) are reported by the detection. +-- Note that conflict zones overrule all other zones, i.e. if a unit is outside of an accept zone and inside a reject zone, it is still reported if inside a conflict zone. +-- @param #INTEL self +-- @param Core.Set#SET_ZONE ConflictZoneSet Set of conflict zone(s). +-- @return #INTEL self +function INTEL:SetConflictZones(ConflictZoneSet) + self.conflictzoneset=ConflictZoneSet or SET_ZONE:New() + return self +end + +--- Add a conflict zone. Contacts detected in this zone are conflicted and not reported by the detection. +-- Note that conflict zones overrule all other zones, i.e. if a unit is outside of an accept zone and inside a reject zone, it is still reported if inside a conflict zone. +-- @param #INTEL self +-- @param Core.Zone#ZONE ConflictZone Add a zone to the conflict zone set. +-- @return #INTEL self +function INTEL:AddConflictZone(ConflictZone) + self.conflictzoneset:AddZone(ConflictZone) + return self +end + +--- Remove a conflict zone from the conflict zone set. +-- Note that conflict zones overrule all other zones, i.e. if a unit is outside of an accept zone and inside a reject zone, it is still reported if inside a conflict zone. +-- @param #INTEL self +-- @param Core.Zone#ZONE ConflictZone Remove a zone from the conflict zone set. +-- @return #INTEL self +function INTEL:RemoveConflictZone(ConflictZone) + self.conflictzoneset:Remove(ConflictZone:GetName(), true) + return self +end + --- **OBSOLETE, will be removed in next version!** Set forget contacts time interval. -- Previously known contacts that are not detected any more, are "lost" after this time. -- This avoids fast oscillations between a contact being detected and undetected. @@ -481,6 +512,33 @@ function INTEL:SetFilterCategory(Categories) return self end +--- Method to make the radar detection less accurate, e.g. for WWII scenarios. +-- @param #INTEL self +-- @param #number minheight Minimum flight height to be detected, in meters AGL (above ground) +-- @param #number thresheight Threshold to escape the radar if flying below minheight, defaults to 90 (90% escape chance) +-- @param #number thresblur Threshold to be detected by the radar overall, defaults to 85 (85% chance to be found) +-- @param #number closing Closing-in in km - the limit of km from which on it becomes increasingly difficult to escape radar detection if flying towards the radar position. Should be about 1/3 of the radar detection radius in kilometers, defaults to 20. +-- @return #INTEL self +function INTEL:SetRadarBlur(minheight,thresheight,thresblur,closing) + self.RadarBlur = true + self.RadarBlurMinHeight = minheight or 250 -- meters + self.RadarBlurThresHeight = thresheight or 90 -- 10% chance to find a low flying group + self.RadarBlurThresBlur = thresblur or 85 -- 25% chance to escape the radar overall + self.RadarBlurClosing = closing or 20 -- 20km + self.RadarBlurClosingSquare = self.RadarBlurClosing * self.RadarBlurClosing + return self +end + +--- Set the accept range in kilometers from each of the recce. Only object closer than this range will be detected. +-- @param #INTEL self +-- @param #number Range Range in kilometers +-- @return #INTEL self +function INTEL:SetAcceptRange(Range) + self.RadarAcceptRange = true + self.RadarAcceptRangeKilometers = Range or 75 + return self +end + --- Filter group categories. Valid categories are: -- -- * Group.Category.AIRPLANE @@ -780,7 +838,19 @@ function INTEL:UpdateIntel() local remove={} for unitname,_unit in pairs(DetectedUnits) do local unit=_unit --Wrapper.Unit#UNIT - + + local inconflictzone=false + -- Check if unit is in any of the conflict zones. + if self.conflictzoneset:Count()>0 then + for _,_zone in pairs(self.conflictzoneset.Set) do + local zone=_zone --Core.Zone#ZONE + if unit:IsInZone(zone) then + inconflictzone=true + break + end + end + end + -- Check if unit is in any of the accept zones. if self.acceptzoneset:Count()>0 then local inzone=false @@ -793,7 +863,7 @@ function INTEL:UpdateIntel() end -- Unit is not in accept zone ==> remove! - if not inzone then + if (not inzone) and (not inconflictzone) then table.insert(remove, unitname) end end @@ -810,7 +880,7 @@ function INTEL:UpdateIntel() end -- Unit is inside a reject zone ==> remove! - if inzone then + if inzone and (not inconflictzone) then table.insert(remove, unitname) end end @@ -1037,7 +1107,7 @@ function INTEL:CreateDetectedItems(DetectedGroups, DetectedStatics, RecceDetecti end --- (Internal) Return the detected target groups of the controllable as a @{SET_GROUP}. --- The optional parametes specify the detection methods that can be applied. +-- The optional parameters specify the detection methods that can be applied. -- If no detection method is given, the detection will use all the available methods by default. -- @param #INTEL self -- @param Wrapper.Unit#UNIT Unit The unit detecting. @@ -1053,6 +1123,7 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua -- Get detected DCS units. local reccename = Unit:GetName() + local detectedtargets=Unit:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) for DetectionObjectID, Detection in pairs(detectedtargets or {}) do @@ -1071,11 +1142,47 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua if status then local unit=UNIT:FindByName(name) - + if unit and unit:IsAlive() then - DetectedUnits[name]=unit - RecceDetecting[name]=reccename - self:T(string.format("Unit %s detect by %s", name, reccename)) + local DetectionAccepted = true + + if self.RadarAcceptRange then + local reccecoord = Unit:GetCoordinate() + local coord = unit:GetCoordinate() + local dist = math.floor(coord:Get2DDistance(reccecoord)/1000) -- km + if dist > self.RadarAcceptRangeKilometers then DetectionAccepted = false end + end + + if self.RadarBlur then + local reccecoord = Unit:GetCoordinate() + local coord = unit:GetCoordinate() + local dist = math.floor(coord:Get2DDistance(reccecoord)/1000) -- km + local AGL = unit:GetAltitude(true) + local minheight = self.RadarBlurMinHeight or 250 -- meters + local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group + local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall + --local dist = math.floor(Distance) + if dist <= self.RadarBlurClosing then + thresheight = (((dist*dist)/self.RadarBlurClosingSquare)*thresheight) + thresblur = (((dist*dist)/self.RadarBlurClosingSquare)*thresblur) + end + local fheight = math.floor(math.random(1,10000)/100) + local fblur = math.floor(math.random(1,10000)/100) + if fblur > thresblur then DetectionAccepted = false end + if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end + if self.debug or self.verbose > 1 then + MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + MESSAGE:New("Unit "..name.." is at "..math.floor(AGL).."m. Distance "..math.floor(dist).."km.",10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + MESSAGE:New(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur),10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + MESSAGE:New("Detection Accepted = "..tostring(DetectionAccepted),10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + end + end + + if DetectionAccepted then + DetectedUnits[name]=unit + RecceDetecting[name]=reccename + self:T(string.format("Unit %s detect by %s", name, reccename)) + end else if self.detectStatics then local static=STATIC:FindByName(name, false) @@ -1093,7 +1200,6 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua end end end - end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 8382eb9cd80cc0144b9cb4f407b9383086035cfe Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:21:28 +0100 Subject: [PATCH 25/32] Update Range.lua (#2066) MSRS config compatibility --- Moose Development/Moose/Functional/Range.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index e238914a9..13fb54c04 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -1207,18 +1207,18 @@ end -- @return #RANGE self function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, PathToGoogleKey) - if PathToSRS then + if PathToSRS or MSRS.path then self.useSRS=true - self.controlmsrs=MSRS:New(PathToSRS, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0) - self.controlmsrs:SetPort(Port) + self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0) + self.controlmsrs:SetPort(Port or MSRS.port) self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.controlmsrs:SetLabel("RANGEC") self.controlsrsQ = MSRSQUEUE:New("CONTROL") - self.instructmsrs=MSRS:New(PathToSRS, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0) - self.instructmsrs:SetPort(Port) + self.instructmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0) + self.instructmsrs:SetPort(Port or MSRS.port) self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.instructmsrs:SetLabel("RANGEI") self.instructsrsQ = MSRSQUEUE:New("INSTRUCT") From 42fd2322d233a061faf0dce204b2c47ae737ba49 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:33:07 +0100 Subject: [PATCH 26/32] Update Range.lua (#2066) (#2067) MSRS config compatibility --- Moose Development/Moose/Functional/Range.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index e238914a9..13fb54c04 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -1207,18 +1207,18 @@ end -- @return #RANGE self function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, PathToGoogleKey) - if PathToSRS then + if PathToSRS or MSRS.path then self.useSRS=true - self.controlmsrs=MSRS:New(PathToSRS, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0) - self.controlmsrs:SetPort(Port) + self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0) + self.controlmsrs:SetPort(Port or MSRS.port) self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.controlmsrs:SetLabel("RANGEC") self.controlsrsQ = MSRSQUEUE:New("CONTROL") - self.instructmsrs=MSRS:New(PathToSRS, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0) - self.instructmsrs:SetPort(Port) + self.instructmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0) + self.instructmsrs:SetPort(Port or MSRS.port) self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.instructmsrs:SetLabel("RANGEI") self.instructsrsQ = MSRSQUEUE:New("INSTRUCT") From 68548f45815f682a81cecf4538b242e0f883238e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Dec 2023 11:12:14 +0100 Subject: [PATCH 27/32] #COORDINATE * Fix for NewFromMGRS for less precise coordinates (below level 5) --- Moose Development/Moose/Core/Point.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 9cf13ba3e..a3c83da1f 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -24,7 +24,8 @@ do -- COORDINATE - + + --- -- @type COORDINATE -- @field #string ClassName Name of the class -- @field #number x Component of the 3D vector. @@ -3107,13 +3108,16 @@ do -- COORDINATE -- @return #COORDINATE self function COORDINATE:NewFromMGRSString( MGRSString ) local myparts = UTILS.Split(MGRSString," ") - UTILS.PrintTableToLog(myparts,1) + local northing = tostring(myparts[5]) or "" + local easting = tostring(myparts[4]) or "" + if string.len(easting) < 5 then easting = easting..string.rep("0",5-string.len(easting)) end + if string.len(northing) < 5 then northing = northing..string.rep("0",5-string.len(northing)) end local MGRS = { UTMZone = myparts[2], MGRSDigraph = myparts[3], - Easting = tonumber(myparts[4]), - Northing = tonumber(myparts[5]), - } + Easting = easting, + Northing = northing, + } local lat, lon = coord.MGRStoLL(MGRS) local point = coord.LLtoLO(lat, lon, 0) local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z}) @@ -3124,10 +3128,12 @@ do -- COORDINATE -- @param #COORDINATE self -- @param #string UTMZone UTM Zone, e.g. "37T" -- @param #string MGRSDigraph Digraph, e.g. "DK" - -- @param #number Easting Meters easting - -- @param #number Northing Meters northing + -- @param #string Easting Meters easting - string in order to allow for leading zeros, e.g. "01234". Should be 5 digits. + -- @param #string Northing Meters northing - string in order to allow for leading zeros, e.g. "12340". Should be 5 digits. -- @return #COORDINATE self function COORDINATE:NewFromMGRS( UTMZone, MGRSDigraph, Easting, Northing ) + if string.len(Easting) < 5 then Easting = Easting..string.rep("0",5-string.len(Easting) )end + if string.len(Northing) < 5 then Northing = Northing..string.rep("0",5-string.len(Northing) )end local MGRS = { UTMZone = UTMZone, MGRSDigraph = MGRSDigraph, From b31fc3ed446c686e42d73fc66c377e6ab3c2286c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Dec 2023 11:12:50 +0100 Subject: [PATCH 28/32] Limit Attacked() to have at least the capture threatlevel --- Moose Development/Moose/Ops/OpsZone.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/OpsZone.lua b/Moose Development/Moose/Ops/OpsZone.lua index 780b389c0..ee83650aa 100644 --- a/Moose Development/Moose/Ops/OpsZone.lua +++ b/Moose Development/Moose/Ops/OpsZone.lua @@ -97,7 +97,7 @@ OPSZONE.ZoneType={ --- OPSZONE class version. -- @field #string version -OPSZONE.version="0.6.0" +OPSZONE.version="0.6.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -1277,7 +1277,7 @@ function OPSZONE:EvaluateZone() if Nblu>0 then - if not self:IsAttacked() then + if not self:IsAttacked() and self.Tnut>=self.threatlevelCapture then self:Attacked(coalition.side.BLUE) end @@ -1329,7 +1329,7 @@ function OPSZONE:EvaluateZone() if Nred>0 then - if not self:IsAttacked() then + if not self:IsAttacked() and self.Tnut>=self.threatlevelCapture then -- Red is attacking blue zone. self:Attacked(coalition.side.RED) end From 55ffe37a794e7dba9eeaf3bb5fee618ec2989a60 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Dec 2023 12:42:13 +0100 Subject: [PATCH 29/32] #USERSOUND * Added USERSOUND:ToClient( Client, Delay ) --- Moose Development/Moose/Sound/UserSound.lua | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Sound/UserSound.lua b/Moose Development/Moose/Sound/UserSound.lua index cbccffe12..1c753a538 100644 --- a/Moose Development/Moose/Sound/UserSound.lua +++ b/Moose Development/Moose/Sound/UserSound.lua @@ -137,7 +137,7 @@ do -- UserSound return self end - --- Play the usersound to the given @{Wrapper.Unit}. + --- Play the usersound to the given @{Wrapper.Unit}. -- @param #USERSOUND self -- @param Wrapper.Unit#UNIT Unit The @{Wrapper.Unit} to play the usersound to. -- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0. @@ -159,4 +159,24 @@ do -- UserSound return self end + + --- Play the usersound to the given @{Wrapper.Unit}. + -- @param #USERSOUND self + -- @param Wrapper.Client#CLIENT The @{Wrapper.Client} to play the usersound to. + -- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0. + -- @return #USERSOUND The usersound instance. + -- @usage + -- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" ) + -- local PlayerUnit = CLIENT:FindByPlayerName("Karl Heinz")-- Search for the active client with playername "Karl Heinz", a human player. + -- BlueVictory:ToClient( PlayerUnit ) -- Play the victory sound to the player unit. + -- + function USERSOUND:ToClient( Client, Delay ) + Delay=Delay or 0 + if Delay>0 then + SCHEDULER:New(nil, USERSOUND.ToClient,{self, Client}, Delay) + else + trigger.action.outSoundForUnit( Client:GetID(), self.UserSoundFileName ) + end + return self + end end \ No newline at end of file From e84e16f58bf975dc7bdd9787ad227f286010efe0 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 14 Dec 2023 12:43:36 +0100 Subject: [PATCH 30/32] xx --- Moose Development/Moose/Sound/UserSound.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Sound/UserSound.lua b/Moose Development/Moose/Sound/UserSound.lua index 1c753a538..ceaeeb6e2 100644 --- a/Moose Development/Moose/Sound/UserSound.lua +++ b/Moose Development/Moose/Sound/UserSound.lua @@ -160,7 +160,7 @@ do -- UserSound end - --- Play the usersound to the given @{Wrapper.Unit}. + --- Play the usersound to the given @{Wrapper.Client}. -- @param #USERSOUND self -- @param Wrapper.Client#CLIENT The @{Wrapper.Client} to play the usersound to. -- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0. From bda4efc634c804ea01ddebc97163477932a99985 Mon Sep 17 00:00:00 2001 From: kaltokri Date: Fri, 15 Dec 2023 14:08:45 +0100 Subject: [PATCH 31/32] Added page "Create your own Hello world" --- docs/beginner/demo-missions.md | 13 ++ docs/beginner/hello-world-build.md | 169 +++++++++++++++++- .../dcs-triggers-once-conditions-conf.png | Bin 0 -> 11728 bytes 3 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 docs/beginner/demo-missions.md create mode 100644 docs/images/beginner/dcs-triggers-once-conditions-conf.png diff --git a/docs/beginner/demo-missions.md b/docs/beginner/demo-missions.md new file mode 100644 index 000000000..073ae42fd --- /dev/null +++ b/docs/beginner/demo-missions.md @@ -0,0 +1,13 @@ +--- +parent: Beginner +nav_order: 04 +--- + +# Demo missions +{: .no_toc } + +1. Table of contents +{:toc} + +{: .warning } +> THIS DOCUMENT IS STILL WORK IN PROGRESS! diff --git a/docs/beginner/hello-world-build.md b/docs/beginner/hello-world-build.md index fde7e63da..1f7509abd 100644 --- a/docs/beginner/hello-world-build.md +++ b/docs/beginner/hello-world-build.md @@ -4,6 +4,171 @@ nav_order: 03 --- # Create your own Hello world +{: .no_toc } -{: .warning } -> THIS DOCUMENT IS STILL WORK IN PROGRESS! +1. Table of contents +{:toc} + +This page will lead you step by step through the process of creating a mission +with MOOSE. This time we include a simple mission script, which sends only +a "Hello world" message to all players. But the steps are the same to add +another mission script, which will do whatever class(es) you want to use. + +## Create Mission script + +At first we will create the mission script. It is a simple text file and can be +changed with a lot of different tools. Theoretically even the Microsoft Notepad +editor can be used. But it lacks a lot of features, which helps you to avoid +errors. + +For this guide we suggest you to download, install and use [Notepad++]{:target="_blank"}. + +{: .important } +> Windows hides filename extensions by default. So when you create a text file +> and name it `hello-world.lua` it's name is `hello-world.lua.txt` in reality. +> You must activate the display of the file name extension. +> Open a `File Explorer`, switch to menu `View` and find the option +> `File name extensions` in the section `Show/hide`. Activate it. + +- Open a File Explorer. +- Go to the subfolder `Missions` of your [Saved Games folder]{:target="_blank"}. +- Create a new text file and name it `hello-world.lua`. +- Add the following content and save the file: + + `MESSAGE:New( "Hello World! This messages is printed by MOOSE", 35, "INFO" ):ToAll()` + +## Get Moose + +To download Moose click on the following link: + +- [Moose_.lua from develop branch]{:target="_blank"} + +Press `Ctrl + S` to save the file on your hard disk next to your mission script. + +## Create the mission + +- Start DCS. +- In the main menu choose `MISSION EDITOR`. +- Click on `create new mission`. +- In the dialog `NEW MISSION SETTINGS`: + - Choose map `Caucasus`. + - In the drop box upper left choose `Modern` as coalition preset. + - Click on `OK`. +- The mission editor will load with a fresh new and empty mission. +- Click on `File` in the menu bar and `SAVE` or Press `Ctrl + S`. +- Open `My Missions` and save the file with the name `hello-world.miz`. + +## Add Moose to the mission + +- On the left side activate `TRIGGERS`: + + ![dcs-triggers-toolbar.png](../images/beginner/dcs-triggers-toolbar.png) + +- On the right side the `TRIGGERS` dialog opens with a lot of options. +- Click on `NEW`, choose `4 MISSION START` as **TYPE**. +- Give it the `Load MOOSE` as **NAME**. +- Leave the **EVENT** option set to `NO EVENT`. +- Optional: Choose a color for easy recognition (e.g. yellow). + + ![dcs-triggers-mission-start-conf.png](../images/beginner/dcs-triggers-mission-start-conf.png) + +- In the middle part the `CONDITIONS` will be shown. + For this trigger we do not configure any conditions. + + ![dcs-triggers-mission-start-conditions.png](../images/beginner/dcs-triggers-mission-start-conditions.png) + + {: .important } + > The trigger type `4 MISSION START` does not support `CONDITIONS`.
+ > So `CONDITIONS` must left blank when using it.
+ > **If you add a condition the trigger will never be executed!** + + ![dcs-triggers-mission-start-actions-conf.png](../images/beginner/dcs-triggers-mission-start-actions-conf.png) + +- On the right side `ACTIONS` is shown. +- We need to click on `NEW`. +- Choose **ACTION** `Do SCRIPT FILE` and ignore all other actions. +- Click **OPEN** and navigate to the downloaded `Moose_.lua` file. +- The result should look like this: + + ![dcs-triggers-mission-start-actions.png](../images/beginner/dcs-triggers-mission-start-actions.png) + +## Add the mission script + +- Click on `NEW`, choose `1 ONCE` as **TYPE**. +- Give it the `Load Mission Script` as **NAME**. +- Leave the **EVENT** option set to `NO EVENT`. +- Optional: Choose a color for easy recognition (e.g. green). +- The result should look like this: + + ![dcs-triggers-once-conf.png](../images/beginner/dcs-triggers-once-conf.png) + +- Switch to the middle part, the `CONDITIONS` section.
+ For this trigger we add one condition: + + ![dcs-triggers-once-conditions.png](../images/beginner/dcs-triggers-once-conditions-conf.png) + +- The combination of `1 ONCE` with `TIME MORE(1)` will ensure, that the mission + script is executed 1 second after the mission is started. + +- On the right side under `ACTIONS` you need to add the script: +- Click on `NEW`. +- Choose **ACTION** `Do SCRIPT FILE`. +- Click **OPEN** and navigate to the created `hello-world.lua` file. + +{: .important } +> Most important is the fact, that the mission script (`hello-world.lua`) +> is executed **after** `Moose_.lua`, because the mission script needs the +> classes defined in `Moose_.lua`. And they are only available when `Moose_.lua` +> is executed before the mission script. + +## Test the mission + +- Save the mission again. +- Click on the green **Fly mission** cirlce on the left tool side bar. +- It is an empty mission, so skip `BRIEFING` with `START` and then `FLY`. +- You spawn as a spectator. After some seconds you will see this message in + the upper right corner: + + ![dcs-message.jpg](../images/beginner/dcs-message.jpg) + +This is the same result as already seen in the last chapter, but this time you +have create everything on your own. + +{: .note } +> You can use this mission as a template for your own missions. So you don't +> need to do alle these steps again and again. + +## Update mission script + +- Open the `hello-world.lua` with Notepad++ again. +- Change the text a little bit, like `Hello Dude! ...` and save the file. +- Run the mission again. +- The text will not be changed in the mission. Why? + The mission editor copies the script into the mission file when you add it. + Ever change on the script file on your hard disk is not recognized by mission editor. + You have to add the file after each change again. + +- On the left side of the `TRIGGERS` dialog click on `Load Mission Script`. +- On the right side under `ACTIONS` you need to add the script again: + - Click **OPEN** and navigate to the created `hello-world.lua` file. +- Save the mission and test it again. +- Now the new text should be shown. + +## Update Moose + +Moose is constantly being developed so that new functionallity is added or +existing errors are corrected. Also from time to time changes of the DCS +scripting engine comes with a new DCS version. It may therefore be useful or +necessary to update Moose. + +- To update Moose download it again and add it again in the same way you did + with the mission script in the last step. + +## Next step + +Let's move on to the [demo missions]. + +[Notepad++]: https://notepad-plus-plus.org/downloads/ +[Saved Games folder]: tipps-and-tricks.md#find-the-saved-games-folder +[Moose_.lua from develop branch]: https://raw.githubusercontent.com/FlightControl-Master/MOOSE_INCLUDE/develop/Moose_Include_Static/Moose_.lua +[demo missions]: demo-missions.md diff --git a/docs/images/beginner/dcs-triggers-once-conditions-conf.png b/docs/images/beginner/dcs-triggers-once-conditions-conf.png new file mode 100644 index 0000000000000000000000000000000000000000..e751ea40ff51d2066e06b7a5b10522d0d7051005 GIT binary patch literal 11728 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 literal 0 HcmV?d00001 From 0ae9be49daacf38be2efbeef7224d3e3ceace495 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 16 Dec 2023 09:31:44 +0100 Subject: [PATCH 32/32] Update Range.lua - Fixed random good by phrase --- Moose Development/Moose/Functional/Range.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 13fb54c04..8da132f14 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -2187,7 +2187,7 @@ function RANGE:onafterExitRange( From, Event, To, player ) local text = "You left the bombing range zone. " - local r=math.random(2) + local r=math.random(5) if r==1 then text=text.."Have a nice day!"