From ca32c57c52b83aa4e20fd3c17a0d8d0c06c9df27 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 24 Mar 2018 07:32:04 +0100 Subject: [PATCH 001/170] Progress on the new cargo group movements --- Moose Development/Moose/Core/Cargo.lua | 57 ++++++++++++++++------- Moose Development/Moose/Wrapper/Group.lua | 2 +- Moose Development/Moose/Wrapper/Unit.lua | 6 ++- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 991669931..495938e77 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -1,5 +1,7 @@ --- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers. -- +-- === +-- -- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) -- -- === @@ -602,23 +604,19 @@ end -- CARGO_REPRESENTABLE --- CARGO_REPORTABLE Constructor. -- @param #CARGO_REPORTABLE self - -- @param Wrapper.Controllable#Controllable CargoObject -- @param #string Type -- @param #string Name -- @param #number Weight -- @param #number ReportRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_REPORTABLE - function CARGO_REPORTABLE:New( CargoObject, Type, Name, Weight, ReportRadius ) + function CARGO_REPORTABLE:New( Type, Name, Weight, ReportRadius ) local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE self:F( { Type, Name, Weight, ReportRadius } ) self.CargoSet = SET_CARGO:New() -- Core.Set#SET_CARGO self.ReportRadius = ReportRadius or 1000 - self.CargoObject = CargoObject - - return self end @@ -776,8 +774,9 @@ do -- CARGO_UNIT -- Respawn the group... if self.CargoObject then + self:F( { CargoObject = self.CargoObject } ) self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) - self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) + --self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) self.CargoCarrier = nil local Points = {} @@ -1150,6 +1149,8 @@ do -- CARGO_GROUP } --- CARGO_GROUP constructor. +-- This make a new CARGO_GROUP from a @{Group} object. +-- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. -- @param #CARGO_GROUP self -- @param Wrapper.Group#GROUP CargoGroup -- @param #string Type @@ -1158,23 +1159,47 @@ do -- CARGO_GROUP -- @param #number NearRadius (optional) -- @return #CARGO_GROUP function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP self:F( { Type, Name, ReportRadius } ) - self.CargoObject = CargoGroup self:SetDeployed( false ) - self.CargoGroup = CargoGroup local WeightGroup = 0 + local GroupName = CargoGroup:GetName() - for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - local WeightUnit = Unit:GetDesc().massEmpty - WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit ) - self.CargoSet:Add( CargoUnit:GetName(), CargoUnit ) + CargoGroup:Destroy() + + -- We iterate through the group template and for each unit in the template, we create a new group with one unit. + for UnitID, UnitTemplate in pairs( _DATABASE:GetGroupTemplate(GroupName).units ) do + + local GroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate(GroupName) ) + local GroupName = env.getValueDictByKey( GroupTemplate.name ) + self:E( GroupName ) + + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.units = {} + GroupTemplate.units[1] = UnitTemplate + local UnitName = UnitTemplate.name .. "#CARGO" + GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" + + + -- Then we register the new group in the database + local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + + -- And we register the spawned unit as part of the CargoSet. + local Unit = UNIT:FindByName( UnitName ) + --local WeightUnit = Unit:GetDesc().massEmpty + --WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) + self.CargoSet:Add( UnitName, CargoUnit ) end + self:SetWeight( WeightGroup ) self:T( { "Weight Cargo", WeightGroup } ) @@ -1355,7 +1380,7 @@ function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius function( Cargo, NearRadius ) Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 10 + Timer = Timer + 1 end, { NearRadius } ) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index f46c2701b..0606b14a0 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -336,7 +336,7 @@ end -- @param #number UnitNumber The number of the UNIT wrapper class to be returned. -- @return Wrapper.Unit#UNIT The UNIT wrapper class. function GROUP:GetUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) + self:E( { self.GroupName, UnitNumber } ) local DCSGroup = self:GetDCSObject() diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 26d30ed91..695774052 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -193,10 +193,12 @@ end -- @param #number Heading The heading of the unit respawn. function UNIT:ReSpawn( SpawnVec3, Heading ) + self:T( self:Name() ) local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) self:T( SpawnGroupTemplate ) local SpawnGroup = self:GetGroup() + self:T( { SpawnGroup = SpawnGroup } ) if SpawnGroup then @@ -221,7 +223,7 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) end for UnitTemplateID, UnitTemplateData in pairs( SpawnGroupTemplate.units ) do - self:T( UnitTemplateData.name ) + self:T( { UnitTemplateData.name, self:Name() } ) if UnitTemplateData.name == self:Name() then self:T("Adjusting") SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y @@ -261,6 +263,8 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) i = i + 1 end end + + self:T( SpawnGroupTemplate ) _DATABASE:Spawn( SpawnGroupTemplate ) end From 7963f04bdc41576227ea29c6e2cc0bba7ca665a8 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 24 Mar 2018 08:01:49 +0100 Subject: [PATCH 002/170] progress --- Moose Development/Moose/Core/Cargo.lua | 11 +++++++---- Moose Development/Moose/Core/Point.lua | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 495938e77..7a1949fbc 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -261,7 +261,7 @@ function CARGO:New( Type, Name, Weight ) --R2.1 self.Name = Name self.Weight = Weight self.CargoObject = nil - self.CargoCarrier = nil + self.CargoCarrier = nil -- Wrapper.Client#CLIENT self.Representable = false self.Slingloadable = false self.Moveable = false @@ -753,7 +753,7 @@ do -- CARGO_UNIT if From == "Loaded" then - local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE + local CargoCarrier = self.CargoCarrier -- Wrapper.Client#CLIENT local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. @@ -764,11 +764,12 @@ do -- CARGO_UNIT -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 + ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, 5 ) local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2) local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3) local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, 5 ) local FromPointVec2 = CargoCarrierPointVec2 @@ -937,7 +938,7 @@ do -- CARGO_UNIT -- @param #string Event -- @param #string From -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param Wrapper.Client#CLIENT CargoCarrier -- @param #number NearRadius function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) @@ -1366,6 +1367,8 @@ function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius self:F( {From, Event, To, ToPointVec2, NearRadius } ) NearRadius = NearRadius or 25 + + local CargoCarrier = self.CargoCarrier -- Wrapper.Client#CLIENT local Timer = 1 diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index b5556abea..f3eb0b5b7 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -303,6 +303,18 @@ do -- COORDINATE end + --- Return a random Coordinate within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. + -- @param #COORDINATE self + -- @param Dcs.DCSTypes#Distance OuterRadius + -- @param Dcs.DCSTypes#Distance InnerRadius + -- @return #COORDINATE + function COORDINATE:GetRandomCoordinateInRadius( OuterRadius, InnerRadius ) + self:F2( { OuterRadius, InnerRadius } ) + + return COORDINATE:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) + end + + --- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Distance OuterRadius From 7088c4c426dc597198c1f509f81d9acf26221b57 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 25 Mar 2018 08:15:13 +0200 Subject: [PATCH 003/170] updated branched creation of include repo --- .appveyor/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index 8f77f698d..1430d6ceb 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -48,7 +48,7 @@ install: build_script: - ps: | - if( $env:appveyor_repo_branch -eq 'master' ) + if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' ) { $apiUrl = 'https://ci.appveyor.com/api' $token = 'qts80b5kpq0ooj4x6vvw' @@ -56,7 +56,7 @@ build_script: "Authorization" = "Bearer $token" "Content-type" = "application/json" } - $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = 'master'; environmentVariables = @{} } | ConvertTo-Json + $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json # get project with last build details $project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody } From c4f2446b92497662657c7359b718e781464ee03d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 25 Mar 2018 08:17:33 +0200 Subject: [PATCH 004/170] fix --- .appveyor/appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index 1430d6ceb..ce7a2f7b6 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -57,7 +57,7 @@ build_script: "Content-type" = "application/json" } $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json - # get project with last build details + # Generate the new version ... $project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody } - ps: | From cce90b1f46da60f844ef1e851c4825320ac141a7 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 26 Mar 2018 06:52:24 +0200 Subject: [PATCH 005/170] New AI_CARGO_TROOPS class --- .../Moose/AI/AI_Cargo_Troops.lua | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 Moose Development/Moose/AI/AI_Cargo_Troops.lua diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua new file mode 100644 index 000000000..373c6682a --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -0,0 +1,105 @@ +--- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo). +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Troops + +--- @type AI_Cargo_Troops +-- @extends Core.Base#BASE + + +--- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE} +-- +-- === +-- +-- @field #AI_CARGO_TROOPS +AI_CARGO_TROOPS = { + ClassName = "AI_CARGO_TROOPS", +} + +--- Creates a new AI_CARGO_TROOPS object +-- @param #AI_CARGO_TROOPS self +-- @return #AI_CARGO_TROOPS +function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) + + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( ) ) -- #AI_CARGO_TROOPS + + self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT + self.CargoGroup = CargoGroup -- Core.Cargo#CARGO_GROUP + self.CombatRadius = CombatRadius + + self:SetControllable( self.CargoCarrier ) + + self:SetStartState( "UnLoaded" ) + + self:AddTransition( "*", "Load", "Boarding" ) + self:AddTransition( "Boarding", "Boarding", "Boarding" ) + self:AddTransition( "Boarding", "Loaded", "Loaded" ) + self:AddTransition( "Loaded", "Unload", "Unboarding" ) + self:AddTransition( "UnBoarding", "Unloaded", "Unloaded" ) + + self:AddTransition( "*", "Monitor", "*" ) + + self:__Monitor( 1 ) + self:__Load( 1 ) + + return self +end + + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + end + + self:__Monitor( 1 ) + +end + + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + self.CargoGroup:__Board( 1, CargoCarrier, 100 ) + self:__Boarding( 1 ) + end + +end + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterBoarding( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + if self.CargoGroup:IsBoarding() then + self:__Boarding( 1 ) + end + + if self.CargoGroup:IsLoaded() then + self:__Loaded( 1 ) + end + end + +end + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterLoaded( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + end + +end + From e7518d69e66c8c1b24591e11b0621f000b7d87d1 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 26 Mar 2018 07:39:55 +0200 Subject: [PATCH 006/170] Cargo Troops --- .../Moose/AI/AI_Cargo_Troops.lua | 25 +++++++++++++++-- Moose Development/Moose/Core/Point.lua | 28 +++++++++++++++++++ .../Moose/Wrapper/Controllable.lua | 22 +++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 373c6682a..58374618f 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -8,8 +8,8 @@ -- -- @module AI_Cargo_Troops ---- @type AI_Cargo_Troops --- @extends Core.Base#BASE +--- @type AI_CARGO_TROOPS +-- @extends Core.Fsm#FSM_CONTROLLABLE --- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE} @@ -19,6 +19,7 @@ -- @field #AI_CARGO_TROOPS AI_CARGO_TROOPS = { ClassName = "AI_CARGO_TROOPS", + Coordinate = nil -- Core.Point#COORDINATE, } --- Creates a new AI_CARGO_TROOPS object @@ -32,6 +33,9 @@ function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) self.CargoGroup = CargoGroup -- Core.Cargo#CARGO_GROUP self.CombatRadius = CombatRadius + self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, CombatRadius ) + self.Coalition = self.CargoCarrier:GetCoalition() + self:SetControllable( self.CargoCarrier ) self:SetStartState( "UnLoaded" ) @@ -57,6 +61,22 @@ function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then + if self.Coordinate then + local Coordinate = CargoCarrier:GetCoordinate() + if Coordinate:IsAtCoordinate2D( self.Coordinate, 2 ) then + self.Zone:Scan( { Object.Category.UNIT } ) + if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then + else + if not self:Is( "Unloaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + self:__Unload( 1 ) + self.CargoCarrier:RouteStop() + end + end + end + else + self.Coordinate = CargoCarrier:GetCoordinate() + end end self:__Monitor( 1 ) @@ -99,6 +119,7 @@ function AI_CARGO_TROOPS:onafterLoaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then + CargoCarrier:RouteStop() end end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index b5556abea..df0a3d21a 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -192,6 +192,20 @@ do -- COORDINATE return self end + --- COORDINATE constructor. + -- @param #COORDINATE self + -- @param #COORDINATE Coordinate. + -- @return #COORDINATE + function COORDINATE:NewFromCoordinate( Coordinate ) + + local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE + self.x = Coordinate.x + self.y = Coordinate.y + self.z = Coordinate.z + + return self + end + --- Create a new COORDINATE object from Vec2 coordinates. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. @@ -241,6 +255,20 @@ do -- COORDINATE return { x = self.x, y = self.z } end + + --- Returns if the 2 coordinates are at the same 2D position. + -- @param #COORDINATE self + -- @return #boolean true if at the same position. + function COORDINATE:IsAtCoordinate2D( Coordinate, Precision ) + + local x = Coordinate.x + local z = Coordinate.z + + return x - Precision <= self.x and x + Precision >= self.x and z - Precision <= self.z and z + Precision >= self.z + end + + + --TODO: check this to replace --- Calculate the distance from a reference @{DCSTypes#Vec2}. -- @param #COORDINATE self diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index fe3d1378d..01fe228e4 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1908,6 +1908,28 @@ function CONTROLLABLE:Route( Route, DelaySeconds ) end +--- Stops the movement of the vehicle on the route. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE +function CONTROLLABLE:RouteStop() + self:F2() + + local CommandStop = self:CommandStopRoute( true ) + self:SetCommand( CommandStop ) + +end + +--- Resumes the movement of the vehicle on the route. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE +function CONTROLLABLE:RouteResume() + self:F2() + + local CommandResume = self:CommandStopRoute( false ) + self:SetCommand( CommandResume ) + +end + --- Make the GROUND Controllable to drive towards a specific point. -- @param #CONTROLLABLE self -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. From b6fc46fdd01a66d4aba855db96eafd547fcc5af2 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 26 Mar 2018 17:53:23 +0200 Subject: [PATCH 007/170] Cargo Troops --- .../Moose/AI/AI_Cargo_Troops.lua | 89 ++++++++++++++----- Moose Development/Moose/Core/Cargo.lua | 22 +++++ 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 58374618f..7cb69ab0c 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -36,15 +36,16 @@ function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, CombatRadius ) self.Coalition = self.CargoCarrier:GetCoalition() - self:SetControllable( self.CargoCarrier ) + self:SetControllable( CargoCarrier ) self:SetStartState( "UnLoaded" ) self:AddTransition( "*", "Load", "Boarding" ) - self:AddTransition( "Boarding", "Boarding", "Boarding" ) + self:AddTransition( "Boarding", "Board", "Boarding" ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) - self:AddTransition( "UnBoarding", "Unloaded", "Unloaded" ) + self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) + self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) self:AddTransition( "*", "Monitor", "*" ) @@ -63,17 +64,24 @@ function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then if self.Coordinate then local Coordinate = CargoCarrier:GetCoordinate() - if Coordinate:IsAtCoordinate2D( self.Coordinate, 2 ) then - self.Zone:Scan( { Object.Category.UNIT } ) - if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - else - if not self:Is( "Unloaded" ) then - -- There are enemies within combat range. Unload the CargoCarrier. - self:__Unload( 1 ) - self.CargoCarrier:RouteStop() - end + self.Zone:Scan( { Object.Category.UNIT } ) + if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then +-- if self:Is( "Unloaded" ) then +-- -- There are no enemies within combat range. Load the CargoCarrier. +-- self:__Load( 1 ) +-- end + else + if self:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + self:__Unload( 1 ) end end + if self:Is( "Unloaded" ) then + if not Coordinate:IsAtCoordinate2D( self.Coordinate, 2 ) then + --self.CargoGroup:RouteTo( Coordinate, 30 ) + end + end + else self.Coordinate = CargoCarrier:GetCoordinate() end @@ -90,23 +98,23 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then - self.CargoGroup:__Board( 1, CargoCarrier, 100 ) - self:__Boarding( 1 ) + CargoCarrier:RouteStop() + self:Board() + self.CargoGroup:Board( CargoCarrier, 100 ) end end --- @param #AI_CARGO_TROOPS self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterBoarding( CargoCarrier, From, Event, To ) +function AI_CARGO_TROOPS:onafterBoard( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then - if self.CargoGroup:IsBoarding() then - self:__Boarding( 1 ) - end - - if self.CargoGroup:IsLoaded() then + self:F({ IsLoaded = self.CargoGroup:IsLoaded() } ) + if not self.CargoGroup:IsLoaded() then + self:__Board( 1 ) + else self:__Loaded( 1 ) end end @@ -119,8 +127,47 @@ function AI_CARGO_TROOPS:onafterLoaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteStop() + CargoCarrier:RouteResume() end end + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterUnload( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + CargoCarrier:RouteStop() + self.CargoGroup:UnBoard( ) + self:__Unboard( 1 ) + end + +end + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterUnboard( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + if not self.CargoGroup:IsUnLoaded() then + self:__Unboard( 1 ) + else + self:Unloaded() + end + end + +end + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterUnloaded( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + if CargoCarrier and CargoCarrier:IsAlive() then + CargoCarrier:RouteResume() + end + +end diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 991669931..66f9c04c8 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -1312,6 +1312,7 @@ function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, if not Boarded then self:__Boarding( 1, CargoCarrier, NearRadius, ... ) else + self:F("Group Cargo is loaded") self:__Load( 1, CargoCarrier, ... ) end else @@ -1458,6 +1459,27 @@ end end end + + --- Route Cargo to Coordinate and randomize locations. + -- @param #CARGO_GROUP self + -- @param Core.Point#COORDINATE Coordinate + function CARGO_GROUP:RouteTo( Coordinate ) + self:F( ) + + --local NearRadius = NearRadius or 25 + + if From == "UnLoaded" then + + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, Coordinate ) + Cargo.CargoObject:RouteTo( Coordinate ) + end, Coordinate + ) + + end + + end end -- CARGO_GROUP From 727d64927b79ffd2eb06c10efc7f49abd484219d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 27 Mar 2018 12:07:16 +0200 Subject: [PATCH 008/170] First working prototype of AI_CARGO_TROOPS. --- .../Moose/AI/AI_Cargo_Troops.lua | 98 ++- Moose Development/Moose/Core/Cargo.lua | 589 +++++++++--------- Moose Development/Moose/Core/Point.lua | 5 + 3 files changed, 396 insertions(+), 296 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 7cb69ab0c..dd2104ccc 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -48,6 +48,8 @@ function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) self:AddTransition( "*", "Monitor", "*" ) + self:AddTransition( "*", "Follow", "Following" ) + self:AddTransition( "*", "Guard", "Guarding" ) self:__Monitor( 1 ) self:__Load( 1 ) @@ -56,38 +58,94 @@ function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) end +--- Follow Infantry to the Carrier. +-- @param #AI_CARGO_TROOPS self +-- @return #AI_CARGO_TROOPS +function AI_CARGO_TROOPS:FollowToCarrier( Me ) + + self = Me + + self:F( { self = self:GetClassNameAndID(), CargoGroup = self.CargoGroup:GetName() } ) + + -- We check if the Cargo is near to the CargoCarrier. + if self.CargoGroup:IsNear( self.CargoCarrier, 5 ) then + + -- The Cargo does not need to follow the Carrier. + self:Guard() + + else + + -- The Cargo needs to continue to follow the Carrier. + if self:Is( "Following" ) then + + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoGroup.CargoSet:ForEach( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoUnit = Cargo.CargoObject -- Wrapper.Unit#UNIT + self:F( { UnitName = CargoUnit:GetName() } ) + + if CargoUnit:IsAlive() then + + local InfantryGroup = CargoUnit:GetGroup() + self:F( { GroupName = InfantryGroup:GetName() } ) + + local Waypoints = {} + + -- Calculate the new Route. + local FromCoord = InfantryGroup:GetCoordinate() + local FromGround = FromCoord:WaypointGround( 10, "Diamond" ) + table.insert( Waypoints, FromGround ) + + local ToCoord = self.CargoCarrier:GetCoordinate() + local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) + table.insert( Waypoints, ToGround ) + + local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_TROOPS.FollowToCarrier", self ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. + + InfantryGroup:Route( Waypoints ) -- Move after a random seconds to the Route. See the Route method for details. + end + end + ) + end + end +end + + --- @param #AI_CARGO_TROOPS self -- @param Wrapper.Unit#UNIT CargoCarrier function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then - if self.Coordinate then + if self.CarrierCoordinate then local Coordinate = CargoCarrier:GetCoordinate() self.Zone:Scan( { Object.Category.UNIT } ) if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then --- if self:Is( "Unloaded" ) then --- -- There are no enemies within combat range. Load the CargoCarrier. --- self:__Load( 1 ) --- end + if self:Is( "Unloaded" ) or self:Is( "Guarding" ) then + -- There are no enemies within combat range. Load the CargoCarrier. + self:__Load( 1 ) + end else if self:Is( "Loaded" ) then -- There are enemies within combat range. Unload the CargoCarrier. self:__Unload( 1 ) end end - if self:Is( "Unloaded" ) then - if not Coordinate:IsAtCoordinate2D( self.Coordinate, 2 ) then - --self.CargoGroup:RouteTo( Coordinate, 30 ) + if self:Is( "Guarding" ) then + if not self.CargoGroup:IsNear( CargoCarrier, 5 ) then + self:Follow() end end - - else - self.Coordinate = CargoCarrier:GetCoordinate() end + self.CarrierCoordinate = CargoCarrier:GetCoordinate() end - self:__Monitor( 1 ) + self:__Monitor( -5 ) end @@ -167,7 +225,23 @@ function AI_CARGO_TROOPS:onafterUnloaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then + self:Guard() + self.CargoCarrier = CargoCarrier CargoCarrier:RouteResume() end end + + +--- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_TROOPS:onafterFollow( CargoCarrier, From, Event, To ) + self:F( { CargoCarrier, From, Event, To } ) + + self:F( "Follow" ) + if CargoCarrier and CargoCarrier:IsAlive() then + self:FollowToCarrier( self ) + end + +end + diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 66f9c04c8..f767c5ea7 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -491,17 +491,22 @@ end -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2, NearRadius } ) + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) - --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - self:T( Distance ) - - if Distance <= NearRadius then - return true - else - return false + if self.CargoObject:IsAlive() then + --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:F( { CargoObjectName = self.CargoObject:GetName() } ) + self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) + self:F( { PointVec2 = PointVec2:GetVec2() } ) + local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + + if Distance <= NearRadius then + return true + end end + + return false end --- Get the current PointVec2 of the cargo. @@ -746,7 +751,7 @@ do -- CARGO_UNIT function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + NearRadius = NearRadius or 100 local Angle = 180 local Speed = 60 @@ -804,7 +809,7 @@ do -- CARGO_UNIT function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + NearRadius = NearRadius or 100 local Angle = 180 local Speed = 10 @@ -831,7 +836,7 @@ do -- CARGO_UNIT function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + NearRadius = NearRadius or 100 self.CargoInAir = self.CargoObject:InAir() @@ -1149,299 +1154,299 @@ do -- CARGO_GROUP ClassName = "CARGO_GROUP", } ---- CARGO_GROUP constructor. --- @param #CARGO_GROUP self --- @param Wrapper.Group#GROUP CargoGroup --- @param #string Type --- @param #string Name --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #CARGO_GROUP -function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, ReportRadius } ) - - self.CargoObject = CargoGroup - self:SetDeployed( false ) - self.CargoGroup = CargoGroup + --- CARGO_GROUP constructor. + -- @param #CARGO_GROUP self + -- @param Wrapper.Group#GROUP CargoGroup + -- @param #string Type + -- @param #string Name + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_GROUP + function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP + self:F( { Type, Name, ReportRadius } ) - local WeightGroup = 0 + self.CargoObject = CargoGroup + self:SetDeployed( false ) + self.CargoGroup = CargoGroup + + local WeightGroup = 0 + + for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + local WeightUnit = Unit:GetDesc().massEmpty + WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit ) + self.CargoSet:Add( CargoUnit:GetName(), CargoUnit ) + end - for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - local WeightUnit = Unit:GetDesc().massEmpty - WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit ) - self.CargoSet:Add( CargoUnit:GetName(), CargoUnit ) + self:SetWeight( WeightGroup ) + + self:T( { "Weight Cargo", WeightGroup } ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) + + return self end - self:SetWeight( WeightGroup ) + --- @param #CARGO_GROUP self + -- @param Core.Event#EVENTDATA EventData + function CARGO_GROUP:OnEventCargoDead( EventData ) - self:T( { "Weight Cargo", WeightGroup } ) - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) - - self:SetEventPriority( 4 ) - - return self -end - ---- @param #CARGO_GROUP self --- @param Core.Event#EVENTDATA EventData -function CARGO_GROUP:OnEventCargoDead( EventData ) - - local Destroyed = false - - if self:IsDestroyed() or self:IsUnLoaded() then - Destroyed = true - for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- #CARGO - if Cargo:IsAlive() then - Destroyed = false - else - Cargo:Destroyed() - end - end - else - local CarrierName = self.CargoCarrier:GetName() - if CarrierName == EventData.IniDCSUnitName then - MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() + local Destroyed = false + + if self:IsDestroyed() or self:IsUnLoaded() then Destroyed = true - self.CargoCarrier:ClearCargo() + for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do + local Cargo = CargoData -- #CARGO + if Cargo:IsAlive() then + Destroyed = false + else + Cargo:Destroyed() + end + end + else + local CarrierName = self.CargoCarrier:GetName() + if CarrierName == EventData.IniDCSUnitName then + MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() + Destroyed = true + self.CargoCarrier:ClearCargo() + end end - end - - if Destroyed then - self:Destroyed() - self:E( { "Cargo group destroyed" } ) - end - -end - ---- Enter Boarding State. --- @param #CARGO_GROUP self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local NearRadius = NearRadius or 25 - - if From == "UnLoaded" then - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, ... ) - Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) - end, ... - ) - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + if Destroyed then + self:Destroyed() + self:E( { "Cargo group destroyed" } ) + end + end - -end ---- Enter Loaded State. --- @param #CARGO_GROUP self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) - self:F( { From, Event, To, CargoCarrier, ...} ) + --- Enter Boarding State. + -- @param #CARGO_GROUP self + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local NearRadius = NearRadius or 25 + + if From == "UnLoaded" then - if From == "UnLoaded" then - -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, ... ) + Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) + end, ... + ) + + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + end + + end + + --- Enter Loaded State. + -- @param #CARGO_GROUP self + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) + self:F( { From, Event, To, CargoCarrier, ...} ) + + if From == "UnLoaded" then + -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + Cargo:Load( CargoCarrier ) + end + end + + --self.CargoObject:Destroy() + self.CargoCarrier = CargoCarrier + + end + + --- Leave Boarding State. + -- @param #CARGO_GROUP self + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local NearRadius = NearRadius or 100 + + local Boarded = true + local Cancelled = false + local Dead = true + + self.CargoSet:Flush() + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - Cargo:Load( CargoCarrier ) - end - end + self:T( { Cargo:GetName(), Cargo.current } ) + + + if not Cargo:is( "Loaded" ) + and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. + Boarded = false + end + + if Cargo:is( "UnLoaded" ) then + Cancelled = true + end - --self.CargoObject:Destroy() - self.CargoCarrier = CargoCarrier + if not Cargo:is( "Destroyed" ) then + Dead = false + end + + end -end - ---- Leave Boarding State. --- @param #CARGO_GROUP self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local NearRadius = NearRadius or 25 - - local Boarded = true - local Cancelled = false - local Dead = true - - self.CargoSet:Flush() - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( { Cargo:GetName(), Cargo.current } ) - - - if not Cargo:is( "Loaded" ) - and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. - Boarded = false - end - - if Cargo:is( "UnLoaded" ) then - Cancelled = true - end - - if not Cargo:is( "Destroyed" ) then - Dead = false - end - - end - - if not Dead then - - if not Cancelled then - if not Boarded then - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + if not Dead then + + if not Cancelled then + if not Boarded then + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + else + self:F("Group Cargo is loaded") + self:__Load( 1, CargoCarrier, ... ) + end else - self:F("Group Cargo is loaded") - self:__Load( 1, CargoCarrier, ... ) + self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) end else - self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) + self:__Destroyed( 1, CargoCarrier, NearRadius, ... ) end - else - self:__Destroyed( 1, CargoCarrier, NearRadius, ... ) + end -end - ---- Get the amount of cargo units in the group. --- @param #CARGO_GROUP self --- @return #CARGO_GROUP -function CARGO_GROUP:GetCount() - return self.CargoSet:Count() -end - - ---- Enter UnBoarding State. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( {From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 25 - - local Timer = 1 - - if From == "Loaded" then - - if self.CargoObject then - self.CargoObject:Destroy() - end - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, NearRadius ) - - Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 10 - end, { NearRadius } - ) - - - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) + --- Get the amount of cargo units in the group. + -- @param #CARGO_GROUP self + -- @return #CARGO_GROUP + function CARGO_GROUP:GetCount() + return self.CargoSet:Count() end -end ---- Leave UnBoarding State. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - local UnBoarded = true - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "UnLoaded" ) then - UnBoarded = false + --- Enter UnBoarding State. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( {From, Event, To, ToPointVec2, NearRadius } ) + + NearRadius = NearRadius or 100 + + local Timer = 1 + + if From == "Loaded" then + + if self.CargoObject then + self.CargoObject:Destroy() end - end - if UnBoarded then - return true - else + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, NearRadius ) + + Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) + Timer = Timer + 10 + end, { NearRadius } + ) + + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) end - - return false - end -end + end ---- UnBoard Event. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - self:__UnLoad( 1, ToPointVec2, ... ) -end - - - ---- Enter UnLoaded State. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) - self:F( { From, Event, To, ToPointVec2 } ) - - if From == "Loaded" then - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - --Cargo:UnLoad( ToPointVec2 ) - local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10) - Cargo:UnLoad( RandomVec2 ) + --- Leave UnBoarding State. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + --local NearRadius = NearRadius or 25 + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "UnBoarding" then + local UnBoarded = true + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( Cargo.current ) + if not Cargo:is( "UnLoaded" ) then + UnBoarded = false + end end - ) - + + if UnBoarded then + return true + else + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) + end + + return false + end + end + + --- UnBoard Event. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) -end + --local NearRadius = NearRadius or 25 + + self:__UnLoad( 1, ToPointVec2, ... ) + end + + + + --- Enter UnLoaded State. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) + self:F( { From, Event, To, ToPointVec2 } ) + + if From == "Loaded" then + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + --Cargo:UnLoad( ToPointVec2 ) + local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10) + Cargo:UnLoad( RandomVec2 ) + end + ) + + end + + end --- Respawn the cargo when destroyed @@ -1464,21 +1469,37 @@ end -- @param #CARGO_GROUP self -- @param Core.Point#COORDINATE Coordinate function CARGO_GROUP:RouteTo( Coordinate ) - self:F( ) + self:F( {Coordinate = Coordinate } ) - --local NearRadius = NearRadius or 25 - - if From == "UnLoaded" then - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, Coordinate ) - Cargo.CargoObject:RouteTo( Coordinate ) - end, Coordinate - ) + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 ) + end + ) + end + + --- Check if Cargo is near to the Carrier. + -- The Cargo is near to the Carrier if the first unit of the Cargo Group is within NearRadius. + -- @param #CARGO_GROUP self + -- @param Wrapper.Group#GROUP CargoCarrier + -- @param #number NearRadius + -- @return #boolean The Cargo is near to the Carrier. + -- @return #nil The Cargo is not near to the Carrier. + function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) + self:F( {NearRadius = NearRadius } ) + + local FirstCargo = self.CargoSet:GetFirst() -- #CARGO + + if FirstCargo then + if FirstCargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then + self:F( "Near" ) + return true + end end + return nil end end -- CARGO_GROUP diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index df0a3d21a..0a787216a 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -258,9 +258,14 @@ do -- COORDINATE --- Returns if the 2 coordinates are at the same 2D position. -- @param #COORDINATE self + -- @param #COORDINATE Coordinate + -- @param #number Precision -- @return #boolean true if at the same position. function COORDINATE:IsAtCoordinate2D( Coordinate, Precision ) + self:F( { Coordinate = Coordinate:GetVec2() } ) + self:F( { self = self:GetVec2() } ) + local x = Coordinate.x local z = Coordinate.z From 9759640d52264a3042366b4b46209b0753714a2a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 27 Mar 2018 13:46:55 +0200 Subject: [PATCH 009/170] comment --- Moose Development/Moose/AI/AI_Cargo_Troops.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index dd2104ccc..eecf65e2b 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -22,7 +22,7 @@ AI_CARGO_TROOPS = { Coordinate = nil -- Core.Point#COORDINATE, } ---- Creates a new AI_CARGO_TROOPS object +--- Creates a new AI_CARGO_TROOPS object. -- @param #AI_CARGO_TROOPS self -- @return #AI_CARGO_TROOPS function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) From 21a7bac4e0938071fbd3ec34c6a3cf11086b46fb Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 27 Mar 2018 13:56:53 +0200 Subject: [PATCH 010/170] added file --- Moose Setup/Moose.files | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index 1e575f0f2..49a8fc08b 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -61,6 +61,7 @@ AI/AI_Cap.lua AI/AI_Cas.lua AI/AI_Bai.lua AI/AI_Formation.lua +AI/AI_Cargo_Troops.lua Actions/Act_Assign.lua Actions/Act_Route.lua From b1a1c6c5523c77b10dc513c6233d84f80146f146 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 27 Mar 2018 14:16:04 +0200 Subject: [PATCH 011/170] -- The infantry must only be 5 meters near. --- Moose Development/Moose/AI/AI_Cargo_Troops.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index eecf65e2b..55494fa21 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -158,7 +158,7 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() self:Board() - self.CargoGroup:Board( CargoCarrier, 100 ) + self.CargoGroup:Board( CargoCarrier, 5 ) end end From 7a579a0ab5e8c7ad71f480c18bed8cf160f730c3 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 27 Mar 2018 20:59:37 +0200 Subject: [PATCH 012/170] -- Fixed a lot of issues with cargo when the cargo representative is destroyed. --- .../Moose/AI/AI_Cargo_Troops.lua | 4 +- Moose Development/Moose/Core/Cargo.lua | 75 ++++++++++--------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 55494fa21..8c6491753 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -126,7 +126,7 @@ function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) local Coordinate = CargoCarrier:GetCoordinate() self.Zone:Scan( { Object.Category.UNIT } ) if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - if self:Is( "Unloaded" ) or self:Is( "Guarding" ) then + if self:Is( "Unloaded" ) or self:Is( "Guarding" ) or self:Is( "Following" ) then -- There are no enemies within combat range. Load the CargoCarrier. self:__Load( 1 ) end @@ -158,7 +158,7 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() self:Board() - self.CargoGroup:Board( CargoCarrier, 5 ) + self.CargoGroup:Board( CargoCarrier, 25 ) end end diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index f767c5ea7..4cc5eac2b 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -760,41 +760,44 @@ do -- CARGO_UNIT if From == "Loaded" then - local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE + if not self:IsDestroyed() then - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - - - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 - local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2) - local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3) - - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle ) - - local FromPointVec2 = CargoCarrierPointVec2 - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) - self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) - self.CargoCarrier = nil - - local Points = {} - Points[#Points+1] = CargoCarrierPointVec2:WaypointGround( Speed ) - - Points[#Points+1] = ToPointVec2:WaypointGround( Speed ) + local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + + + local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - self:__UnBoarding( 1, ToPointVec2, NearRadius ) + + -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 + ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 + local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2) + local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3) + + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle ) + + local FromPointVec2 = CargoCarrierPointVec2 + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) + self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) + self.CargoCarrier = nil + + local Points = {} + Points[#Points+1] = CargoCarrierPointVec2:WaypointGround( Speed ) + + Points[#Points+1] = ToPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 1 ) + + + self:__UnBoarding( 1, ToPointVec2, NearRadius ) + end end end @@ -949,7 +952,7 @@ do -- CARGO_UNIT self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - if CargoCarrier and CargoCarrier:IsAlive() then + if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then if CargoCarrier:InAir() == false then if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then self:__Load( 1, CargoCarrier, ... ) @@ -1200,9 +1203,11 @@ do -- CARGO_GROUP -- @param Core.Event#EVENTDATA EventData function CARGO_GROUP:OnEventCargoDead( EventData ) + self:_F( { "Dead Event", EventData = EventData } ) + local Destroyed = false - if self:IsDestroyed() or self:IsUnLoaded() then + if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then Destroyed = true for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do local Cargo = CargoData -- #CARGO @@ -1392,7 +1397,7 @@ do -- CARGO_GROUP -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do self:T( Cargo.current ) - if not Cargo:is( "UnLoaded" ) then + if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then UnBoarded = false end end From 7a8881974caa8b340eb235954b36892739e5fb77 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 28 Mar 2018 16:42:37 +0200 Subject: [PATCH 013/170] Optimizations of cargo deployment. --- .../Moose/AI/AI_Cargo_Troops.lua | 10 +++---- Moose Development/Moose/Core/Cargo.lua | 27 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index defb6bd81..f0d524be3 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -148,7 +148,7 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() - self:Board() + self:__Board( 10 ) self.CargoGroup:Board( CargoCarrier, 25 ) end @@ -162,7 +162,7 @@ function AI_CARGO_TROOPS:onafterBoard( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then self:F({ IsLoaded = self.CargoGroup:IsLoaded() } ) if not self.CargoGroup:IsLoaded() then - self:__Board( 1 ) + self:__Board( 10 ) else self:__Loaded( 1 ) end @@ -190,7 +190,7 @@ function AI_CARGO_TROOPS:onafterUnload( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() self.CargoGroup:UnBoard( ) - self:__Unboard( 1 ) + self:__Unboard( 10 ) end end @@ -202,9 +202,9 @@ function AI_CARGO_TROOPS:onafterUnboard( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then if not self.CargoGroup:IsUnLoaded() then - self:__Unboard( 1 ) + self:__Unboard( 10 ) else - self:Unloaded() + self:__Unloaded( 1 ) end end diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 8cfa3037f..e0a42c690 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -771,25 +771,26 @@ do -- CARGO_UNIT -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, 5 ) - local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2) - local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3) - - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, 5 ) + local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) + local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) + local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) + --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) + + ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) - local FromPointVec2 = CargoCarrierPointVec2 - -- Respawn the group... if self.CargoObject then - self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) + self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) self.CargoCarrier = nil local Points = {} - Points[#Points+1] = CargoCarrierPointVec2:WaypointGround( Speed ) - Points[#Points+1] = ToPointVec2:WaypointGround( Speed ) + -- From + Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) + + -- To + Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) local TaskRoute = self.CargoObject:TaskRoute( Points ) self.CargoObject:SetTask( TaskRoute, 1 ) @@ -1375,7 +1376,7 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) self:F( {From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 100 + NearRadius = NearRadius or 25 local Timer = 1 @@ -1390,7 +1391,7 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) function( Cargo, NearRadius ) Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 10 + Timer = Timer + 3 end, { NearRadius } ) From 31a7a4e9935a54156a432c24b11b5620235a08b0 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 28 Mar 2018 16:48:03 +0200 Subject: [PATCH 014/170] Default of near radius is 25 meters. --- Moose Development/Moose/Core/Cargo.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index e0a42c690..4a88b528b 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -749,7 +749,7 @@ do -- CARGO_UNIT function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 100 + NearRadius = NearRadius or 25 local Angle = 180 local Speed = 60 From b29ce9b45eca5ea5676a121d8f13828be943b0fb Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 28 Mar 2018 18:00:17 +0200 Subject: [PATCH 015/170] Boarding of troops --- Moose Development/Moose/AI/AI_Cargo_Troops.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index f0d524be3..754409aeb 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -149,7 +149,7 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() self:__Board( 10 ) - self.CargoGroup:Board( CargoCarrier, 25 ) + self.CargoGroup:Board( CargoCarrier, 100 ) end end From c37560275ecc68db55806b89aa0666442db14a2c Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 29 Mar 2018 12:00:11 +0200 Subject: [PATCH 016/170] -- A lot of fixes to the new Cargo handling model. Now also TASK_CARGO_TRANSPORT is working. --- Moose Development/Moose/Core/Cargo.lua | 208 ++++++++++++++++------- Moose Development/Moose/Wrapper/Unit.lua | 8 +- 2 files changed, 152 insertions(+), 64 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 4a88b528b..407e8bd87 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -418,11 +418,12 @@ end --- Smoke the CARGO. -- @param #CARGO self -function CARGO:Smoke( SmokeColor, Range ) - self:F2() +-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. +-- @param #number Radius The radius of randomization around the center of the Cargo. +function CARGO:Smoke( SmokeColor, Radius ) if self:IsUnLoaded() then - if Range then - trigger.action.smoke( self.CargoObject:GetRandomVec3( Range ), SmokeColor ) + if Radius then + trigger.action.smoke( self.CargoObject:GetRandomVec3( Radius ), SmokeColor ) else trigger.action.smoke( self.CargoObject:GetVec3(), SmokeColor ) end @@ -626,31 +627,7 @@ end -- CARGO_REPRESENTABLE return self end - --- Check if CargoCarrier is in the ReportRadius for the Cargo to be Loaded. - -- @param #CARGO_REPORTABLE self - -- @param Core.Point#POINT_VEC2 PointVec2 - -- @return #boolean - function CARGO_REPORTABLE:IsInRadius( PointVec2 ) - self:F( { PointVec2 } ) - - local Distance = 0 - if self:IsLoaded() then - Distance = PointVec2:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) - else - Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - end - self:T( Distance ) - - if Distance <= self.ReportRadius then - return true - else - return false - end - - - end - - --- Send a CC message to a GROUP. + --- Send a CC message to a @{Group}. -- @param #CARGO_REPORTABLE self -- @param #string Message -- @param Wrapper.Group#GROUP TaskGroup @@ -663,37 +640,13 @@ end -- CARGO_REPRESENTABLE end - --- Get the range till cargo will board. + --- Get the Report radius, which is the radius when the Cargo is reporting itself. -- @param #CARGO_REPORTABLE self - -- @return #number The range till cargo will board. + -- @return #number The range till Cargo reports itself. function CARGO_REPORTABLE:GetBoardingRange() return self.ReportRadius end - --- Respawn the cargo. - -- @param #CARGO_REPORTABLE self - function CARGO_REPORTABLE:Respawn() - - self:F({"Respawning"}) - - for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- #CARGO - Cargo:Destroy() - Cargo:SetStartState( "UnLoaded" ) - end - - local CargoObject = self.CargoObject -- Wrapper.Group#GROUP - CargoObject:Destroy() - local Template = CargoObject:GetTemplate() - CargoObject:Respawn( Template ) - - self:SetDeployed( false ) - - local WeightGroup = 0 - - self:SetStartState( "UnLoaded" ) - - end end @@ -1495,13 +1448,55 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) end + --- Get the current Coordinate of the CargoGroup. + -- @param #CARGO_GROUP self + -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. + -- @return #nil There is no valid Cargo in the CargoGroup. + function CARGO_GROUP:GetCoordinate() + self:F() + + local Cargo = self.CargoSet:GetFirst() + + if Cargo then + return Cargo.CargoObject:GetCoordinate() + end + + return nil + end + + --- Check if the CargoGroup is alive. + -- @param #CARGO_GROUP self + -- @return #boolean true if the CargoGroup is alive. + -- @return #boolean false if the CargoGroup is dead. + function CARGO_GROUP:IsAlive() + + local Alive = true + + -- For each Cargo within the CargoSet, check if the Cargo is Alive. + -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. + -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. + self.CargoSet:ForEach( + function( Cargo ) + if self:IsLoaded() then + Alive = Alive == true and Cargo.CargoCarrier:IsAlive() + else + Alive = Alive == true and Cargo.CargoObject:IsAlive() + end + end + ) + + return Alive + + end + + --- Route Cargo to Coordinate and randomize locations. -- @param #CARGO_GROUP self -- @param Core.Point#COORDINATE Coordinate function CARGO_GROUP:RouteTo( Coordinate ) self:F( {Coordinate = Coordinate } ) - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + -- For each Cargo within the CargoSet, route each object to the Coordinate self.CargoSet:ForEach( function( Cargo ) Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 ) @@ -1520,16 +1515,109 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) self:F( {NearRadius = NearRadius } ) - local FirstCargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self.CargoSet:GetFirst() -- #CARGO - if FirstCargo then - if FirstCargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then - self:F( "Near" ) + if Cargo then + return Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + end + + return nil + end + + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + -- @param #CARGO_GROUP self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the reporting radius. + function CARGO_GROUP:IsInRadius( Coordinate ) + self:F( { Coordinate } ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + local Distance = 0 + if Cargo:IsLoaded() then + Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoCarrier:GetPointVec2() ) + else + Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + end + self:T( Distance ) + + if Distance <= self.ReportRadius then return true + else + return false end end return nil + + end + + --- Respawn the CargoGroup. + -- @param #CARGO_GROUP self + function CARGO_GROUP:Respawn() + + self:F({"Respawning"}) + + for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do + local Cargo = CargoData -- #CARGO + Cargo:Destroy() + Cargo:SetStartState( "UnLoaded" ) + end + + local CargoObject = self.CargoObject -- Wrapper.Group#GROUP + CargoObject:Destroy() + local Template = CargoObject:GetTemplate() + CargoObject:Respawn( Template ) + + self:SetDeployed( false ) + + local WeightGroup = 0 + + self:SetStartState( "UnLoaded" ) + + end + + --- Signal a flare at the position of the CargoGroup. + -- @param #CARGO_GROUP self + -- @param Utilities.Utils#FLARECOLOR FlareColor + function CARGO_GROUP:Flare( FlareColor ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + if Cargo then + Cargo:Flare( FlareColor ) + end + end + + --- Smoke the CargoGroup. + -- @param #CARGO_GROUP self + -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. + -- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup. + function CARGO_GROUP:Smoke( SmokeColor, Radius ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + Cargo:Smoke( SmokeColor, Radius ) + end + end + + --- Check if the first element of the CargoGroup is the given @{Zone}. + -- @param #CARGO self + -- @param Core.Zone#ZONE_BASE Zone + -- @return #boolean **true** if the first element of the CargoGroup is in the Zone + -- @return #boolean **false** if there is no element of the CargoGroup in the Zone. + function CARGO_GROUP:IsInZone( Zone ) + self:F( { Zone } ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + return Cargo:IsInZone( Zone ) + end + + return nil + end end -- CARGO_GROUP diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 9c0fcad57..219705f85 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -531,16 +531,16 @@ function UNIT:GetFuel() return nil end ---- Returns the UNIT in a UNIT list of one element. +--- Returns a list of one @{Unit}. -- @param #UNIT self --- @return #list The UNITs wrappers. +-- @return #list A list of one @{Unit}. function UNIT:GetUnits() self:F2( { self.UnitName } ) local DCSUnit = self:GetDCSObject() + local Units = {} + if DCSUnit then - local DCSUnits = DCSUnit:getUnits() - local Units = {} Units[1] = UNIT:Find( DCSUnit ) self:T3( Units ) return Units From 93640b1d8eaaf27b733e168db7e4160f2aa3140d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 29 Mar 2018 12:02:07 +0200 Subject: [PATCH 017/170] -- Further fixes for TASK_CARGO_TRANSPORT --- .../Moose/Wrapper/Controllable.lua | 20 ------------------- Moose Development/Moose/Wrapper/Group.lua | 19 ++++++++++++++++++ 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 01fe228e4..7da5fe917 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -202,26 +202,6 @@ end -- Get methods ---- Returns the UNITs wrappers of the DCS Units of the Controllable (default is a GROUP). --- @param #CONTROLLABLE self --- @return #list The UNITs wrappers. -function CONTROLLABLE:GetUnits() - self:F2( { self.ControllableName } ) - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local DCSUnits = DCSControllable:getUnits() - local Units = {} - for Index, UnitData in pairs( DCSUnits ) do - Units[#Units+1] = UNIT:Find( UnitData ) - end - self:T3( Units ) - return Units - end - - return nil -end - --- Returns the health. Dead controllables have health <= 1.0. -- @param #CONTROLLABLE self diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 0606b14a0..66d9068a3 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -330,6 +330,25 @@ function GROUP:GetCountry() return nil end +--- Returns a list of @{Unit} objects of the @{Group}. +-- @param #GROUP self +-- @return #list The list of @{Unit} objects of the @{Group}. +function GROUP:GetUnits() + self:F2( { self.GroupName } ) + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local DCSUnits = DCSGroup:getUnits() + local Units = {} + for Index, UnitData in pairs( DCSUnits ) do + Units[#Units+1] = UNIT:Find( UnitData ) + end + self:T3( Units ) + return Units + end + + return nil +end --- Returns the UNIT wrapper class with number UnitNumber. -- If the underlying DCS Unit does not exist, the method will return nil. . -- @param #GROUP self From 35f18d0d1f70e7bdc46bc1b3e8facde4e712b7b2 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 29 Mar 2018 12:48:24 +0200 Subject: [PATCH 018/170] -- Fixing respawning of CargoGroups after dead event. --- Moose Development/Moose/Core/Cargo.lua | 656 +++++++++++++------------ 1 file changed, 339 insertions(+), 317 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 407e8bd87..613fbc7b1 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -226,317 +226,316 @@ do -- CARGO Containable = false, } ---- @type CARGO.CargoObjects --- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. - - ---- CARGO Constructor. This class is an abstract class and should not be instantiated. --- @param #CARGO self --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number NearRadius (optional) --- @return #CARGO -function CARGO:New( Type, Name, Weight ) --R2.1 - - local self = BASE:Inherit( self, FSM:New() ) -- #CARGO - self:F( { Type, Name, Weight } ) + --- @type CARGO.CargoObjects + -- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. - self:SetStartState( "UnLoaded" ) - self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) - self:AddTransition( "Boarding" , "Boarding", "Boarding" ) - self:AddTransition( "Boarding", "CancelBoarding", "UnLoaded" ) - self:AddTransition( "Boarding", "Load", "Loaded" ) - self:AddTransition( "UnLoaded", "Load", "Loaded" ) - self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) - self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) - self:AddTransition( "*", "Damaged", "Damaged" ) - self:AddTransition( "*", "Destroyed", "Destroyed" ) - self:AddTransition( "*", "Respawn", "UnLoaded" ) - - - self.Type = Type - self.Name = Name - self.Weight = Weight - self.CargoObject = nil - self.CargoCarrier = nil -- Wrapper.Client#CLIENT - self.Representable = false - self.Slingloadable = false - self.Moveable = false - self.Containable = false - self:SetDeployed( false ) - - self.CargoScheduler = SCHEDULER:New() - - CARGOS[self.Name] = self - + --- CARGO Constructor. This class is an abstract class and should not be instantiated. + -- @param #CARGO self + -- @param #string Type + -- @param #string Name + -- @param #number Weight + -- @param #number NearRadius (optional) + -- @return #CARGO + function CARGO:New( Type, Name, Weight ) --R2.1 - return self -end - ---- Destroy the cargo. --- @param #CARGO self -function CARGO:Destroy() - if self.CargoObject then - self.CargoObject:Destroy() - end - self:Destroyed() -end - ---- Get the name of the Cargo. --- @param #CARGO self --- @return #string The name of the Cargo. -function CARGO:GetName() --R2.1 - return self.Name -end - ---- Get the object name of the Cargo. --- @param #CARGO self --- @return #string The object name of the Cargo. -function CARGO:GetObjectName() --R2.1 - if self:IsLoaded() then - return self.CargoCarrier:GetName() - else - return self.CargoObject:GetName() - end -end - ---- Get the type of the Cargo. --- @param #CARGO self --- @return #string The type of the Cargo. -function CARGO:GetType() - return self.Type -end - ---- Get the current coordinates of the Cargo. --- @param #CARGO self --- @return Core.Point#COORDINATE The coordinates of the Cargo. -function CARGO:GetCoordinate() - return self.CargoObject:GetCoordinate() -end - ---- Check if cargo is destroyed. --- @param #CARGO self --- @return #boolean true if destroyed -function CARGO:IsDestroyed() - return self:Is( "Destroyed" ) -end - - ---- Check if cargo is loaded. --- @param #CARGO self --- @return #boolean true if loaded -function CARGO:IsLoaded() - return self:Is( "Loaded" ) -end - ---- Check if cargo is unloaded. --- @param #CARGO self --- @return #boolean true if unloaded -function CARGO:IsUnLoaded() - return self:Is( "UnLoaded" ) -end - ---- Check if cargo is boarding. --- @param #CARGO self --- @return #boolean true if boarding -function CARGO:IsBoarding() - return self:Is( "Boarding" ) -end - ---- Check if cargo is alive. --- @param #CARGO self --- @return #boolean true if unloaded -function CARGO:IsAlive() - - if self:IsLoaded() then - return self.CargoCarrier:IsAlive() - else - return self.CargoObject:IsAlive() - end -end - ---- Set the cargo as deployed --- @param #CARGO self -function CARGO:SetDeployed( Deployed ) - self.Deployed = Deployed -end - ---- Is the cargo deployed --- @param #CARGO self --- @return #boolean -function CARGO:IsDeployed() - return self.Deployed -end - - - - ---- Template method to spawn a new representation of the CARGO in the simulator. --- @param #CARGO self --- @return #CARGO -function CARGO:Spawn( PointVec2 ) - self:F() - -end - ---- Signal a flare at the position of the CARGO. --- @param #CARGO self --- @param Utilities.Utils#FLARECOLOR FlareColor -function CARGO:Flare( FlareColor ) - if self:IsUnLoaded() then - trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 ) - end -end - ---- Signal a white flare at the position of the CARGO. --- @param #CARGO self -function CARGO:FlareWhite() - self:Flare( trigger.flareColor.White ) -end - ---- Signal a yellow flare at the position of the CARGO. --- @param #CARGO self -function CARGO:FlareYellow() - self:Flare( trigger.flareColor.Yellow ) -end - ---- Signal a green flare at the position of the CARGO. --- @param #CARGO self -function CARGO:FlareGreen() - self:Flare( trigger.flareColor.Green ) -end - ---- Signal a red flare at the position of the CARGO. --- @param #CARGO self -function CARGO:FlareRed() - self:Flare( trigger.flareColor.Red ) -end - ---- Smoke the CARGO. --- @param #CARGO self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. --- @param #number Radius The radius of randomization around the center of the Cargo. -function CARGO:Smoke( SmokeColor, Radius ) - if self:IsUnLoaded() then - if Radius then - trigger.action.smoke( self.CargoObject:GetRandomVec3( Radius ), SmokeColor ) - else - trigger.action.smoke( self.CargoObject:GetVec3(), SmokeColor ) - end - end -end - ---- Smoke the CARGO Green. --- @param #CARGO self -function CARGO:SmokeGreen() - self:Smoke( trigger.smokeColor.Green, Range ) -end - ---- Smoke the CARGO Red. --- @param #CARGO self -function CARGO:SmokeRed() - self:Smoke( trigger.smokeColor.Red, Range ) -end - ---- Smoke the CARGO White. --- @param #CARGO self -function CARGO:SmokeWhite() - self:Smoke( trigger.smokeColor.White, Range ) -end - ---- Smoke the CARGO Orange. --- @param #CARGO self -function CARGO:SmokeOrange() - self:Smoke( trigger.smokeColor.Orange, Range ) -end - ---- Smoke the CARGO Blue. --- @param #CARGO self -function CARGO:SmokeBlue() - self:Smoke( trigger.smokeColor.Blue, Range ) -end - - - - - - ---- Check if Cargo is the given @{Zone}. --- @param #CARGO self --- @param Core.Zone#ZONE_BASE Zone --- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. -function CARGO:IsInZone( Zone ) - self:F( { Zone } ) - - if self:IsLoaded() then - return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) - else - self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) - if self.CargoObject:GetSize() ~= 0 then - return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) - else - return false - end - end - - return nil - -end - - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #CARGO self --- @param Core.Point#POINT_VEC2 PointVec2 --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). --- @return #boolean -function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) - - if self.CargoObject:IsAlive() then - --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:F( { CargoObjectName = self.CargoObject:GetName() } ) - self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) - self:F( { PointVec2 = PointVec2:GetVec2() } ) - local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - self:T( Distance ) + local self = BASE:Inherit( self, FSM:New() ) -- #CARGO + self:F( { Type, Name, Weight } ) - if Distance <= NearRadius then - return true + self:SetStartState( "UnLoaded" ) + self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) + self:AddTransition( "Boarding" , "Boarding", "Boarding" ) + self:AddTransition( "Boarding", "CancelBoarding", "UnLoaded" ) + self:AddTransition( "Boarding", "Load", "Loaded" ) + self:AddTransition( "UnLoaded", "Load", "Loaded" ) + self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) + self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) + self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) + self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) + self:AddTransition( "*", "Damaged", "Damaged" ) + self:AddTransition( "*", "Destroyed", "Destroyed" ) + self:AddTransition( "*", "Respawn", "UnLoaded" ) + + + self.Type = Type + self.Name = Name + self.Weight = Weight + self.CargoObject = nil + self.CargoCarrier = nil -- Wrapper.Client#CLIENT + self.Representable = false + self.Slingloadable = false + self.Moveable = false + self.Containable = false + + self:SetDeployed( false ) + + self.CargoScheduler = SCHEDULER:New() + + CARGOS[self.Name] = self + + + return self + end + + --- Destroy the cargo. + -- @param #CARGO self + function CARGO:Destroy() + if self.CargoObject then + self.CargoObject:Destroy() + end + self:Destroyed() + end + + --- Get the name of the Cargo. + -- @param #CARGO self + -- @return #string The name of the Cargo. + function CARGO:GetName() --R2.1 + return self.Name + end + + --- Get the object name of the Cargo. + -- @param #CARGO self + -- @return #string The object name of the Cargo. + function CARGO:GetObjectName() --R2.1 + if self:IsLoaded() then + return self.CargoCarrier:GetName() + else + return self.CargoObject:GetName() + end + end + + --- Get the type of the Cargo. + -- @param #CARGO self + -- @return #string The type of the Cargo. + function CARGO:GetType() + return self.Type + end + + --- Get the current coordinates of the Cargo. + -- @param #CARGO self + -- @return Core.Point#COORDINATE The coordinates of the Cargo. + function CARGO:GetCoordinate() + return self.CargoObject:GetCoordinate() + end + + --- Check if cargo is destroyed. + -- @param #CARGO self + -- @return #boolean true if destroyed + function CARGO:IsDestroyed() + return self:Is( "Destroyed" ) + end + + + --- Check if cargo is loaded. + -- @param #CARGO self + -- @return #boolean true if loaded + function CARGO:IsLoaded() + return self:Is( "Loaded" ) + end + + --- Check if cargo is unloaded. + -- @param #CARGO self + -- @return #boolean true if unloaded + function CARGO:IsUnLoaded() + return self:Is( "UnLoaded" ) + end + + --- Check if cargo is boarding. + -- @param #CARGO self + -- @return #boolean true if boarding + function CARGO:IsBoarding() + return self:Is( "Boarding" ) + end + + --- Check if cargo is alive. + -- @param #CARGO self + -- @return #boolean true if unloaded + function CARGO:IsAlive() + + if self:IsLoaded() then + return self.CargoCarrier:IsAlive() + else + return self.CargoObject:IsAlive() + end + end + + --- Set the cargo as deployed + -- @param #CARGO self + function CARGO:SetDeployed( Deployed ) + self.Deployed = Deployed + end + + --- Is the cargo deployed + -- @param #CARGO self + -- @return #boolean + function CARGO:IsDeployed() + return self.Deployed + end + + + + + --- Template method to spawn a new representation of the CARGO in the simulator. + -- @param #CARGO self + -- @return #CARGO + function CARGO:Spawn( PointVec2 ) + self:F() + + end + + --- Signal a flare at the position of the CARGO. + -- @param #CARGO self + -- @param Utilities.Utils#FLARECOLOR FlareColor + function CARGO:Flare( FlareColor ) + if self:IsUnLoaded() then + trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 ) end end - return false -end - ---- Get the current PointVec2 of the cargo. --- @param #CARGO self --- @return Core.Point#POINT_VEC2 -function CARGO:GetPointVec2() - return self.CargoObject:GetPointVec2() -end - ---- Get the current Coordinate of the cargo. --- @param #CARGO self --- @return Core.Point#COORDINATE -function CARGO:GetCoordinate() - return self.CargoObject:GetCoordinate() -end - ---- Set the weight of the cargo. --- @param #CARGO self --- @param #number Weight The weight in kg. --- @return #CARGO -function CARGO:SetWeight( Weight ) - self.Weight = Weight - return self -end - -end + --- Signal a white flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareWhite() + self:Flare( trigger.flareColor.White ) + end + + --- Signal a yellow flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareYellow() + self:Flare( trigger.flareColor.Yellow ) + end + + --- Signal a green flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareGreen() + self:Flare( trigger.flareColor.Green ) + end + + --- Signal a red flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareRed() + self:Flare( trigger.flareColor.Red ) + end + + --- Smoke the CARGO. + -- @param #CARGO self + -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. + -- @param #number Radius The radius of randomization around the center of the Cargo. + function CARGO:Smoke( SmokeColor, Radius ) + if self:IsUnLoaded() then + if Radius then + trigger.action.smoke( self.CargoObject:GetRandomVec3( Radius ), SmokeColor ) + else + trigger.action.smoke( self.CargoObject:GetVec3(), SmokeColor ) + end + end + end + + --- Smoke the CARGO Green. + -- @param #CARGO self + function CARGO:SmokeGreen() + self:Smoke( trigger.smokeColor.Green, Range ) + end + + --- Smoke the CARGO Red. + -- @param #CARGO self + function CARGO:SmokeRed() + self:Smoke( trigger.smokeColor.Red, Range ) + end + + --- Smoke the CARGO White. + -- @param #CARGO self + function CARGO:SmokeWhite() + self:Smoke( trigger.smokeColor.White, Range ) + end + + --- Smoke the CARGO Orange. + -- @param #CARGO self + function CARGO:SmokeOrange() + self:Smoke( trigger.smokeColor.Orange, Range ) + end + + --- Smoke the CARGO Blue. + -- @param #CARGO self + function CARGO:SmokeBlue() + self:Smoke( trigger.smokeColor.Blue, Range ) + end + + + + + + + --- Check if Cargo is the given @{Zone}. + -- @param #CARGO self + -- @param Core.Zone#ZONE_BASE Zone + -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. + function CARGO:IsInZone( Zone ) + self:F( { Zone } ) + + if self:IsLoaded() then + return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) + else + self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) + if self.CargoObject:GetSize() ~= 0 then + return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) + else + return false + end + end + + return nil + + end + + + --- Check if CargoCarrier is near the Cargo to be Loaded. + -- @param #CARGO self + -- @param Core.Point#POINT_VEC2 PointVec2 + -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). + -- @return #boolean + function CARGO:IsNear( PointVec2, NearRadius ) + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + + if self.CargoObject:IsAlive() then + --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:F( { CargoObjectName = self.CargoObject:GetName() } ) + self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) + self:F( { PointVec2 = PointVec2:GetVec2() } ) + local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + + if Distance <= NearRadius then + return true + end + end + + return false + end + + --- Get the current PointVec2 of the cargo. + -- @param #CARGO self + -- @return Core.Point#POINT_VEC2 + function CARGO:GetPointVec2() + return self.CargoObject:GetPointVec2() + end + + --- Get the current Coordinate of the cargo. + -- @param #CARGO self + -- @return Core.Point#COORDINATE + function CARGO:GetCoordinate() + return self.CargoObject:GetCoordinate() + end + + --- Set the weight of the cargo. + -- @param #CARGO self + -- @param #number Weight The weight in kg. + -- @return #CARGO + function CARGO:SetWeight( Weight ) + self.Weight = Weight + return self + end +end -- CARGO do -- CARGO_REPRESENTABLE @@ -600,7 +599,7 @@ do -- CARGO_REPRESENTABLE end -- CARGO_REPRESENTABLE - do -- CARGO_REPORTABLE +do -- CARGO_REPORTABLE --- @type CARGO_REPORTABLE -- @extends #CARGO @@ -989,7 +988,6 @@ do -- CARGO_UNIT end -- CARGO_UNIT - do -- CARGO_CRATE --- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters using the DCS menus. @@ -1127,16 +1125,17 @@ function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) self:SetDeployed( false ) local WeightGroup = 0 - local GroupName = CargoGroup:GetName() + + self.GroupName = CargoGroup:GetName() + self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) CargoGroup:Destroy() -- We iterate through the group template and for each unit in the template, we create a new group with one unit. - for UnitID, UnitTemplate in pairs( _DATABASE:GetGroupTemplate(GroupName).units ) do + for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do - local GroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate(GroupName) ) + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) local GroupName = env.getValueDictByKey( GroupTemplate.name ) - self:E( GroupName ) -- We create a new group object with one unit... -- First we prepare the template... @@ -1557,7 +1556,7 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) -- @param #CARGO_GROUP self function CARGO_GROUP:Respawn() - self:F({"Respawning"}) + self:F( { "Respawning" } ) for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do local Cargo = CargoData -- #CARGO @@ -1565,15 +1564,38 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) Cargo:SetStartState( "UnLoaded" ) end - local CargoObject = self.CargoObject -- Wrapper.Group#GROUP - CargoObject:Destroy() - local Template = CargoObject:GetTemplate() - CargoObject:Respawn( Template ) + + -- We iterate through the group template and for each unit in the template, we create a new group with one unit. + for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + local GroupName = env.getValueDictByKey( GroupTemplate.name ) + + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.groupId = nil + GroupTemplate.units = {} + GroupTemplate.units[1] = UnitTemplate + local UnitName = UnitTemplate.name .. "#CARGO" + GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" + + -- Then we register the new group in the database + local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + + -- And we register the spawned unit as part of the CargoSet. + local Unit = UNIT:FindByName( UnitName ) + --local WeightUnit = Unit:GetDesc().massEmpty + --WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) + self.CargoSet:Add( UnitName, CargoUnit ) + end + self:SetDeployed( false ) - - local WeightGroup = 0 - self:SetStartState( "UnLoaded" ) end From 9688c606f07c2d8306ea2fea136bcc2983dfb955 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 29 Mar 2018 17:55:58 +0200 Subject: [PATCH 019/170] New Cargo files --- Moose Development/Moose/Cargo/Cargo.lua | 870 ++++++++ Moose Development/Moose/Cargo/CargoCrate.lua | 120 ++ Moose Development/Moose/Cargo/CargoGroup.lua | 577 ++++++ Moose Development/Moose/Cargo/CargoUnit.lua | 358 ++++ Moose Development/Moose/Core/Cargo.lua | 1860 ------------------ Moose Setup/Moose.files | 6 +- 6 files changed, 1930 insertions(+), 1861 deletions(-) create mode 100644 Moose Development/Moose/Cargo/Cargo.lua create mode 100644 Moose Development/Moose/Cargo/CargoCrate.lua create mode 100644 Moose Development/Moose/Cargo/CargoGroup.lua create mode 100644 Moose Development/Moose/Cargo/CargoUnit.lua delete mode 100644 Moose Development/Moose/Core/Cargo.lua diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua new file mode 100644 index 000000000..e6b3bde6e --- /dev/null +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -0,0 +1,870 @@ +--- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers. +-- +-- === +-- +-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) +-- +-- === +-- +-- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): +-- +-- * CARGO_UNIT, represented by a @{Unit} in a singleton @{Group}: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable... +-- * CARGO_GROUP, represented by a @{Group}. A CARGO_GROUP is reportable... +-- +-- This module is still under construction, but is described above works already, and will keep working ... +-- +-- === +-- +-- # Demo Missions +-- +-- ### [CARGO Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CGO%20-%20Cargo) +-- +-- ### [CARGO Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CGO%20-%20Cargo) +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- === +-- +-- # YouTube Channel +-- +-- ### [CARGO YouTube Channel](https://www.youtube.com/watch?v=tM00lTlkpYs&list=PL7ZUrU4zZUl2zUTuKrLW5RsO9zLMqUtbf) +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: +-- +-- === +-- +-- @module Cargo + +-- Events + +-- Board + +--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#CARGO] Board +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. +-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). + +--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#CARGO] __Board +-- @param #CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. +-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). + + +-- UnBoard + +--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#CARGO] UnBoard +-- @param #CARGO self +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. + +--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#CARGO] __UnBoard +-- @param #CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. + + +-- Load + +--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#CARGO] Load +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. + +--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#CARGO] __Load +-- @param #CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. + + +-- UnLoad + +--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#CARGO] UnLoad +-- @param #CARGO self +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. + +--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#CARGO] __UnLoad +-- @param #CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. + +-- State Transition Functions + +-- UnLoaded + +--- @function [parent=#CARGO] OnLeaveUnLoaded +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#CARGO] OnEnterUnLoaded +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + +-- Loaded + +--- @function [parent=#CARGO] OnLeaveLoaded +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#CARGO] OnEnterLoaded +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + +-- Boarding + +--- @function [parent=#CARGO] OnLeaveBoarding +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#CARGO] OnEnterBoarding +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). + +-- UnBoarding + +--- @function [parent=#CARGO] OnLeaveUnBoarding +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#CARGO] OnEnterUnBoarding +-- @param #CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + + +-- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation. + +CARGOS = {} + +do -- CARGO + + --- @type CARGO + -- @extends Core.Fsm#FSM_PROCESS + -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. + -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. + -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. + -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. + -- @field Wrapper.Unit#UNIT CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... + -- @field Wrapper.Client#CLIENT CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... + -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. + -- @field #boolean Moveable This flag defines if the cargo is moveable. + -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. + -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. + + --- # (R2.1) CARGO class, extends @{Fsm#FSM_PROCESS} + -- + -- The CARGO class defines the core functions that defines a cargo object within MOOSE. + -- A cargo is a logical object defined that is available for transport, and has a life status within a simulation. + -- + -- The CARGO is a state machine: it manages the different events and states of the cargo. + -- All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. + -- + -- ## CARGO Events: + -- + -- * @{#CARGO.Board}( ToCarrier ): Boards the cargo to a carrier. + -- * @{#CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. + -- * @{#CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. + -- * @{#CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. + -- * @{#CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. + -- + -- ## CARGO States: + -- + -- * **UnLoaded**: The cargo is unloaded from a carrier. + -- * **Boarding**: The cargo is currently boarding (= running) into a carrier. + -- * **Loaded**: The cargo is loaded into a carrier. + -- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. + -- * **Dead**: The cargo is dead ... + -- * **End**: The process has come to an end. + -- + -- ## CARGO state transition methods: + -- + -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. + -- There are 2 moments when state transition methods will be called by the state machine: + -- + -- * **Leaving** the state. + -- The state transition method needs to start with the name **OnLeave + the name of the state**. + -- If the state transition method returns false, then the processing of the state transition will not be done! + -- If you want to change the behaviour of the AIControllable at this event, return false, + -- but then you'll need to specify your own logic using the AIControllable! + -- + -- * **Entering** the state. + -- The state transition method needs to start with the name **OnEnter + the name of the state**. + -- These state transition methods need to provide a return value, which is specified at the function description. + -- + -- @field #CARGO + CARGO = { + ClassName = "CARGO", + Type = nil, + Name = nil, + Weight = nil, + CargoObject = nil, + CargoCarrier = nil, + Representable = false, + Slingloadable = false, + Moveable = false, + Containable = false, + } + + --- @type CARGO.CargoObjects + -- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. + + + --- CARGO Constructor. This class is an abstract class and should not be instantiated. + -- @param #CARGO self + -- @param #string Type + -- @param #string Name + -- @param #number Weight + -- @param #number NearRadius (optional) + -- @return #CARGO + function CARGO:New( Type, Name, Weight ) --R2.1 + + local self = BASE:Inherit( self, FSM:New() ) -- #CARGO + self:F( { Type, Name, Weight } ) + + self:SetStartState( "UnLoaded" ) + self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) + self:AddTransition( "Boarding" , "Boarding", "Boarding" ) + self:AddTransition( "Boarding", "CancelBoarding", "UnLoaded" ) + self:AddTransition( "Boarding", "Load", "Loaded" ) + self:AddTransition( "UnLoaded", "Load", "Loaded" ) + self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) + self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) + self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) + self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) + self:AddTransition( "*", "Damaged", "Damaged" ) + self:AddTransition( "*", "Destroyed", "Destroyed" ) + self:AddTransition( "*", "Respawn", "UnLoaded" ) + + + self.Type = Type + self.Name = Name + self.Weight = Weight + self.CargoObject = nil + self.CargoCarrier = nil -- Wrapper.Client#CLIENT + self.Representable = false + self.Slingloadable = false + self.Moveable = false + self.Containable = false + + self:SetDeployed( false ) + + self.CargoScheduler = SCHEDULER:New() + + CARGOS[self.Name] = self + + + return self + end + + --- Destroy the cargo. + -- @param #CARGO self + function CARGO:Destroy() + if self.CargoObject then + self.CargoObject:Destroy() + end + self:Destroyed() + end + + --- Get the name of the Cargo. + -- @param #CARGO self + -- @return #string The name of the Cargo. + function CARGO:GetName() --R2.1 + return self.Name + end + + --- Get the object name of the Cargo. + -- @param #CARGO self + -- @return #string The object name of the Cargo. + function CARGO:GetObjectName() --R2.1 + if self:IsLoaded() then + return self.CargoCarrier:GetName() + else + return self.CargoObject:GetName() + end + end + + --- Get the type of the Cargo. + -- @param #CARGO self + -- @return #string The type of the Cargo. + function CARGO:GetType() + return self.Type + end + + --- Get the current coordinates of the Cargo. + -- @param #CARGO self + -- @return Core.Point#COORDINATE The coordinates of the Cargo. + function CARGO:GetCoordinate() + return self.CargoObject:GetCoordinate() + end + + --- Check if cargo is destroyed. + -- @param #CARGO self + -- @return #boolean true if destroyed + function CARGO:IsDestroyed() + return self:Is( "Destroyed" ) + end + + + --- Check if cargo is loaded. + -- @param #CARGO self + -- @return #boolean true if loaded + function CARGO:IsLoaded() + return self:Is( "Loaded" ) + end + + --- Check if cargo is unloaded. + -- @param #CARGO self + -- @return #boolean true if unloaded + function CARGO:IsUnLoaded() + return self:Is( "UnLoaded" ) + end + + --- Check if cargo is boarding. + -- @param #CARGO self + -- @return #boolean true if boarding + function CARGO:IsBoarding() + return self:Is( "Boarding" ) + end + + --- Check if cargo is alive. + -- @param #CARGO self + -- @return #boolean true if unloaded + function CARGO:IsAlive() + + if self:IsLoaded() then + return self.CargoCarrier:IsAlive() + else + return self.CargoObject:IsAlive() + end + end + + --- Set the cargo as deployed + -- @param #CARGO self + function CARGO:SetDeployed( Deployed ) + self.Deployed = Deployed + end + + --- Is the cargo deployed + -- @param #CARGO self + -- @return #boolean + function CARGO:IsDeployed() + return self.Deployed + end + + + + + --- Template method to spawn a new representation of the CARGO in the simulator. + -- @param #CARGO self + -- @return #CARGO + function CARGO:Spawn( PointVec2 ) + self:F() + + end + + --- Signal a flare at the position of the CARGO. + -- @param #CARGO self + -- @param Utilities.Utils#FLARECOLOR FlareColor + function CARGO:Flare( FlareColor ) + if self:IsUnLoaded() then + trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 ) + end + end + + --- Signal a white flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareWhite() + self:Flare( trigger.flareColor.White ) + end + + --- Signal a yellow flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareYellow() + self:Flare( trigger.flareColor.Yellow ) + end + + --- Signal a green flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareGreen() + self:Flare( trigger.flareColor.Green ) + end + + --- Signal a red flare at the position of the CARGO. + -- @param #CARGO self + function CARGO:FlareRed() + self:Flare( trigger.flareColor.Red ) + end + + --- Smoke the CARGO. + -- @param #CARGO self + -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. + -- @param #number Radius The radius of randomization around the center of the Cargo. + function CARGO:Smoke( SmokeColor, Radius ) + if self:IsUnLoaded() then + if Radius then + trigger.action.smoke( self.CargoObject:GetRandomVec3( Radius ), SmokeColor ) + else + trigger.action.smoke( self.CargoObject:GetVec3(), SmokeColor ) + end + end + end + + --- Smoke the CARGO Green. + -- @param #CARGO self + function CARGO:SmokeGreen() + self:Smoke( trigger.smokeColor.Green, Range ) + end + + --- Smoke the CARGO Red. + -- @param #CARGO self + function CARGO:SmokeRed() + self:Smoke( trigger.smokeColor.Red, Range ) + end + + --- Smoke the CARGO White. + -- @param #CARGO self + function CARGO:SmokeWhite() + self:Smoke( trigger.smokeColor.White, Range ) + end + + --- Smoke the CARGO Orange. + -- @param #CARGO self + function CARGO:SmokeOrange() + self:Smoke( trigger.smokeColor.Orange, Range ) + end + + --- Smoke the CARGO Blue. + -- @param #CARGO self + function CARGO:SmokeBlue() + self:Smoke( trigger.smokeColor.Blue, Range ) + end + + + + + + + --- Check if Cargo is the given @{Zone}. + -- @param #CARGO self + -- @param Core.Zone#ZONE_BASE Zone + -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. + function CARGO:IsInZone( Zone ) + self:F( { Zone } ) + + if self:IsLoaded() then + return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) + else + self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) + if self.CargoObject:GetSize() ~= 0 then + return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) + else + return false + end + end + + return nil + + end + + + --- Check if CargoCarrier is near the Cargo to be Loaded. + -- @param #CARGO self + -- @param Core.Point#POINT_VEC2 PointVec2 + -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). + -- @return #boolean + function CARGO:IsNear( PointVec2, NearRadius ) + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + + if self.CargoObject:IsAlive() then + --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:F( { CargoObjectName = self.CargoObject:GetName() } ) + self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) + self:F( { PointVec2 = PointVec2:GetVec2() } ) + local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + + if Distance <= NearRadius then + return true + end + end + + return false + end + + --- Get the current PointVec2 of the cargo. + -- @param #CARGO self + -- @return Core.Point#POINT_VEC2 + function CARGO:GetPointVec2() + return self.CargoObject:GetPointVec2() + end + + --- Get the current Coordinate of the cargo. + -- @param #CARGO self + -- @return Core.Point#COORDINATE + function CARGO:GetCoordinate() + return self.CargoObject:GetCoordinate() + end + + --- Set the weight of the cargo. + -- @param #CARGO self + -- @param #number Weight The weight in kg. + -- @return #CARGO + function CARGO:SetWeight( Weight ) + self.Weight = Weight + return self + end + +end -- CARGO + +do -- CARGO_REPRESENTABLE + + --- @type CARGO_REPRESENTABLE + -- @extends #CARGO + -- @field test + + --- Models CARGO that is representable by a Unit. + -- @field #CARGO_REPRESENTABLE CARGO_REPRESENTABLE + CARGO_REPRESENTABLE = { + ClassName = "CARGO_REPRESENTABLE" + } + + --- CARGO_REPRESENTABLE Constructor. + -- @param #CARGO_REPRESENTABLE self + -- @param #string Type + -- @param #string Name + -- @param #number Weight + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_REPRESENTABLE + function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + return self + end + + --- CARGO_REPRESENTABLE Destructor. + -- @param #CARGO_REPRESENTABLE self + -- @return #CARGO_REPRESENTABLE + function CARGO_REPRESENTABLE:Destroy() + + -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects. + self:F( { CargoName = self:GetName() } ) + _EVENTDISPATCHER:CreateEventDeleteCargo( self ) + + return self + end + + --- Route a cargo unit to a PointVec2. + -- @param #CARGO_REPRESENTABLE self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #number Speed + -- @return #CARGO_REPRESENTABLE + function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) + self:F2( ToPointVec2 ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) + Points[#Points+1] = ToPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 2 ) + return self + end + + +end -- CARGO_REPRESENTABLE + +do -- CARGO_REPORTABLE + + --- @type CARGO_REPORTABLE + -- @extends #CARGO + CARGO_REPORTABLE = { + ClassName = "CARGO_REPORTABLE" + } + + --- CARGO_REPORTABLE Constructor. + -- @param #CARGO_REPORTABLE self + -- @param #string Type + -- @param #string Name + -- @param #number Weight + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_REPORTABLE + function CARGO_REPORTABLE:New( Type, Name, Weight, ReportRadius ) + local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE + self:F( { Type, Name, Weight, ReportRadius } ) + + self.ReportRadius = ReportRadius or 1000 + + return self + end + + --- Send a CC message to a @{Group}. + -- @param #CARGO_REPORTABLE self + -- @param #string Message + -- @param Wrapper.Group#GROUP TaskGroup + -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. + function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name ) + + local Prefix = Name and "@ " .. Name .. ": " or "@ " .. TaskGroup:GetCallsign() .. ": " + Message = Prefix .. Message + MESSAGE:New( Message, 20, "Cargo: " .. self:GetName() ):ToGroup( TaskGroup ) + + end + + --- Get the Report radius, which is the radius when the Cargo is reporting itself. + -- @param #CARGO_REPORTABLE self + -- @return #number The range till Cargo reports itself. + function CARGO_REPORTABLE:GetBoardingRange() + return self.ReportRadius + end + + + +end + + + + + + + +do -- CARGO_PACKAGE + + --- @type CARGO_PACKAGE + -- @extends #CARGO_REPRESENTABLE + CARGO_PACKAGE = { + ClassName = "CARGO_PACKAGE" + } + +--- CARGO_PACKAGE Constructor. +-- @param #CARGO_PACKAGE self +-- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package. +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #CARGO_PACKAGE +function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_PACKAGE + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + self:T( CargoCarrier ) + self.CargoCarrier = CargoCarrier + + return self +end + +--- Board Event. +-- @param #CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed +-- @param #number BoardDistance +-- @param #number Angle +function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + self:F() + + self.CargoInAir = self.CargoCarrier:InAir() + + self:T( self.CargoInAir ) + + -- Only move the CargoCarrier to the New CargoCarrier when the New CargoCarrier is not in the air. + if not self.CargoInAir then + + local Points = {} + + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) + local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading ) + + Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoCarrier:TaskRoute( Points ) + self.CargoCarrier:SetTask( TaskRoute, 1 ) + end + + self:Boarded( CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + +end + +--- Check if CargoCarrier is near the Cargo to be Loaded. +-- @param #CARGO_PACKAGE self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @return #boolean +function CARGO_PACKAGE:IsNear( CargoCarrier ) + self:F() + + local CargoCarrierPoint = CargoCarrier:GetPointVec2() + + local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + self:T( Distance ) + + if Distance <= self.NearRadius then + return true + else + return false + end +end + +--- Boarded Event. +-- @param #CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + self:F() + + if self:IsNear( CargoCarrier ) then + self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) + else + self:__Boarded( 1, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + end +end + +--- UnBoard Event. +-- @param #CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param #number Speed +-- @param #number UnLoadDistance +-- @param #number UnBoardDistance +-- @param #number Radius +-- @param #number Angle +function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) + self:F() + + self.CargoInAir = self.CargoCarrier:InAir() + + self:T( self.CargoInAir ) + + -- Only unboard the cargo when the carrier is not in the air. + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + + self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle ) + + local Points = {} + + local StartPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) + local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading ) + + Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = CargoCarrier:TaskRoute( Points ) + CargoCarrier:SetTask( TaskRoute, 1 ) + end + + self:__UnBoarded( 1 , CargoCarrier, Speed ) + +end + +--- UnBoarded Event. +-- @param #CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) + self:F() + + if self:IsNear( CargoCarrier ) then + self:__UnLoad( 1, CargoCarrier, Speed ) + else + self:__UnBoarded( 1, CargoCarrier, Speed ) + end +end + +--- Load Event. +-- @param #CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed +-- @param #number LoadDistance +-- @param #number Angle +function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) + self:F() + + self.CargoCarrier = CargoCarrier + + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading ) + + local Points = {} + Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoCarrier:TaskRoute( Points ) + self.CargoCarrier:SetTask( TaskRoute, 1 ) + +end + +--- UnLoad Event. +-- @param #CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param #number Distance +-- @param #number Angle +function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) + self:F() + + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) + + self.CargoCarrier = CargoCarrier + + local Points = {} + Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoCarrier:TaskRoute( Points ) + self.CargoCarrier:SetTask( TaskRoute, 1 ) + +end + + +end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua new file mode 100644 index 000000000..3f943d1ed --- /dev/null +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -0,0 +1,120 @@ +--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. +-- +-- === +-- +-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) +-- +-- === +-- +-- ### [Demo Missions]() +-- +-- ### [YouTube Playlist]() +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: +-- +-- === +-- +-- @module CargoCrate + +do -- CARGO_CRATE + + --- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters. + -- @type CARGO_CRATE + -- @extends #CARGO_REPRESENTABLE + + --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} + -- + -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. + -- + -- === + -- + -- @field #CARGO_CRATE + CARGO_CRATE = { + ClassName = "CARGO_CRATE" + } + + --- CARGO_CRATE Constructor. + -- @param #CARGO_CRATE self + -- @param Wrapper.Static#STATIC CargoStatic + -- @param #string Type + -- @param #string Name + -- @param #number Weight + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_CRATE + function CARGO_CRATE:New( CargoStatic, Type, Name, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, NearRadius ) ) -- #CARGO_CRATE + self:F( { Type, Name, NearRadius } ) + + self.CargoObject = CargoStatic + + self:T( self.ClassName ) + + self:SetEventPriority( 5 ) + + return self + end + + + + --- Enter UnLoaded State. + -- @param #CARGO_CRATE self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Core.Point#POINT_VEC2 + function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + local Angle = 180 + local Speed = 10 + local Distance = 10 + + if From == "Loaded" then + local StartCoordinate = self.CargoCarrier:GetCoordinate() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployCoord = StartCoordinate:Translate( Distance, CargoDeployHeading ) + + ToPointVec2 = ToPointVec2 or COORDINATE:NewFromVec2( { x= CargoDeployCoord.x, y = CargoDeployCoord.z } ) + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( ToPointVec2, 0 ) + self.CargoCarrier = nil + end + + end + + if self.OnUnLoadedCallBack then + self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) + self.OnUnLoadedCallBack = nil + end + + end + + + --- Loaded State. + -- @param #CARGO_CRATE self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier + function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier ) + self:F( { From, Event, To, CargoCarrier } ) + + self.CargoCarrier = CargoCarrier + + -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). + if self.CargoObject then + self:T("Destroying") + self.CargoObject:Destroy() + end + end + +end + diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua new file mode 100644 index 000000000..2a5f8fee5 --- /dev/null +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -0,0 +1,577 @@ +--- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Group} object. +-- +-- === +-- +-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) +-- +-- === +-- +-- ### [Demo Missions]() +-- +-- ### [YouTube Playlist]() +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: +-- +-- === +-- +-- @module CargoGroup + + +do -- CARGO_GROUP + + --- @type CARGO_GROUP + -- @extends #CARGO_REPORTABLE + -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. + -- @field #string GroupName The name of the CargoGroup. + + --- # CARGO\_GROUP class + -- + -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator. + -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. + -- + -- @field #CARGO_GROUP CARGO_GROUP + -- + CARGO_GROUP = { + ClassName = "CARGO_GROUP", + } + +--- CARGO_GROUP constructor. +-- This make a new CARGO_GROUP from a @{Group} object. +-- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. +-- @param #CARGO_GROUP self +-- @param Wrapper.Group#GROUP CargoGroup +-- @param #string Type +-- @param #string Name +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #CARGO_GROUP +function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP + self:F( { Type, Name, ReportRadius } ) + + self.CargoSet = SET_CARGO:New() + + self:SetDeployed( false ) + + local WeightGroup = 0 + + self.GroupName = CargoGroup:GetName() + self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) + + CargoGroup:Destroy() + + -- We iterate through the group template and for each unit in the template, we create a new group with one unit. + for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + local GroupName = env.getValueDictByKey( GroupTemplate.name ) + + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.groupId = nil + GroupTemplate.units = {} + GroupTemplate.units[1] = UnitTemplate + local UnitName = UnitTemplate.name .. "#CARGO" + GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" + + + -- Then we register the new group in the database + local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + + -- And we register the spawned unit as part of the CargoSet. + local Unit = UNIT:FindByName( UnitName ) + --local WeightUnit = Unit:GetDesc().massEmpty + --WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) + self.CargoSet:Add( UnitName, CargoUnit ) + end + + + self:SetWeight( WeightGroup ) + + self:T( { "Weight Cargo", WeightGroup } ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) + + return self +end + +--- @param #CARGO_GROUP self +-- @param Core.Event#EVENTDATA EventData +function CARGO_GROUP:OnEventCargoDead( EventData ) + + local Destroyed = false + + if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then + Destroyed = true + for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do + local Cargo = CargoData -- #CARGO + if Cargo:IsAlive() then + Destroyed = false + else + Cargo:Destroyed() + end + end + else + local CarrierName = self.CargoCarrier:GetName() + if CarrierName == EventData.IniDCSUnitName then + MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() + Destroyed = true + self.CargoCarrier:ClearCargo() + end + end + + if Destroyed then + self:Destroyed() + self:E( { "Cargo group destroyed" } ) + end + + end + + --- Enter Boarding State. + -- @param #CARGO_GROUP self + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local NearRadius = NearRadius or 25 + + if From == "UnLoaded" then + + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, ... ) + Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) + end, ... + ) + + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + end + + end + + --- Enter Loaded State. + -- @param #CARGO_GROUP self + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) + self:F( { From, Event, To, CargoCarrier, ...} ) + + if From == "UnLoaded" then + -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + Cargo:Load( CargoCarrier ) + end + end + + --self.CargoObject:Destroy() + self.CargoCarrier = CargoCarrier + + end + + --- Leave Boarding State. + -- @param #CARGO_GROUP self + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local NearRadius = NearRadius or 100 + + local Boarded = true + local Cancelled = false + local Dead = true + + self.CargoSet:Flush() + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( { Cargo:GetName(), Cargo.current } ) + + + if not Cargo:is( "Loaded" ) + and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. + Boarded = false + end + + if Cargo:is( "UnLoaded" ) then + Cancelled = true + end + + if not Cargo:is( "Destroyed" ) then + Dead = false + end + + end + + if not Dead then + + if not Cancelled then + if not Boarded then + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + else + self:F("Group Cargo is loaded") + self:__Load( 1, CargoCarrier, ... ) + end + else + self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) + end + else + self:__Destroyed( 1, CargoCarrier, NearRadius, ... ) + end + + end + + --- Get the amount of cargo units in the group. + -- @param #CARGO_GROUP self + -- @return #CARGO_GROUP + function CARGO_GROUP:GetCount() + return self.CargoSet:Count() + end + + + --- Enter UnBoarding State. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( {From, Event, To, ToPointVec2, NearRadius } ) + + NearRadius = NearRadius or 25 + + local Timer = 1 + + if From == "Loaded" then + + if self.CargoObject then + self.CargoObject:Destroy() + end + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, NearRadius ) + + Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) + Timer = Timer + 3 + end, { NearRadius } + ) + + + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) + end + + end + + --- Leave UnBoarding State. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + --local NearRadius = NearRadius or 25 + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "UnBoarding" then + local UnBoarded = true + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( Cargo.current ) + if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then + UnBoarded = false + end + end + + if UnBoarded then + return true + else + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) + end + + return false + end + + end + + --- UnBoard Event. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + --local NearRadius = NearRadius or 25 + + self:__UnLoad( 1, ToPointVec2, ... ) + end + + + + --- Enter UnLoaded State. + -- @param #CARGO_GROUP self + -- @param Core.Point#POINT_VEC2 + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) + self:F( { From, Event, To, ToPointVec2 } ) + + if From == "Loaded" then + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + --Cargo:UnLoad( ToPointVec2 ) + local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10) + Cargo:UnLoad( RandomVec2 ) + end + ) + + end + + end + + + --- Respawn the cargo when destroyed + -- @param #CARGO_GROUP self + -- @param #boolean RespawnDestroyed + function CARGO_GROUP:RespawnOnDestroyed( RespawnDestroyed ) + self:F({"In function RespawnOnDestroyed"}) + if RespawnDestroyed then + self.onenterDestroyed = function( self ) + self:F("IN FUNCTION") + self:Respawn() + end + else + self.onenterDestroyed = nil + end + + end + + --- Get the current Coordinate of the CargoGroup. + -- @param #CARGO_GROUP self + -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. + -- @return #nil There is no valid Cargo in the CargoGroup. + function CARGO_GROUP:GetCoordinate() + self:F() + + local Cargo = self.CargoSet:GetFirst() + + if Cargo then + return Cargo.CargoObject:GetCoordinate() + end + + return nil + end + + --- Check if the CargoGroup is alive. + -- @param #CARGO_GROUP self + -- @return #boolean true if the CargoGroup is alive. + -- @return #boolean false if the CargoGroup is dead. + function CARGO_GROUP:IsAlive() + + local Alive = true + + -- For each Cargo within the CargoSet, check if the Cargo is Alive. + -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. + -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. + self.CargoSet:ForEach( + function( Cargo ) + if self:IsLoaded() then + Alive = Alive == true and Cargo.CargoCarrier:IsAlive() + else + Alive = Alive == true and Cargo.CargoObject:IsAlive() + end + end + ) + + return Alive + + end + + + --- Route Cargo to Coordinate and randomize locations. + -- @param #CARGO_GROUP self + -- @param Core.Point#COORDINATE Coordinate + function CARGO_GROUP:RouteTo( Coordinate ) + self:F( {Coordinate = Coordinate } ) + + -- For each Cargo within the CargoSet, route each object to the Coordinate + self.CargoSet:ForEach( + function( Cargo ) + Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 ) + end + ) + + end + + --- Check if Cargo is near to the Carrier. + -- The Cargo is near to the Carrier if the first unit of the Cargo Group is within NearRadius. + -- @param #CARGO_GROUP self + -- @param Wrapper.Group#GROUP CargoCarrier + -- @param #number NearRadius + -- @return #boolean The Cargo is near to the Carrier. + -- @return #nil The Cargo is not near to the Carrier. + function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) + self:F( {NearRadius = NearRadius } ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + return Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + end + + return nil + end + + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + -- @param #CARGO_GROUP self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the reporting radius. + function CARGO_GROUP:IsInRadius( Coordinate ) + self:F( { Coordinate } ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + local Distance = 0 + if Cargo:IsLoaded() then + Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoCarrier:GetPointVec2() ) + else + Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + end + self:T( Distance ) + + if Distance <= self.ReportRadius then + return true + else + return false + end + end + + return nil + + end + + --- Respawn the CargoGroup. + -- @param #CARGO_GROUP self + function CARGO_GROUP:Respawn() + + self:F( { "Respawning" } ) + + for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do + local Cargo = CargoData -- #CARGO + Cargo:Destroy() + Cargo:SetStartState( "UnLoaded" ) + end + + + -- We iterate through the group template and for each unit in the template, we create a new group with one unit. + for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + local GroupName = env.getValueDictByKey( GroupTemplate.name ) + + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.groupId = nil + GroupTemplate.units = {} + GroupTemplate.units[1] = UnitTemplate + local UnitName = UnitTemplate.name .. "#CARGO" + GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" + + + -- Then we register the new group in the database + local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + + -- And we register the spawned unit as part of the CargoSet. + local Unit = UNIT:FindByName( UnitName ) + --local WeightUnit = Unit:GetDesc().massEmpty + --WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) + self.CargoSet:Add( UnitName, CargoUnit ) + end + + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + + end + + --- Signal a flare at the position of the CargoGroup. + -- @param #CARGO_GROUP self + -- @param Utilities.Utils#FLARECOLOR FlareColor + function CARGO_GROUP:Flare( FlareColor ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + if Cargo then + Cargo:Flare( FlareColor ) + end + end + + --- Smoke the CargoGroup. + -- @param #CARGO_GROUP self + -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. + -- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup. + function CARGO_GROUP:Smoke( SmokeColor, Radius ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + Cargo:Smoke( SmokeColor, Radius ) + end + end + + --- Check if the first element of the CargoGroup is the given @{Zone}. + -- @param #CARGO self + -- @param Core.Zone#ZONE_BASE Zone + -- @return #boolean **true** if the first element of the CargoGroup is in the Zone + -- @return #boolean **false** if there is no element of the CargoGroup in the Zone. + function CARGO_GROUP:IsInZone( Zone ) + self:F( { Zone } ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + return Cargo:IsInZone( Zone ) + end + + return nil + + end + +end -- CARGO_GROUP diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua new file mode 100644 index 000000000..ba9c17f61 --- /dev/null +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -0,0 +1,358 @@ +--- **Cargo** -- Management of single cargo logistics, which are based on a @{Unit} object. +-- +-- === +-- +-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) +-- +-- === +-- +-- ### [Demo Missions]() +-- +-- ### [YouTube Playlist]() +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: +-- +-- === +-- +-- @module CargoUnit + +do -- CARGO_UNIT + + --- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded. + -- @type CARGO_UNIT + -- @extends #CARGO_REPRESENTABLE + + --- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE} + -- + -- The CARGO\_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_UNIT objects to and from carriers. + -- + -- === + -- + -- @field #CARGO_UNIT CARGO_UNIT + -- + CARGO_UNIT = { + ClassName = "CARGO_UNIT" + } + + --- CARGO_UNIT Constructor. + -- @param #CARGO_UNIT self + -- @param Wrapper.Unit#UNIT CargoUnit + -- @param #string Type + -- @param #string Name + -- @param #number Weight + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_UNIT + function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT + self:F( { Type, Name, Weight, NearRadius } ) + + self:T( CargoUnit ) + self.CargoObject = CargoUnit + + self:T( self.ClassName ) + + self:SetEventPriority( 5 ) + + return self + end + + --- Enter UnBoarding State. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Core.Point#POINT_VEC2 ToPointVec2 + function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + NearRadius = NearRadius or 25 + + local Angle = 180 + local Speed = 60 + local DeployDistance = 9 + local RouteDistance = 60 + + if From == "Loaded" then + + if not self:IsDestroyed() then + + local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE + + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + + + local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) + + + -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 + local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) + local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) + local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) + --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) + + ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) + self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) + self.CargoCarrier = nil + + local Points = {} + + -- From + Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) + + -- To + Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 1 ) + + + self:__UnBoarding( 1, ToPointVec2, NearRadius ) + end + end + end + + end + + --- Leave UnBoarding State. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Core.Point#POINT_VEC2 ToPointVec2 + function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + NearRadius = NearRadius or 100 + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "UnBoarding" then + if self:IsNear( ToPointVec2, NearRadius ) then + return true + else + + self:__UnBoarding( 1, ToPointVec2, NearRadius ) + end + return false + end + + end + + --- UnBoard Event. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Core.Point#POINT_VEC2 ToPointVec2 + function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + NearRadius = NearRadius or 100 + + self.CargoInAir = self.CargoObject:InAir() + + self:T( self.CargoInAir ) + + -- Only unboard the cargo when the carrier is not in the air. + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + + end + + self:__UnLoad( 1, ToPointVec2, NearRadius ) + + end + + + + --- Enter UnLoaded State. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Core.Point#POINT_VEC2 + function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "Loaded" then + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployCoord = StartPointVec2:Translate( Distance, CargoDeployHeading ) + + ToPointVec2 = ToPointVec2 or COORDINATE:New( CargoDeployCoord.x, CargoDeployCoord.z ) + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 ) + self.CargoCarrier = nil + end + + end + + if self.OnUnLoadedCallBack then + self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) + self.OnUnLoadedCallBack = nil + end + + end + + --- Board Event. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { From, Event, To, CargoCarrier, NearRadius } ) + + local NearRadius = NearRadius or 25 + + self.CargoInAir = self.CargoObject:InAir() + + self:T( self.CargoInAir ) + + -- Only move the group to the carrier when the cargo is not in the air + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then + self:Load( CargoCarrier, NearRadius, ... ) + else + local Speed = 90 + local Angle = 180 + local Distance = 5 + + NearRadius = NearRadius or 25 + + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 2 ) + self:__Boarding( -1, CargoCarrier, NearRadius ) + self.RunCount = 0 + end + end + + end + + + --- Boarding Event. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Wrapper.Client#CLIENT CargoCarrier + -- @param #number NearRadius + function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + + + if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then + if CargoCarrier:InAir() == false then + if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then + self:__Load( 1, CargoCarrier, ... ) + else + self:__Boarding( -1, CargoCarrier, NearRadius, ... ) + self.RunCount = self.RunCount + 1 + if self.RunCount >= 60 then + self.RunCount = 0 + local Speed = 90 + local Angle = 180 + local Distance = 5 + + NearRadius = NearRadius or 25 + + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 0.2 ) + end + end + else + self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() ) + self:CancelBoarding( CargoCarrier, NearRadius, ... ) + self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) + end + else + self:E("Something is wrong") + end + + end + + + --- Enter Boarding State. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier + function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + + local Speed = 90 + local Angle = 180 + local Distance = 5 + + local NearRadius = NearRadius or 25 + + if From == "UnLoaded" or From == "Boarding" then + + end + + end + + --- Loaded State. + -- @param #CARGO_UNIT self + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier + function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) + self:F( { From, Event, To, CargoCarrier } ) + + self.CargoCarrier = CargoCarrier + + -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). + if self.CargoObject then + self:T("Destroying") + self.CargoObject:Destroy() + end + end + +end -- CARGO_UNIT diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua deleted file mode 100644 index 613fbc7b1..000000000 --- a/Moose Development/Moose/Core/Cargo.lua +++ /dev/null @@ -1,1860 +0,0 @@ ---- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers. --- --- === --- --- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) --- --- === --- --- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): --- --- * CARGO_UNIT, represented by a @{Unit} in a singleton @{Group}: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable... --- * CARGO_GROUP, represented by a @{Group}. A CARGO_GROUP is reportable... --- --- This module is still under construction, but is described above works already, and will keep working ... --- --- === --- --- # Demo Missions --- --- ### [CARGO Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CGO%20-%20Cargo) --- --- ### [CARGO Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CGO%20-%20Cargo) --- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) --- --- === --- --- # YouTube Channel --- --- ### [CARGO YouTube Channel](https://www.youtube.com/watch?v=tM00lTlkpYs&list=PL7ZUrU4zZUl2zUTuKrLW5RsO9zLMqUtbf) --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: --- --- === --- --- @module Cargo - --- Events - --- Board - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] Board --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] __Board --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - - --- UnBoard - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] UnBoard --- @param #CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] __UnBoard --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - - --- Load - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] Load --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] __Load --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - - --- UnLoad - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] UnLoad --- @param #CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] __UnLoad --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - --- State Transition Functions - --- UnLoaded - ---- @function [parent=#CARGO] OnLeaveUnLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterUnLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Loaded - ---- @function [parent=#CARGO] OnLeaveLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Boarding - ---- @function [parent=#CARGO] OnLeaveBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - --- UnBoarding - ---- @function [parent=#CARGO] OnLeaveUnBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterUnBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - - --- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation. - -CARGOS = {} - -do -- CARGO - - --- @type CARGO - -- @extends Core.Fsm#FSM_PROCESS - -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. - -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. - -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. - -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. - -- @field Wrapper.Unit#UNIT CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... - -- @field Wrapper.Client#CLIENT CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... - -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. - -- @field #boolean Moveable This flag defines if the cargo is moveable. - -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. - -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - - --- # (R2.1) CARGO class, extends @{Fsm#FSM_PROCESS} - -- - -- The CARGO class defines the core functions that defines a cargo object within MOOSE. - -- A cargo is a logical object defined that is available for transport, and has a life status within a simulation. - -- - -- The CARGO is a state machine: it manages the different events and states of the cargo. - -- All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. - -- - -- ## CARGO Events: - -- - -- * @{#CARGO.Board}( ToCarrier ): Boards the cargo to a carrier. - -- * @{#CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. - -- * @{#CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. - -- * @{#CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. - -- * @{#CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. - -- - -- ## CARGO States: - -- - -- * **UnLoaded**: The cargo is unloaded from a carrier. - -- * **Boarding**: The cargo is currently boarding (= running) into a carrier. - -- * **Loaded**: The cargo is loaded into a carrier. - -- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. - -- * **Dead**: The cargo is dead ... - -- * **End**: The process has come to an end. - -- - -- ## CARGO state transition methods: - -- - -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. - -- There are 2 moments when state transition methods will be called by the state machine: - -- - -- * **Leaving** the state. - -- The state transition method needs to start with the name **OnLeave + the name of the state**. - -- If the state transition method returns false, then the processing of the state transition will not be done! - -- If you want to change the behaviour of the AIControllable at this event, return false, - -- but then you'll need to specify your own logic using the AIControllable! - -- - -- * **Entering** the state. - -- The state transition method needs to start with the name **OnEnter + the name of the state**. - -- These state transition methods need to provide a return value, which is specified at the function description. - -- - -- @field #CARGO - CARGO = { - ClassName = "CARGO", - Type = nil, - Name = nil, - Weight = nil, - CargoObject = nil, - CargoCarrier = nil, - Representable = false, - Slingloadable = false, - Moveable = false, - Containable = false, - } - - --- @type CARGO.CargoObjects - -- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. - - - --- CARGO Constructor. This class is an abstract class and should not be instantiated. - -- @param #CARGO self - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number NearRadius (optional) - -- @return #CARGO - function CARGO:New( Type, Name, Weight ) --R2.1 - - local self = BASE:Inherit( self, FSM:New() ) -- #CARGO - self:F( { Type, Name, Weight } ) - - self:SetStartState( "UnLoaded" ) - self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) - self:AddTransition( "Boarding" , "Boarding", "Boarding" ) - self:AddTransition( "Boarding", "CancelBoarding", "UnLoaded" ) - self:AddTransition( "Boarding", "Load", "Loaded" ) - self:AddTransition( "UnLoaded", "Load", "Loaded" ) - self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) - self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) - self:AddTransition( "*", "Damaged", "Damaged" ) - self:AddTransition( "*", "Destroyed", "Destroyed" ) - self:AddTransition( "*", "Respawn", "UnLoaded" ) - - - self.Type = Type - self.Name = Name - self.Weight = Weight - self.CargoObject = nil - self.CargoCarrier = nil -- Wrapper.Client#CLIENT - self.Representable = false - self.Slingloadable = false - self.Moveable = false - self.Containable = false - - self:SetDeployed( false ) - - self.CargoScheduler = SCHEDULER:New() - - CARGOS[self.Name] = self - - - return self - end - - --- Destroy the cargo. - -- @param #CARGO self - function CARGO:Destroy() - if self.CargoObject then - self.CargoObject:Destroy() - end - self:Destroyed() - end - - --- Get the name of the Cargo. - -- @param #CARGO self - -- @return #string The name of the Cargo. - function CARGO:GetName() --R2.1 - return self.Name - end - - --- Get the object name of the Cargo. - -- @param #CARGO self - -- @return #string The object name of the Cargo. - function CARGO:GetObjectName() --R2.1 - if self:IsLoaded() then - return self.CargoCarrier:GetName() - else - return self.CargoObject:GetName() - end - end - - --- Get the type of the Cargo. - -- @param #CARGO self - -- @return #string The type of the Cargo. - function CARGO:GetType() - return self.Type - end - - --- Get the current coordinates of the Cargo. - -- @param #CARGO self - -- @return Core.Point#COORDINATE The coordinates of the Cargo. - function CARGO:GetCoordinate() - return self.CargoObject:GetCoordinate() - end - - --- Check if cargo is destroyed. - -- @param #CARGO self - -- @return #boolean true if destroyed - function CARGO:IsDestroyed() - return self:Is( "Destroyed" ) - end - - - --- Check if cargo is loaded. - -- @param #CARGO self - -- @return #boolean true if loaded - function CARGO:IsLoaded() - return self:Is( "Loaded" ) - end - - --- Check if cargo is unloaded. - -- @param #CARGO self - -- @return #boolean true if unloaded - function CARGO:IsUnLoaded() - return self:Is( "UnLoaded" ) - end - - --- Check if cargo is boarding. - -- @param #CARGO self - -- @return #boolean true if boarding - function CARGO:IsBoarding() - return self:Is( "Boarding" ) - end - - --- Check if cargo is alive. - -- @param #CARGO self - -- @return #boolean true if unloaded - function CARGO:IsAlive() - - if self:IsLoaded() then - return self.CargoCarrier:IsAlive() - else - return self.CargoObject:IsAlive() - end - end - - --- Set the cargo as deployed - -- @param #CARGO self - function CARGO:SetDeployed( Deployed ) - self.Deployed = Deployed - end - - --- Is the cargo deployed - -- @param #CARGO self - -- @return #boolean - function CARGO:IsDeployed() - return self.Deployed - end - - - - - --- Template method to spawn a new representation of the CARGO in the simulator. - -- @param #CARGO self - -- @return #CARGO - function CARGO:Spawn( PointVec2 ) - self:F() - - end - - --- Signal a flare at the position of the CARGO. - -- @param #CARGO self - -- @param Utilities.Utils#FLARECOLOR FlareColor - function CARGO:Flare( FlareColor ) - if self:IsUnLoaded() then - trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 ) - end - end - - --- Signal a white flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareWhite() - self:Flare( trigger.flareColor.White ) - end - - --- Signal a yellow flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareYellow() - self:Flare( trigger.flareColor.Yellow ) - end - - --- Signal a green flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareGreen() - self:Flare( trigger.flareColor.Green ) - end - - --- Signal a red flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareRed() - self:Flare( trigger.flareColor.Red ) - end - - --- Smoke the CARGO. - -- @param #CARGO self - -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. - -- @param #number Radius The radius of randomization around the center of the Cargo. - function CARGO:Smoke( SmokeColor, Radius ) - if self:IsUnLoaded() then - if Radius then - trigger.action.smoke( self.CargoObject:GetRandomVec3( Radius ), SmokeColor ) - else - trigger.action.smoke( self.CargoObject:GetVec3(), SmokeColor ) - end - end - end - - --- Smoke the CARGO Green. - -- @param #CARGO self - function CARGO:SmokeGreen() - self:Smoke( trigger.smokeColor.Green, Range ) - end - - --- Smoke the CARGO Red. - -- @param #CARGO self - function CARGO:SmokeRed() - self:Smoke( trigger.smokeColor.Red, Range ) - end - - --- Smoke the CARGO White. - -- @param #CARGO self - function CARGO:SmokeWhite() - self:Smoke( trigger.smokeColor.White, Range ) - end - - --- Smoke the CARGO Orange. - -- @param #CARGO self - function CARGO:SmokeOrange() - self:Smoke( trigger.smokeColor.Orange, Range ) - end - - --- Smoke the CARGO Blue. - -- @param #CARGO self - function CARGO:SmokeBlue() - self:Smoke( trigger.smokeColor.Blue, Range ) - end - - - - - - - --- Check if Cargo is the given @{Zone}. - -- @param #CARGO self - -- @param Core.Zone#ZONE_BASE Zone - -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. - function CARGO:IsInZone( Zone ) - self:F( { Zone } ) - - if self:IsLoaded() then - return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) - else - self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) - if self.CargoObject:GetSize() ~= 0 then - return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) - else - return false - end - end - - return nil - - end - - - --- Check if CargoCarrier is near the Cargo to be Loaded. - -- @param #CARGO self - -- @param Core.Point#POINT_VEC2 PointVec2 - -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - -- @return #boolean - function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) - - if self.CargoObject:IsAlive() then - --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:F( { CargoObjectName = self.CargoObject:GetName() } ) - self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) - self:F( { PointVec2 = PointVec2:GetVec2() } ) - local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - self:T( Distance ) - - if Distance <= NearRadius then - return true - end - end - - return false - end - - --- Get the current PointVec2 of the cargo. - -- @param #CARGO self - -- @return Core.Point#POINT_VEC2 - function CARGO:GetPointVec2() - return self.CargoObject:GetPointVec2() - end - - --- Get the current Coordinate of the cargo. - -- @param #CARGO self - -- @return Core.Point#COORDINATE - function CARGO:GetCoordinate() - return self.CargoObject:GetCoordinate() - end - - --- Set the weight of the cargo. - -- @param #CARGO self - -- @param #number Weight The weight in kg. - -- @return #CARGO - function CARGO:SetWeight( Weight ) - self.Weight = Weight - return self - end - -end -- CARGO - -do -- CARGO_REPRESENTABLE - - --- @type CARGO_REPRESENTABLE - -- @extends #CARGO - -- @field test - - --- Models CARGO that is representable by a Unit. - -- @field #CARGO_REPRESENTABLE CARGO_REPRESENTABLE - CARGO_REPRESENTABLE = { - ClassName = "CARGO_REPRESENTABLE" - } - - --- CARGO_REPRESENTABLE Constructor. - -- @param #CARGO_REPRESENTABLE self - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number ReportRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - return self - end - - --- CARGO_REPRESENTABLE Destructor. - -- @param #CARGO_REPRESENTABLE self - -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:Destroy() - - -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects. - self:F( { CargoName = self:GetName() } ) - _EVENTDISPATCHER:CreateEventDeleteCargo( self ) - - return self - end - - --- Route a cargo unit to a PointVec2. - -- @param #CARGO_REPRESENTABLE self - -- @param Core.Point#POINT_VEC2 ToPointVec2 - -- @param #number Speed - -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) - self:F2( ToPointVec2 ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = ToPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - return self - end - - -end -- CARGO_REPRESENTABLE - -do -- CARGO_REPORTABLE - - --- @type CARGO_REPORTABLE - -- @extends #CARGO - CARGO_REPORTABLE = { - ClassName = "CARGO_REPORTABLE" - } - - --- CARGO_REPORTABLE Constructor. - -- @param #CARGO_REPORTABLE self - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number ReportRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_REPORTABLE - function CARGO_REPORTABLE:New( Type, Name, Weight, ReportRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE - self:F( { Type, Name, Weight, ReportRadius } ) - - self.CargoSet = SET_CARGO:New() -- Core.Set#SET_CARGO - - self.ReportRadius = ReportRadius or 1000 - - return self - end - - --- Send a CC message to a @{Group}. - -- @param #CARGO_REPORTABLE self - -- @param #string Message - -- @param Wrapper.Group#GROUP TaskGroup - -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. - function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name ) - - local Prefix = Name and "@ " .. Name .. ": " or "@ " .. TaskGroup:GetCallsign() .. ": " - Message = Prefix .. Message - MESSAGE:New( Message, 20, "Cargo: " .. self:GetName() ):ToGroup( TaskGroup ) - - end - - --- Get the Report radius, which is the radius when the Cargo is reporting itself. - -- @param #CARGO_REPORTABLE self - -- @return #number The range till Cargo reports itself. - function CARGO_REPORTABLE:GetBoardingRange() - return self.ReportRadius - end - - - -end - -do -- CARGO_UNIT - - --- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded. - -- @type CARGO_UNIT - -- @extends #CARGO_REPRESENTABLE - - --- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE} - -- - -- The CARGO\_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. - -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_UNIT objects to and from carriers. - -- - -- === - -- - -- @field #CARGO_UNIT CARGO_UNIT - -- - CARGO_UNIT = { - ClassName = "CARGO_UNIT" - } - - --- CARGO_UNIT Constructor. - -- @param #CARGO_UNIT self - -- @param Wrapper.Unit#UNIT CargoUnit - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number ReportRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_UNIT - function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT - self:F( { Type, Name, Weight, NearRadius } ) - - self:T( CargoUnit ) - self.CargoObject = CargoUnit - - self:T( self.ClassName ) - - self:SetEventPriority( 5 ) - - return self - end - - --- Enter UnBoarding State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#POINT_VEC2 ToPointVec2 - function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 25 - - local Angle = 180 - local Speed = 60 - local DeployDistance = 9 - local RouteDistance = 60 - - if From == "Loaded" then - - if not self:IsDestroyed() then - - local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - - - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) - local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) - local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) - --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) - - ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) - self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) - self.CargoCarrier = nil - - local Points = {} - - -- From - Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) - - -- To - Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - - - self:__UnBoarding( 1, ToPointVec2, NearRadius ) - end - end - end - - end - - --- Leave UnBoarding State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#POINT_VEC2 ToPointVec2 - function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 100 - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - if self:IsNear( ToPointVec2, NearRadius ) then - return true - else - - self:__UnBoarding( 1, ToPointVec2, NearRadius ) - end - return false - end - - end - - --- UnBoard Event. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#POINT_VEC2 ToPointVec2 - function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 100 - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier is not in the air. - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - - end - - self:__UnLoad( 1, ToPointVec2, NearRadius ) - - end - - - - --- Enter UnLoaded State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#POINT_VEC2 - function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "Loaded" then - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployCoord = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - ToPointVec2 = ToPointVec2 or COORDINATE:New( CargoDeployCoord.x, CargoDeployCoord.z ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 ) - self.CargoCarrier = nil - end - - end - - if self.OnUnLoadedCallBack then - self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) - self.OnUnLoadedCallBack = nil - end - - end - - --- Board Event. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier, NearRadius } ) - - local NearRadius = NearRadius or 25 - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only move the group to the carrier when the cargo is not in the air - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:Load( CargoCarrier, NearRadius, ... ) - else - local Speed = 90 - local Angle = 180 - local Distance = 5 - - NearRadius = NearRadius or 25 - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - self:__Boarding( -1, CargoCarrier, NearRadius ) - self.RunCount = 0 - end - end - - end - - - --- Boarding Event. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Client#CLIENT CargoCarrier - -- @param #number NearRadius - function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - - - if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then - if CargoCarrier:InAir() == false then - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:__Load( 1, CargoCarrier, ... ) - else - self:__Boarding( -1, CargoCarrier, NearRadius, ... ) - self.RunCount = self.RunCount + 1 - if self.RunCount >= 60 then - self.RunCount = 0 - local Speed = 90 - local Angle = 180 - local Distance = 5 - - NearRadius = NearRadius or 25 - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 0.2 ) - end - end - else - self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() ) - self:CancelBoarding( CargoCarrier, NearRadius, ... ) - self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) - end - else - self:E("Something is wrong") - end - - end - - - --- Enter Boarding State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - - local Speed = 90 - local Angle = 180 - local Distance = 5 - - local NearRadius = NearRadius or 25 - - if From == "UnLoaded" or From == "Boarding" then - - end - - end - - --- Loaded State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) - self:F( { From, Event, To, CargoCarrier } ) - - self.CargoCarrier = CargoCarrier - - -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). - if self.CargoObject then - self:T("Destroying") - self.CargoObject:Destroy() - end - end - -end -- CARGO_UNIT - -do -- CARGO_CRATE - - --- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters using the DCS menus. - -- @type CARGO_CRATE - -- @extends #CARGO_REPRESENTABLE - - --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} - -- - -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. - -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. - -- - -- === - -- - -- @field #CARGO_CRATE - CARGO_CRATE = { - ClassName = "CARGO_CRATE" - } - - --- CARGO_CRATE Constructor. - -- @param #CARGO_CRATE self - -- @param #string CrateName - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number ReportRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_CRATE - function CARGO_CRATE:New( CargoCrateName, Type, Name, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCrateName, Type, Name, nil, NearRadius ) ) -- #CARGO_CRATE - self:F( { Type, Name, NearRadius } ) - - self:T( CargoCrateName ) - _DATABASE:AddStatic( CargoCrateName ) - - self.CargoObject = STATIC:FindByName( CargoCrateName ) - - self:T( self.ClassName ) - - self:SetEventPriority( 5 ) - - return self - end - - - - --- Enter UnLoaded State. - -- @param #CARGO_CRATE self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#POINT_VEC2 - function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 10 - - if From == "Loaded" then - local StartCoordinate = self.CargoCarrier:GetCoordinate() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployCoord = StartCoordinate:Translate( Distance, CargoDeployHeading ) - - ToPointVec2 = ToPointVec2 or COORDINATE:NewFromVec2( { x= CargoDeployCoord.x, y = CargoDeployCoord.z } ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( ToPointVec2, 0 ) - self.CargoCarrier = nil - end - - end - - if self.OnUnLoadedCallBack then - self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) - self.OnUnLoadedCallBack = nil - end - - end - - - --- Loaded State. - -- @param #CARGO_CRATE self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier ) - self:F( { From, Event, To, CargoCarrier } ) - - self.CargoCarrier = CargoCarrier - - -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). - if self.CargoObject then - self:T("Destroying") - self.CargoObject:Destroy() - end - end - - - -end - -do -- CARGO_GROUP - - --- @type CARGO_GROUP - -- @extends #CARGO_REPORTABLE - - --- # CARGO\_GROUP class - -- - -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator, and can be transported by a carrier. - -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_GROUP to and from carrier. - -- - -- @field #CARGO_GROUP CARGO_GROUP - -- - CARGO_GROUP = { - ClassName = "CARGO_GROUP", - } - ---- CARGO_GROUP constructor. --- This make a new CARGO_GROUP from a @{Group} object. --- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. --- @param #CARGO_GROUP self --- @param Wrapper.Group#GROUP CargoGroup --- @param #string Type --- @param #string Name --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #CARGO_GROUP -function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, ReportRadius } ) - - self:SetDeployed( false ) - - local WeightGroup = 0 - - self.GroupName = CargoGroup:GetName() - self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) - - CargoGroup:Destroy() - - -- We iterate through the group template and for each unit in the template, we create a new group with one unit. - for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do - - local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - local GroupName = env.getValueDictByKey( GroupTemplate.name ) - - -- We create a new group object with one unit... - -- First we prepare the template... - GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID - GroupTemplate.groupId = nil - GroupTemplate.units = {} - GroupTemplate.units[1] = UnitTemplate - local UnitName = UnitTemplate.name .. "#CARGO" - GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" - - - -- Then we register the new group in the database - local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) - - -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) - - -- And we register the spawned unit as part of the CargoSet. - local Unit = UNIT:FindByName( UnitName ) - --local WeightUnit = Unit:GetDesc().massEmpty - --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) - self.CargoSet:Add( UnitName, CargoUnit ) - end - - - self:SetWeight( WeightGroup ) - - self:T( { "Weight Cargo", WeightGroup } ) - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) - - self:SetEventPriority( 4 ) - - return self -end - ---- @param #CARGO_GROUP self --- @param Core.Event#EVENTDATA EventData -function CARGO_GROUP:OnEventCargoDead( EventData ) - - local Destroyed = false - - if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then - Destroyed = true - for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- #CARGO - if Cargo:IsAlive() then - Destroyed = false - else - Cargo:Destroyed() - end - end - else - local CarrierName = self.CargoCarrier:GetName() - if CarrierName == EventData.IniDCSUnitName then - MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() - Destroyed = true - self.CargoCarrier:ClearCargo() - end - end - - if Destroyed then - self:Destroyed() - self:E( { "Cargo group destroyed" } ) - end - - end - - --- Enter Boarding State. - -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local NearRadius = NearRadius or 25 - - if From == "UnLoaded" then - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, ... ) - Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) - end, ... - ) - - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) - end - - end - - --- Enter Loaded State. - -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) - self:F( { From, Event, To, CargoCarrier, ...} ) - - if From == "UnLoaded" then - -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - Cargo:Load( CargoCarrier ) - end - end - - --self.CargoObject:Destroy() - self.CargoCarrier = CargoCarrier - - end - - --- Leave Boarding State. - -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local NearRadius = NearRadius or 100 - - local Boarded = true - local Cancelled = false - local Dead = true - - self.CargoSet:Flush() - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( { Cargo:GetName(), Cargo.current } ) - - - if not Cargo:is( "Loaded" ) - and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. - Boarded = false - end - - if Cargo:is( "UnLoaded" ) then - Cancelled = true - end - - if not Cargo:is( "Destroyed" ) then - Dead = false - end - - end - - if not Dead then - - if not Cancelled then - if not Boarded then - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) - else - self:F("Group Cargo is loaded") - self:__Load( 1, CargoCarrier, ... ) - end - else - self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) - end - else - self:__Destroyed( 1, CargoCarrier, NearRadius, ... ) - end - - end - - --- Get the amount of cargo units in the group. - -- @param #CARGO_GROUP self - -- @return #CARGO_GROUP - function CARGO_GROUP:GetCount() - return self.CargoSet:Count() - end - - - --- Enter UnBoarding State. - -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 ToPointVec2 - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( {From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 25 - - local Timer = 1 - - if From == "Loaded" then - - if self.CargoObject then - self.CargoObject:Destroy() - end - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, NearRadius ) - - Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 3 - end, { NearRadius } - ) - - - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) - end - - end - - --- Leave UnBoarding State. - -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 ToPointVec2 - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - local UnBoarded = true - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then - UnBoarded = false - end - end - - if UnBoarded then - return true - else - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) - end - - return false - end - - end - - --- UnBoard Event. - -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 ToPointVec2 - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - self:__UnLoad( 1, ToPointVec2, ... ) - end - - - - --- Enter UnLoaded State. - -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 - -- @param #string Event - -- @param #string From - -- @param #string To - function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) - self:F( { From, Event, To, ToPointVec2 } ) - - if From == "Loaded" then - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - --Cargo:UnLoad( ToPointVec2 ) - local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10) - Cargo:UnLoad( RandomVec2 ) - end - ) - - end - - end - - - --- Respawn the cargo when destroyed - -- @param #CARGO_GROUP self - -- @param #boolean RespawnDestroyed - function CARGO_GROUP:RespawnOnDestroyed( RespawnDestroyed ) - self:F({"In function RespawnOnDestroyed"}) - if RespawnDestroyed then - self.onenterDestroyed = function( self ) - self:F("IN FUNCTION") - self:Respawn() - end - else - self.onenterDestroyed = nil - end - - end - - --- Get the current Coordinate of the CargoGroup. - -- @param #CARGO_GROUP self - -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. - -- @return #nil There is no valid Cargo in the CargoGroup. - function CARGO_GROUP:GetCoordinate() - self:F() - - local Cargo = self.CargoSet:GetFirst() - - if Cargo then - return Cargo.CargoObject:GetCoordinate() - end - - return nil - end - - --- Check if the CargoGroup is alive. - -- @param #CARGO_GROUP self - -- @return #boolean true if the CargoGroup is alive. - -- @return #boolean false if the CargoGroup is dead. - function CARGO_GROUP:IsAlive() - - local Alive = true - - -- For each Cargo within the CargoSet, check if the Cargo is Alive. - -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. - -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. - self.CargoSet:ForEach( - function( Cargo ) - if self:IsLoaded() then - Alive = Alive == true and Cargo.CargoCarrier:IsAlive() - else - Alive = Alive == true and Cargo.CargoObject:IsAlive() - end - end - ) - - return Alive - - end - - - --- Route Cargo to Coordinate and randomize locations. - -- @param #CARGO_GROUP self - -- @param Core.Point#COORDINATE Coordinate - function CARGO_GROUP:RouteTo( Coordinate ) - self:F( {Coordinate = Coordinate } ) - - -- For each Cargo within the CargoSet, route each object to the Coordinate - self.CargoSet:ForEach( - function( Cargo ) - Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 ) - end - ) - - end - - --- Check if Cargo is near to the Carrier. - -- The Cargo is near to the Carrier if the first unit of the Cargo Group is within NearRadius. - -- @param #CARGO_GROUP self - -- @param Wrapper.Group#GROUP CargoCarrier - -- @param #number NearRadius - -- @return #boolean The Cargo is near to the Carrier. - -- @return #nil The Cargo is not near to the Carrier. - function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) - self:F( {NearRadius = NearRadius } ) - - local Cargo = self.CargoSet:GetFirst() -- #CARGO - - if Cargo then - return Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) - end - - return nil - end - - --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. - -- @param #CARGO_GROUP self - -- @param Core.Point#Coordinate Coordinate - -- @return #boolean true if the CargoGroup is within the reporting radius. - function CARGO_GROUP:IsInRadius( Coordinate ) - self:F( { Coordinate } ) - - local Cargo = self.CargoSet:GetFirst() -- #CARGO - - if Cargo then - local Distance = 0 - if Cargo:IsLoaded() then - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoCarrier:GetPointVec2() ) - else - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) - end - self:T( Distance ) - - if Distance <= self.ReportRadius then - return true - else - return false - end - end - - return nil - - end - - --- Respawn the CargoGroup. - -- @param #CARGO_GROUP self - function CARGO_GROUP:Respawn() - - self:F( { "Respawning" } ) - - for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- #CARGO - Cargo:Destroy() - Cargo:SetStartState( "UnLoaded" ) - end - - - -- We iterate through the group template and for each unit in the template, we create a new group with one unit. - for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do - - local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - local GroupName = env.getValueDictByKey( GroupTemplate.name ) - - -- We create a new group object with one unit... - -- First we prepare the template... - GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID - GroupTemplate.groupId = nil - GroupTemplate.units = {} - GroupTemplate.units[1] = UnitTemplate - local UnitName = UnitTemplate.name .. "#CARGO" - GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" - - - -- Then we register the new group in the database - local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) - - -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) - - -- And we register the spawned unit as part of the CargoSet. - local Unit = UNIT:FindByName( UnitName ) - --local WeightUnit = Unit:GetDesc().massEmpty - --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) - self.CargoSet:Add( UnitName, CargoUnit ) - end - - self:SetDeployed( false ) - self:SetStartState( "UnLoaded" ) - - end - - --- Signal a flare at the position of the CargoGroup. - -- @param #CARGO_GROUP self - -- @param Utilities.Utils#FLARECOLOR FlareColor - function CARGO_GROUP:Flare( FlareColor ) - - local Cargo = self.CargoSet:GetFirst() -- #CARGO - if Cargo then - Cargo:Flare( FlareColor ) - end - end - - --- Smoke the CargoGroup. - -- @param #CARGO_GROUP self - -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. - -- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup. - function CARGO_GROUP:Smoke( SmokeColor, Radius ) - - local Cargo = self.CargoSet:GetFirst() -- #CARGO - - if Cargo then - Cargo:Smoke( SmokeColor, Radius ) - end - end - - --- Check if the first element of the CargoGroup is the given @{Zone}. - -- @param #CARGO self - -- @param Core.Zone#ZONE_BASE Zone - -- @return #boolean **true** if the first element of the CargoGroup is in the Zone - -- @return #boolean **false** if there is no element of the CargoGroup in the Zone. - function CARGO_GROUP:IsInZone( Zone ) - self:F( { Zone } ) - - local Cargo = self.CargoSet:GetFirst() -- #CARGO - - if Cargo then - return Cargo:IsInZone( Zone ) - end - - return nil - - end - -end -- CARGO_GROUP - -do -- CARGO_PACKAGE - - --- @type CARGO_PACKAGE - -- @extends #CARGO_REPRESENTABLE - CARGO_PACKAGE = { - ClassName = "CARGO_PACKAGE" - } - ---- CARGO_PACKAGE Constructor. --- @param #CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package. --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #CARGO_PACKAGE -function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_PACKAGE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:T( CargoCarrier ) - self.CargoCarrier = CargoCarrier - - return self -end - ---- Board Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number BoardDistance --- @param #number Angle -function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only move the CargoCarrier to the New CargoCarrier when the New CargoCarrier is not in the air. - if not self.CargoInAir then - - local Points = {} - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:Boarded( CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - -end - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier --- @return #boolean -function CARGO_PACKAGE:IsNear( CargoCarrier ) - self:F() - - local CargoCarrierPoint = CargoCarrier:GetPointVec2() - - local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) - self:T( Distance ) - - if Distance <= self.NearRadius then - return true - else - return false - end -end - ---- Boarded Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() - - if self:IsNear( CargoCarrier ) then - self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) - else - self:__Boarded( 1, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - end -end - ---- UnBoard Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param #number Speed --- @param #number UnLoadDistance --- @param #number UnBoardDistance --- @param #number Radius --- @param #number Angle -function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) - self:F() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier is not in the air. - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - - self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle ) - - local Points = {} - - local StartPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = CargoCarrier:TaskRoute( Points ) - CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:__UnBoarded( 1 , CargoCarrier, Speed ) - -end - ---- UnBoarded Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) - self:F() - - if self:IsNear( CargoCarrier ) then - self:__UnLoad( 1, CargoCarrier, Speed ) - else - self:__UnBoarded( 1, CargoCarrier, Speed ) - end -end - ---- Load Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number LoadDistance --- @param #number Angle -function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) - self:F() - - self.CargoCarrier = CargoCarrier - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading ) - - local Points = {} - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - ---- UnLoad Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param #number Distance --- @param #number Angle -function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) - self:F() - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - self.CargoCarrier = CargoCarrier - - local Points = {} - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - - -end diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index 49a8fc08b..ebc56985c 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -21,7 +21,6 @@ Core/Radio.lua Core/Spawn.lua Core/SpawnStatic.lua Core/Goal.lua -Core/Cargo.lua Core/Spot.lua Wrapper/Object.lua @@ -35,6 +34,11 @@ Wrapper/Static.lua Wrapper/Airbase.lua Wrapper/Scenery.lua +Cargo/Cargo.lua +Cargo/CargoUnit.lua +Cargo/CargoCrate.lua +Cargo/CargoGroup.lua + Functional/Scoring.lua Functional/CleanUp.lua Functional/Movement.lua From a94e7440284d60c04f372f8ec90d7a9e65212a62 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 31 Mar 2018 07:35:18 +0200 Subject: [PATCH 020/170] -- New modules for CSAR tasking. --- .../Moose/Tasking/Task_CARGO.lua | 5 +- .../Moose/Tasking/Task_Cargo_CSAR.lua | 187 +++++++++ .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 362 ++++++++++++++++++ .../Moose/Tasking/Task_Cargo_Transport.lua | 187 +++++++++ .../Moose/Tasking/Task_Manager.lua | 150 ++++++++ Moose Setup/Moose.files | 4 + 6 files changed, 892 insertions(+), 3 deletions(-) create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_Transport.lua create mode 100644 Moose Development/Moose/Tasking/Task_Manager.lua diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 7d11cae8d..c9127d3fe 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -726,10 +726,9 @@ do -- TASK_CARGO end --- @param #TASK_CARGO self - -- @param @list DeployZones - -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #list DeployZones -- @return #TASK_CARGO - function TASK_CARGO:SetDeployZones( DeployZones, TaskUnit ) + function TASK_CARGO:SetDeployZones( DeployZones ) for DeployZoneID, DeployZone in pairs( DeployZones ) do self.DeployZones[DeployZone:GetName()] = DeployZone diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua new file mode 100644 index 000000000..b45dc7e26 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -0,0 +1,187 @@ +--- **Tasking** -- Models tasks for players to execute CSAR @{Cargo} downed pilots. +-- +-- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) +-- +-- === + + +do -- TASK_CARGO_CSAR + + --- The TASK_CARGO_CSAR class + -- @type TASK_CARGO_CSAR + -- @extends Tasking.Task_Cargo#TASK_CARGO + TASK_CARGO_CSAR = { + ClassName = "TASK_CARGO_CSAR", + } + + --- Instantiates a new TASK_CARGO_CSAR. + -- @param #TASK_CARGO_CSAR self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. + -- @param #string TaskBriefing The Cargo Task briefing. + -- @return #TASK_CARGO_CSAR self + function TASK_CARGO_CSAR:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_CSAR + self:F() + + Mission:AddTask( self ) + + + -- Events + + self:AddTransition( "*", "CargoPickedUp", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) + + self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + + --- OnBefore Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] OnBeforeCargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] OnAfterCargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Synchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] CargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Asynchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] __CargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- OnBefore Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] OnBeforeCargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] OnAfterCargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Synchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] CargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Asynchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] __CargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + local Fsm = self:GetUnitProcess() + + local CargoReport = REPORT:New( "Rescue a downed pilot from the following position:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + + + return self + end + + function TASK_CARGO_CSAR:ReportOrder( ReportGroup ) + + return 0 + end + + + --- + -- @param #TASK_CARGO_CSAR self + -- @return #boolean + function TASK_CARGO_CSAR:IsAllCargoTransported() + + local CargoSet = self:GetCargoSet() + local Set = CargoSet:GetSet() + + local DeployZones = self:GetDeployZones() + + local CargoDeployed = true + + -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). + for CargoID, CargoData in pairs( Set ) do + local Cargo = CargoData -- Core.Cargo#CARGO + + self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) + + if Cargo:IsDeployed() then + +-- -- Loop the DeployZones set for the TASK_CARGO_CSAR. +-- for DeployZoneID, DeployZone in pairs( DeployZones ) do +-- +-- -- If all cargo is in one of the deploy zones, then all is good. +-- self:T( { Cargo.CargoObject } ) +-- if Cargo:IsInZone( DeployZone ) == false then +-- CargoDeployed = false +-- end +-- end + else + CargoDeployed = false + end + end + + self:F( { CargoDeployed = CargoDeployed } ) + + return CargoDeployed + end + + --- @param #TASK_CARGO_CSAR self + function TASK_CARGO_CSAR:onafterGoal( TaskUnit, From, Event, To ) + local CargoSet = self.CargoSet + + if self:IsAllCargoTransported() then + self:Success() + end + + self:__Goal( -10 ) + end + +end + diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua new file mode 100644 index 000000000..3b22c9e01 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -0,0 +1,362 @@ +--- **Tasking** - Creates and manages player TASK_CARGO tasks. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- ### Contributions: +-- +-- === +-- +-- @module Task_Cargo_Dispatcher + +do -- TASK_CARGO_DISPATCHER + + --- TASK_CARGO_DISPATCHER class. + -- @type TASK_CARGO_DISPATCHER + -- @extends Tasking.Task_Manager#TASK_MANAGER + -- @field TASK_CARGO_DISPATCHER.CSAR CSAR + + --- @type TASK_CARGO_DISPATCHER.CSAR + -- @field Wrapper.Unit#UNIT PilotUnit + -- @field Tasking.Task#TASK Task + + + --- # TASK_CARGO_DISPATCHER class, extends @{Task_Manager#TASK_MANAGER} + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia1.JPG) + -- + -- The @{#TASK_CARGO_DISPATCHER} class implements the dynamic dispatching of cargo tasks. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia3.JPG) + -- + -- The EWR will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched. + -- Find a summary below describing for which situation a task type is created: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia9.JPG) + -- + -- * **CSAR Task**: Is created when a fiendly pilot has ejected from a plane, and needs to be rescued (sometimes behind enemy lines). + -- + -- ## 1. TASK\_A2A\_DISPATCHER constructor: + -- + -- The @{#TASK_CARGO_DISPATCHER.New}() method creates a new TASK\_A2A\_DISPATCHER instance. + -- + -- ### 1.1. Define or set the **Mission**: + -- + -- Tasking is executed to accomplish missions. Therefore, a MISSION object needs to be given as the first parameter. + -- + -- local HQ = GROUP:FindByName( "HQ", "Bravo" ) + -- local CommandCenter = COMMANDCENTER:New( HQ, "Lima" ) + -- local Mission = MISSION:New( CommandCenter, "A2A Mission", "High", "Watch the air enemy units being detected.", coalition.side.RED ) + -- + -- Missions are governed by COMMANDCENTERS, so, ensure you have a COMMANDCENTER object installed and setup within your mission. + -- Create the MISSION object, and hook it under the command center. + -- + -- ### 1.2. Build a set of the groups seated by human players: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia6.JPG) + -- + -- A set or collection of the groups wherein human players can be seated, these can be clients or units that can be joined as a slot or jumping into. + -- + -- local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "Defender" ):FilterStart() + -- + -- The set is built using the SET_GROUP class. Apply any filter criteria to identify the correct groups for your mission. + -- Only these slots or units will be able to execute the mission and will receive tasks for this mission, once available. + -- + -- ### 1.3. Define the **EWR network**: + -- + -- As part of the TASK\_A2A\_DISPATCHER constructor, an EWR network must be given as the third parameter. + -- An EWR network, or, Early Warning Radar network, is used to early detect potential airborne targets and to understand the position of patrolling targets of the enemy. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia5.JPG) + -- + -- Typically EWR networks are setup using 55G6 EWR, 1L13 EWR, Hawk sr and Patriot str ground based radar units. + -- These radars have different ranges and 55G6 EWR and 1L13 EWR radars are Eastern Bloc units (eg Russia, Ukraine, Georgia) while the Hawk and Patriot radars are Western (eg US). + -- Additionally, ANY other radar capable unit can be part of the EWR network! Also AWACS airborne units, planes, helicopters can help to detect targets, as long as they have radar. + -- The position of these units is very important as they need to provide enough coverage + -- to pick up enemy aircraft as they approach so that CAP and GCI flights can be tasked to intercept them. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia7.JPG) + -- + -- Additionally in a hot war situation where the border is no longer respected the placement of radars has a big effect on how fast the war escalates. + -- For example if they are a long way forward and can detect enemy planes on the ground and taking off + -- they will start to vector CAP and GCI flights to attack them straight away which will immediately draw a response from the other coalition. + -- Having the radars further back will mean a slower escalation because fewer targets will be detected and + -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. + -- It all depends on what the desired effect is. + -- + -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. + -- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network, + -- increasing or decreasing the radar coverage of the Early Warning System. + -- + -- See the following example to setup an EWR network containing EWR stations and AWACS. + -- + -- local EWRSet = SET_GROUP:New():FilterPrefixes( "EWR" ):FilterCoalitions("red"):FilterStart() + -- + -- local EWRDetection = DETECTION_AREAS:New( EWRSet, 6000 ) + -- EWRDetection:SetFriendliesRange( 10000 ) + -- EWRDetection:SetRefreshTimeInterval(30) + -- + -- -- Setup the A2A dispatcher, and initialize it. + -- A2ADispatcher = TASK_CARGO_DISPATCHER:New( Mission, AttackGroups, EWRDetection ) + -- + -- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**. + -- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set. + -- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set. + -- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is choosen, which is 6km. + -- The **EWRDetection** object is then passed to the @{#TASK_CARGO_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism. + -- + -- ### 2. Define the detected **target grouping radius**: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia8.JPG) + -- + -- The target grouping radius is a property of the Detection object, that was passed to the AI\_A2A\_DISPATCHER object, but can be changed. + -- The grouping radius should not be too small, but also depends on the types of planes and the era of the simulation. + -- Fast planes like in the 80s, need a larger radius than WWII planes. + -- Typically I suggest to use 30000 for new generation planes and 10000 for older era aircraft. + -- + -- Note that detected targets are constantly re-grouped, that is, when certain detected aircraft are moving further than the group radius, then these aircraft will become a separate + -- group being detected. This may result in additional GCI being started by the dispatcher! So don't make this value too small! + -- + -- ## 3. Set the **Engage radius**: + -- + -- Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia11.JPG) + -- + -- So, if there is a target area detected and reported, + -- then any friendlies that are airborne near this target area, + -- will be commanded to (re-)engage that target when available (if no other tasks were commanded). + -- For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, + -- will be considered to receive the command to engage that target area. + -- You need to evaluate the value of this parameter carefully. + -- If too small, more intercept missions may be triggered upon detected target areas. + -- If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far. + -- + -- ## 4. Set **Scoring** and **Messages**: + -- + -- The TASK\_A2A\_DISPATCHER is a state machine. It triggers the event Assign when a new player joins a @{Task} dispatched by the TASK\_A2A\_DISPATCHER. + -- An _event handler_ can be defined to catch the **Assign** event, and add **additional processing** to set _scoring_ and to _define messages_, + -- when the player reaches certain achievements in the task. + -- + -- The prototype to handle the **Assign** event needs to be developed as follows: + -- + -- TaskDispatcher = TASK_CARGO_DISPATCHER:New( ... ) + -- + -- --- @param #TaskDispatcher self + -- -- @param #string From Contains the name of the state from where the Event was triggered. + -- -- @param #string Event Contains the name of the event that was triggered. In this case Assign. + -- -- @param #string To Contains the name of the state that will be transitioned to. + -- -- @param Tasking.Task_A2A#TASK_A2A Task The Task object, which is any derived object from TASK_A2A. + -- -- @param Wrapper.Unit#UNIT TaskUnit The Unit or Client that contains the Player. + -- -- @param #string PlayerName The name of the Player that joined the TaskUnit. + -- function TaskDispatcher:OnAfterAssign( From, Event, To, Task, TaskUnit, PlayerName ) + -- Task:SetScoreOnProgress( PlayerName, 20, TaskUnit ) + -- Task:SetScoreOnSuccess( PlayerName, 200, TaskUnit ) + -- Task:SetScoreOnFail( PlayerName, -100, TaskUnit ) + -- end + -- + -- The **OnAfterAssign** method (function) is added to the TaskDispatcher object. + -- This method will be called when a new player joins a unit in the set of groups in scope of the dispatcher. + -- So, this method will be called only **ONCE** when a player joins a unit in scope of the task. + -- + -- The TASK class implements various methods to additional **set scoring** for player achievements: + -- + -- * @{Tasking.Task#TASK.SetScoreOnProgress}() will add additional scores when a player achieves **Progress** while executing the task. + -- Examples of **task progress** can be destroying units, arriving at zones etc. + -- + -- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional scores when the task goes into **Success** state. + -- This means the **task has been successfully completed**. + -- + -- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional (negative) scores when the task goes into **Failed** state. + -- This means the **task has not been successfully completed**, and the scores must be given with a negative value! + -- + -- @field #TASK_CARGO_DISPATCHER + TASK_CARGO_DISPATCHER = { + ClassName = "TASK_CARGO_DISPATCHER", + Mission = nil, + Tasks = {}, + CSAR = {}, + } + + + --- TASK_CARGO_DISPATCHER constructor. + -- @param #TASK_CARGO_DISPATCHER self + -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. + -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @return #TASK_CARGO_DISPATCHER self + function TASK_CARGO_DISPATCHER:New( Mission, SetGroup ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CARGO_DISPATCHER + + self.Mission = Mission + + self:AddTransition( "Started", "Assign", "Started" ) + + --- OnAfter Transition Handler for Event Assign. + -- @function [parent=#TASK_CARGO_DISPATCHER] OnAfterAssign + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Tasking.Task_A2A#TASK_A2A Task + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #string PlayerName + + self:SetCSARRadius() + self:__Start( 5 ) + + -- For CSAR missions, we process the event when a pilot ejects. + + self:HandleEvent( EVENTS.Ejection ) + + return self + end + + + --- Handle the event when a pilot ejects. + -- @param #TASK_CARGO_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) + + self:E( { EventData = EventData } ) + + local PilotUnit = EventData.IniUnit + local CSARName = EventData.IniUnitName + + self.CSAR[CSARName] = {} + self.CSAR[CSARName].PilotUnit = PilotUnit + self.CSAR[CSARName].Task = nil + + return self + end + + + --- Define the radius to when a CSAR task will be generated for any downed pilot within range of the nearest CSAR airbase. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #number CSARRadius (Optional, Default = 50000) The radius in meters to decide whether a CSAR needs to be created. + -- @return #TASK_CARGO_DISPATCHER + -- @usage + -- + -- -- Set 20km as the radius to CSAR any downed pilot within range of the nearest CSAR airbase. + -- TaskA2ADispatcher:SetEngageRadius( 20000 ) + -- + -- -- Set 50km as the radius to to CSAR any downed pilot within range of the nearest CSAR airbase. + -- TaskA2ADispatcher:SetEngageRadius() -- 50000 is the default value. + -- + function TASK_CARGO_DISPATCHER:SetCSARRadius( CSARRadius ) + + self.Detection:SetFriendliesRange( CSARRadius or 50000 ) + + return self + end + + + --- Define one deploy zone for the CSAR tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DeployZone A deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARDeployZone ) + + self.CSARDeployZones = { CSARDeployZone } + + return self + end + + + --- Define the deploy zones for the CSAR tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DeployZones A list of the deploy zones. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) + + self.CSARDeployZones = CSARDeployZones + + return self + end + + + --- Evaluates of a CSAR task needs to be started. + -- @param #TASK_CARGO_DISPATCHER self + -- @return Set#SET_CARGO The SetCargo to be rescued. + -- @return #nil If there is no CSAR task required. + function TASK_CARGO_DISPATCHER:EvaluateCSAR( CSARUnit ) + + local CSARCargo = CARGO_UNIT:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) + + local SetCargo = SET_CARGO:New() + SetCargo:AddCargosByName( CSARUnit:GetName() ) + + SetCargo:Flush(self) + + return SetCargo + + end + + + + --- Assigns tasks to the @{Set#SET_GROUP}. + -- @param #TASK_CARGO_DISPATCHER self + -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. + function TASK_CARGO_DISPATCHER:ManageTasks() + self:F() + + local AreaMsg = {} + local TaskMsg = {} + local ChangeMsg = {} + + local Mission = self.Mission + + if Mission:IsIDLE() or Mission:IsENGAGED() then + + local TaskReport = REPORT:New() + + -- Checking the task queue for the dispatcher, and removing any obsolete task! + for TaskIndex, TaskData in pairs( self.Tasks ) do + local Task = TaskData -- Tasking.Task#TASK + if Task:IsStatePlanned() then + -- Here we need to check if the pilot is still existing. +-- local DetectedItem = Detection:GetDetectedItemByIndex( TaskIndex ) +-- if not DetectedItem then +-- local TaskText = Task:GetName() +-- for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do +-- Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2A task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup ) +-- end +-- Task = self:RemoveTask( TaskIndex ) +-- end + end + end + + -- Now that all obsolete tasks are removed, loop through the CSAR pilots. + for CSARID, CSARData in pairs( self.CSAR ) do + + if CSARData.Task then + else + -- New CSAR Task + local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) + local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, "Rescue Pilot", SetCargo ) + CSARTask:SetDeployZones( { self.CSARDeployZones } ) + Mission:AddTask( CSARTask ) + TaskReport:Add( CSARTask:GetName() ) + end + end + + + -- TODO set menus using the HQ coordinator + Mission:GetCommandCenter():SetMenu() + + local TaskText = TaskReport:Text(", ") + + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then + Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) + end + end + + end + + return true + end + +end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua new file mode 100644 index 000000000..0deff06e4 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -0,0 +1,187 @@ +--- **Tasking** -- The TASK_CARGO models tasks for players to transport @{Cargo}. +-- +-- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) +-- +-- === + + +do -- TASK_CARGO_TRANSPORT + + --- The TASK_CARGO_TRANSPORT class + -- @type TASK_CARGO_TRANSPORT + -- @extends Tasking.Task_Cargo#TASK_CARGO + TASK_CARGO_TRANSPORT = { + ClassName = "TASK_CARGO_TRANSPORT", + } + + --- Instantiates a new TASK_CARGO_TRANSPORT. + -- @param #TASK_CARGO_TRANSPORT self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. + -- @param #string TaskBriefing The Cargo Task briefing. + -- @return #TASK_CARGO_TRANSPORT self + function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_TRANSPORT + self:F() + + Mission:AddTask( self ) + + + -- Events + + self:AddTransition( "*", "CargoPickedUp", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) + + self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + + --- OnBefore Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Synchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] CargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Asynchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- OnBefore Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Synchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] CargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Asynchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + local Fsm = self:GetUnitProcess() + + local CargoReport = REPORT:New( "Transport Cargo. The following cargo needs to be transported including initial positions:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + + + return self + end + + function TASK_CARGO_TRANSPORT:ReportOrder( ReportGroup ) + + return 0 + end + + + --- + -- @param #TASK_CARGO_TRANSPORT self + -- @return #boolean + function TASK_CARGO_TRANSPORT:IsAllCargoTransported() + + local CargoSet = self:GetCargoSet() + local Set = CargoSet:GetSet() + + local DeployZones = self:GetDeployZones() + + local CargoDeployed = true + + -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). + for CargoID, CargoData in pairs( Set ) do + local Cargo = CargoData -- Core.Cargo#CARGO + + self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) + + if Cargo:IsDeployed() then + +-- -- Loop the DeployZones set for the TASK_CARGO_TRANSPORT. +-- for DeployZoneID, DeployZone in pairs( DeployZones ) do +-- +-- -- If all cargo is in one of the deploy zones, then all is good. +-- self:T( { Cargo.CargoObject } ) +-- if Cargo:IsInZone( DeployZone ) == false then +-- CargoDeployed = false +-- end +-- end + else + CargoDeployed = false + end + end + + self:F( { CargoDeployed = CargoDeployed } ) + + return CargoDeployed + end + + --- @param #TASK_CARGO_TRANSPORT self + function TASK_CARGO_TRANSPORT:onafterGoal( TaskUnit, From, Event, To ) + local CargoSet = self.CargoSet + + if self:IsAllCargoTransported() then + self:Success() + end + + self:__Goal( -10 ) + end + +end + diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua new file mode 100644 index 000000000..2bf10fea6 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -0,0 +1,150 @@ +--- This module contains the TASK_MANAGER class and derived classes. +-- +-- === +-- +-- 1) @{Task_Manager#TASK_MANAGER} class, extends @{Fsm#FSM} +-- === +-- The @{Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. +-- Reportings can be done in several manners, and it is up to the derived classes if TASK_MANAGER to model the reporting behaviour. +-- +-- 1.1) TASK_MANAGER constructor: +-- ----------------------------------- +-- * @{Task_Manager#TASK_MANAGER.New}(): Create a new TASK_MANAGER instance. +-- +-- 1.2) TASK_MANAGER reporting: +-- --------------------------------- +-- Derived TASK_MANAGER classes will manage tasks using the method @{Task_Manager#TASK_MANAGER.ManageTasks}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the task management can be changed using the methods @{Task_Manager#TASK_MANAGER.SetRefreshTimeInterval}(). +-- To control how long a reporting message is displayed, use @{Task_Manager#TASK_MANAGER.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Task_Manager#TASK_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Task management can be started and stopped using the methods @{Task_Manager#TASK_MANAGER.StartTasks}() and @{Task_Manager#TASK_MANAGER.StopTasks}() respectively. +-- If an ad-hoc report is requested, use the method @{Task_Manager#TASK_MANAGER#ManageTasks}(). +-- +-- The default task management interval is every 60 seconds. +-- +-- === +-- +-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing +-- ### Author: FlightControl - Framework Design & Programming +-- +-- @module Task_Manager + +do -- TASK_MANAGER + + --- TASK_MANAGER class. + -- @type TASK_MANAGER + -- @field Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @extends Core.Fsm#FSM + TASK_MANAGER = { + ClassName = "TASK_MANAGER", + SetGroup = nil, + } + + --- TASK\_MANAGER constructor. + -- @param #TASK_MANAGER self + -- @param Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @return #TASK_MANAGER self + function TASK_MANAGER:New( SetGroup ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM:New() ) -- #TASK_MANAGER + + self.SetGroup = SetGroup + + self:SetStartState( "Stopped" ) + self:AddTransition( "Stopped", "StartTasks", "Started" ) + + --- StartTasks Handler OnBefore for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnBeforeStartTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- StartTasks Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterStartTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- StartTasks Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] StartTasks + -- @param #TASK_MANAGER self + + --- StartTasks Asynchronous Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] __StartTasks + -- @param #TASK_MANAGER self + -- @param #number Delay + + + + self:AddTransition( "Started", "StopTasks", "Stopped" ) + + --- StopTasks Handler OnBefore for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnBeforeStopTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- StopTasks Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterStopTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- StopTasks Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] StopTasks + -- @param #TASK_MANAGER self + + --- StopTasks Asynchronous Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] __StopTasks + -- @param #TASK_MANAGER self + -- @param #number Delay + + + self:AddTransition( "Started", "Manage", "Started" ) + + self:SetRefreshTimeInterval( 30 ) + + return self + end + + function TASK_MANAGER:onafterStartTasks( From, Event, To ) + self:Report() + end + + function TASK_MANAGER:onafterManage( From, Event, To ) + + self:__Manage( -self._RefreshTimeInterval ) + + self:ManageTasks() + end + + --- Set the refresh time interval in seconds when a new task management action needs to be done. + -- @param #TASK_MANAGER self + -- @param #number RefreshTimeInterval The refresh time interval in seconds when a new task management action needs to be done. + -- @return #TASK_MANAGER self + function TASK_MANAGER:SetRefreshTimeInterval( RefreshTimeInterval ) + self:F2() + + self._RefreshTimeInterval = RefreshTimeInterval + end + + + --- Manages the tasks for the @{Set#SET_GROUP}. + -- @param #TASK_MANAGER self + -- @return #TASK_MANAGER self + function TASK_MANAGER:ManageTasks() + self:E() + + end + +end + diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index ebc56985c..d1328835d 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -76,12 +76,16 @@ Tasking/CommandCenter.lua Tasking/Mission.lua Tasking/Task.lua Tasking/TaskInfo.lua +Tasking/Task_Manager.lua Tasking/DetectionManager.lua Tasking/Task_A2G_Dispatcher.lua Tasking/Task_A2G.lua Tasking/Task_A2A_Dispatcher.lua Tasking/Task_A2A.lua Tasking/Task_Cargo.lua +Tasking/Task_Cargo_Transport.lua +Tasking/Task_Cargo_CSAR.lua +Tasking/Task_Cargo_Dispatcher.lua Tasking/TaskZoneCapture.lua Moose.lua From a4d3089fdb6e204d9fd4a49d91dd852835854c88 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 31 Mar 2018 09:10:11 +0200 Subject: [PATCH 021/170] Updates Csar --- Moose Development/Moose/Cargo/Cargo.lua | 11 ++++ .../Moose/Tasking/Task_CARGO.lua | 5 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 54 ++++++++++++++++--- .../Moose/Tasking/Task_Manager.lua | 2 +- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index e6b3bde6e..07ee37a6d 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -277,6 +277,17 @@ do -- CARGO return self end + + --- Find a CARGO in the _DATABASE. + -- @param #CARGO self + -- @param #string CargoName The Cargo Name. + -- @return #CARGO self + function CARGO:FindByName( CargoName ) + + local CargoFound = _DATABASE:FindCargo( CargoName ) + return CargoFound + end + --- Destroy the cargo. -- @param #CARGO self function CARGO:Destroy() diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index c9127d3fe..d59473047 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -727,10 +727,11 @@ do -- TASK_CARGO --- @param #TASK_CARGO self -- @param #list DeployZones + -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK_CARGO - function TASK_CARGO:SetDeployZones( DeployZones ) + function TASK_CARGO:SetDeployZones( DeployZones, TaskUnit ) - for DeployZoneID, DeployZone in pairs( DeployZones ) do + for DeployZoneID, DeployZone in pairs( DeployZones or {} ) do self.DeployZones[DeployZone:GetName()] = DeployZone end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 3b22c9e01..7e07deb90 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -205,7 +205,7 @@ do -- TASK_CARGO_DISPATCHER -- @param #string PlayerName self:SetCSARRadius() - self:__Start( 5 ) + self:__StartTasks( 5 ) -- For CSAR missions, we process the event when a pilot ejects. @@ -221,14 +221,52 @@ do -- TASK_CARGO_DISPATCHER function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) self:E( { EventData = EventData } ) - - local PilotUnit = EventData.IniUnit + + local PlaneUnit = EventData.IniUnit local CSARName = EventData.IniUnitName - self.CSAR[CSARName] = {} - self.CSAR[CSARName].PilotUnit = PilotUnit - self.CSAR[CSARName].Task = nil + local PilotUnit = nil + + self:ScheduleOnce( 1, + function() + + -- Search for the ejected pilot + + local PlaneCoord = PlaneUnit:GetCoordinate() + + local SphereSearch = { + id = world.VolumeType.SPHERE, + params = { + point = PlaneCoord:GetVec3(), + radius = 100, + } + + } + + --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit + -- @param Wrapper.Group#GROUP ReportGroup + -- @param Set#SET_GROUP ReportSetGroup + local FindEjectedPilot = function( FoundDCSUnit ) + + local UnitName = FoundDCSUnit:getName() + + self:E( { "Units near Plane:", UnitName } ) + + PilotUnit = UNIT:Register( UnitName ) + + return true + end + + world.searchObjects( { Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY, Object.Category.WEAPON }, SphereSearch, FindEjectedPilot ) + + self.CSAR[CSARName] = {} + self.CSAR[CSARName].PilotUnit = PlaneUnit + self.CSAR[CSARName].Task = nil + end + ) + + return self end @@ -247,7 +285,7 @@ do -- TASK_CARGO_DISPATCHER -- function TASK_CARGO_DISPATCHER:SetCSARRadius( CSARRadius ) - self.Detection:SetFriendliesRange( CSARRadius or 50000 ) + self.CSARRadius = CSARRadius or 50000 return self end @@ -336,7 +374,7 @@ do -- TASK_CARGO_DISPATCHER -- New CSAR Task local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, "Rescue Pilot", SetCargo ) - CSARTask:SetDeployZones( { self.CSARDeployZones } ) + CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) TaskReport:Add( CSARTask:GetName() ) end diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index 2bf10fea6..340fd8233 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -117,7 +117,7 @@ do -- TASK_MANAGER end function TASK_MANAGER:onafterStartTasks( From, Event, To ) - self:Report() + self:Manage() end function TASK_MANAGER:onafterManage( From, Event, To ) From d0925ddfc189bbab0944df2b359a476de90b5787 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 2 Apr 2018 09:29:51 +0200 Subject: [PATCH 022/170] Progress --- Moose Development/Moose/Core/Spawn.lua | 249 ++++++++++++++++-- .../Moose/Tasking/Task_Cargo_CSAR.lua | 2 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 71 +++-- 3 files changed, 251 insertions(+), 71 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 5342a6e92..1e4640a62 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -288,20 +288,20 @@ function SPAWN:New( SpawnTemplatePrefix ) self.SpawnIndex = 0 self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnInitLimit = false -- By default, no InitLimit - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - self.AIOnOff = true -- The AI is on by default when spawning a group. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false - self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. - self.DelayOnOff = false -- No intial delay when spawning the first group. - self.Grouping = nil -- No grouping + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil -- No grouping self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -334,19 +334,19 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) self.SpawnIndex = 0 self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnInitLimit = false -- By default, no InitLimit - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - self.AIOnOff = true -- The AI is on by default when spawning a group. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false - self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. - self.DelayOnOff = false -- No intial delay when spawning the first group. + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. self.Grouping = nil self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. @@ -361,6 +361,55 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) end +--- Creates a new SPAWN instance to create new groups based on the provided template. +-- @param #SPAWN self +-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure! +-- @param #string SpawnTemplatePrefix is the name of the Group that will be given at each spawn. +-- @param #string SpawnAliasPrefix (optional) is the name that will be given to the Group at runtime. +-- @return #SPAWN +-- @usage +-- -- Create a new SPAWN object based on a Group Template defined from scratch. +-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' ) +-- @usage +-- -- Create a new CSAR_Spawn object based on a normal Group Template to spawn a soldier. +-- local CSAR_Spawn = SPAWN:NewWithFromTemplate( Template, "CSAR", "Pilot" ) +function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } ) + + if SpawnTemplate then + self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! + self.SpawnTemplatePrefix = SpawnTemplatePrefix + self.SpawnAliasPrefix = SpawnAliasPrefix + self.SpawnIndex = 0 + self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. + self.AliveUnits = 0 -- Contains the counter how many units are currently alive + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit. + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. + self.SpawnUnControlled = false + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil + + self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. + else + error( "There is no template provided for SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) + end + + self:SetEventPriority( 5 ) + self.SpawnHookScheduler = SCHEDULER:New( nil ) + + return self +end + + --- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned. -- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units. -- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used... @@ -404,6 +453,57 @@ function SPAWN:InitKeepUnitNames() return self end +--- Defines the Heading for the new spawned units. +-- The heading can be given as one fixed degree, or can be randomized between minimum and maximum degrees. +-- @param #SPAWN self +-- @param #number HeadingMin The minimum or fixed heading in degrees. +-- @param #number HeadingMax (optional) The maximum heading in degrees. This there is no maximum heading, then the heading will be fixed for all units using minimum heading. +-- @return #SPAWN self +-- @usage +-- +-- Spawn = SPAWN:New( ... ) +-- +-- -- Spawn the units pointing to 100 degrees. +-- Spawn:InitHeading( 100 ) +-- +-- -- Spawn the units pointing between 100 and 150 degrees. +-- Spawn:InitHeading( 100, 150 ) +-- +function SPAWN:InitHeading( HeadingMin, HeadingMax ) + self:F( ) + + self.SpawnInitHeadingMin = HeadingMin + self.SpawnInitHeadingMax = HeadingMax + + return self +end + + +function SPAWN:InitCoalition( Coalition ) + self:F( ) + + self.SpawnInitCoalition = Coalition + + return self +end + + +function SPAWN:InitCountry( Country ) + self:F( ) + + self.SpawnInitCountry = Country + + return self +end + + +function SPAWN:InitCategory( Category ) + self:F( ) + + self.SpawnInitCategory = Category + + return self +end --- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups. -- @param #SPAWN self @@ -941,6 +1041,18 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) end end + -- If Heading is given, point all the units towards the given Heading. + if self.SpawnInitHeadingMin then + for UnitID = 1, #SpawnTemplate.units do + SpawnTemplate.units[UnitID].heading = self.SpawnInitHeadingMax and math.random( self.SpawnInitHeadingMin, self.SpawnInitHeadingMax ) or self.SpawnInitHeadingMin + end + end + + SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID + SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID + SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID + + if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then if SpawnTemplate.route.points[1].type == "TakeOffParking" then SpawnTemplate.uncontrolled = self.SpawnUnControlled @@ -1247,14 +1359,20 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } ) - local TemplateHeight = SpawnTemplate.route.points[1].alt + local TemplateHeight = SpawnTemplate.route and SpawnTemplate.route.points[1].alt or nil + + SpawnTemplate.route = SpawnTemplate.route or {} + SpawnTemplate.route.points = SpawnTemplate.route.points or {} + SpawnTemplate.route.points[1] = SpawnTemplate.route.points[1] or {} + SpawnTemplate.route.points[1].x = SpawnTemplate.route.points[1].x or 0 + SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y or 0 -- Translate the position of the Group Template to the Vec3. for UnitID = 1, #SpawnTemplate.units do - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + --self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) local UnitTemplate = SpawnTemplate.units[UnitID] - local SX = UnitTemplate.x - local SY = UnitTemplate.y + local SX = UnitTemplate.x or 0 + local SY = UnitTemplate.y or 0 local BX = SpawnTemplate.route.points[1].x local BY = SpawnTemplate.route.points[1].y local TX = Vec3.x + ( SX - BX ) @@ -1266,7 +1384,6 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) end self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) end - SpawnTemplate.route.points[1].x = Vec3.x SpawnTemplate.route.points[1].y = Vec3.z if SpawnTemplate.CategoryID ~= Group.Category.SHIP then @@ -1283,6 +1400,47 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) return nil end + +--- Will spawn a group from a Coordinate in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + return self:SpawnFromVec3( Coordinate:GetVec3(), SpawnIndex ) +end + + + +--- Will spawn a group from a PointVec3 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +-- @usage +-- +-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground. +-- +-- -- Spawn at the zone center position at 2000 meters from the ground! +-- SpawnAirplanes:SpawnFromPointVec3( SpawnPointVec3 ) +-- +function SPAWN:SpawnFromPointVec3( PointVec3, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + return self:SpawnFromVec3( PointVec3:GetVec3(), SpawnIndex ) +end + + --- Will spawn a group from a Vec2 in 3D space. -- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. @@ -1317,6 +1475,35 @@ function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex ) end +--- Will spawn a group from a POINT_VEC2 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 coordinates where to spawn the group. +-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone. +-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +-- @usage +-- +-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2() +-- +-- -- Spawn at the zone center position at the height specified in the ME of the group template! +-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2 ) +-- +-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters. +-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2, 2000, 4000 ) +-- +function SPAWN:SpawnFromPointVec2( PointVec2, MinHeight, MaxHeight, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) + + return self:SpawnFromVec2( PointVec2:GetVec2(), MinHeight, MaxHeight, SpawnIndex ) +end + + + --- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. -- You can use the returned group to further define the route to be followed. @@ -1715,7 +1902,11 @@ end function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + if not self.SpawnTemplate then + self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + end + + local SpawnTemplate = self.SpawnTemplate SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) SpawnTemplate.groupId = nil diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index b45dc7e26..b2e2aebdb 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -23,7 +23,7 @@ do -- TASK_CARGO_CSAR -- @param #string TaskBriefing The Cargo Task briefing. -- @return #TASK_CARGO_CSAR self function TASK_CARGO_CSAR:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) - local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_CSAR + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "CSAR", TaskBriefing ) ) -- #TASK_CARGO_CSAR self:F() Mission:AddTask( self ) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 7e07deb90..3832d4a7a 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -210,6 +210,26 @@ do -- TASK_CARGO_DISPATCHER -- For CSAR missions, we process the event when a pilot ejects. self:HandleEvent( EVENTS.Ejection ) + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["taskSelected"] = true, + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["type"] = "Soldier M4", + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + }, -- end of [1] + }, -- end of ["units"] + ["task"] = "Ground Nothing", + } + + self.PilotSpawn = SPAWN:NewFromTemplate( Template, "CSAR Pilot" ) return self end @@ -225,47 +245,16 @@ do -- TASK_CARGO_DISPATCHER local PlaneUnit = EventData.IniUnit local CSARName = EventData.IniUnitName - local PilotUnit = nil - - self:ScheduleOnce( 1, - function() - - -- Search for the ejected pilot - - local PlaneCoord = PlaneUnit:GetCoordinate() - - local SphereSearch = { - id = world.VolumeType.SPHERE, - params = { - point = PlaneCoord:GetVec3(), - radius = 100, - } - - } - - --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit - -- @param Wrapper.Group#GROUP ReportGroup - -- @param Set#SET_GROUP ReportSetGroup - local FindEjectedPilot = function( FoundDCSUnit ) - - local UnitName = FoundDCSUnit:getName() - - self:E( { "Units near Plane:", UnitName } ) - - PilotUnit = UNIT:Register( UnitName ) - - return true - end - - world.searchObjects( { Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY, Object.Category.WEAPON }, SphereSearch, FindEjectedPilot ) + local PointVec2Spawn = EventData.IniUnit:GetPointVec2() - self.CSAR[CSARName] = {} - self.CSAR[CSARName].PilotUnit = PlaneUnit - self.CSAR[CSARName].Task = nil - - end - ) - + self.PilotSpawn:InitHeading( EventData.IniUnit:GetHeading() ) -- This will ensure that the new pilot will point towards the same heading as the plane. + self.PilotSpawn:InitCategory( Group.Category.GROUND ) + self.PilotSpawn:InitCountry( EventData.IniUnit:GetCountry() ) + self.PilotSpawn:InitCoalition( EventData.IniUnit:GetCoalition() ) + + self.CSAR[#self.CSAR+1] = {} + self.CSAR[#self.CSAR].PilotUnit = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) + self.CSAR[#self.CSAR].Task = nil return self end @@ -373,7 +362,7 @@ do -- TASK_CARGO_DISPATCHER else -- New CSAR Task local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) - local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, "Rescue Pilot", SetCargo ) + local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) TaskReport:Add( CSARTask:GetName() ) From 25831db0571e07aefef31f30fed07b12f9bb0962 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 2 Apr 2018 19:33:44 +0200 Subject: [PATCH 023/170] Progress -- Still need to fix an issue with some strang objects appearing and a crash. --- Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 3832d4a7a..5795b947b 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -253,7 +253,7 @@ do -- TASK_CARGO_DISPATCHER self.PilotSpawn:InitCoalition( EventData.IniUnit:GetCoalition() ) self.CSAR[#self.CSAR+1] = {} - self.CSAR[#self.CSAR].PilotUnit = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) + self.CSAR[#self.CSAR].PilotGroup = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) self.CSAR[#self.CSAR].Task = nil return self @@ -310,7 +310,7 @@ do -- TASK_CARGO_DISPATCHER -- @return #nil If there is no CSAR task required. function TASK_CARGO_DISPATCHER:EvaluateCSAR( CSARUnit ) - local CSARCargo = CARGO_UNIT:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) + local CSARCargo = CARGO_GROUP:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) local SetCargo = SET_CARGO:New() SetCargo:AddCargosByName( CSARUnit:GetName() ) @@ -361,7 +361,8 @@ do -- TASK_CARGO_DISPATCHER if CSARData.Task then else -- New CSAR Task - local SetCargo = self:EvaluateCSAR( CSARData.PilotUnit ) + self:F( { PilotGroup = CSARData.PilotGroup } ) + local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) From ec973fcc76944a5c012aee5a98349f8edb02b757 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 3 Apr 2018 07:43:55 +0200 Subject: [PATCH 024/170] Working CSAR ... huray --- .../Moose/Dcs/DCSCoalitionObject.lua | 2 +- Moose Development/Moose/Dcs/DCScoalition.lua | 2 + .../Moose/Tasking/CommandCenter.lua | 8 ++ Moose Development/Moose/Tasking/Mission.lua | 4 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 74 +++++++++++-------- Moose Development/Moose/Wrapper/Group.lua | 2 +- 6 files changed, 58 insertions(+), 34 deletions(-) diff --git a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua index be7dc106b..119c9a807 100644 --- a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua +++ b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua @@ -4,7 +4,7 @@ --- @type CoalitionObject -- @extends Dcs.DCSWrapper.Object#Object -coalition = {} --#coalition + --- Returns coalition of the object. -- @function [parent=#CoalitionObject] getCoalition diff --git a/Moose Development/Moose/Dcs/DCScoalition.lua b/Moose Development/Moose/Dcs/DCScoalition.lua index 4ec5f6f10..e51508a3e 100644 --- a/Moose Development/Moose/Dcs/DCScoalition.lua +++ b/Moose Development/Moose/Dcs/DCScoalition.lua @@ -12,3 +12,5 @@ --- @function [parent=#coalition] getCountryCoalition -- @param #number countryId -- @return #number coalitionId + +coalition = coalition -- #coalition diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index e8e4f1d32..e521f63df 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -220,6 +220,14 @@ function COMMANDCENTER:GetShortText() end +--- Gets the coalition of the command center. +-- @param #COMMANDCENTER self +-- @return DCScoalition#coalition +function COMMANDCENTER:GetCoalition() + + return self.CommandCenterCoalition +end + --- Gets the POSITIONABLE of the HQ command center. -- @param #COMMANDCENTER self diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 06a7e7d9b..441b463aa 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -29,7 +29,7 @@ MISSION = { -- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. -- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. -- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. --- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... +-- @param #string MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... -- @return #MISSION self function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) @@ -265,6 +265,8 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi end + + --- FSM function for a MISSION -- @param #MISSION self -- @param #string From diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 5795b947b..df9c36dec 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -177,6 +177,7 @@ do -- TASK_CARGO_DISPATCHER Mission = nil, Tasks = {}, CSAR = {}, + CSARSpawned = 0, } @@ -210,26 +211,6 @@ do -- TASK_CARGO_DISPATCHER -- For CSAR missions, we process the event when a pilot ejects. self:HandleEvent( EVENTS.Ejection ) - - -- Create the CSAR Pilot SPAWN object. - -- Let us create the Template for the replacement Pilot :-) - local Template = { - ["visible"] = false, - ["taskSelected"] = true, - ["hidden"] = false, - ["units"] = - { - [1] = - { - ["type"] = "Soldier M4", - ["skill"] = "Excellent", - ["playerCanDrive"] = false, - }, -- end of [1] - }, -- end of ["units"] - ["task"] = "Ground Nothing", - } - - self.PilotSpawn = SPAWN:NewFromTemplate( Template, "CSAR Pilot" ) return self end @@ -242,19 +223,50 @@ do -- TASK_CARGO_DISPATCHER self:E( { EventData = EventData } ) + self.CSARSpawned = self.CSARSpawned + 1 + local PlaneUnit = EventData.IniUnit local CSARName = EventData.IniUnitName - local PointVec2Spawn = EventData.IniUnit:GetPointVec2() + local CargoPointVec2 = EventData.IniUnit:GetPointVec2() + local CargoCoalition = EventData.IniUnit:GetCoalition() + local CargoCountry = EventData.IniUnit:GetCountry() + + -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. - self.PilotSpawn:InitHeading( EventData.IniUnit:GetHeading() ) -- This will ensure that the new pilot will point towards the same heading as the plane. - self.PilotSpawn:InitCategory( Group.Category.GROUND ) - self.PilotSpawn:InitCountry( EventData.IniUnit:GetCountry() ) - self.PilotSpawn:InitCoalition( EventData.IniUnit:GetCoalition() ) - - self.CSAR[#self.CSAR+1] = {} - self.CSAR[#self.CSAR].PilotGroup = self.PilotSpawn:SpawnFromPointVec2( PointVec2Spawn ) - self.CSAR[#self.CSAR].Task = nil + if CargoCoalition == self.Mission:GetCommandCenter():GetCoalition() then + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["hidden"] = false, + ["task"] = "Ground Nothing", + ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), + ["x"] = CargoPointVec2:GetLat(), + ["y"] = CargoPointVec2:GetLon(), + ["units"] = + { + [1] = + { + ["type"] = ( CargoCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", + ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + ["x"] = CargoPointVec2:GetLat(), + ["y"] = CargoPointVec2:GetLon(), + ["heading"] = EventData.IniUnit:GetHeading(), + }, -- end of [1] + }, -- end of ["units"] + } + + local CargoGroup = GROUP:NewTemplate( Template, CargoCoalition, Group.Category.GROUND, CargoCountry ) + + self.CSAR[#self.CSAR+1] = {} + self.CSAR[#self.CSAR].PilotGroup = CargoGroup + self.CSAR[#self.CSAR].Task = nil + + end return self end @@ -294,7 +306,7 @@ do -- TASK_CARGO_DISPATCHER --- Define the deploy zones for the CSAR tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param DeployZones A list of the deploy zones. + -- @param CSARDeployZones A list of the deploy zones. -- @return #TASK_CARGO_DISPATCHER function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) @@ -361,12 +373,12 @@ do -- TASK_CARGO_DISPATCHER if CSARData.Task then else -- New CSAR Task - self:F( { PilotGroup = CSARData.PilotGroup } ) local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) CSARTask:SetDeployZones( self.CSARDeployZones or {} ) Mission:AddTask( CSARTask ) TaskReport:Add( CSARTask:GetName() ) + CSARData.Task = CSARTask end end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 66d9068a3..26062ea09 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -121,7 +121,7 @@ GROUPTEMPLATE.Takeoff = { -- @return #GROUP self function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID ) local GroupName = GroupTemplate.name - _DATABASE:_RegisterGroupTemplate( GroupTemplate, CategoryID, CountryID, CoalitionSide, GroupName ) + _DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName ) self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self:F2( GroupName ) self.GroupName = GroupName From 1f578d4ab5d169cf74dce2390986e52885a0f61c Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 3 Apr 2018 07:45:26 +0200 Subject: [PATCH 025/170] Working CSAR ... huray --- Moose Development/Moose/Cargo/Cargo.lua | 11 + Moose Development/Moose/Core/Spawn.lua | 249 +++++++++-- .../Moose/Dcs/DCSCoalitionObject.lua | 2 +- Moose Development/Moose/Dcs/DCScoalition.lua | 2 + .../Moose/Tasking/CommandCenter.lua | 8 + Moose Development/Moose/Tasking/Mission.lua | 4 +- .../Moose/Tasking/Task_CARGO.lua | 4 +- .../Moose/Tasking/Task_Cargo_CSAR.lua | 187 ++++++++ .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 402 ++++++++++++++++++ .../Moose/Tasking/Task_Cargo_Transport.lua | 187 ++++++++ .../Moose/Tasking/Task_Manager.lua | 150 +++++++ Moose Development/Moose/Wrapper/Group.lua | 2 +- Moose Setup/Moose.files | 4 + 13 files changed, 1178 insertions(+), 34 deletions(-) create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua create mode 100644 Moose Development/Moose/Tasking/Task_Cargo_Transport.lua create mode 100644 Moose Development/Moose/Tasking/Task_Manager.lua diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index e6b3bde6e..07ee37a6d 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -277,6 +277,17 @@ do -- CARGO return self end + + --- Find a CARGO in the _DATABASE. + -- @param #CARGO self + -- @param #string CargoName The Cargo Name. + -- @return #CARGO self + function CARGO:FindByName( CargoName ) + + local CargoFound = _DATABASE:FindCargo( CargoName ) + return CargoFound + end + --- Destroy the cargo. -- @param #CARGO self function CARGO:Destroy() diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 5342a6e92..1e4640a62 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -288,20 +288,20 @@ function SPAWN:New( SpawnTemplatePrefix ) self.SpawnIndex = 0 self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnInitLimit = false -- By default, no InitLimit - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - self.AIOnOff = true -- The AI is on by default when spawning a group. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false - self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. - self.DelayOnOff = false -- No intial delay when spawning the first group. - self.Grouping = nil -- No grouping + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil -- No grouping self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -334,19 +334,19 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) self.SpawnIndex = 0 self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnInitLimit = false -- By default, no InitLimit - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - self.AIOnOff = true -- The AI is on by default when spawning a group. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false - self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. - self.DelayOnOff = false -- No intial delay when spawning the first group. + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. self.Grouping = nil self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. @@ -361,6 +361,55 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) end +--- Creates a new SPAWN instance to create new groups based on the provided template. +-- @param #SPAWN self +-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure! +-- @param #string SpawnTemplatePrefix is the name of the Group that will be given at each spawn. +-- @param #string SpawnAliasPrefix (optional) is the name that will be given to the Group at runtime. +-- @return #SPAWN +-- @usage +-- -- Create a new SPAWN object based on a Group Template defined from scratch. +-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' ) +-- @usage +-- -- Create a new CSAR_Spawn object based on a normal Group Template to spawn a soldier. +-- local CSAR_Spawn = SPAWN:NewWithFromTemplate( Template, "CSAR", "Pilot" ) +function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } ) + + if SpawnTemplate then + self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! + self.SpawnTemplatePrefix = SpawnTemplatePrefix + self.SpawnAliasPrefix = SpawnAliasPrefix + self.SpawnIndex = 0 + self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. + self.AliveUnits = 0 -- Contains the counter how many units are currently alive + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit. + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. + self.SpawnUnControlled = false + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil + + self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. + else + error( "There is no template provided for SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) + end + + self:SetEventPriority( 5 ) + self.SpawnHookScheduler = SCHEDULER:New( nil ) + + return self +end + + --- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned. -- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units. -- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used... @@ -404,6 +453,57 @@ function SPAWN:InitKeepUnitNames() return self end +--- Defines the Heading for the new spawned units. +-- The heading can be given as one fixed degree, or can be randomized between minimum and maximum degrees. +-- @param #SPAWN self +-- @param #number HeadingMin The minimum or fixed heading in degrees. +-- @param #number HeadingMax (optional) The maximum heading in degrees. This there is no maximum heading, then the heading will be fixed for all units using minimum heading. +-- @return #SPAWN self +-- @usage +-- +-- Spawn = SPAWN:New( ... ) +-- +-- -- Spawn the units pointing to 100 degrees. +-- Spawn:InitHeading( 100 ) +-- +-- -- Spawn the units pointing between 100 and 150 degrees. +-- Spawn:InitHeading( 100, 150 ) +-- +function SPAWN:InitHeading( HeadingMin, HeadingMax ) + self:F( ) + + self.SpawnInitHeadingMin = HeadingMin + self.SpawnInitHeadingMax = HeadingMax + + return self +end + + +function SPAWN:InitCoalition( Coalition ) + self:F( ) + + self.SpawnInitCoalition = Coalition + + return self +end + + +function SPAWN:InitCountry( Country ) + self:F( ) + + self.SpawnInitCountry = Country + + return self +end + + +function SPAWN:InitCategory( Category ) + self:F( ) + + self.SpawnInitCategory = Category + + return self +end --- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups. -- @param #SPAWN self @@ -941,6 +1041,18 @@ function SPAWN:SpawnWithIndex( SpawnIndex ) end end + -- If Heading is given, point all the units towards the given Heading. + if self.SpawnInitHeadingMin then + for UnitID = 1, #SpawnTemplate.units do + SpawnTemplate.units[UnitID].heading = self.SpawnInitHeadingMax and math.random( self.SpawnInitHeadingMin, self.SpawnInitHeadingMax ) or self.SpawnInitHeadingMin + end + end + + SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID + SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID + SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID + + if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then if SpawnTemplate.route.points[1].type == "TakeOffParking" then SpawnTemplate.uncontrolled = self.SpawnUnControlled @@ -1247,14 +1359,20 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } ) - local TemplateHeight = SpawnTemplate.route.points[1].alt + local TemplateHeight = SpawnTemplate.route and SpawnTemplate.route.points[1].alt or nil + + SpawnTemplate.route = SpawnTemplate.route or {} + SpawnTemplate.route.points = SpawnTemplate.route.points or {} + SpawnTemplate.route.points[1] = SpawnTemplate.route.points[1] or {} + SpawnTemplate.route.points[1].x = SpawnTemplate.route.points[1].x or 0 + SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y or 0 -- Translate the position of the Group Template to the Vec3. for UnitID = 1, #SpawnTemplate.units do - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + --self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) local UnitTemplate = SpawnTemplate.units[UnitID] - local SX = UnitTemplate.x - local SY = UnitTemplate.y + local SX = UnitTemplate.x or 0 + local SY = UnitTemplate.y or 0 local BX = SpawnTemplate.route.points[1].x local BY = SpawnTemplate.route.points[1].y local TX = Vec3.x + ( SX - BX ) @@ -1266,7 +1384,6 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) end self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) end - SpawnTemplate.route.points[1].x = Vec3.x SpawnTemplate.route.points[1].y = Vec3.z if SpawnTemplate.CategoryID ~= Group.Category.SHIP then @@ -1283,6 +1400,47 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) return nil end + +--- Will spawn a group from a Coordinate in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + return self:SpawnFromVec3( Coordinate:GetVec3(), SpawnIndex ) +end + + + +--- Will spawn a group from a PointVec3 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +-- @usage +-- +-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground. +-- +-- -- Spawn at the zone center position at 2000 meters from the ground! +-- SpawnAirplanes:SpawnFromPointVec3( SpawnPointVec3 ) +-- +function SPAWN:SpawnFromPointVec3( PointVec3, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + return self:SpawnFromVec3( PointVec3:GetVec3(), SpawnIndex ) +end + + --- Will spawn a group from a Vec2 in 3D space. -- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. @@ -1317,6 +1475,35 @@ function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex ) end +--- Will spawn a group from a POINT_VEC2 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 coordinates where to spawn the group. +-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone. +-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +-- @usage +-- +-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2() +-- +-- -- Spawn at the zone center position at the height specified in the ME of the group template! +-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2 ) +-- +-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters. +-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2, 2000, 4000 ) +-- +function SPAWN:SpawnFromPointVec2( PointVec2, MinHeight, MaxHeight, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) + + return self:SpawnFromVec2( PointVec2:GetVec2(), MinHeight, MaxHeight, SpawnIndex ) +end + + + --- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. -- You can use the returned group to further define the route to be followed. @@ -1715,7 +1902,11 @@ end function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + if not self.SpawnTemplate then + self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + end + + local SpawnTemplate = self.SpawnTemplate SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) SpawnTemplate.groupId = nil diff --git a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua index be7dc106b..119c9a807 100644 --- a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua +++ b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua @@ -4,7 +4,7 @@ --- @type CoalitionObject -- @extends Dcs.DCSWrapper.Object#Object -coalition = {} --#coalition + --- Returns coalition of the object. -- @function [parent=#CoalitionObject] getCoalition diff --git a/Moose Development/Moose/Dcs/DCScoalition.lua b/Moose Development/Moose/Dcs/DCScoalition.lua index 4ec5f6f10..e51508a3e 100644 --- a/Moose Development/Moose/Dcs/DCScoalition.lua +++ b/Moose Development/Moose/Dcs/DCScoalition.lua @@ -12,3 +12,5 @@ --- @function [parent=#coalition] getCountryCoalition -- @param #number countryId -- @return #number coalitionId + +coalition = coalition -- #coalition diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index e8e4f1d32..e521f63df 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -220,6 +220,14 @@ function COMMANDCENTER:GetShortText() end +--- Gets the coalition of the command center. +-- @param #COMMANDCENTER self +-- @return DCScoalition#coalition +function COMMANDCENTER:GetCoalition() + + return self.CommandCenterCoalition +end + --- Gets the POSITIONABLE of the HQ command center. -- @param #COMMANDCENTER self diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 06a7e7d9b..441b463aa 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -29,7 +29,7 @@ MISSION = { -- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. -- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. -- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. --- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... +-- @param #string MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... -- @return #MISSION self function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) @@ -265,6 +265,8 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi end + + --- FSM function for a MISSION -- @param #MISSION self -- @param #string From diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 7d11cae8d..d59473047 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -726,12 +726,12 @@ do -- TASK_CARGO end --- @param #TASK_CARGO self - -- @param @list DeployZones + -- @param #list DeployZones -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK_CARGO function TASK_CARGO:SetDeployZones( DeployZones, TaskUnit ) - for DeployZoneID, DeployZone in pairs( DeployZones ) do + for DeployZoneID, DeployZone in pairs( DeployZones or {} ) do self.DeployZones[DeployZone:GetName()] = DeployZone end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua new file mode 100644 index 000000000..b2e2aebdb --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -0,0 +1,187 @@ +--- **Tasking** -- Models tasks for players to execute CSAR @{Cargo} downed pilots. +-- +-- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) +-- +-- === + + +do -- TASK_CARGO_CSAR + + --- The TASK_CARGO_CSAR class + -- @type TASK_CARGO_CSAR + -- @extends Tasking.Task_Cargo#TASK_CARGO + TASK_CARGO_CSAR = { + ClassName = "TASK_CARGO_CSAR", + } + + --- Instantiates a new TASK_CARGO_CSAR. + -- @param #TASK_CARGO_CSAR self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. + -- @param #string TaskBriefing The Cargo Task briefing. + -- @return #TASK_CARGO_CSAR self + function TASK_CARGO_CSAR:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "CSAR", TaskBriefing ) ) -- #TASK_CARGO_CSAR + self:F() + + Mission:AddTask( self ) + + + -- Events + + self:AddTransition( "*", "CargoPickedUp", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) + + self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + + --- OnBefore Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] OnBeforeCargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] OnAfterCargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Synchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] CargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Asynchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_CSAR] __CargoPickedUp + -- @param #TASK_CARGO_CSAR self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- OnBefore Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] OnBeforeCargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] OnAfterCargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Synchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] CargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Asynchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_CSAR] __CargoDeployed + -- @param #TASK_CARGO_CSAR self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + local Fsm = self:GetUnitProcess() + + local CargoReport = REPORT:New( "Rescue a downed pilot from the following position:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + + + return self + end + + function TASK_CARGO_CSAR:ReportOrder( ReportGroup ) + + return 0 + end + + + --- + -- @param #TASK_CARGO_CSAR self + -- @return #boolean + function TASK_CARGO_CSAR:IsAllCargoTransported() + + local CargoSet = self:GetCargoSet() + local Set = CargoSet:GetSet() + + local DeployZones = self:GetDeployZones() + + local CargoDeployed = true + + -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). + for CargoID, CargoData in pairs( Set ) do + local Cargo = CargoData -- Core.Cargo#CARGO + + self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) + + if Cargo:IsDeployed() then + +-- -- Loop the DeployZones set for the TASK_CARGO_CSAR. +-- for DeployZoneID, DeployZone in pairs( DeployZones ) do +-- +-- -- If all cargo is in one of the deploy zones, then all is good. +-- self:T( { Cargo.CargoObject } ) +-- if Cargo:IsInZone( DeployZone ) == false then +-- CargoDeployed = false +-- end +-- end + else + CargoDeployed = false + end + end + + self:F( { CargoDeployed = CargoDeployed } ) + + return CargoDeployed + end + + --- @param #TASK_CARGO_CSAR self + function TASK_CARGO_CSAR:onafterGoal( TaskUnit, From, Event, To ) + local CargoSet = self.CargoSet + + if self:IsAllCargoTransported() then + self:Success() + end + + self:__Goal( -10 ) + end + +end + diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua new file mode 100644 index 000000000..df9c36dec --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -0,0 +1,402 @@ +--- **Tasking** - Creates and manages player TASK_CARGO tasks. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- ### Contributions: +-- +-- === +-- +-- @module Task_Cargo_Dispatcher + +do -- TASK_CARGO_DISPATCHER + + --- TASK_CARGO_DISPATCHER class. + -- @type TASK_CARGO_DISPATCHER + -- @extends Tasking.Task_Manager#TASK_MANAGER + -- @field TASK_CARGO_DISPATCHER.CSAR CSAR + + --- @type TASK_CARGO_DISPATCHER.CSAR + -- @field Wrapper.Unit#UNIT PilotUnit + -- @field Tasking.Task#TASK Task + + + --- # TASK_CARGO_DISPATCHER class, extends @{Task_Manager#TASK_MANAGER} + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia1.JPG) + -- + -- The @{#TASK_CARGO_DISPATCHER} class implements the dynamic dispatching of cargo tasks. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia3.JPG) + -- + -- The EWR will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched. + -- Find a summary below describing for which situation a task type is created: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia9.JPG) + -- + -- * **CSAR Task**: Is created when a fiendly pilot has ejected from a plane, and needs to be rescued (sometimes behind enemy lines). + -- + -- ## 1. TASK\_A2A\_DISPATCHER constructor: + -- + -- The @{#TASK_CARGO_DISPATCHER.New}() method creates a new TASK\_A2A\_DISPATCHER instance. + -- + -- ### 1.1. Define or set the **Mission**: + -- + -- Tasking is executed to accomplish missions. Therefore, a MISSION object needs to be given as the first parameter. + -- + -- local HQ = GROUP:FindByName( "HQ", "Bravo" ) + -- local CommandCenter = COMMANDCENTER:New( HQ, "Lima" ) + -- local Mission = MISSION:New( CommandCenter, "A2A Mission", "High", "Watch the air enemy units being detected.", coalition.side.RED ) + -- + -- Missions are governed by COMMANDCENTERS, so, ensure you have a COMMANDCENTER object installed and setup within your mission. + -- Create the MISSION object, and hook it under the command center. + -- + -- ### 1.2. Build a set of the groups seated by human players: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia6.JPG) + -- + -- A set or collection of the groups wherein human players can be seated, these can be clients or units that can be joined as a slot or jumping into. + -- + -- local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "Defender" ):FilterStart() + -- + -- The set is built using the SET_GROUP class. Apply any filter criteria to identify the correct groups for your mission. + -- Only these slots or units will be able to execute the mission and will receive tasks for this mission, once available. + -- + -- ### 1.3. Define the **EWR network**: + -- + -- As part of the TASK\_A2A\_DISPATCHER constructor, an EWR network must be given as the third parameter. + -- An EWR network, or, Early Warning Radar network, is used to early detect potential airborne targets and to understand the position of patrolling targets of the enemy. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia5.JPG) + -- + -- Typically EWR networks are setup using 55G6 EWR, 1L13 EWR, Hawk sr and Patriot str ground based radar units. + -- These radars have different ranges and 55G6 EWR and 1L13 EWR radars are Eastern Bloc units (eg Russia, Ukraine, Georgia) while the Hawk and Patriot radars are Western (eg US). + -- Additionally, ANY other radar capable unit can be part of the EWR network! Also AWACS airborne units, planes, helicopters can help to detect targets, as long as they have radar. + -- The position of these units is very important as they need to provide enough coverage + -- to pick up enemy aircraft as they approach so that CAP and GCI flights can be tasked to intercept them. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia7.JPG) + -- + -- Additionally in a hot war situation where the border is no longer respected the placement of radars has a big effect on how fast the war escalates. + -- For example if they are a long way forward and can detect enemy planes on the ground and taking off + -- they will start to vector CAP and GCI flights to attack them straight away which will immediately draw a response from the other coalition. + -- Having the radars further back will mean a slower escalation because fewer targets will be detected and + -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. + -- It all depends on what the desired effect is. + -- + -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. + -- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network, + -- increasing or decreasing the radar coverage of the Early Warning System. + -- + -- See the following example to setup an EWR network containing EWR stations and AWACS. + -- + -- local EWRSet = SET_GROUP:New():FilterPrefixes( "EWR" ):FilterCoalitions("red"):FilterStart() + -- + -- local EWRDetection = DETECTION_AREAS:New( EWRSet, 6000 ) + -- EWRDetection:SetFriendliesRange( 10000 ) + -- EWRDetection:SetRefreshTimeInterval(30) + -- + -- -- Setup the A2A dispatcher, and initialize it. + -- A2ADispatcher = TASK_CARGO_DISPATCHER:New( Mission, AttackGroups, EWRDetection ) + -- + -- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**. + -- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set. + -- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set. + -- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is choosen, which is 6km. + -- The **EWRDetection** object is then passed to the @{#TASK_CARGO_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism. + -- + -- ### 2. Define the detected **target grouping radius**: + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia8.JPG) + -- + -- The target grouping radius is a property of the Detection object, that was passed to the AI\_A2A\_DISPATCHER object, but can be changed. + -- The grouping radius should not be too small, but also depends on the types of planes and the era of the simulation. + -- Fast planes like in the 80s, need a larger radius than WWII planes. + -- Typically I suggest to use 30000 for new generation planes and 10000 for older era aircraft. + -- + -- Note that detected targets are constantly re-grouped, that is, when certain detected aircraft are moving further than the group radius, then these aircraft will become a separate + -- group being detected. This may result in additional GCI being started by the dispatcher! So don't make this value too small! + -- + -- ## 3. Set the **Engage radius**: + -- + -- Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission. + -- + -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia11.JPG) + -- + -- So, if there is a target area detected and reported, + -- then any friendlies that are airborne near this target area, + -- will be commanded to (re-)engage that target when available (if no other tasks were commanded). + -- For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, + -- will be considered to receive the command to engage that target area. + -- You need to evaluate the value of this parameter carefully. + -- If too small, more intercept missions may be triggered upon detected target areas. + -- If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far. + -- + -- ## 4. Set **Scoring** and **Messages**: + -- + -- The TASK\_A2A\_DISPATCHER is a state machine. It triggers the event Assign when a new player joins a @{Task} dispatched by the TASK\_A2A\_DISPATCHER. + -- An _event handler_ can be defined to catch the **Assign** event, and add **additional processing** to set _scoring_ and to _define messages_, + -- when the player reaches certain achievements in the task. + -- + -- The prototype to handle the **Assign** event needs to be developed as follows: + -- + -- TaskDispatcher = TASK_CARGO_DISPATCHER:New( ... ) + -- + -- --- @param #TaskDispatcher self + -- -- @param #string From Contains the name of the state from where the Event was triggered. + -- -- @param #string Event Contains the name of the event that was triggered. In this case Assign. + -- -- @param #string To Contains the name of the state that will be transitioned to. + -- -- @param Tasking.Task_A2A#TASK_A2A Task The Task object, which is any derived object from TASK_A2A. + -- -- @param Wrapper.Unit#UNIT TaskUnit The Unit or Client that contains the Player. + -- -- @param #string PlayerName The name of the Player that joined the TaskUnit. + -- function TaskDispatcher:OnAfterAssign( From, Event, To, Task, TaskUnit, PlayerName ) + -- Task:SetScoreOnProgress( PlayerName, 20, TaskUnit ) + -- Task:SetScoreOnSuccess( PlayerName, 200, TaskUnit ) + -- Task:SetScoreOnFail( PlayerName, -100, TaskUnit ) + -- end + -- + -- The **OnAfterAssign** method (function) is added to the TaskDispatcher object. + -- This method will be called when a new player joins a unit in the set of groups in scope of the dispatcher. + -- So, this method will be called only **ONCE** when a player joins a unit in scope of the task. + -- + -- The TASK class implements various methods to additional **set scoring** for player achievements: + -- + -- * @{Tasking.Task#TASK.SetScoreOnProgress}() will add additional scores when a player achieves **Progress** while executing the task. + -- Examples of **task progress** can be destroying units, arriving at zones etc. + -- + -- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional scores when the task goes into **Success** state. + -- This means the **task has been successfully completed**. + -- + -- * @{Tasking.Task#TASK.SetScoreOnSuccess}() will add additional (negative) scores when the task goes into **Failed** state. + -- This means the **task has not been successfully completed**, and the scores must be given with a negative value! + -- + -- @field #TASK_CARGO_DISPATCHER + TASK_CARGO_DISPATCHER = { + ClassName = "TASK_CARGO_DISPATCHER", + Mission = nil, + Tasks = {}, + CSAR = {}, + CSARSpawned = 0, + } + + + --- TASK_CARGO_DISPATCHER constructor. + -- @param #TASK_CARGO_DISPATCHER self + -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. + -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @return #TASK_CARGO_DISPATCHER self + function TASK_CARGO_DISPATCHER:New( Mission, SetGroup ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CARGO_DISPATCHER + + self.Mission = Mission + + self:AddTransition( "Started", "Assign", "Started" ) + + --- OnAfter Transition Handler for Event Assign. + -- @function [parent=#TASK_CARGO_DISPATCHER] OnAfterAssign + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Tasking.Task_A2A#TASK_A2A Task + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #string PlayerName + + self:SetCSARRadius() + self:__StartTasks( 5 ) + + -- For CSAR missions, we process the event when a pilot ejects. + + self:HandleEvent( EVENTS.Ejection ) + + return self + end + + + --- Handle the event when a pilot ejects. + -- @param #TASK_CARGO_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) + + self:E( { EventData = EventData } ) + + self.CSARSpawned = self.CSARSpawned + 1 + + local PlaneUnit = EventData.IniUnit + local CSARName = EventData.IniUnitName + + local CargoPointVec2 = EventData.IniUnit:GetPointVec2() + local CargoCoalition = EventData.IniUnit:GetCoalition() + local CargoCountry = EventData.IniUnit:GetCountry() + + -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. + + if CargoCoalition == self.Mission:GetCommandCenter():GetCoalition() then + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["hidden"] = false, + ["task"] = "Ground Nothing", + ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), + ["x"] = CargoPointVec2:GetLat(), + ["y"] = CargoPointVec2:GetLon(), + ["units"] = + { + [1] = + { + ["type"] = ( CargoCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", + ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + ["x"] = CargoPointVec2:GetLat(), + ["y"] = CargoPointVec2:GetLon(), + ["heading"] = EventData.IniUnit:GetHeading(), + }, -- end of [1] + }, -- end of ["units"] + } + + local CargoGroup = GROUP:NewTemplate( Template, CargoCoalition, Group.Category.GROUND, CargoCountry ) + + self.CSAR[#self.CSAR+1] = {} + self.CSAR[#self.CSAR].PilotGroup = CargoGroup + self.CSAR[#self.CSAR].Task = nil + + end + + return self + end + + + --- Define the radius to when a CSAR task will be generated for any downed pilot within range of the nearest CSAR airbase. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #number CSARRadius (Optional, Default = 50000) The radius in meters to decide whether a CSAR needs to be created. + -- @return #TASK_CARGO_DISPATCHER + -- @usage + -- + -- -- Set 20km as the radius to CSAR any downed pilot within range of the nearest CSAR airbase. + -- TaskA2ADispatcher:SetEngageRadius( 20000 ) + -- + -- -- Set 50km as the radius to to CSAR any downed pilot within range of the nearest CSAR airbase. + -- TaskA2ADispatcher:SetEngageRadius() -- 50000 is the default value. + -- + function TASK_CARGO_DISPATCHER:SetCSARRadius( CSARRadius ) + + self.CSARRadius = CSARRadius or 50000 + + return self + end + + + --- Define one deploy zone for the CSAR tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DeployZone A deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARDeployZone ) + + self.CSARDeployZones = { CSARDeployZone } + + return self + end + + + --- Define the deploy zones for the CSAR tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param CSARDeployZones A list of the deploy zones. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) + + self.CSARDeployZones = CSARDeployZones + + return self + end + + + --- Evaluates of a CSAR task needs to be started. + -- @param #TASK_CARGO_DISPATCHER self + -- @return Set#SET_CARGO The SetCargo to be rescued. + -- @return #nil If there is no CSAR task required. + function TASK_CARGO_DISPATCHER:EvaluateCSAR( CSARUnit ) + + local CSARCargo = CARGO_GROUP:New( CSARUnit, "Pilot", CSARUnit:GetName(), 80, 1500, 10 ) + + local SetCargo = SET_CARGO:New() + SetCargo:AddCargosByName( CSARUnit:GetName() ) + + SetCargo:Flush(self) + + return SetCargo + + end + + + + --- Assigns tasks to the @{Set#SET_GROUP}. + -- @param #TASK_CARGO_DISPATCHER self + -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. + function TASK_CARGO_DISPATCHER:ManageTasks() + self:F() + + local AreaMsg = {} + local TaskMsg = {} + local ChangeMsg = {} + + local Mission = self.Mission + + if Mission:IsIDLE() or Mission:IsENGAGED() then + + local TaskReport = REPORT:New() + + -- Checking the task queue for the dispatcher, and removing any obsolete task! + for TaskIndex, TaskData in pairs( self.Tasks ) do + local Task = TaskData -- Tasking.Task#TASK + if Task:IsStatePlanned() then + -- Here we need to check if the pilot is still existing. +-- local DetectedItem = Detection:GetDetectedItemByIndex( TaskIndex ) +-- if not DetectedItem then +-- local TaskText = Task:GetName() +-- for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do +-- Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2A task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup ) +-- end +-- Task = self:RemoveTask( TaskIndex ) +-- end + end + end + + -- Now that all obsolete tasks are removed, loop through the CSAR pilots. + for CSARID, CSARData in pairs( self.CSAR ) do + + if CSARData.Task then + else + -- New CSAR Task + local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) + local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) + CSARTask:SetDeployZones( self.CSARDeployZones or {} ) + Mission:AddTask( CSARTask ) + TaskReport:Add( CSARTask:GetName() ) + CSARData.Task = CSARTask + end + end + + + -- TODO set menus using the HQ coordinator + Mission:GetCommandCenter():SetMenu() + + local TaskText = TaskReport:Text(", ") + + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then + Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) + end + end + + end + + return true + end + +end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua new file mode 100644 index 000000000..0deff06e4 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -0,0 +1,187 @@ +--- **Tasking** -- The TASK_CARGO models tasks for players to transport @{Cargo}. +-- +-- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) +-- +-- === + + +do -- TASK_CARGO_TRANSPORT + + --- The TASK_CARGO_TRANSPORT class + -- @type TASK_CARGO_TRANSPORT + -- @extends Tasking.Task_Cargo#TASK_CARGO + TASK_CARGO_TRANSPORT = { + ClassName = "TASK_CARGO_TRANSPORT", + } + + --- Instantiates a new TASK_CARGO_TRANSPORT. + -- @param #TASK_CARGO_TRANSPORT self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. + -- @param #string TaskBriefing The Cargo Task briefing. + -- @return #TASK_CARGO_TRANSPORT self + function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_TRANSPORT + self:F() + + Mission:AddTask( self ) + + + -- Events + + self:AddTransition( "*", "CargoPickedUp", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) + + self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) + + --- OnBefore Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Synchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] CargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- Asynchronous Event Trigger for Event CargoPickedUp. + -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoPickedUp + -- @param #TASK_CARGO_TRANSPORT self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + + --- OnBefore Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Synchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] CargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + --- Asynchronous Event Trigger for Event CargoDeployed. + -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoDeployed + -- @param #TASK_CARGO_TRANSPORT self + -- @param #number Delay The delay in seconds. + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. + + local Fsm = self:GetUnitProcess() + + local CargoReport = REPORT:New( "Transport Cargo. The following cargo needs to be transported including initial positions:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + + + return self + end + + function TASK_CARGO_TRANSPORT:ReportOrder( ReportGroup ) + + return 0 + end + + + --- + -- @param #TASK_CARGO_TRANSPORT self + -- @return #boolean + function TASK_CARGO_TRANSPORT:IsAllCargoTransported() + + local CargoSet = self:GetCargoSet() + local Set = CargoSet:GetSet() + + local DeployZones = self:GetDeployZones() + + local CargoDeployed = true + + -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). + for CargoID, CargoData in pairs( Set ) do + local Cargo = CargoData -- Core.Cargo#CARGO + + self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) + + if Cargo:IsDeployed() then + +-- -- Loop the DeployZones set for the TASK_CARGO_TRANSPORT. +-- for DeployZoneID, DeployZone in pairs( DeployZones ) do +-- +-- -- If all cargo is in one of the deploy zones, then all is good. +-- self:T( { Cargo.CargoObject } ) +-- if Cargo:IsInZone( DeployZone ) == false then +-- CargoDeployed = false +-- end +-- end + else + CargoDeployed = false + end + end + + self:F( { CargoDeployed = CargoDeployed } ) + + return CargoDeployed + end + + --- @param #TASK_CARGO_TRANSPORT self + function TASK_CARGO_TRANSPORT:onafterGoal( TaskUnit, From, Event, To ) + local CargoSet = self.CargoSet + + if self:IsAllCargoTransported() then + self:Success() + end + + self:__Goal( -10 ) + end + +end + diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua new file mode 100644 index 000000000..340fd8233 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -0,0 +1,150 @@ +--- This module contains the TASK_MANAGER class and derived classes. +-- +-- === +-- +-- 1) @{Task_Manager#TASK_MANAGER} class, extends @{Fsm#FSM} +-- === +-- The @{Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. +-- Reportings can be done in several manners, and it is up to the derived classes if TASK_MANAGER to model the reporting behaviour. +-- +-- 1.1) TASK_MANAGER constructor: +-- ----------------------------------- +-- * @{Task_Manager#TASK_MANAGER.New}(): Create a new TASK_MANAGER instance. +-- +-- 1.2) TASK_MANAGER reporting: +-- --------------------------------- +-- Derived TASK_MANAGER classes will manage tasks using the method @{Task_Manager#TASK_MANAGER.ManageTasks}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the task management can be changed using the methods @{Task_Manager#TASK_MANAGER.SetRefreshTimeInterval}(). +-- To control how long a reporting message is displayed, use @{Task_Manager#TASK_MANAGER.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Task_Manager#TASK_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Task management can be started and stopped using the methods @{Task_Manager#TASK_MANAGER.StartTasks}() and @{Task_Manager#TASK_MANAGER.StopTasks}() respectively. +-- If an ad-hoc report is requested, use the method @{Task_Manager#TASK_MANAGER#ManageTasks}(). +-- +-- The default task management interval is every 60 seconds. +-- +-- === +-- +-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing +-- ### Author: FlightControl - Framework Design & Programming +-- +-- @module Task_Manager + +do -- TASK_MANAGER + + --- TASK_MANAGER class. + -- @type TASK_MANAGER + -- @field Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @extends Core.Fsm#FSM + TASK_MANAGER = { + ClassName = "TASK_MANAGER", + SetGroup = nil, + } + + --- TASK\_MANAGER constructor. + -- @param #TASK_MANAGER self + -- @param Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @return #TASK_MANAGER self + function TASK_MANAGER:New( SetGroup ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM:New() ) -- #TASK_MANAGER + + self.SetGroup = SetGroup + + self:SetStartState( "Stopped" ) + self:AddTransition( "Stopped", "StartTasks", "Started" ) + + --- StartTasks Handler OnBefore for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnBeforeStartTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- StartTasks Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterStartTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- StartTasks Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] StartTasks + -- @param #TASK_MANAGER self + + --- StartTasks Asynchronous Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] __StartTasks + -- @param #TASK_MANAGER self + -- @param #number Delay + + + + self:AddTransition( "Started", "StopTasks", "Stopped" ) + + --- StopTasks Handler OnBefore for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnBeforeStopTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- StopTasks Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterStopTasks + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- StopTasks Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] StopTasks + -- @param #TASK_MANAGER self + + --- StopTasks Asynchronous Trigger for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] __StopTasks + -- @param #TASK_MANAGER self + -- @param #number Delay + + + self:AddTransition( "Started", "Manage", "Started" ) + + self:SetRefreshTimeInterval( 30 ) + + return self + end + + function TASK_MANAGER:onafterStartTasks( From, Event, To ) + self:Manage() + end + + function TASK_MANAGER:onafterManage( From, Event, To ) + + self:__Manage( -self._RefreshTimeInterval ) + + self:ManageTasks() + end + + --- Set the refresh time interval in seconds when a new task management action needs to be done. + -- @param #TASK_MANAGER self + -- @param #number RefreshTimeInterval The refresh time interval in seconds when a new task management action needs to be done. + -- @return #TASK_MANAGER self + function TASK_MANAGER:SetRefreshTimeInterval( RefreshTimeInterval ) + self:F2() + + self._RefreshTimeInterval = RefreshTimeInterval + end + + + --- Manages the tasks for the @{Set#SET_GROUP}. + -- @param #TASK_MANAGER self + -- @return #TASK_MANAGER self + function TASK_MANAGER:ManageTasks() + self:E() + + end + +end + diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 66d9068a3..26062ea09 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -121,7 +121,7 @@ GROUPTEMPLATE.Takeoff = { -- @return #GROUP self function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID ) local GroupName = GroupTemplate.name - _DATABASE:_RegisterGroupTemplate( GroupTemplate, CategoryID, CountryID, CoalitionSide, GroupName ) + _DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName ) self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self:F2( GroupName ) self.GroupName = GroupName diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index ebc56985c..d1328835d 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -76,12 +76,16 @@ Tasking/CommandCenter.lua Tasking/Mission.lua Tasking/Task.lua Tasking/TaskInfo.lua +Tasking/Task_Manager.lua Tasking/DetectionManager.lua Tasking/Task_A2G_Dispatcher.lua Tasking/Task_A2G.lua Tasking/Task_A2A_Dispatcher.lua Tasking/Task_A2A.lua Tasking/Task_Cargo.lua +Tasking/Task_Cargo_Transport.lua +Tasking/Task_Cargo_CSAR.lua +Tasking/Task_Cargo_Dispatcher.lua Tasking/TaskZoneCapture.lua Moose.lua From e094c8133a80ea26204983a16f9001202df14b5c Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 3 Apr 2018 16:49:34 +0200 Subject: [PATCH 026/170] Added PseudoATC and Suppression --- .../Moose/Functional/PseudoATC.lua | 766 +++++++ .../Moose/Functional/Suppression.lua | 1816 +++++++++++++++++ 2 files changed, 2582 insertions(+) create mode 100644 Moose Development/Moose/Functional/PseudoATC.lua create mode 100644 Moose Development/Moose/Functional/Suppression.lua diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua new file mode 100644 index 000000000..9e93073d6 --- /dev/null +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -0,0 +1,766 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- **Functional** - Pseudo ATC. +-- +-- ![Banner Image](..\Presentations\PSEUDOATC\PSEUDOATC_Main.jpg) +-- +-- ==== +-- +-- The pseudo ATC enhances the standard DCS ATC functions. +-- +-- In particular, a menu entry "Pseudo ATC" is created in the special F10 menu. +-- +-- ## Features +-- +-- * Report QFE or QNH pressures at nearby airbases. +-- * Report wind direction and strength at airbases. +-- * Report temperature at airbases +-- * Report absolute bearing and range to nearest airports. +-- * Report current altitude AGL of own aircraft. +-- * Upon request, ATC reports altitude until touchdown. +-- * Pressure temperature, wind data and BR for mission waypoints. +-- * Works with static and dynamic weather. +-- * All maps supported (Caucasus, NTTR, Normandy, and all future maps). +-- * Multiplayer ready (?) (I suppose yes, but I don't have a server to test or debug. Jumping from client to client works.) +-- +-- Pressure units: hPa (european aircraft), mmHg (russian aircraft), inHg (american aircraft). +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) +-- +-- === +-- +-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** +-- +-- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- +-- ==== +-- @module PeusoATC + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- PSEUDOATC class +-- @type PSEUDOATC +-- @field #string ClassName Name of the Class. +-- @field #boolean Debug If true, print debug info to dcs.log file. +-- @field #table player Table comprising the player info. +-- @field #number mdur Duration in seconds how low messages to the player are displayed. +-- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. +-- @extends Core.Base#BASE + +---# PSEUDOATC class, extends @{Base#BASE} +-- The PSEUDOATC class adds some rudimentary ATC functionality via the radio menu. +-- +-- ## Scripting: +-- +-- Scripting is almost trivial. Just add the following line to your script: +-- +-- PSEUDOATC:Start() +-- +-- +-- @field #PSEUDOATC +PSEUDOATC={ + ClassName = "PSEUDOATC", + Debug=true, + player={}, + maxairport=9, + mdur=30, + mrefresh=120, +} + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- PSEUDOATC unit conversions. +-- @list unit +PSEUDOATC.unit={ + hPa2inHg=0.0295299830714, + hPa2mmHg=0.7500615613030, + meter2feet=3.28084, + km2nm=0.539957, +} + +--- Some ID to identify who we are in output of the DCS.log file. +-- @field #string id +PSEUDOATC.id="PseudoATC | " + +--- PSEUDOATC version. +-- @field #list +PSEUDOATC.version={ + version = "0.5.0", + print = true, +} + + +--- PSEUDOATC contructor. Starts the PseudoATC. +-- @param #PSEUDOATC self +-- @return #PSEUDOATC Returns a PSEUDOATC object. +function PSEUDOATC:Start() + + -- Inherit BASE. + local self=BASE:Inherit(self, BASE:New()) -- #PSEUDOATC + + -- Debug info + env.info(PSEUDOATC.id..string.format("Creating PseudoATC object. PseudoATC version %s", PSEUDOATC.version.version)) + + -- Handle events. + if self.eventsmoose then + self:HandleEvent(EVENTS.Birth, self._OnBirth) + self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft) + --self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft) + self:HandleEvent(EVENTS.Land, self._PlayerLanded) + --self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeoff) + else + -- Events are handled directly by DCS. + world.addEventHandler(self) + end + + -- Return object. + return self +end + +----------------------------------------------------------------------------------------------------------------------------------------- +-- Event Handling + +--- Event handler for suppressed groups. +--@param #PSEUDOATC self +--@param #table Event Event data table. Holds event.id, event.initiator and event.target etc. +function PSEUDOATC:onEvent(Event) + if Event == nil or Event.initiator == nil or Unit.getByName(Event.initiator:getName()) == nil then + return true + end + + local DCSiniunit = Event.initiator + local DCSplace = Event.place + local DCSsubplace = Event.subplace + + local EventData={} + local _playerunit=nil + local _playername=nil + + if Event.initiator then + EventData.IniUnitName = Event.initiator:getName() + EventData.IniDCSGroup = Event.initiator:getGroup() + EventData.IniGroupName = Event.initiator:getGroup():getName() + -- Get player unit and name. This returns nil,nil if the event was not fired by a player unit. And these are the only events we are interested in. + _playerunit, _playername = self:_GetPlayerUnitAndName(EventData.IniUnitName) + end + + if Event.place then + EventData.Place=Event.place + EventData.PlaceName=Event.place:getName() + end + if Event.subplace then + EventData.SubPlace=Event.subplace + EventData.SubPlaceName=Event.subplace:getName() + end + + -- Event info. + if self.Debug then + env.info(PSEUDOATC.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id))) + env.info(PSEUDOATC.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName))) + env.info(PSEUDOATC.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName))) + env.info(PSEUDOATC.id..string.format("EVENT: Ini player = %s" , tostring(_playername))) + env.info(PSEUDOATC.id..string.format("EVENT: Place = %s" , tostring(EventData.PlaceName))) + env.info(PSEUDOATC.id..string.format("EVENT: SubPlace = %s" , tostring(EventData.SubPlaceName))) + end + + -- Event birth. + if Event.id == world.event.S_EVENT_BIRTH and _playername then + self:_OnBirth(EventData) + end + + -- Event land. + if Event.id == world.event.S_EVENT_LAND and _playername and EventData.Place then + self:_PlayerLanded(EventData) + end + + -- Event player left unit + if Event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and _playername then + self:_PlayerLeft(EventData) + end + +end + +--- Function called my MOOSE event handler when a player enters a unit. +-- @param #PSEUDOATC self +-- @param Core.Event#EVENTDATA EventData +function PSEUDOATC:_OnBirth(EventData) + env.info(PSEUDOATC.id.."PlayerEntered event caught my MOOSE.") + + local _unitName=EventData.IniUnitName + local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + + if _unit and _playername then + self:PlayerEntered(_unit) + end + +end + +--- Function called by MOOSE event handler when a player leaves a unit or dies. +-- @param #PSEUDOATC self +-- @param Core.Event#EVENTDATA EventData +function PSEUDOATC:_PlayerLeft(EventData) + + local _unitName=EventData.IniUnitName + local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + + if _unit and _playername then + self:PlayerLeft(_unit) + end +end + +--- Function called by MOOSE event handler when a player landed. +-- @param #PSEUDOATC self +-- @param Core.Event#EVENTDATA EventData +function PSEUDOATC:_PlayerLanded(EventData) + + local _unitName=EventData.IniUnitName + local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + local _base=EventData.Place + local _baseName=EventData.PlaceName + + if _unit and _playername and _base then + self:PlayerLanded(_unit, _baseName) + end +end + +----------------------------------------------------------------------------------------------------------------------------------------- +-- Menu Functions + +--- Function called when a player enters a unit. +-- @param #PSEUDOATC self +-- @param Wrapper.Unit#UNIT unit Unit the player entered. +function PSEUDOATC:PlayerEntered(unit) + self:F2({unit=unit}) + + local group=unit:GetGroup() --Wrapper.Group#GROUP + local GID=group:GetID() + local GroupName=group:GetName() + local PlayerName=unit:GetPlayerName() + local UnitName=unit:GetName() + local CallSign=unit:GetCallsign() + + -- Init player table. + self.player[GID]={} + self.player[GID].group=group + self.player[GID].unit=unit + self.player[GID].groupname=GroupName + self.player[GID].unitname=UnitName + self.player[GID].playername=PlayerName + self.player[GID].callsign=CallSign + self.player[GID].waypoints=group:GetTaskRoute() + + -- Info message. + local text=string.format("Player %s entered unit %s of group %s. ID = %d", PlayerName, UnitName, GroupName, GID) + if self.Debug then + MESSAGE:New(text, 30):ToGroup(group) + env.info(PSEUDOATC.id..text) + end + + -- Create main F10 menu, i.e. "F10/Pseudo ATC" + self.player[GID].menu_main=missionCommands.addSubMenuForGroup(GID, "Pseudo ATC") + + -- Create list of nearby airports. + self:LocalAirports(GID) + + -- Create submenu My Positon. + self:MenuAircraft(GID) + + -- Create submenu airports. + self:MenuAirports(GID) + + -- Start scheduler to refresh the F10 menues. + self.player[GID].scheduler, self.player[GID].schedulerid=SCHEDULER:New(nil, self.MenuRefresh, {self, GID}, self.mrefresh, self.mrefresh) + + self:T2(self.player[GID]) +end + +--- Function called when a player has landed. +-- @param #PSEUDOATC self +-- @param Wrapper.Unit#UNIT unit Unit of player which has landed. +-- @param #string place Name of the place the player landed at. +function PSEUDOATC:PlayerLanded(unit, place) + self:F2({unit=unit, place=place}) + + -- Gather some information. + local group=unit:GetGroup() + local id=group:GetID() + local PlayerName=self.player[id].playername + local UnitName=self.player[id].playername + local GroupName=self.player[id].groupname + local CallSign=self.player[id].callsign + + -- Debug message. + if self.Debug then + local text=string.format("Player %s (%s) from group %s with ID %d landed at %s", PlayerName, UnitName, GroupName, place) + MESSAGE:New(text,30):ToAll() + env.info(PSEUDOATC.id..text) + end + + -- Stop altitude reporting timer if its activated. + self:AltidudeStopTimer(id) + + -- Welcome message. + if place then + local text=string.format("Touchdown! Welcome to %s. Have a nice day!", place) + MESSAGE:New(text, self.mdur):ToGroup(group) + end + +end + +--- Function called when a player leaves a unit or dies. +-- @param #PSEUDOATC self +-- @param Wrapper.Unit#UNIT unit Player unit which was left. +function PSEUDOATC:PlayerLeft(unit) + self:F2({unit=unit}) + + -- Get id. + local group=unit:GetGroup() + local id=group:GetID() + + -- Debug message. + if self.Debug then + local text=string.format("Player %s (%s) callsign %s of group %s just left.", self.player[id].playername, self.player[id].unitname, self.player[id].callsign, self.player[id].groupname) + MESSAGE:New(text,30):ToAll() + env.info(PSEUDOATC.id..text) + end + + -- Stop scheduler for menu updates + if self.player[id].schedulerid then + self.player[id].scheduler:Stop(self.player[id].schedulerid) + self.player[id].scheduler=nil + self.player[id].schedulerid=nil + end + + -- Remove main menu + missionCommands.removeItem(self.player[id].menu_main) + + -- Remove player array. + self.player[id]=nil + +end + +----------------------------------------------------------------------------------------------------------------------------------------- +-- Menu Functions + +--- Refreshes all player menues. +-- @param #PSEUDOATC self. +-- @param #number id Group id of player unit. +function PSEUDOATC:MenuRefresh(id) + self:F(id) + + if self.Debug then + local text=string.format("Refreshing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) + env.info(PSEUDOATC.id..text) + MESSAGE:New(text,30):ToAll() + end + + -- Clear menu. + self:MenuClear(id) + + -- Create list of nearby airports. + self:LocalAirports(id) + + -- Create submenu My Positon. + self:MenuAircraft(id) + + -- Create submenu airports. + self:MenuAirports(id) +end + + +--- Clear player menues. +-- @param #PSEUDOATC self. +-- @param #number id Group id of player unit. +function PSEUDOATC:MenuClear(id) + self:F(id) + + if self.Debug then + local text=string.format("Clearing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) + env.info(PSEUDOATC.id..text) + MESSAGE:New(text,30):ToAll() + end + + BASE:E(self.player[id].menu_airports) + + if self.player[id].menu_airports then + for name,item in pairs(self.player[id].menu_airports) do + + if self.Debug then + env.info(PSEUDOATC.id..string.format("Deleting menu item %s for ID %d", name, id)) + BASE:E(item) + end + + missionCommands.removeItemForGroup(id, self.player[id].menu_airports[name]) + --missionCommands.removeItemForGroup(id, item) + end + + else + if self.Debug then + local text=string.format("no airports to clear menues") + env.info(PSEUDOATC.id..text) + end + end + + if self.player[id].menu_aircraft then + missionCommands.removeItemForGroup(id, self.player[id].menu_aircraft.main) + end + + self.player[id].menu_airports=nil + self.player[id].menu_aircraft=nil +end + +--- Create "F10/Pseudo ATC" menu items "Airport Data". +-- @param #PSEUDOATC self +-- @param #number id Group id of player unit for which menues are created. +function PSEUDOATC:MenuAirports(id) + self:F(id) + + -- Table for menu entries. + self.player[id].menu_airports={} + + local i=0 + for _,airport in pairs(self.player[id].airports) do + + i=i+1 + if i>self.maxairport then + break -- Max X<10 airports due to 10 menu items restriction. + end + + local name=airport.name + local d=airport.distance + local pos=AIRBASE:FindByName(name):GetCoordinate() + + --F10menu_ATC_airports[ID][name] = missionCommands.addSubMenuForGroup(ID, name, F10menu_ATC) + local submenu=missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) + self.player[id].menu_airports[name]=submenu + + -- Create menu reporting commands + missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, name) + missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, name) + missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, name) + missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, name) + missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, name) + + if self.Debug then + env.info(string.format(PSEUDOATC.id.."Creating airport menu item %s for ID %d", name, id)) + end + end +end + +--- Create F10/Pseudo ATC menu item "My Plane". +-- @param #PSEUDOATC self +-- @param #number id Group id of player unit for which menues are created. +function PSEUDOATC:MenuAircraft(id) + self:F(id) + + -- Table for menu entries. + self.player[id].menu_aircraft={} + + local unit=self.player[id].unit --Wrapper.Unit#UNIT + local callsign=self.player[id].callsign + local name=string.format("My Aircraft (%s)", callsign) + + -- Debug info. + if self.Debug then + env.info(PSEUDOATC.id..string.format("Creating menu item %s for ID %d", name,id)) + end + + -- F10/PseudoATC/My Aircraft (callsign) + self.player[id].menu_aircraft.main = missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) + + -- F10/PseudoATC/My Aircraft (callsign)/Waypoints + if #self.player[id].waypoints>0 then + + --F10menu_ATC_waypoints[ID]={} + self.player[id].menu_aircraft_waypoints={} + self.player[id].menu_aircraft_waypoints.main=missionCommands.addSubMenuForGroup(id, "Waypoints", self.player[id].menu_aircraft.main) + + local j=0 + for i, wp in pairs(self.player[id].waypoints) do + -- Increase counter + j=j+1 + + if j>10 then + break -- max ten menu entries + end + + local pos=COORDINATE:New(wp.x,wp.alt,wp.z) + + local fname=string.format("Waypoint %d for %s", i-1, callsign) + local pname=string.format("Waypoint %d", i-1) + + -- "F10/PseudoATC/My Aircraft (callsign)/Waypoints/Waypoint X" + local submenu=missionCommands.addSubMenuForGroup(id, pname, self.player[id].menu_aircraft_waypoints.main) + self.player[id].menu_aircraft_waypoints.pname=submenu + + -- Menu commands for each waypoint "F10/PseudoATC/My Aircraft (callsign)/Waypoints/Waypoint X/" + missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, pname) + missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, pname) + missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, pname) + missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, pname) + missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, pname) + end + end + missionCommands.addCommandForGroup(id, "Request current altitude AGL", self.player[id].menu_aircraft.main, self.ReportHeight, self, id) + missionCommands.addCommandForGroup(id, "Report altitude until touchdown", self.player[id].menu_aircraft.main, self.AltidudeStartTimer, self, id) + missionCommands.addCommandForGroup(id, "Quit reporting altitude", self.player[id].menu_aircraft.main, self.AltidudeStopTimer, self, id) +end + +----------------------------------------------------------------------------------------------------------------------------------------- +-- Reporting Functions + +--- Report pressure. +-- @param #PSEUDOATC self +-- @param #number id Group id to which the report is delivered. +-- @param #string Qcode Can be "QNH" for pressure at sea level or "QFE" for pressure at field elevation. Default is QFE or more precisely pressure at position. +-- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. +-- @param #string location Name of the location at which the pressure is measured. +function PSEUDOATC:ReportPressure(id, Qcode, position, location) + self:F({id=id, Qcode=Qcode, position=position, location=location}) + + -- Get pressure in hPa. + local P + if Qcode=="QNH" then + P=position:GetPressure(0) -- Get pressure at sea level. + else + P=position:GetPressure() -- Get pressure at (land) height of position. + end + + -- Unit conversion. + local P_inHg=P * PSEUDOATC.unit.hPa2inHg + local P_mmHg=P * PSEUDOATC.unit.hPa2mmHg + + -- Message text. + local text=string.format("%s at %s: P = %.1f hPa = %.2f inHg = %.1f mmHg.", Qcode, location, P, P_inHg, P_mmHg) + + -- Send message. + MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) +end + +--- Report temperature. +-- @param #PSEUDOATC self +-- @param #number id Group id to the report is delivered. +-- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. +-- @param #string location Name of the location at which the pressure is measured. +function PSEUDOATC:ReportTemperature(id, position, location) + self:F({id=id, position=position, location=location}) + + --- convert celsius to fahrenheit + local function celsius2fahrenheit(degC) + return degC*1.8+32 + end + + -- Get temperature at position in degrees Celsius. + local T=position:GetTemperature() + + -- Formatted temperature in Celsius and Fahrenheit. + local Tc=string.format('%d°C', T) + local Tf=string.format('%d°F', celsius2fahrenheit(T)) + + -- Message text. + local text=string.format("Temperature at %s is %s = %s", location, Tc, Tf) + + -- Send message to player group. + MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) +end + +--- Report wind direction and strength. +-- @param #PSEUDOATC self +-- @param #number id Group id to the report is delivered. +-- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. +-- @param #string location Name of the location at which the pressure is measured. +function PSEUDOATC:ReportWind(id, position, location) + self:F({id=id, position=position, location=location}) + + -- Get wind direction and speed. + local Dir,Vel=position:GetWind() + + -- Get Beaufort wind scale. + local Bn,Bd=UTILS.BeaufortScale(Vel) + + -- Formatted wind direction. + local Ds = string.format('%03d°', Dir) + + -- Message text. + local text=string.format("%s: Wind from %s at %.1f m/s (%s).", location, Ds, Vel, Bd) + + -- Send message to player group. + MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) +end + +--- Report absolute bearing and range form player unit to airport. +-- @param #PSEUDOATC self +-- @param #number id Group id to the report is delivered. +-- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. +-- @param #string location Name of the location at which the pressure is measured. +function PSEUDOATC:ReportBR(id, position, location) + self:F({id=id, position=position, location=location}) + + -- Current coordinates. + local unit=self.player[id].unit --Wrapper.Unit#UNIT + local coord=unit:GetCoordinate() + + -- Direction vector from current position (coord) to target (position). + local vec3=coord:GetDirectionVec3(position) + local angle=coord:GetAngleDegrees(vec3) + local range=coord:Get2DDistance(position) + + -- Bearing string. + local Bs=string.format('%03d°', angle) + + -- Message text. + local text=string.format("%s: Bearing %s, Range %.1f km = %.1f NM.", location, Bs, range/1000, range/1000 * PSEUDOATC.unit.km2nm) + + -- Send message to player group. + MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) +end + +--- Report altitude above ground level of player unit. +-- @param #PSEUDOATC self +-- @param #number id Group id to the report is delivered. +-- @param #number dt (Optional) Duration the message is displayed. +-- @return #number Altuitude above ground. +function PSEUDOATC:ReportHeight(id, dt) + self:F({id=id, dt=dt}) + + local dt = dt or self.mdur + + -- Return height [m] above ground level. + local function get_AGL(p) + local vec2={x=p.x,y=p.z} + local ground=land.getHeight(vec2) + local agl=p.y-ground + return agl + end + + -- Get height AGL. + local unit=self.player[id].unit --Wrapper.Unit#UNIT + local position=unit:GetCoordinate() + local height=get_AGL(position) + local callsign=unit:GetCallsign() + + -- Message text. + local text=string.format("%s: Your altitude is %d m = %d ft AGL.", callsign, height, height*PSEUDOATC.unit.meter2feet) + + -- Send message to player group. + MESSAGE:New(text, dt):ToGroup(self.player[id].group) + + -- Return height + return height +end + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Start DCS scheduler function. +-- @param #PSEUDOATC self. +-- @param #number id Group id of player unit. +function PSEUDOATC:AltidudeStartTimer(id) + self:F(id) + + -- Debug info. + if self.Debug then + env.info(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", id)) + end + + -- Start timer. + --self.player[id].altimer=timer.scheduleFunction(self.ReportAltTouchdown, self, id, Tnow+2) + self.player[id].altimer, self.player[id].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, id, 0.1}, 1, 5) +end + +--- Stop/destroy DCS scheduler function for reporting altitude. +-- @param #PSEUDOATC self. +-- @param #number id Group id of player unit. +function PSEUDOATC:AltidudeStopTimer(id) + + -- Debug info. + if self.Debug then + env.info(PSEUDOATC.id..string.format("Stopping altitude report timer for player ID %d.", id)) + end + + -- Stop timer. + --timer.removeFunction(self.player[id].alttimer) + if self.player[id].altimerid then + self.player[id].altimer:Stop(self.player[id].altimerid) + end + + self.player[id].altimer=nil + self.player[id].altimerid=nil +end + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Misc + +--- Create list of nearby airports sorted by distance to player unit. +-- @param #PSEUDOATC self +-- @param #number id Group id of player unit. +function PSEUDOATC:LocalAirports(id) + self:F(id) + + -- Airports table. + self.player[id].airports=nil + self.player[id].airports={} + + -- Current player position. + local pos=self.player[id].unit:GetCoordinate() + + -- Loop over coalitions. + for i=0,2 do + + -- Get all airbases of coalition. + local airports=coalition.getAirbases(i) + + -- Loop over airbases + for _,airbase in pairs(airports) do + + local name=airbase:getName() + local q=AIRBASE:FindByName(name):GetCoordinate() + local d=q:Get2DDistance(pos) + + -- Add to table. + table.insert(self.player[id].airports, {distance=d, name=name}) + + end + end + + --- compare distance (for sorting airports) + local function compare(a,b) + return a.distance < b.distance + end + + -- Sort airports table w.r.t. distance to player. + table.sort(self.player[id].airports, compare) + +end + +--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. +-- @param #PSEUDOATC self +-- @param #string _unitName Name of the player unit. +-- @return Wrapper.Unit#UNIT Unit of player. +-- @return #string Name of the player. +-- @return nil If player does not exist. +function PSEUDOATC:_GetPlayerUnitAndName(_unitName) + self:F(_unitName) + + if _unitName ~= nil then + local DCSunit=Unit.getByName(_unitName) + local playername=DCSunit:getPlayerName() + local unit=UNIT:Find(DCSunit) + + if DCSunit and unit and playername then + return unit, playername + end + end + + return nil,nil +end + + + diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua new file mode 100644 index 000000000..f3a4c4954 --- /dev/null +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -0,0 +1,1816 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- **Functional** - Suppress fire of ground units when they get hit. +-- +-- ![Banner Image](..\Presentations\SUPPRESSION\Suppression_Main.png) +-- +-- ==== +-- +-- When ground units get hit by (suppressive) enemy fire, they will not be able to shoot back for a certain amount of time. +-- +-- The implementation is based on an idea and script by MBot. See the [DCS forum threat](https://forums.eagle.ru/showthread.php?t=107635) for details. +-- +-- In addition to suppressing the fire, conditions can be specified which let the group retreat to a defined zone, move away from the attacker +-- or hide at a nearby scenery object. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) +-- +-- === +-- +-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** +-- +-- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- +-- ==== +-- @module Suppression + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- SUPPRESSION class +-- @type SUPPRESSION +-- @field #string ClassName Name of the class. +-- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players. +-- @field #boolean flare Flare units when they get hit or die. +-- @field #boolean smoke Smoke places to which the group retreats, falls back or hides. +-- @field #list DCSdesc Table containing all DCS descriptors of the group. +-- @field #string Type Type of the group. +-- @field #number SpeedMax Maximum speed of group in km/h. +-- @field #boolean IsInfantry True if group has attribute Infantry. +-- @field Core.Controllable#CONTROLLABLE Controllable Controllable of the FSM. Must be a ground group. +-- @field #number Tsuppress_ave Average time in seconds a group gets suppressed. Actual value is sampled randomly from a Gaussian distribution. +-- @field #number Tsuppress_min Minimum time in seconds the group gets suppressed. +-- @field #number Tsuppress_max Maximum time in seconds the group gets suppressed. +-- @field #number TsuppressionOver Time at which the suppression will be over. +-- @field #number IniGroupStrength Number of units in a group at start. +-- @field #number Nhit Number of times the group was hit. +-- @field #string Formation Formation which will be used when falling back, taking cover or retreating. Default "Vee". +-- @field #number Speed Speed the unit will use when falling back, taking cover or retreating. Default 999. +-- @field #boolean MenuON If true creates a entry in the F10 menu. +-- @field #boolean FallbackON If true, group can fall back, i.e. move away from the attacking unit. +-- @field #number FallbackWait Time in seconds the unit will wait at the fall back point before it resumes its mission. +-- @field #number FallbackDist Distance in meters the unit will fall back. +-- @field #number FallbackHeading Heading in degrees to which the group should fall back. Default is directly away from the attacking unit. +-- @field #boolean TakecoverON If true, group can hide at a nearby scenery object. +-- @field #number TakecoverWait Time in seconds the group will hide before it will resume its mission. +-- @field #number TakecoverRange Range in which the group will search for scenery objects to hide at. +-- @field Core.Point#COORDINATE hideout Coordinate/place where the group will try to take cover. +-- @field #number PminFlee Minimum probability in percent that a group will flee (fall back or take cover) at each hit event. Default is 10 %. +-- @field #number PmaxFlee Maximum probability in percent that a group will flee (fall back or take cover) at each hit event. Default is 90 %. +-- @field Core.Zone#ZONE RetreatZone Zone to which a group retreats. +-- @field #number RetreatDamage Damage in percent at which the group will be ordered to retreat. +-- @field #number RetreatWait Time in seconds the group will wait in the retreat zone before it resumes its mission. Default two hours. +-- @field #string CurrentAlarmState Alam state the group is currently in. +-- @field #string CurrentROE ROE the group currently has. +-- @field #string DefaultAlarmState Alarm state the group will go to when it is changed back from another state. Default is "Auto". +-- @field #string DefaultROE ROE the group will get once suppression is over. Default is "Free". +-- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true. +-- @extends Core.Fsm#FSM_CONTROLLABLE +-- + +---# SUPPRESSION class, extends @{Core.Fsm#FSM_CONTROLLABLE} +-- Mimic suppressive enemy fire and let groups flee or retreat. +-- +-- ## Suppression Process +-- +-- ![Process](..\Presentations\SUPPRESSION\Suppression_Process.png) +-- +-- The suppression process can be described as follows. +-- +-- ### CombatReady +-- +-- A group starts in the state **CombatReady**. In this state the group is ready to fight. The ROE is set to either "Weapon Free" or "Return Fire". +-- The alarm state is set to either "Auto" or "Red". +-- +-- ### Event Hit +-- The most important event in this scenario is the **Hit** event. This is an event of the FSM and triggered by the DCS event hit. +-- +-- ### Suppressed +-- After the **Hit** event the group changes its state to **Suppressed**. Technically, the ROE of the group is changed to "Weapon Hold". +-- The suppression of the group will last a certain amount of time. It is randomized an will vary each time the group is hit. +-- The expected suppression time is set to 15 seconds by default. But the actual value is sampled from a Gaussian distribution. +-- +-- ![Process](..\Presentations\SUPPRESSION\Suppression_Gaussian.png) +-- +-- The graph shows the distribution of suppression times if a group would be hit 100,000 times. As can be seen, on most hits the group gets +-- suppressed for around 15 seconds. Other values are also possible but they become less likely the further away from the "expected" suppression time they are. +-- Minimal and maximal suppression times can also be specified. By default these are set to 5 and 25 seconds, respectively. This can also be seen in the graph +-- because the tails of the Gaussian distribution are cut off at these values. +-- +-- ### Event Recovered +-- After the suppression time is over, the event **Recovered** is initiated and the group becomes **CombatReady** again. +-- The ROE of the group will be set to "Weapon Free". +-- +-- Of course, it can also happen that a group is hit again while it is still suppressed. In that case a new random suppression time is calculated. +-- If the new suppression time is longer than the remaining suppression of the previous hit, then the group recovers when the suppression time of the last +-- hit has passed. +-- If the new suppression time is shorter than the remaining suppression, the group will recover after the longer time of the first suppression has passed. +-- +-- For example: +-- +-- * A group gets hit the first time and is suppressed for - let's say - 15 seconds. +-- * After 10 seconds, i.e. when 5 seconds of the old suppression are left, the group gets hit a again. +-- * A new suppression time is calculated which can be smaller or larger than the remaining 5 seconds. +-- * If the new suppression time is smaller, e.g. three seconds, than five seconds, the group will recover after the 5 remaining seconds of the first suppression have passed. +-- * If the new suppression time is longer than last suppression time, e.g. 10 seconds, then the group will recover after the 10 seconds of the new hit have passed. +-- +-- Generally speaking, the suppression times are not just added on top of each other. Because this could easily lead to the situation that a group +-- never becomes CombatReady again before it gets destroyed. +-- +-- The mission designer can capture the event **Recovered** by the function @{#SUPPRESSION.OnAfterRecovered}(). +-- +-- ## Flee Events and States +-- Apart from being suppressed the groups can also flee from the enemy under certain conditions. +-- +-- ### Event Retreat +-- The first option is a retreat. This can be enabled by setting a retreat zone, i.e. a trigger zone defined in the mission editor. +-- +-- If the group takes a certain amount of damage, the event **Retreat** will be called and the group will start to move to the retreat zone. +-- The group will be in the state **Retreating**, which means that its ROE is set to "Weapon Hold" and the alarm state is set to "Green". +-- Setting the alarm state to green is necessary to enable the group to move under fire. +-- +-- When the group has reached the retreat zone, the event **Retreated** is triggered and the state will change to **Retreated** (note that both the event and +-- the state of the same name in this case). ROE and alarm state are +-- set to "Return Fire" and "Auto", respectively. The group will stay in the retreat zone and not actively participate in the combat any more. +-- +-- If no option retreat zone has been specified, the option retreat is not available. +-- +-- The mission designer can capture the events **Retreat** and **Retreated** by the functions @{#SUPPRESSION.OnAfterRetreat}() and @{#SUPPRESSION.OnAfterRetreated}(). +-- +-- ### Fallback +-- +-- If a group is attacked by another ground group, it has the option to fall back, i.e. move away from the enemy. The probability of the event **FallBack** to +-- happen depends on the damage of the group that was hit. The more a group gets damaged, the more likely **FallBack** event becomes. +-- +-- If the group enters the state **FallingBack** it will move 100 meters in the opposite direction of the attacking unit. ROE and alarmstate are set to "Weapon Hold" +-- and "Green", respectively. +-- +-- At the fallback point the group will wait for 60 seconds before it resumes its normal mission. +-- +-- The mission designer can capture the event **FallBack** by the function @{#SUPPRESSION.OnAfterFallBack}(). +-- +-- ### TakeCover +-- +-- If a group is hit by either another ground or air unit, it has the option to "take cover" or "hide". This means that the group will move to a random +-- scenery object in it vicinity. +-- +-- Analogously to the fall back case, the probability of a **TakeCover** event to occur, depends on the damage of the group. The more a group is damaged, the more +-- likely it becomes that a group takes cover. +-- +-- When a **TakeCover** event occurs an area with a radius of 300 meters around the hit group is searched for an arbitrary scenery object. +-- If at least one scenery object is found, the group will move there. One it has reached its "hideout", it will wait there for two minutes before it resumes its +-- normal mission. +-- +-- If more than one scenery object is found, the group will move to a random one. +-- If no scenery object is near the group the **TakeCover** event is rejected and the group will not move. +-- +-- The mission designer can capture the event **TakeCover** by the function @{#SUPPRESSION.OnAfterTakeCover}(). +-- +-- ### Choice of FallBack or TakeCover if both are enabled? +-- +-- If both **FallBack** and **TakeCover** events are enabled by the functions @{#SUPPRESSION.Fallback}() and @{#SUPPRESSION.Takecover}() the algorithm does the following: +-- +-- * If the attacking unit is a ground unit, then the **FallBack** event is executed. +-- * Otherwise, i.e. if the attacker is *not* a ground unit, then the **TakeCover** event is triggered. +-- +-- ### FightBack +-- +-- When a group leaves the states **TakingCover** or **FallingBack** the event **FightBack** is triggered. This changes the ROE and the alarm state back to their default values. +-- +-- The mission designer can capture the event **FightBack** by the function @{#SUPPRESSION.OnAfterFightBack}() +-- +-- # Examples +-- +-- ## Simple Suppression +-- This example shows the basic steps to use suppressive fire for a group. +-- +-- ![Process](..\Presentations\SUPPRESSION\Suppression_Example_01.png) +-- +-- ## Suppression and Rescure +-- This example shows how the event **Retreat** can be captured. Here, a transport is started which picks up the wounded troups and drives them to a safe zone. +-- +-- ![Process](..\Presentations\SUPPRESSION\Suppression_Rescue.png) +-- +-- # Customization and Fine Tuning +-- The following user functions can be used to change the default values +-- +-- * @{#SUPPRESSION.SetSuppressionTime}() can be used to set the time a goup gets suppressed. +-- * @{#SUPPRESSION.SetRetreatZone}() sets the retreat zone and enables the possiblity for the group to retreat. +-- * @{#SUPPRESSION.SetFallbackDistance}() sets a value how far the unit moves away from the attacker after the fallback event. +-- * @{#SUPPRESSION.SetFallbackWait}() sets the time after which the group resumes its mission after a FallBack event. +-- * @{#SUPPRESSION.SetTakecoverWait}() sets the time after which the group resumes its mission after a TakeCover event. +-- * @{#SUPPRESSION.SetTakecoverRange}() sets the radius in which hideouts are searched. +-- * @{#SUPPRESSION.SetTakecoverPlace}() explicitly sets the place where the group will run at a TakeCover event. +-- * @{#SUPPRESSION.SetMinimumFleeProbability}() sets the minimum probability that a group flees (FallBack or TakeCover) after a hit. Note taht the probability increases with damage. +-- * @{#SUPPRESSION.SetMaximumFleeProbability}() sets the maximum probability that a group flees (FallBack or TakeCover) after a hit. Default is 90%. +-- * @{#SUPPRESSION.SetRetreatDamage}() sets the damage a group/unit can take before it is ordered to retreat. +-- * @{#SUPPRESSION.SetRetreatWait}() sets the time a group waits in the retreat zone after a retreat. +-- * @{#SUPPRESSION.SetDefaultAlarmState}() sets the alarm state a group gets after it becomes CombatReady again. +-- * @{#SUPPRESSION.SetDefaultROE}() set the rules of engagement a group gets after it becomes CombatReady again. +-- * @{#SUPPRESSION.FlareOn}() is mainly for debugging. A flare is fired when a unit is hit, gets suppressed, recovers, dies. +-- * @{#SUPPRESSION.SmokeOn}() is mainly for debugging. Puts smoke on retreat zone, hideouts etc. +-- * @{#SUPPRESSION.MenuON}() is mainly for debugging. Activates a radio menu item where certain functions like retreat etc. can be triggered manually. +-- +-- +-- @field #SUPPRESSION +SUPPRESSION={ + ClassName = "SUPPRESSION", + Debug = false, + flare = false, + smoke = false, + DCSdesc = nil, + Type = nil, + IsInfantry=nil, + SpeedMax = nil, + Tsuppress_ave = 15, + Tsuppress_min = 5, + Tsuppress_max = 25, + TsuppressOver = nil, + IniGroupStrength = nil, + Nhit = 0, + Formation = "Off road", + Speed = 4, + MenuON = false, + FallbackON = false, + FallbackWait = 60, + FallbackDist = 100, + FallbackHeading = nil, + TakecoverON = false, + TakecoverWait = 120, + TakecoverRange = 300, + hideout = nil, + PminFlee = 10, + PmaxFlee = 90, + RetreatZone = nil, + RetreatDamage = nil, + RetreatWait = 7200, + CurrentAlarmState = "unknown", + CurrentROE = "unknown", + DefaultAlarmState = "Auto", + DefaultROE = "Weapon Free", + eventmoose = true, +} + +--- Enumerator of possible rules of engagement. +-- @field #list ROE +SUPPRESSION.ROE={ + Hold="Weapon Hold", + Free="Weapon Free", + Return="Return Fire", +} + +--- Enumerator of possible alarm states. +-- @field #list AlarmState +SUPPRESSION.AlarmState={ + Auto="Auto", + Green="Green", + Red="Red", +} + +--- Main F10 menu for suppresion, i.e. F10/Suppression. +-- @field #string MenuF10 +SUPPRESSION.MenuF10=nil + +--- Some ID to identify who we are in output of the DCS.log file. +-- @field #string id +SUPPRESSION.id="SFX | " + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--TODO: Figure out who was shooting and move away from him. +--TODO: Move behind a scenery building if there is one nearby. +--TODO: Retreat to a given zone or point. + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Creates a new AI_suppression object. +-- @param #SUPPRESSION self +-- @param Wrapper.Group#GROUP group The GROUP object for which suppression should be applied. +-- @return #SUPPRESSION SUPPRESSION object. +-- @return nil If group does not exist or is not a ground group. +function SUPPRESSION:New(group) + BASE:F2(group) + + -- Inherits from FSM_CONTROLLABLE + local self=BASE:Inherit(self, FSM_CONTROLLABLE:New()) -- #SUPPRESSION + + -- Check that group is present. + if group then + self:T(SUPPRESSION.id.."Suppressive fire for group "..group:GetName()) + else + self:E(SUPPRESSION.id.."Suppressive fire: Requested group does not exist! (Has to be a MOOSE group.)") + return nil + end + + -- Check that we actually have a GROUND group. + if group:IsGround()==false then + self:E(SUPPRESSION.id.."SUPPRESSION fire group "..group:GetName().." has to be a GROUND group!") + return nil + end + + -- Set the controllable for the FSM. + self:SetControllable(group) + + -- Get DCS descriptors of group. + local DCSgroup=Group.getByName(group:GetName()) + local DCSunit=DCSgroup:getUnit(1) + self.DCSdesc=DCSunit:getDesc() + + -- Get max speed the group can do and convert to km/h. + self.SpeedMax=self.DCSdesc.speedMaxOffRoad*3.6 + --self.SpeedMaxOffRoad=DCSdesc.speedMaxOffRoad + + -- Set speed to maximum. + self.Speed=self.SpeedMax + + -- Is this infantry or not. + self.IsInfantry=DCSunit:hasAttribute("Infantry") + + -- Type of group. + self.Type=group:GetTypeName() + + -- Initial group strength. + self.IniGroupStrength=#group:GetUnits() + + -- Set ROE and Alarm State. + self:SetDefaultROE("Free") + self:SetDefaultAlarmState("Auto") + + -- Transitions + self:AddTransition("*", "Start", "CombatReady") + self:AddTransition("CombatReady", "Hit", "Suppressed") + self:AddTransition("Suppressed", "Hit", "Suppressed") + self:AddTransition("Suppressed", "Recovered", "CombatReady") + self:AddTransition("Suppressed", "TakeCover", "TakingCover") + self:AddTransition("Suppressed", "FallBack", "FallingBack") + self:AddTransition("*", "Retreat", "Retreating") + self:AddTransition("TakingCover", "FightBack", "CombatReady") + self:AddTransition("FallingBack", "FightBack", "CombatReady") + self:AddTransition("Retreating", "Retreated", "Retreated") + self:AddTransition("*", "Dead", "*") + + + --- User function for OnBefore "Hit" event. + -- @function [parent=#SUPPRESSION] OnBeforeHit + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Unit#UNIT Unit Unit that was hit. + -- @param Wrapper.Unit#UNIT AttackUnit Unit that attacked. + -- @return #boolean + + --- User function for OnAfer "Hit" event. + -- @function [parent=#SUPPRESSION] OnAfterHit + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Unit#UNIT Unit Unit that was hit. + -- @param Wrapper.Unit#UNIT AttackUnit Unit that attacked. + + + --- User function for OnBefore "Recovered" event. + -- @function [parent=#SUPPRESSION] OnBeforeRecovered + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean + + --- User function for OnAfter "Recovered" event. + -- @function [parent=#SUPPRESSION] OnAfterRecovered + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "TakeCover" event. + -- @function [parent=#SUPPRESSION] OnBeforeTakeCover + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Core.Point#COORDINATE Hideout Place where the group will hide. + -- @return #boolean + + --- User function for OnAfter "TakeCover" event. + -- @function [parent=#SUPPRESSION] OnAfterTakeCover + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Core.Point#COORDINATE Hideout Place where the group will hide. + + + --- User function for OnBefore "FallBack" event. + -- @function [parent=#SUPPRESSION] OnBeforeFallBack + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Unit#UNIT AttackUnit Attacking unit. We will move away from this. + -- @return #boolean + + --- User function for OnAfter "FallBack" event. + -- @function [parent=#SUPPRESSION] OnAfterFallBack + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Unit#UNIT AttackUnit Attacking unit. We will move away from this. + + + --- User function for OnBefore "Retreat" event. + -- @function [parent=#SUPPRESSION] OnBeforeRetreat + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean + + --- User function for OnAfter "Retreat" event. + -- @function [parent=#SUPPRESSION] OnAfterRetreat + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "Retreated" event. + -- @function [parent=#SUPPRESSION] OnBeforeRetreated + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean + + --- User function for OnAfter "Retreated" event. + -- @function [parent=#SUPPRESSION] OnAfterRetreated + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "FlightBack" event. + -- @function [parent=#SUPPRESSION] OnBeforeFightBack + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean + + --- User function for OnAfter "FlightBack" event. + -- @function [parent=#SUPPRESSION] OnAfterFightBack + -- @param #SUPPRESSION self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Set average, minimum and maximum time a unit is suppressed each time it gets hit. +-- @param #SUPPRESSION self +-- @param #number Tave Average time [seconds] a group will be suppressed. Default is 15 seconds. +-- @param #number Tmin (Optional) Minimum time [seconds] a group will be suppressed. Default is 5 seconds. +-- @param #number Tmax (Optional) Maximum time a group will be suppressed. Default is 25 seconds. +function SUPPRESSION:SetSuppressionTime(Tave, Tmin, Tmax) + + -- Minimum suppression time is input or default but at least 1 second. + self.Tsuppress_min=Tmin or self.Tsuppress_min + self.Tsuppress_min=math.max(self.Tsuppress_min, 1) + + -- Maximum suppression time is input or dault but at least Tmin. + self.Tsuppress_max=Tmax or self.Tsuppress_max + self.Tsuppress_max=math.max(self.Tsuppress_max, self.Tsuppress_min) + + -- Expected suppression time is input or default but at leat Tmin and at most Tmax. + self.Tsuppress_ave=Tave or self.Tsuppress_ave + self.Tsuppress_ave=math.max(self.Tsuppress_min) + self.Tsuppress_ave=math.min(self.Tsuppress_max) + + self:T(SUPPRESSION.id..string.format("Set ave suppression time to %d seconds.", self.Tsuppress_ave)) + self:T(SUPPRESSION.id..string.format("Set min suppression time to %d seconds.", self.Tsuppress_min)) + self:T(SUPPRESSION.id..string.format("Set max suppression time to %d seconds.", self.Tsuppress_max)) +end + +--- Set the zone to which a group retreats after being damaged too much. +-- @param #SUPPRESSION self +-- @param Core.Zone#ZONE zone MOOSE zone object. +function SUPPRESSION:SetRetreatZone(zone) + self.RetreatZone=zone +end + +--- Turn Debug mode on. Enables messages and more output to DCS log file. +-- @param #SUPPRESSION self +function SUPPRESSION:DebugOn() + self.Debug=true +end + +--- Flare units when they are hit, die or recover from suppression. +-- @param #SUPPRESSION self +function SUPPRESSION:FlareOn() + self.flare=true +end + +--- Smoke positions where units fall back to, hide or retreat. +-- @param #SUPPRESSION self +function SUPPRESSION:SmokeOn() + self.smoke=true +end + +--- Set the formation a group uses for fall back, hide or retreat. +-- @param #SUPPRESSION self +-- @param #string formation Formation of the group. Default "Vee". +function SUPPRESSION:SetFormation(formation) + self.Formation=formation or "Vee" +end + +--- Set speed a group moves at for fall back, hide or retreat. +-- @param #SUPPRESSION self +-- @param #number speed Speed in km/h of group. Default max speed the group can do. +function SUPPRESSION:SetSpeed(speed) + self.Speed=speed or self.SpeedMax + self.Speed=math.min(self.Speed, self.SpeedMax) +end + +--- Enable fall back if a group is hit. +-- @param #SUPPRESSION self +-- @param #boolean switch Enable=true or disable=false fall back of group. +function SUPPRESSION:Fallback(switch) + if switch==nil then + switch=true + end + self.FallbackON=switch +end + +--- Set distance a group will fall back when it gets hit. +-- @param #SUPPRESSION self +-- @param #number distance Distance in meters. +function SUPPRESSION:SetFallbackDistance(distance) + self.FallbackDist=distance +end + +--- Set time a group waits at its fall back position before it resumes its normal mission. +-- @param #SUPPRESSION self +-- @param #number time Time in seconds. +function SUPPRESSION:SetFallbackWait(time) + self.FallbackWait=time +end + +--- Enable take cover option if a unit is hit. +-- @param #SUPPRESSION self +-- @param #boolean switch Enable=true or disable=false fall back of group. +function SUPPRESSION:Takecover(switch) + if switch==nil then + switch=true + end + self.TakecoverON=switch +end + +--- Set time a group waits at its hideout position before it resumes its normal mission. +-- @param #SUPPRESSION self +-- @param #number time Time in seconds. +function SUPPRESSION:SetTakecoverWait(time) + self.TakecoverWait=time +end + +--- Set distance a group searches for hideout places. +-- @param #SUPPRESSION self +-- @param #number range Search range in meters. +function SUPPRESSION:SetTakecoverRange(range) + self.TakecoverRange=range +end + +--- Set hideout place explicitly. +-- @param #SUPPRESSION self +-- @param Core.Point#COORDINATE Hideout Place where the group will hide after the TakeCover event. +function SUPPRESSION:SetTakecoverPlace(Hideout) + self.hideout=Hideout +end + +--- Set minimum probability that a group flees (falls back or takes cover) after a hit event. Default is 10%. +-- @param #SUPPRESSION self +-- @param #number probability Probability in percent. +function SUPPRESSION:SetMinimumFleeProbability(probability) + self.PminFlee=probability or 10 +end + +--- Set maximum probability that a group flees (falls back or takes cover) after a hit event. Default is 90%. +-- @param #SUPPRESSION self +-- @param #number probability Probability in percent. +function SUPPRESSION:SetMaximumFleeProbability(probability) + self.PmaxFlee=probability or 90 +end + +--- Set damage threshold before a group is ordered to retreat if a retreat zone was defined. +-- If the group consists of only a singe unit, this referrs to the life of the unit. +-- If the group consists of more than one unit, this referrs to the group strength relative to its initial strength. +-- @param #SUPPRESSION self +-- @param #number damage Damage in percent. If group gets damaged above this value, the group will retreat. Default 50 %. +function SUPPRESSION:SetRetreatDamage(damage) + self.RetreatDamage=damage or 50 +end + +--- Set time a group waits in the retreat zone before it resumes its mission. Default is two hours. +-- @param #SUPPRESSION self +-- @param #number time Time in seconds. Default 7200 seconds = 2 hours. +function SUPPRESSION:SetRetreatWait(time) + self.RetreatWait=time or 7200 +end + +--- Set alarm state a group will get after it returns from a fall back or take cover. +-- @param #SUPPRESSION self +-- @param #string alarmstate Alarm state. Possible "Auto", "Green", "Red". Default is "Auto". +function SUPPRESSION:SetDefaultAlarmState(alarmstate) + if alarmstate:lower()=="auto" then + self.DefaultAlarmState=SUPPRESSION.AlarmState.Auto + elseif alarmstate:lower()=="green" then + self.DefaultAlarmState=SUPPRESSION.AlarmState.Green + elseif alarmstate:lower()=="red" then + self.DefaultAlarmState=SUPPRESSION.AlarmState.Red + else + self.DefaultAlarmState=SUPPRESSION.AlarmState.Auto + end +end + +--- Set Rules of Engagement (ROE) a group will get when it recovers from suppression. +-- @param #SUPPRESSION self +-- @param #string roe ROE after suppression. Possible "Free", "Hold" or "Return". Default "Free". +function SUPPRESSION:SetDefaultROE(roe) + if roe:lower()=="free" then + self.DefaultROE=SUPPRESSION.ROE.Free + elseif roe:lower()=="hold" then + self.DefaultROE=SUPPRESSION.ROE.Hold + elseif roe:lower()=="return" then + self.DefaultROE=SUPPRESSION.ROE.Return + else + self.DefaultROE=SUPPRESSION.ROE.Free + end +end + +--- Create an F10 menu entry for the suppressed group. The menu is mainly for Debugging purposes. +-- @param #SUPPRESSION self +-- @param #boolean switch Enable=true or disable=false menu group. Default is true. +function SUPPRESSION:MenuOn(switch) + if switch==nil then + switch=true + end + self.MenuON=switch +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Create F10 main menu, i.e. F10/Suppression. The menu is mainly for Debugging purposes. +-- @param #SUPPRESSION self +function SUPPRESSION:_CreateMenuGroup() + local SubMenuName=self.Controllable:GetName() + local MenuGroup=MENU_MISSION:New(SubMenuName, SUPPRESSION.MenuF10) + MENU_MISSION_COMMAND:New("Fallback!", MenuGroup, self.OrderFallBack, self) + MENU_MISSION_COMMAND:New("Take Cover!", MenuGroup, self.OrderTakeCover, self) + MENU_MISSION_COMMAND:New("Retreat!", MenuGroup, self.OrderRetreat, self) + MENU_MISSION_COMMAND:New("Report Status", MenuGroup, self.Status, self, true) +end + +--- Order group to fall back between 100 and 150 meters in a random direction. +-- @param #SUPPRESSION self +function SUPPRESSION:OrderFallBack() + local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + local vicinity=group:GetCoordinate():GetRandomVec2InRadius(150, 100) + local coord=COORDINATE:NewFromVec2(vicinity) + self:FallBack(self.Controllable) +end + +--- Order group to take cover at a nearby scenery object. +-- @param #SUPPRESSION self +function SUPPRESSION:OrderTakeCover() + -- Search place to hide or take specified one. + local Hideout=self.hideout + if self.hideout==nil then + Hideout=self:_SearchHideout() + end + -- Trigger TakeCover event. + self:TakeCover(Hideout) +end + +--- Order group to retreat to a pre-defined zone. +-- @param #SUPPRESSION self +function SUPPRESSION:OrderRetreat() + self:Retreat() +end + +--- Status of group. Current ROE, alarm state, life. +-- @param #SUPPRESSION self +-- @param #boolean message Send message to all players. +function SUPPRESSION:Status(message) + + local name=self.Controllable:GetName() + local nunits=#self.Controllable:GetUnits() + local roe=self.CurrentROE + local state=self.CurrentAlarmState + local life_min, life_max, life_ave, life_ave0, groupstrength=self:_GetLife() + + local text=string.format("Status of group %s\n", name) + text=text..string.format("Number of units: %d of %d\n", nunits, self.IniGroupStrength) + text=text..string.format("Current state: %s\n", self:GetState()) + text=text..string.format("ROE: %s\n", roe) + text=text..string.format("Alarm state: %s\n", state) + text=text..string.format("Hits taken: %d\n", self.Nhit) + text=text..string.format("Life min: %3.0f\n", life_min) + text=text..string.format("Life max: %3.0f\n", life_max) + text=text..string.format("Life ave: %3.0f\n", life_ave) + text=text..string.format("Life ave0: %3.0f\n", life_ave0) + text=text..string.format("Group strength: %3.0f", groupstrength) + + MESSAGE:New(text, 10):ToAllIf(message or self.Debug) + self:T(SUPPRESSION.id.."\n"..text) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- After "Start" event. Initialized ROE and alarm state. Starts the event handler. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterStart(Controllable, From, Event, To) + self:_EventFromTo("onafterStart", Event, From, To) + + local text=string.format("Started SUPPRESSION for group %s.", Controllable:GetName()) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + + local rzone="not defined" + if self.RetreatZone then + rzone=self.RetreatZone:GetName() + end + + -- Set retreat damage value if it was not set by user input. + if self.RetreatDamage==nil then + if self.RetreatZone then + if self.IniGroupStrength==1 then + self.RetreatDamage=60.0 -- 40% of life is left. + elseif self.IniGroupStrength==2 then + self.RetreatDamage=50.0 -- 50% of group left, i.e. 1 of 2. We already order a retreat, because if for a group 2 two a zone is defined it would not be used at all. + else + self.RetreatDamage=66.5 -- 34% of the group is left, e.g. 1 of 3,4 or 5, 2 of 6,7 or 8, 3 of 9,10 or 11, 4/12, 4/13, 4/14, 5/15, ... + end + else + self.RetreatDamage=100 -- If no retreat then this should be set to 100%. + end + end + + -- Create main F10 menu if it is not there yet. + if self.MenuON then + if not SUPPRESSION.MenuF10 then + SUPPRESSION.MenuF10 = MENU_MISSION:New("Suppression") + end + self:_CreateMenuGroup() + end + + -- Set the current ROE and alam state. + self:_SetAlarmState(self.DefaultAlarmState) + self:_SetROE(self.DefaultROE) + + local text=string.format("\n******************************************************\n") + text=text..string.format("Suppressed group = %s\n", Controllable:GetName()) + text=text..string.format("Type = %s\n", self.Type) + text=text..string.format("IsInfantry = %s\n", tostring(self.IsInfantry)) + text=text..string.format("Group strength = %d\n", self.IniGroupStrength) + text=text..string.format("Average time = %5.1f seconds\n", self.Tsuppress_ave) + text=text..string.format("Minimum time = %5.1f seconds\n", self.Tsuppress_min) + text=text..string.format("Maximum time = %5.1f seconds\n", self.Tsuppress_max) + text=text..string.format("Default ROE = %s\n", self.DefaultROE) + text=text..string.format("Default AlarmState = %s\n", self.DefaultAlarmState) + text=text..string.format("Fall back ON = %s\n", tostring(self.FallbackON)) + text=text..string.format("Fall back distance = %5.1f m\n", self.FallbackDist) + text=text..string.format("Fall back wait = %5.1f seconds\n", self.FallbackWait) + text=text..string.format("Fall back heading = %s degrees\n", tostring(self.FallbackHeading)) + text=text..string.format("Take cover ON = %s\n", tostring(self.TakecoverON)) + text=text..string.format("Take cover search = %5.1f m\n", self.TakecoverRange) + text=text..string.format("Take cover wait = %5.1f seconds\n", self.TakecoverWait) + text=text..string.format("Min flee probability = %5.1f\n", self.PminFlee) + text=text..string.format("Max flee probability = %5.1f\n", self.PmaxFlee) + text=text..string.format("Retreat zone = %s\n", rzone) + text=text..string.format("Retreat damage = %5.1f %%\n", self.RetreatDamage) + text=text..string.format("Retreat wait = %5.1f seconds\n", self.RetreatWait) + text=text..string.format("Speed = %5.1f km/h\n", self.Speed) + text=text..string.format("Speed max = %5.1f km/h\n", self.SpeedMax) + text=text..string.format("Formation = %s\n", self.Formation) + text=text..string.format("******************************************************\n") + self:T(SUPPRESSION.id..text) + + -- Add event handler. + if self.eventmoose then + self:HandleEvent(EVENTS.Hit, self._OnEventHit) + self:HandleEvent(EVENTS.Dead, self._OnEventDead) + else + world.addEventHandler(self) + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "Hit" event. (Of course, this is not really before the group got hit.) +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Unit#UNIT Unit Unit that was hit. +-- @param Wrapper.Unit#UNIT AttackUnit Unit that attacked. +-- @return boolean +function SUPPRESSION:onbeforeHit(Controllable, From, Event, To, Unit, AttackUnit) + self:_EventFromTo("onbeforeHit", Event, From, To) + + --local Tnow=timer.getTime() + --env.info(SUPPRESSION.id..string.format("Last hit = %s %s", tostring(self.LastHit), tostring(Tnow))) + + return true +end + +--- After "Hit" event. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Unit#UNIT Unit Unit that was hit. +-- @param Wrapper.Unit#UNIT AttackUnit Unit that attacked. +function SUPPRESSION:onafterHit(Controllable, From, Event, To, Unit, AttackUnit) + self:_EventFromTo("onafterHit", Event, From, To) + + -- Suppress unit. + if From=="CombatReady" or From=="Suppressed" then + self:_Suppress() + end + + -- Get life of group in %. + local life_min, life_max, life_ave, life_ave0, groupstrength=self:_GetLife() + + -- Damage in %. If group consists only of one unit, we take its life value. + local Damage=100-life_ave0 + + -- Condition for retreat. + local RetreatCondition = Damage >= self.RetreatDamage-0.01 and self.RetreatZone + + -- Probability that a unit flees. The probability increases linearly with the damage of the group/unit. + -- If Damage=0 ==> P=Pmin + -- if Damage=RetreatDamage ==> P=Pmax + -- If no retreat zone has been specified, RetreatDamage is 100. + local Pflee=(self.PmaxFlee-self.PminFlee)/self.RetreatDamage * math.min(Damage, self.RetreatDamage) + self.PminFlee + + -- Evaluate flee condition. + local P=math.random(0,100) + local FleeCondition = P < Pflee + + local text + text=string.format("\nGroup %s: Life min=%5.1f, max=%5.1f, ave=%5.1f, ave0=%5.1f group=%5.1f\n", Controllable:GetName(), life_min, life_max, life_ave, life_ave0, groupstrength) + text=string.format("Group %s: Damage = %8.4f (%8.4f retreat threshold).\n", Controllable:GetName(), Damage, self.RetreatDamage) + text=string.format("Group %s: P_Flee = %5.1f %5.1f=P_rand (P_Flee > Prand ==> Flee)\n", Controllable:GetName(), Pflee, P) + self:T(SUPPRESSION.id..text) + + -- Group is obviously destroyed. + if Damage >= 99.9 then + return + end + + if RetreatCondition then + + -- Trigger Retreat event. + self:Retreat() + + elseif FleeCondition then + + if self.FallbackON and AttackUnit:IsGround() then + + -- Trigger FallBack event. + self:FallBack(AttackUnit) + + elseif self.TakecoverON then + + -- Search place to hide or take specified one. + local Hideout=self.hideout + if self.hideout==nil then + Hideout=self:_SearchHideout() + end + + -- Trigger TakeCover event. + self:TakeCover(Hideout) + end + end + + -- Give info on current status. + if self.Debug then + self:Status() + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "Recovered" event. Check if suppression time is over. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @return #boolean +function SUPPRESSION:onbeforeRecovered(Controllable, From, Event, To) + self:_EventFromTo("onbeforeRecovered", Event, From, To) + + -- Current time. + local Tnow=timer.getTime() + + -- Debug info + self:T(SUPPRESSION.id..string.format("onbeforeRecovered: Time now: %d - Time over: %d", Tnow, self.TsuppressionOver)) + + -- Recovery is only possible if enough time since the last hit has passed. + if Tnow >= self.TsuppressionOver then + return true + else + return false + end + +end + +--- After "Recovered" event. Group has recovered and its ROE is set back to the "normal" unsuppressed state. Optionally the group is flared green. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterRecovered(Controllable, From, Event, To) + self:_EventFromTo("onafterRecovered", Event, From, To) + + if Controllable and Controllable:IsAlive() then + + -- Debug message. + local text=string.format("Group %s has recovered!", Controllable:GetName()) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + self:T(SUPPRESSION.id..text) + + -- Set ROE back to default. + self:_SetROE() + + -- Flare unit green. + if self.flare or self.Debug then + Controllable:FlareGreen() + end + + end +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- After "FightBack" event. ROE and Alarm state are set back to default. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterFightBack(Controllable, From, Event, To) + self:_EventFromTo("onafterFightBack", Event, From, To) + + -- Set ROE and alarm state back to default. + self:_SetROE() + self:_SetAlarmState() +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "FallBack" event. We check that group is not already falling back. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Unit#UNIT AttackUnit Attacking unit. We will move away from this. +-- @return #boolean +function SUPPRESSION:onbeforeFallBack(Controllable, From, Event, To, AttackUnit) + self:_EventFromTo("onbeforeFallBack", Event, From, To) + + --TODO: Add retreat? Only allowd transition is Suppressed-->Fallback. So in principle no need. + if From == "FallingBack" then + return false + else + return true + end +end + +--- After "FallBack" event. We get the heading away from the attacker and route the group a certain distance in that direction. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Unit#UNIT AttackUnit Attacking unit. We will move away from this. +function SUPPRESSION:onafterFallBack(Controllable, From, Event, To, AttackUnit) + self:_EventFromTo("onafterFallback", Event, From, To) + + -- Debug info + self:T(SUPPRESSION.id..string.format("Group %s is falling back after %d hits.", Controllable:GetName(), self.Nhit)) + + -- Coordinate of the attacker and attacked unit. + local ACoord=AttackUnit:GetCoordinate() + local DCoord=Controllable:GetCoordinate() + + -- Heading from attacker to attacked unit. + local heading=self:_Heading(ACoord, DCoord) + + -- Overwrite heading with user specified heading. + if self.FallbackHeading then + heading=self.FallbackHeading + end + + -- Create a coordinate ~ 100 m in opposite direction of the attacking unit. + local Coord=DCoord:Translate(self.FallbackDist, heading) + + -- Place marker + local MarkerID=Coord:MarkToAll("Fall back position for group "..Controllable:GetName()) + + -- Smoke the coordinate. + if self.smoke or self.Debug then + Coord:SmokeBlue() + end + + -- Set ROE to weapon hold. + self:_SetROE(SUPPRESSION.ROE.Hold) + + -- Set alarm state to GREEN and let the unit run away. + self:_SetAlarmState(SUPPRESSION.AlarmState.Green) + + -- Make the group run away. + self:_Run(Coord, self.Speed, self.Formation, self.FallbackWait) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "TakeCover" event. Search an area around the group for possible scenery objects where the group can hide. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Core.Point#COORDINATE Hideout Place where the group will hide. +-- @return #boolean +function SUPPRESSION:onbeforeTakeCover(Controllable, From, Event, To, Hideout) + self:_EventFromTo("onbeforeTakeCover", Event, From, To) + + --TODO: Need to test this! + if From=="TakingCover" then + return false + end + + -- Block transition if no hideout place is given. + if Hideout ~= nil then + return true + else + return false + end + +end + +--- After "TakeCover" event. Group will run to a nearby scenery object and "hide" there for a certain time. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Core.Point#COORDINATE Hideout Place where the group will hide. +function SUPPRESSION:onafterTakeCover(Controllable, From, Event, To, Hideout) + self:_EventFromTo("onafterTakeCover", Event, From, To) + + if self.Debug then + local MarkerID=Hideout:MarkToAll(string.format("Hideout for group %s", Controllable:GetName())) + end + + -- Smoke place of hideout. + if self.smoke or self.Debug then + Hideout:SmokeBlue() + end + + -- Set ROE to weapon hold. + self:_SetROE(SUPPRESSION.ROE.Hold) + + -- Set the ALARM STATE to GREEN. Then the unit will move even if it is under fire. + self:_SetAlarmState(SUPPRESSION.AlarmState.Green) + + -- Make the group run away. + self:_Run(Hideout, self.Speed, self.Formation, self.TakecoverWait) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "Retreat" event. We check that the group is not already retreating. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @return #boolean True if transition is allowed, False if transition is forbidden. +function SUPPRESSION:onbeforeRetreat(Controllable, From, Event, To) + self:_EventFromTo("onbeforeRetreat", Event, From, To) + + if From=="Retreating" then + local text=string.format("Group %s is already retreating.") + self:T2(SUPPRESSION.id..text) + return false + else + return true + end + +end + +--- After "Retreat" event. Find a random point in the retreat zone and route the group there. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterRetreat(Controllable, From, Event, To) + self:_EventFromTo("onafterRetreat", Event, From, To) + + -- Route the group to a zone. + local text=string.format("Group %s is retreating! Alarm state green.", Controllable:GetName()) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + self:T(SUPPRESSION.id..text) + + -- Get a random point in the retreat zone. + local ZoneCoord=self.RetreatZone:GetRandomCoordinate() -- Core.Point#COORDINATE + local ZoneVec2=ZoneCoord:GetVec2() + + -- Debug smoke zone and point. + if self.smoke or self.Debug then + ZoneCoord:SmokeBlue() + end + if self.Debug then + self.RetreatZone:SmokeZone(SMOKECOLOR.Red, 12) + end + + -- Set ROE to weapon hold. + self:_SetROE(SUPPRESSION.ROE.Hold) + + -- Set the ALARM STATE to GREEN. Then the unit will move even if it is under fire. + self:_SetAlarmState(SUPPRESSION.AlarmState.Green) + + -- Make unit run to retreat zone and wait there for ~two hours. + self:_Run(ZoneCoord, self.Speed, self.Formation, self.RetreatWait) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "Retreateded" event. Check that the group is really in the retreat zone. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onbeforeRetreated(Controllable, From, Event, To) + self:_EventFromTo("onbeforeRetreated", Event, From, To) + + -- Check that the group is inside the zone. + local inzone=self.RetreatZone:IsVec3InZone(Controllable:GetVec3()) + + return inzone +end + +--- After "Retreateded" event. Group has reached the retreat zone. Set ROE to return fire and alarm state to auto. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterRetreated(Controllable, From, Event, To) + self:_EventFromTo("onafterRetreated", Event, From, To) + + -- Set ROE to weapon return fire. + self:_SetROE(SUPPRESSION.ROE.Return) + + -- Set the ALARM STATE to GREEN. Then the unit will move even if it is under fire. + self:_SetAlarmState(SUPPRESSION.AlarmState.Auto) + + -- TODO: Add hold task? Move from _Run() +end + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- After "Dead" event, when a unit has died. When all units of a group are dead, FSM is stopped and eventhandler removed. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function SUPPRESSION:onafterDead(Controllable, From, Event, To) + self:_EventFromTo("onafterDead", Event, From, To) + + -- Number of units left in the group. + local nunits=#self.Controllable:GetUnits() + + local text=string.format("Group %s: One of our units just died! %d units left.", self.Controllable:GetName(), nunits) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + self:T(SUPPRESSION.id..text) + + -- Go to stop state. + if nunits==0 then + self:T(SUPPRESSION.id..string.format("Stopping SUPPRESSION for group %s.", Controllable:GetName())) + self:Stop() + if self.mooseevents then + self:UnHandleEvent(EVENTS.Dead) + self:UnHandleEvent(EVENTS.Hit) + else + world.removeEventHandler(self) + end + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Event Handler +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Event handler for suppressed groups. +--@param #SUPPRESSION self +function SUPPRESSION:onEvent(Event) + --self:E(event) + + if Event == nil or Event.initiator == nil or Unit.getByName(Event.initiator:getName()) == nil then + return true + end + + local EventData={} + if Event.initiator then + EventData.IniDCSUnit = Event.initiator + EventData.IniUnitName = Event.initiator:getName() + EventData.IniDCSGroup = Event.initiator:getGroup() + EventData.IniGroupName = Event.initiator:getGroup():getName() + EventData.IniGroup = GROUP:FindByName(EventData.IniGroupName) + EventData.IniUnit = UNIT:FindByName(EventData.IniUnitName) + end + + if Event.target then + EventData.TgtDCSUnit = Event.target + EventData.TgtUnitName = Event.target:getName() + EventData.TgtDCSGroup = Event.target:getGroup() + EventData.TgtGroupName = Event.target:getGroup():getName() + EventData.TgtGroup = GROUP:FindByName(EventData.TgtGroupName) + EventData.TgtUnit = UNIT:FindByName(EventData.TgtUnitName) + end + + + -- Event HIT + if Event.id == world.event.S_EVENT_HIT then + self:_OnEventHit(EventData) + end + + -- Event HIT + if Event.id == world.event.S_EVENT_DEAD then + self:_OnEventDead(EventData) + end + +end + +--- Event handler for Dead event of suppressed groups. +-- @param #SUPPRESSION self +-- @param Core.Event#EVENTDATA EventData +function SUPPRESSION:_OnEventHit(EventData) + + local GroupNameSelf=self.Controllable:GetName() + local GroupNameTgt=EventData.TgtGroupName + local TgtUnit=EventData.TgtUnit + local tgt=EventData.TgtDCSUnit + local IniUnit=EventData.IniUnit + + -- Check that correct group was hit. + if GroupNameTgt == GroupNameSelf then + + self:T2(SUPPRESSION.id..string.format("Hit event at t = %5.1f", timer.getTime())) + + -- Flare unit that was hit. + if self.flare or self.Debug then + TgtUnit:FlareRed() + end + + -- Increase Hit counter. + self.Nhit=self.Nhit+1 + + -- Info on hit times. + self:T(SUPPRESSION.id..string.format("Group %s has just been hit %d times.", self.Controllable:GetName(), self.Nhit)) + + --self:Status() + local life=tgt:getLife()/(tgt:getLife0()+1)*100 + self:T2(SUPPRESSION.id..string.format("Target unit life = %5.1f", life)) + + -- FSM Hit event. + self:__Hit(3, TgtUnit, IniUnit) + end + +end + +--- Event handler for Dead event of suppressed groups. +-- @param #SUPPRESSION self +-- @param Core.Event#EVENTDATA EventData +function SUPPRESSION:_OnEventDead(EventData) + + local GroupNameSelf=self.Controllable:GetName() + local GroupNameIni=EventData.IniGroupName + + -- Check for correct group. + if GroupNameIni== GroupNameSelf then + + -- Dead Unit. + local IniUnit=EventData.IniUnit --Wrapper.Unit#UNIT + local IniUnitName=EventData.IniUnitName + + if EventData.IniUnit then + self:T2(SUPPRESSION.id..string.format("Group %s: Dead MOOSE unit DOES exist! Unit name %s.", GroupNameIni, IniUnitName)) + else + self:T2(SUPPRESSION.id..string.format("Group %s: Dead MOOSE unit DOES NOT not exist! Unit name %s.", GroupNameIni, IniUnitName)) + end + + if EventData.IniDCSUnit then + self:T2(SUPPRESSION.id..string.format("Group %s: Dead DCS unit DOES exist! Unit name %s.", GroupNameIni, IniUnitName)) + else + self:T2(SUPPRESSION.id..string.format("Group %s: Dead DCS unit DOES NOT exist! Unit name %s.", GroupNameIni, IniUnitName)) + end + + -- Flare unit that died. + if IniUnit and (self.flare or self.Debug) then + IniUnit:FlareWhite() + self:T(SUPPRESSION.id..string.format("Flare Dead MOOSE unit.")) + end + + -- Flare unit that died. + if EventData.IniDCSUnit and (self.flare or self.Debug) then + local p=EventData.IniDCSUnit:getPosition().p + trigger.action.signalFlare(p, trigger.flareColor.Yellow , 0) + self:T(SUPPRESSION.id..string.format("Flare Dead DCS unit.")) + end + + -- Get status. + self:Status() + + -- FSM Dead event. + self:__Dead(0.1) + + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Suppress fire of a unit by setting its ROE to "Weapon Hold". +-- @param #SUPPRESSION self +function SUPPRESSION:_Suppress() + + -- Current time. + local Tnow=timer.getTime() + + -- Controllable + local Controllable=self.Controllable --Wrapper.Controllable#CONTROLLABLE + + -- Group will hold their weapons. + self:_SetROE(SUPPRESSION.ROE.Hold) + + -- Get randomized time the unit is suppressed. + local sigma=(self.Tsuppress_max-self.Tsuppress_min)/4 + local Tsuppress=self:_Random_Gaussian(self.Tsuppress_ave,sigma,self.Tsuppress_min, self.Tsuppress_max) + + -- Time at which the suppression is over. + local renew=true + if self.TsuppressionOver ~= nil then + if Tsuppress+Tnow > self.TsuppressionOver then + self.TsuppressionOver=Tnow+Tsuppress + else + renew=false + end + else + self.TsuppressionOver=Tnow+Tsuppress + end + + -- Recovery event will be called in Tsuppress seconds. + if renew then + self:__Recovered(self.TsuppressionOver-Tnow) + end + + -- Debug message. + local text=string.format("Group %s is suppressed for %d seconds. Suppression ends at %d:%02d.", Controllable:GetName(), Tsuppress, self.TsuppressionOver/60, self.TsuppressionOver%60) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + self:T(SUPPRESSION.id..text) + +end + + +--- Make group run/drive to a certain point. We put in several intermediate waypoints because sometimes the group stops before it arrived at the desired point. +--@param #SUPPRESSION self +--@param Core.Point#COORDINATE fin Coordinate where we want to go. +--@param #number speed Speed of group. Default is 999. +--@param #string formation Formation of group. Default is "Vee". +--@param #number wait Time the group will wait/hold at final waypoint. Default is 30 seconds. +function SUPPRESSION:_Run(fin, speed, formation, wait) + + speed=speed or 999 + formation=formation or "Vee" + wait=wait or 30 + + local group=self.Controllable -- Wrapper.Controllable#CONTROLLABLE + + -- Clear all tasks. + group:ClearTasks() + + -- Current coordinates of group. + local ini=group:GetCoordinate() + + -- Distance between current and final point. + local dist=ini:Get2DDistance(fin) + + -- Heading from ini to fin. + local heading=self:_Heading(ini, fin) + + -- Number of waypoints. + local nx + if dist <= 50 then + nx=2 + elseif dist <= 100 then + nx=3 + elseif dist <= 500 then + nx=4 + else + nx=5 + end + + -- Number of intermediate waypoints. + local dx=dist/(nx-1) + + -- Waypoint and task arrays. + local wp={} + local tasks={} + + -- First waypoint is the current position of the group. + wp[1]=ini:WaypointGround(speed, formation) + local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName())) + tasks[1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, 1, false) + + self:T2(SUPPRESSION.id..string.format("Number of waypoints %d", nx)) + for i=1,nx-2 do + + local x=dx*i + local coord=ini:Translate(x, heading) + + wp[#wp+1]=coord:WaypointGround(speed, formation) + tasks[#tasks+1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, false) + + self:T2(SUPPRESSION.id..string.format("%d x = %4.1f", i, x)) + if self.Debug then + local MarkerID=coord:MarkToAll(string.format("Waypoing %d of group %s", #wp, self.Controllable:GetName())) + end + + end + self:T2(SUPPRESSION.id..string.format("Total distance: %4.1f", dist)) + + -- Final waypoint. + wp[#wp+1]=fin:WaypointGround(speed, formation) + if self.Debug then + local MarkerID=fin:MarkToAll(string.format("Waypoing %d of group %s (final)", #wp, self.Controllable:GetName())) + end + + -- Task to hold. + local ConditionWait=group:TaskCondition(nil, nil, nil, nil, wait, nil) + local TaskHold = group:TaskHold() + + -- Task combo to make group hold at final waypoint. + local TaskComboFin = {} + TaskComboFin[#TaskComboFin+1] = group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, true) + TaskComboFin[#TaskComboFin+1] = group:TaskControlled(TaskHold, ConditionWait) + + -- Add final task. + tasks[#tasks+1]=group:TaskCombo(TaskComboFin) + + -- Original waypoints of the group. + local Waypoints = group:GetTemplateRoutePoints() + + -- New points are added to the default route. + for i,p in ipairs(wp) do + table.insert(Waypoints, i, wp[i]) + end + + -- Set task for all waypoints. + for i,wp in ipairs(Waypoints) do + group:SetTaskWaypoint(Waypoints[i], tasks[i]) + end + + -- Submit task and route group along waypoints. + group:Route(Waypoints) + +end + +--- Function called when group is passing a waypoint. At the last waypoint we set the group back to CombatReady. +--@param Wrapper.Group#GROUP group Group which is passing a waypoint. +--@param #SUPPRESSION Fsm The suppression object. +--@param #number i Waypoint number that has been reached. +--@param #boolean final True if it is the final waypoint. Start Fightback. +function SUPPRESSION._Passing_Waypoint(group, Fsm, i, final) + + -- Debug message. + local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final)) + MESSAGE:New(text,10):ToAllIf(Fsm.Debug) + if Fsm.Debug then + env.info(SUPPRESSION.id..text) + end + + if final then + if Fsm:is("Retreating") then + -- Retreated-->Retreated. + Fsm:Retreated() + else + -- FightBack-->Combatready: Change alarm state back to default. + Fsm:FightBack() + end + end +end + + +--- Search a place to hide. This is any scenery object in the vicinity. +--@param #SUPPRESSION self +--@return Core.Point#COORDINATE Coordinate of the hideout place. +--@return nil If no scenery object is within search radius. +function SUPPRESSION:_SearchHideout() + -- We search objects in a zone with radius ~300 m around the group. + local Zone = ZONE_GROUP:New("Zone_Hiding", self.Controllable, self.TakecoverRange) + local gpos = self.Controllable:GetCoordinate() + + -- Scan for Scenery objects to run/drive to. + Zone:Scan(Object.Category.SCENERY) + + -- Array with all possible hideouts, i.e. scenery objects in the vicinity of the group. + local hideouts={} + + for SceneryTypeName, SceneryData in pairs(Zone:GetScannedScenery()) do + for SceneryName, SceneryObject in pairs(SceneryData) do + + local SceneryObject = SceneryObject -- Wrapper.Scenery#SCENERY + + -- Position of the scenery object. + local spos=SceneryObject:GetCoordinate() + + -- Distance from group to hideout. + local distance= spos:Get2DDistance(gpos) + + if self.Debug then + -- Place markers on every possible scenery object. + local MarkerID=SceneryObject:GetCoordinate():MarkToAll(string.format("%s scenery object %s", self.Controllable:GetName(),SceneryObject:GetTypeName())) + local text=string.format("%s scenery: %s, Coord %s", self.Controllable:GetName(), SceneryObject:GetTypeName(), SceneryObject:GetCoordinate():ToStringLLDMS()) + self:T2(SUPPRESSION.id..text) + end + + -- Add to table. + table.insert(hideouts, {object=SceneryObject, distance=distance}) + end + end + + -- Get random hideout place. + local Hideout=nil + if #hideouts>0 then + + -- Debug info. + self:T(SUPPRESSION.id.."Number of hideouts "..#hideouts) + + -- Sort results table wrt number of hits. + local _sort = function(a,b) return a.distance < b.distance end + table.sort(hideouts,_sort) + + -- Pick a random location. + --Hideout=hideouts[math.random(#hideouts)].object + + -- Pick closest location. + Hideout=hideouts[1].object:GetCoordinate() + + else + self:E(SUPPRESSION.id.."No hideouts found!") + end + + return Hideout + +end + +--- Get (relative) life in percent of a group. Function returns the value of the units with the smallest and largest life. Also the average value of all groups is returned. +-- @param #SUPPRESSION self +-- @return #number Smallest life value of all units. +-- @return #number Largest life value of all units. +-- @return #number Average life value of all alife groups +-- @return #number Average life value of all groups including already dead ones. +-- @return #number Relative group strength. +function SUPPRESSION:_GetLife() + + local group=self.Controllable --Wrapper.Group#GROUP + + if group and group:IsAlive() then + + local units=group:GetUnits() + + local life_min=nil + local life_max=nil + local life_ave=0 + local life_ave0=0 + local n=0 + + local groupstrength=#units/self.IniGroupStrength*100 + + self.T2(SUPPRESSION.id..string.format("Group %s _GetLife nunits = %d", self.Controllable:GetName(), #units)) + + for _,unit in pairs(units) do + + local unit=unit -- Wrapper.Unit#UNIT + if unit and unit:IsAlive() then + n=n+1 + local life=unit:GetLife()/(unit:GetLife0()+1)*100 + if life_min==nil or life < life_min then + life_min=life + end + if life_max== nil or life > life_max then + life_max=life + end + life_ave=life_ave+life + if self.Debug then + local text=string.format("n=%02d: Life = %3.1f, Life0 = %3.1f, min=%3.1f, max=%3.1f, ave=%3.1f, group=%3.1f", n, unit:GetLife(), unit:GetLife0(), life_min, life_max, life_ave/n,groupstrength) + self:T2(SUPPRESSION.id..text) + end + end + + end + + -- If the counter did not increase (can happen!) return 0 + if n==0 then + return 0,0,0,0,0 + end + + -- Average life relative to initial group strength including the dead ones. + life_ave0=life_ave/self.IniGroupStrength + + -- Average life of all alive units. + life_ave=life_ave/n + + return life_min, life_max, life_ave, life_ave0, groupstrength + else + return 0, 0, 0, 0, 0 + end +end + + +--- Heading from point a to point b in degrees. +--@param #SUPPRESSION self +--@param Core.Point#COORDINATE a Coordinate. +--@param Core.Point#COORDINATE b Coordinate. +--@return #number angle Angle from a to b in degrees. +function SUPPRESSION:_Heading(a, b, distance) + local dx = b.x-a.x + local dy = b.z-a.z + local angle = math.deg(math.atan2(dy,dx)) + if angle < 0 then + angle = 360 + angle + end + return angle +end + +--- Generate Gaussian pseudo-random numbers. +-- @param #SUPPRESSION self +-- @param #number x0 Expectation value of distribution. +-- @param #number sigma (Optional) Standard deviation. Default 10. +-- @param #number xmin (Optional) Lower cut-off value. +-- @param #number xmax (Optional) Upper cut-off value. +-- @return #number Gaussian random number. +function SUPPRESSION:_Random_Gaussian(x0, sigma, xmin, xmax) + + -- Standard deviation. Default 5 if not given. + sigma=sigma or 5 + + local r + local gotit=false + local i=0 + while not gotit do + + -- Uniform numbers in [0,1). We need two. + local x1=math.random() + local x2=math.random() + + -- Transform to Gaussian exp(-(x-x0)²/(2*sigma²). + r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0 + + i=i+1 + if (r>=xmin and r<=xmax) or i>100 then + gotit=true + end + end + + return r + +end + +--- Sets the ROE for the group and updates the current ROE variable. +-- @param #SUPPRESSION self +-- @param #string roe ROE the group will get. Possible "Free", "Hold", "Return". Default is self.DefaultROE. +function SUPPRESSION:_SetROE(roe) + local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + + -- If no argument is given, we take the default ROE. + roe=roe or self.DefaultROE + + -- Update the current ROE. + self.CurrentROE=roe + + -- Set the ROE. + if roe==SUPPRESSION.ROE.Free then + group:OptionROEOpenFire() + elseif roe==SUPPRESSION.ROE.Hold then + group:OptionROEHoldFire() + elseif roe==SUPPRESSION.ROE.Return then + group:OptionROEReturnFire() + else + self:E(SUPPRESSION.id.."Unknown ROE requested: "..tostring(roe)) + group:OptionROEOpenFire() + self.CurrentROE=SUPPRESSION.ROE.Free + end + + local text=string.format("Group %s now has ROE %s.", self.Controllable:GetName(), self.CurrentROE) + self:T(SUPPRESSION.id..text) +end + +--- Sets the alarm state of the group and updates the current alarm state variable. +-- @param #SUPPRESSION self +-- @param #string state Alarm state the group will get. Possible "Auto", "Green", "Red". Default is self.DefaultAlarmState. +function SUPPRESSION:_SetAlarmState(state) + local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + + -- Input or back to default alarm state. + state=state or self.DefaultAlarmState + + -- Update the current alam state of the group. + self.CurrentAlarmState=state + + -- Set the alarm state. + if state==SUPPRESSION.AlarmState.Auto then + group:OptionAlarmStateAuto() + elseif state==SUPPRESSION.AlarmState.Green then + group:OptionAlarmStateGreen() + elseif state==SUPPRESSION.AlarmState.Red then + group:OptionAlarmStateRed() + else + self:E(SUPPRESSION.id.."Unknown alarm state requested: "..tostring(state)) + group:OptionAlarmStateAuto() + self.CurrentAlarmState=SUPPRESSION.AlarmState.Auto + end + + local text=string.format("Group %s now has Alarm State %s.", self.Controllable:GetName(), self.CurrentAlarmState) + self:T(SUPPRESSION.id..text) +end + +--- Print event-from-to string to DCS log file. +-- @param #SUPPRESSION self +-- @param #string BA Before/after info. +-- @param #string Event Event. +-- @param #string From From state. +-- @param #string To To state. +function SUPPRESSION:_EventFromTo(BA, Event, From, To) + local text=string.format("\n%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) + self:T(SUPPRESSION.id..text) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + From 0d995d183284e4944f09c54fb44b3be6b739e584 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 4 Apr 2018 14:38:49 +0200 Subject: [PATCH 027/170] Progress --- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 305 ++++++++++++++---- 1 file changed, 244 insertions(+), 61 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index df9c36dec..ca96b2d87 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -178,6 +178,9 @@ do -- TASK_CARGO_DISPATCHER Tasks = {}, CSAR = {}, CSARSpawned = 0, + + Transport = {}, + TransportCount = 0, } @@ -214,62 +217,163 @@ do -- TASK_CARGO_DISPATCHER return self end - + + + --- Handle the event when a pilot ejects. -- @param #TASK_CARGO_DISPATCHER self -- @param Core.Event#EVENTDATA EventData function TASK_CARGO_DISPATCHER:OnEventEjection( EventData ) + self:F( { EventData = EventData } ) + + if self.CSARTasks == true then - self:E( { EventData = EventData } ) - - self.CSARSpawned = self.CSARSpawned + 1 - - local PlaneUnit = EventData.IniUnit - local CSARName = EventData.IniUnitName - - local CargoPointVec2 = EventData.IniUnit:GetPointVec2() - local CargoCoalition = EventData.IniUnit:GetCoalition() - local CargoCountry = EventData.IniUnit:GetCountry() - - -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. - - if CargoCoalition == self.Mission:GetCommandCenter():GetCoalition() then - - -- Create the CSAR Pilot SPAWN object. - -- Let us create the Template for the replacement Pilot :-) - local Template = { - ["visible"] = false, - ["hidden"] = false, - ["task"] = "Ground Nothing", - ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), - ["x"] = CargoPointVec2:GetLat(), - ["y"] = CargoPointVec2:GetLon(), - ["units"] = - { - [1] = - { - ["type"] = ( CargoCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", - ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), - ["skill"] = "Excellent", - ["playerCanDrive"] = false, - ["x"] = CargoPointVec2:GetLat(), - ["y"] = CargoPointVec2:GetLon(), - ["heading"] = EventData.IniUnit:GetHeading(), - }, -- end of [1] - }, -- end of ["units"] - } - - local CargoGroup = GROUP:NewTemplate( Template, CargoCoalition, Group.Category.GROUND, CargoCountry ) - - self.CSAR[#self.CSAR+1] = {} - self.CSAR[#self.CSAR].PilotGroup = CargoGroup - self.CSAR[#self.CSAR].Task = nil - + local CSARCoordinate = EventData.IniUnit:GetCoordinate() + local CSARCoalition = EventData.IniUnit:GetCoalition() + local CSARCountry = EventData.IniUnit:GetCountry() + local CSARHeading = EventData.IniUnit:GetHeading() + + -- Only add a CSAR task if the coalition of the mission is equal to the coalition of the ejected unit. + if CSARCoalition == self.Mission:GetCommandCenter():GetCoalition() then + local CSARTaskName = self:AddCSARTask( self.CSARTaskName, CSARCoordinate, CSARHeading, CSARCountry, self.CSARBriefing ) + self:SetCSARDeployZones( CSARTaskName, self.CSARDeployZones ) + end end return self end + + + --- Define one default deploy zone for all the cargo tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DefaultDeployZone A default deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetDefaultDeployZone( DefaultDeployZone ) + + self.DefaultDeployZones = { DefaultDeployZone } + + return self + end + + + --- Define the deploy zones for all the cargo tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param DefaultDeployZones A list of the deploy zones. + -- @return #TASK_CARGO_DISPATCHER + -- + function TASK_CARGO_DISPATCHER:SetDefaultDeployZones( DefaultDeployZones ) + + self.DefaultDeployZones = DefaultDeployZones + + return self + end + + + --- Start the generation of CSAR tasks to retrieve a downed pilots. + -- You need to specify a task briefing, a task name, default deployment zone(s). + -- This method can only be used once! + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string CSARTaskName The CSAR task name. + -- @param #string CSARDeployZones The zones to where the CSAR deployment should be directed. + -- @param #string CSARBriefing The briefing of the CSAR tasks. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:StartCSARTasks( CSARTaskName, CSARDeployZones, CSARBriefing) + + if not self.CSARTasks then + self.CSARTasks = true + self.CSARTaskName = CSARTaskName + self.CSARDeployZones = CSARDeployZones + self.CSARBriefing = CSARBriefing + else + error( "TASK_CARGO_DISPATCHER: The generation of CSAR tasks has already started." ) + end + + return self + end + + + --- Stop the generation of CSAR tasks to retrieve a downed pilots. + -- @param #TASK_CARGO_DISPATCHER self + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:StopCSARTasks() + + if self.CSARTasks then + self.CSARTasks = nil + self.CSARTaskName = nil + self.CSARDeployZones = nil + self.CSARBriefing = nil + else + error( "TASK_CARGO_DISPATCHER: The generation of CSAR tasks was not yet started." ) + end + + return self + end + + + --- Add a CSAR task to retrieve a downed pilot. + -- You need to specify a coordinate from where the pilot will be spawned to be rescued. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string CSARTaskPrefix (optional) The prefix of the CSAR task. + -- @param Core.Point#COORDINATE CSARCoordinate The coordinate where a downed pilot will be spawned. + -- @param #number CSARHeading The heading of the pilot in degrees. + -- @param DCSCountry#Country CSARCountry The country ID of the pilot that will be spawned. + -- @param #string CSARBriefing The briefing of the CSAR task. + -- @return #string The CSAR Task Name as a string. The Task Name is the main key and is shown in the task list of the Mission Tasking menu. + -- @usage + -- + -- -- Add a CSAR task to rescue a downed pilot from within a coordinate. + -- local Coordinate = PlaneUnit:GetPointVec2() + -- TaskA2ADispatcher:AddCSARTask( Coordinate ) + -- + -- -- Add a CSAR task to rescue a downed pilot from within a coordinate of country RUSSIA, which is pointing to the west (270°). + -- local Coordinate = PlaneUnit:GetPointVec2() + -- TaskA2ADispatcher:AddCSARTask( Coordinate, 270, Country.RUSSIA ) + -- + function TASK_CARGO_DISPATCHER:AddCSARTask( CSARTaskPrefix, CSARCoordinate, CSARHeading, CSARCountry, CSARBriefing ) + + local CSARCoalition = self.Mission:GetCommandCenter():GetCoalition() + + CSARHeading = CSARHeading or 0 + CSARCountry = CSARCountry or self.Mission:GetCommandCenter():GetCountry() + + self.CSARSpawned = self.CSARSpawned + 1 + + local CSARTaskName = string.format( ( CSARTaskPrefix or "CSAR" ) .. ".%03d", self.CSARSpawned ) + + -- Create the CSAR Pilot SPAWN object. + -- Let us create the Template for the replacement Pilot :-) + local Template = { + ["visible"] = false, + ["hidden"] = false, + ["task"] = "Ground Nothing", + ["name"] = string.format( "CSAR Pilot#%03d", self.CSARSpawned ), + ["x"] = CSARCoordinate.x, + ["y"] = CSARCoordinate.z, + ["units"] = + { + [1] = + { + ["type"] = ( CSARCoalition == coalition.side.BLUE ) and "Soldier M4" or "Infantry AK", + ["name"] = string.format( "CSAR Pilot#%03d-01", self.CSARSpawned ), + ["skill"] = "Excellent", + ["playerCanDrive"] = false, + ["x"] = CSARCoordinate.x, + ["y"] = CSARCoordinate.z, + ["heading"] = CSARHeading, + }, -- end of [1] + }, -- end of ["units"] + } + + local CSARGroup = GROUP:NewTemplate( Template, CSARCoalition, Group.Category.GROUND, CSARCountry ) + + self.CSAR[CSARTaskName] = {} + self.CSAR[CSARTaskName].PilotGroup = CSARGroup + self.CSAR[CSARTaskName].Briefing = CSARBriefing + self.CSAR[CSARTaskName].Task = nil + + return CSARTaskName + end --- Define the radius to when a CSAR task will be generated for any downed pilot within range of the nearest CSAR airbase. @@ -294,11 +398,14 @@ do -- TASK_CARGO_DISPATCHER --- Define one deploy zone for the CSAR tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param DeployZone A deploy zone. + -- @param #string CSARTaskName (optional) The name of the CSAR task. + -- @param CSARDeployZone A CSAR deploy zone. -- @return #TASK_CARGO_DISPATCHER - function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARDeployZone ) + function TASK_CARGO_DISPATCHER:SetCSARDeployZone( CSARTaskName, CSARDeployZone ) - self.CSARDeployZones = { CSARDeployZone } + if CSARTaskName then + self.CSAR[CSARTaskName].DeployZones = { CSARDeployZone } + end return self end @@ -306,16 +413,73 @@ do -- TASK_CARGO_DISPATCHER --- Define the deploy zones for the CSAR tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param CSARDeployZones A list of the deploy zones. + -- @param #string CSARTaskName (optional) The name of the CSAR task. + -- @param CSARDeployZones A list of the CSAR deploy zones. -- @return #TASK_CARGO_DISPATCHER - function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARDeployZones ) + -- + function TASK_CARGO_DISPATCHER:SetCSARDeployZones( CSARTaskName, CSARDeployZones ) - self.CSARDeployZones = CSARDeployZones + if CSARTaskName and self.CSAR[CSARTaskName] then + self.CSAR[CSARTaskName].DeployZones = CSARDeployZones + end + + return self + end + + + --- Add a Transport task to transport cargo from fixed locations to a deployment zone. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TransportTaskName (optional) The name of the transport task. + -- @param Core.SetCargo#SET_CARGO SetCargo The SetCargo to be transported. + -- @param #string Briefing The briefing of the task transport to be shown to the player. + -- @return #TASK_CARGO_DISPATCHER + -- @usage + -- + -- -- Add a Transport task to transport cargo of different types to a Transport Deployment Zone. + function TASK_CARGO_DISPATCHER:AddTransportTask( TransportTaskName, SetCargo, Briefing ) + + self.TransportCount = self.TransportCount + 1 + local TaskName = string.format( ( TransportTaskName or "Transport" ) .. ".%03d", self.TransportCount ) + + self.Transport[TaskName] = {} + self.Transport[TaskName].SetCargo = SetCargo + self.Transport[TaskName].Briefing = Briefing + self.Transport[TaskName].Task = nil + + return self + end + + + --- Define one deploy zone for the Transport tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TransportTaskName (optional) The name of the Transport task. + -- @param TransportDeployZone A Transport deploy zone. + -- @return #TASK_CARGO_DISPATCHER + function TASK_CARGO_DISPATCHER:SetTransportDeployZone( TransportTaskName, TransportDeployZone ) + + if TransportTaskName then + self.Transport[TransportTaskName].DeployZones = { TransportDeployZone } + end return self end + --- Define the deploy zones for the Transport tasks. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TransportTaskName (optional) The name of the Transport task. + -- @param TransportDeployZones A list of the Transport deploy zones. + -- @return #TASK_CARGO_DISPATCHER + -- + function TASK_CARGO_DISPATCHER:SetTransportDeployZones( TransportTaskName, TransportDeployZones ) + + if TransportTaskName then + self.Transport[TransportTaskName].DeployZones = TransportDeployZones + end + + return self + end + --- Evaluates of a CSAR task needs to be started. -- @param #TASK_CARGO_DISPATCHER self -- @return Set#SET_CARGO The SetCargo to be rescued. @@ -368,17 +532,36 @@ do -- TASK_CARGO_DISPATCHER end -- Now that all obsolete tasks are removed, loop through the CSAR pilots. - for CSARID, CSARData in pairs( self.CSAR ) do + for CSARName, CSAR in pairs( self.CSAR ) do - if CSARData.Task then - else + if not CSAR.Task then -- New CSAR Task - local SetCargo = self:EvaluateCSAR( CSARData.PilotGroup ) - local CSARTask = TASK_CARGO_CSAR:New( Mission, self.SetGroup, string.format( "CSAR.%03d", CSARID ), SetCargo ) - CSARTask:SetDeployZones( self.CSARDeployZones or {} ) - Mission:AddTask( CSARTask ) - TaskReport:Add( CSARTask:GetName() ) - CSARData.Task = CSARTask + local SetCargo = self:EvaluateCSAR( CSAR.PilotGroup ) + CSAR.Task = TASK_CARGO_CSAR:New( Mission, self.SetGroup, CSARName, SetCargo, CSAR.Briefing ) + Mission:AddTask( CSAR.Task ) + TaskReport:Add( CSARName ) + if CSAR.DeployZones then + CSAR.Task:SetDeployZones( CSAR.DeployZones or {} ) + else + CSAR.Task:SetDeployZones( self.DefaultDeployZones or {} ) + end + end + end + + + -- Now that all obsolete tasks are removed, loop through the Transport tasks. + for TransportName, Transport in pairs( self.Transport ) do + + if not Transport.Task then + -- New Transport Task + Transport.Task = TASK_CARGO_TRANSPORT:New( Mission, self.SetGroup, TransportName, Transport.SetCargo, Transport.Briefing ) + Mission:AddTask( Transport.Task ) + TaskReport:Add( TransportName ) + if Transport.DeployZones then + Transport.Task:SetDeployZones( Transport.DeployZones or {} ) + else + Transport.Task:SetDeployZones( self.DefaultDeployZones or {} ) + end end end From c60dda2545b8b2c174098ecce783b5317d5fb2b2 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 5 Apr 2018 15:06:36 +0200 Subject: [PATCH 028/170] Cargo Crate transportation working :-) --- Moose Development/Moose/Cargo/Cargo.lua | 42 ++++++- Moose Development/Moose/Cargo/CargoCrate.lua | 111 +++++++++++++++++- Moose Development/Moose/Core/Database.lua | 46 +++----- Moose Development/Moose/Core/SpawnStatic.lua | 2 +- .../Moose/Tasking/Task_CARGO.lua | 97 ++++++++++++--- .../Moose/Wrapper/Controllable.lua | 10 -- .../Moose/Wrapper/Positionable.lua | 14 ++- Moose Development/Moose/Wrapper/Static.lua | 45 ++++++- 8 files changed, 299 insertions(+), 68 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 07ee37a6d..2528b1b32 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -259,7 +259,7 @@ do -- CARGO self.Type = Type self.Name = Name - self.Weight = Weight + self.Weight = Weight or 0 self.CargoObject = nil self.CargoCarrier = nil -- Wrapper.Client#CLIENT self.Representable = false @@ -288,6 +288,34 @@ do -- CARGO return CargoFound end + --- Check if the cargo can be Boarded. + -- @param #CARGO self + function CARGO:CanBoard() + return true + end + + --- Check if the cargo can be Unboarded. + -- @param #CARGO self + function CARGO:CanUnboard() + return true + end + + --- Check if the cargo can be Loaded. + -- @param #CARGO self + function CARGO:CanLoad() + return true + end + + --- Check if the cargo can be Unloaded. + -- @param #CARGO self + function CARGO:CanUnload() + return true + end + + + + + --- Destroy the cargo. -- @param #CARGO self function CARGO:Destroy() @@ -315,6 +343,13 @@ do -- CARGO end end + --- Get the amount of Cargo. + -- @param #CARGO self + -- @return #number The amount of Cargo. + function CARGO:GetCount() + return 1 + end + --- Get the type of the Cargo. -- @param #CARGO self -- @return #string The type of the Cargo. @@ -569,8 +604,11 @@ do -- CARGO_REPRESENTABLE -- @param #number NearRadius (optional) -- @return #CARGO_REPRESENTABLE function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE + local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPRESENTABLE self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + self.ReportRadius = ReportRadius or 500 + self.NearRadius = NearRadius or 25 return self end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 3f943d1ed..28a231d91 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -42,19 +42,25 @@ do -- CARGO_CRATE -- @param Wrapper.Static#STATIC CargoStatic -- @param #string Type -- @param #string Name - -- @param #number Weight -- @param #number ReportRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_CRATE - function CARGO_CRATE:New( CargoStatic, Type, Name, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, NearRadius ) ) -- #CARGO_CRATE + function CARGO_CRATE:New( CargoStatic, Type, Name, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, ReportRadius, NearRadius ) ) -- #CARGO_CRATE self:F( { Type, Name, NearRadius } ) self.CargoObject = CargoStatic self:T( self.ClassName ) - self:SetEventPriority( 5 ) + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) return self end @@ -116,5 +122,102 @@ do -- CARGO_CRATE end end + --- Check if the cargo can be Boarded. + -- @param #CARGO self + function CARGO:CanBoard() + return false + end + + --- Check if the cargo can be Unboarded. + -- @param #CARGO self + function CARGO_CRATE:CanUnboard() + return false + end + + --- Get the current Coordinate of the CargoGroup. + -- @param #CARGO_CRATE self + -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. + -- @return #nil There is no valid Cargo in the CargoGroup. + function CARGO_CRATE:GetCoordinate() + self:F() + + return self.CargoObject:GetCoordinate() + end + + --- Check if the CargoGroup is alive. + -- @param #CARGO_CRATE self + -- @return #boolean true if the CargoGroup is alive. + -- @return #boolean false if the CargoGroup is dead. + function CARGO_CRATE:IsAlive() + + local Alive = true + + -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. + -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. + if self:IsLoaded() then + Alive = Alive == true and self.CargoCarrier:IsAlive() + else + Alive = Alive == true and self.CargoObject:IsAlive() + end + + return Alive + + end + + + --- Route Cargo to Coordinate and randomize locations. + -- @param #CARGO_CRATE self + -- @param Core.Point#COORDINATE Coordinate + function CARGO_CRATE:RouteTo( Coordinate ) + self:F( {Coordinate = Coordinate } ) + + end + + --- Check if Cargo is near to the Carrier. + -- The Cargo is near to the Carrier within NearRadius. + -- @param #CARGO_CRATE self + -- @param Wrapper.Group#GROUP CargoCarrier + -- @param #number NearRadius + -- @return #boolean The Cargo is near to the Carrier. + -- @return #nil The Cargo is not near to the Carrier. + function CARGO_CRATE:IsNear( CargoCarrier, NearRadius ) + self:F( {NearRadius = NearRadius } ) + + return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + end + + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + -- @param #CARGO_CRATE self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the reporting radius. + function CARGO_CRATE:IsInRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + else + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + end + self:T( Distance ) + + if Distance <= self.ReportRadius then + return true + else + return false + end + end + + --- Respawn the CargoGroup. + -- @param #CARGO_CRATE self + function CARGO_CRATE:Respawn() + + self:F( { "Respawning" } ) + + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + + end + end diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index d90e01284..2235407cb 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -450,8 +450,6 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name ) - local TraceTable = {} - if not self.Templates.Groups[GroupTemplateName] then self.Templates.Groups[GroupTemplateName] = {} self.Templates.Groups[GroupTemplateName].Status = nil @@ -475,18 +473,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionSide self.Templates.Groups[GroupTemplateName].CountryID = CountryID - - TraceTable[#TraceTable+1] = "Group" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName - - TraceTable[#TraceTable+1] = "Coalition" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID - TraceTable[#TraceTable+1] = "Category" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID - TraceTable[#TraceTable+1] = "Country" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID - - TraceTable[#TraceTable+1] = "Units" + local UnitNames = {} for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do @@ -510,10 +497,16 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate end - TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName + UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName end - self:E( TraceTable ) + self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName, + Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID, + Category = self.Templates.Groups[GroupTemplateName].CategoryID, + Country = self.Templates.Groups[GroupTemplateName].CountryID, + Units = UnitNames + } + ) end function DATABASE:GetGroupTemplate( GroupName ) @@ -530,8 +523,6 @@ end -- @return #DATABASE self function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID ) - local TraceTable = {} - local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name) self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {} @@ -547,18 +538,15 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID self.Templates.Statics[StaticTemplateName].CountryID = CountryID + self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName, + Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID, + Category = self.Templates.Statics[StaticTemplateName].CategoryID, + Country = self.Templates.Statics[StaticTemplateName].CountryID + } + ) + + self:AddStatic( StaticTemplateName ) - TraceTable[#TraceTable+1] = "Static" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].StaticName - - TraceTable[#TraceTable+1] = "Coalition" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID - TraceTable[#TraceTable+1] = "Category" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CategoryID - TraceTable[#TraceTable+1] = "Country" - TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CountryID - - self:E( TraceTable ) end diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 92a816257..6772956e0 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -85,7 +85,7 @@ function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1 local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC self:F( { SpawnTemplatePrefix } ) - local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix ) + local TemplateStatic = STATIC:FindByName( SpawnTemplatePrefix ) if TemplateStatic then self.SpawnTemplatePrefix = SpawnTemplatePrefix self.CountryID = CountryID diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index d59473047..78cedeb0c 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -13,6 +13,7 @@ -- The following classes are important to consider: -- -- * @{#TASK_CARGO_TRANSPORT}: Defines a task for a human player to transport a set of cargo between various zones. +-- * @{#TASK_CARGO_CSAR}: Defines a task for a human player to Search and Rescue wounded pilots. -- -- === -- @@ -173,7 +174,7 @@ do -- TASK_CARGO Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) - Fsm:AddTransition( { "Planned", "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Landed", "Boarding" }, "SelectAction", "*" ) + Fsm:AddTransition( { "Planned", "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Loaded", "UnLoaded", "Landed", "Boarding" }, "SelectAction", "*" ) Fsm:AddTransition( "*", "RouteToPickup", "RoutingToPickup" ) Fsm:AddProcess ( "RoutingToPickup", "RouteToPickupPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtPickup", Cancelled = "CancelRouteToPickup" } ) @@ -191,10 +192,14 @@ do -- TASK_CARGO Fsm:AddTransition( "*", "PrepareBoarding", "AwaitBoarding" ) Fsm:AddTransition( "AwaitBoarding", "Board", "Boarding" ) Fsm:AddTransition( "Boarding", "Boarded", "Boarded" ) + + Fsm:AddTransition( "*", "Load", "Loaded" ) Fsm:AddTransition( "*", "PrepareUnBoarding", "AwaitUnBoarding" ) Fsm:AddTransition( "AwaitUnBoarding", "UnBoard", "UnBoarding" ) Fsm:AddTransition( "UnBoarding", "UnBoarded", "UnBoarded" ) + + Fsm:AddTransition( "*", "Unload", "Unloaded" ) Fsm:AddTransition( "*", "Planned", "Planned" ) @@ -254,7 +259,13 @@ do -- TASK_CARGO end if NotInDeployZones then if not TaskUnit:InAir() then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + if Cargo:CanBoard() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + else + if Cargo:CanLoad() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) + end + end TaskUnit.Menu:SetTime( MenuTime ) end end @@ -267,7 +278,13 @@ do -- TASK_CARGO if Cargo:IsLoaded() then if not TaskUnit:InAir() then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnBoardCargo, self, Cargo ):SetTime(MenuTime) + if Cargo:CanUnboard() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime) + else + if Cargo:CanUnload() then + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unload cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnloadCargo, self, Cargo ):SetTime(MenuTime) + end + end TaskUnit.Menu:SetTime( MenuTime ) end -- Deployzones are optional zones that can be selected to request routing information. @@ -305,10 +322,18 @@ do -- TASK_CARGO self:__PrepareBoarding( 1.0, Cargo ) end - function Fsm:MenuUnBoardCargo( Cargo, DeployZone ) + function Fsm:MenuLoadCargo( Cargo ) + self:__Load( 1.0, Cargo ) + end + + function Fsm:MenuUnboardCargo( Cargo, DeployZone ) self:__PrepareUnBoarding( 1.0, Cargo, DeployZone ) end + function Fsm:MenuUnloadCargo( Cargo, DeployZone ) + self:__Unload( 1.0, Cargo, DeployZone ) + end + function Fsm:MenuRouteToPickup( Cargo ) self:__RouteToPickup( 1.0, Cargo ) end @@ -506,9 +531,7 @@ do -- TASK_CARGO self.Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() ) - TaskUnit:AddCargo( self.Cargo ) - - self:__SelectAction( 1 ) + self:Load( self.Cargo ) -- TODO:I need to find a more decent solution for this. Task:E( { CargoPickedUp = Task.CargoPickedUp } ) @@ -521,6 +544,32 @@ do -- TASK_CARGO end + --- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_Cargo#TASK_CARGO Task + function Fsm:onafterLoad( TaskUnit, Task, From, Event, To, Cargo ) + + local TaskUnitName = TaskUnit:GetName() + self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) + + if not Cargo:IsLoaded() then + Cargo:Load( TaskUnit ) + TaskUnit:AddCargo( Cargo ) + end + + self:__SelectAction( 1 ) + + -- TODO:I need to find a more decent solution for this. + Task:E( { CargoPickedUp = Task.CargoPickedUp } ) + if Cargo:IsAlive() then + if Task.CargoPickedUp then + Task:CargoPickedUp( TaskUnit, Cargo ) + end + end + + end + + --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit @@ -530,7 +579,7 @@ do -- TASK_CARGO -- @param To -- @param Cargo -- @param Core.Zone#ZONE_BASE DeployZone - function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo ) + function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo } ) self.Cargo = Cargo @@ -586,33 +635,51 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) self.Cargo:MessageToGroup( "UnBoarded ...", TaskUnit:GetGroup() ) + + self:Unload( self.Cargo ) + end - TaskUnit:RemoveCargo( self.Cargo ) + --- + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_Cargo#TASK_CARGO Task + function Fsm:onafterUnload( TaskUnit, Task, From, Event, To, Cargo, DeployZone ) + + local TaskUnitName = TaskUnit:GetName() + self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) + + if not Cargo:IsUnLoaded() then + if DeployZone then + Cargo:UnLoad( DeployZone:GetPointVec2(), 400, self ) + else + Cargo:UnLoad( TaskUnit:GetPointVec2():AddX(60), 400, self ) + end + end + TaskUnit:RemoveCargo( Cargo ) local NotInDeployZones = true for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if self.Cargo:IsInZone( DeployZone ) then + if Cargo:IsInZone( DeployZone ) then NotInDeployZones = false end end if NotInDeployZones == false then - self.Cargo:SetDeployed( true ) + Cargo:SetDeployed( true ) end -- TODO:I need to find a more decent solution for this. Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } ) - Task:E( { CargoIsAlive = self.Cargo:IsAlive() and "true" or "false" } ) - if self.Cargo:IsAlive() then + Task:E( { CargoIsAlive = Cargo:IsAlive() and "true" or "false" } ) + if Cargo:IsAlive() then if Task.CargoDeployed then - Task:CargoDeployed( TaskUnit, self.Cargo, self.DeployZone ) + Task:CargoDeployed( TaskUnit, Cargo, self.DeployZone ) end end self:Planned() self:__SelectAction( 1 ) end - return self diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 7da5fe917..1847a16cd 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2783,16 +2783,6 @@ function CONTROLLABLE:IsAirPlane() return nil end -function CONTROLLABLE:GetSize() - - local DCSObject = self:GetDCSObject() - - if DCSObject then - return 1 - else - return 0 - end -end -- Message APIs \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 5a7f064c4..b36a2d88b 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -129,7 +129,7 @@ function POSITIONABLE:GetPointVec2() local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) - self:T2( PositionablePointVec2 ) + self:T( PositionablePointVec2 ) return PositionablePointVec2 end @@ -309,6 +309,18 @@ function POSITIONABLE:IsAboveRunway() end +function POSITIONABLE:GetSize() + + local DCSObject = self:GetDCSObject() + + if DCSObject then + return 1 + else + return 0 + end +end + + --- Returns the POSITIONABLE heading in degrees. -- @param Wrapper.Positionable#POSITIONABLE self diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 28e7c364b..2724ef8ed 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -48,6 +48,24 @@ STATIC = { } +function STATIC:Register( StaticName ) + local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) + self.StaticName = StaticName + return self +end + + +--- Finds a STATIC from the _DATABASE using a DCSStatic object. +-- @param #STATIC self +-- @param Dcs.DCSWrapper.Static#Static DCSStatic An existing DCS Static object reference. +-- @return #STATIC self +function STATIC:Find( DCSStatic ) + + local StaticName = DCSStatic:getName() + local StaticFound = _DATABASE:FindStatic( StaticName ) + return StaticFound +end + --- Finds a STATIC from the _DATABASE using the relevant Static Name. -- As an optional parameter, a briefing text can be given also. -- @param #STATIC self @@ -71,12 +89,6 @@ function STATIC:FindByName( StaticName, RaiseError ) return nil end -function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) - self.StaticName = StaticName - return self -end - function STATIC:GetDCSObject() local DCSStatic = StaticObject.getByName( self.StaticName ) @@ -88,6 +100,27 @@ function STATIC:GetDCSObject() return nil end +--- Returns a list of one @{Static}. +-- @param #STATIC self +-- @return #list A list of one @{Static}. +function STATIC:GetUnits() + self:F2( { self.StaticName } ) + local DCSStatic = self:GetDCSObject() + + local Statics = {} + + if DCSStatic then + Statics[1] = STATIC:Find( DCSStatic ) + self:T3( Statics ) + return Statics + end + + return nil +end + + + + function STATIC:GetThreatLevel() return 1, "Static" From 5971f6de090b1ce4ba22b0b404d63840f2adba51 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 5 Apr 2018 19:43:24 +0200 Subject: [PATCH 029/170] Added CARGO_SLINGLOAD --- Moose Development/Moose/Cargo/CargoCrate.lua | 8 +- .../Moose/Cargo/CargoSlingload.lua | 179 ++++++++++++++++++ Moose Development/Moose/Core/Database.lua | 5 +- Moose Development/Moose/Core/SpawnStatic.lua | 75 +++++--- .../Moose/Tasking/Task_CARGO.lua | 17 +- Moose Development/Moose/Wrapper/Static.lua | 2 +- Moose Setup/Moose.files | 1 + 7 files changed, 236 insertions(+), 51 deletions(-) create mode 100644 Moose Development/Moose/Cargo/CargoSlingload.lua diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 28a231d91..1f083a010 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -123,13 +123,13 @@ do -- CARGO_CRATE end --- Check if the cargo can be Boarded. - -- @param #CARGO self - function CARGO:CanBoard() + -- @param #CARGO_CRATE self + function CARGO_CRATE:CanBoard() return false end --- Check if the cargo can be Unboarded. - -- @param #CARGO self + -- @param #CARGO_CRATE self function CARGO_CRATE:CanUnboard() return false end @@ -172,6 +172,7 @@ do -- CARGO_CRATE self:F( {Coordinate = Coordinate } ) end + --- Check if Cargo is near to the Carrier. -- The Cargo is near to the Carrier within NearRadius. @@ -186,6 +187,7 @@ do -- CARGO_CRATE return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) end + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. -- @param #CARGO_CRATE self -- @param Core.Point#Coordinate Coordinate diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua new file mode 100644 index 000000000..21ad7c7e9 --- /dev/null +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -0,0 +1,179 @@ +--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded. +-- +-- === +-- +-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) +-- +-- === +-- +-- ### [Demo Missions]() +-- +-- ### [YouTube Playlist]() +-- +-- === +-- +-- ### Author: **FlightControl** +-- ### Contributions: +-- +-- === +-- +-- @module CargoCrate + +do -- CARGO_SLINGLOAD + + --- Models the behaviour of cargo crates, which can only be slingloaded. + -- @type CARGO_SLINGLOAD + -- @extends #CARGO_REPRESENTABLE + + --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} + -- + -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + -- + -- === + -- + -- @field #CARGO_SLINGLOAD + CARGO_SLINGLOAD = { + ClassName = "CARGO_SLINGLOAD" + } + + --- CARGO_SLINGLOAD Constructor. + -- @param #CARGO_SLINGLOAD self + -- @param Wrapper.Static#STATIC CargoStatic + -- @param #string Type + -- @param #string Name + -- @param #number ReportRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_SLINGLOAD + function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, ReportRadius, NearRadius ) ) -- #CARGO_SLINGLOAD + self:F( { Type, Name, NearRadius } ) + + self.CargoObject = CargoStatic + + self:T( self.ClassName ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) + + return self + end + + + --- Check if the cargo can be Boarded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanBoard() + return false + end + + --- Check if the cargo can be Unboarded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanUnboard() + return false + end + + --- Check if the cargo can be Loaded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanLoad() + return false + end + + --- Check if the cargo can be Unloaded. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanUnload() + return false + end + + --- Get the current Coordinate of the CargoGroup. + -- @param #CARGO_SLINGLOAD self + -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. + -- @return #nil There is no valid Cargo in the CargoGroup. + function CARGO_SLINGLOAD:GetCoordinate() + self:F() + + return self.CargoObject:GetCoordinate() + end + + --- Check if the CargoGroup is alive. + -- @param #CARGO_SLINGLOAD self + -- @return #boolean true if the CargoGroup is alive. + -- @return #boolean false if the CargoGroup is dead. + function CARGO_SLINGLOAD:IsAlive() + + local Alive = true + + -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. + -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. + if self:IsLoaded() then + Alive = Alive == true and self.CargoCarrier:IsAlive() + else + Alive = Alive == true and self.CargoObject:IsAlive() + end + + return Alive + + end + + + --- Route Cargo to Coordinate and randomize locations. + -- @param #CARGO_SLINGLOAD self + -- @param Core.Point#COORDINATE Coordinate + function CARGO_SLINGLOAD:RouteTo( Coordinate ) + self:F( {Coordinate = Coordinate } ) + + end + + + --- Check if Cargo is near to the Carrier. + -- The Cargo is near to the Carrier within NearRadius. + -- @param #CARGO_SLINGLOAD self + -- @param Wrapper.Group#GROUP CargoCarrier + -- @param #number NearRadius + -- @return #boolean The Cargo is near to the Carrier. + -- @return #nil The Cargo is not near to the Carrier. + function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius ) + self:F( {NearRadius = NearRadius } ) + + return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + end + + + --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + -- @param #CARGO_SLINGLOAD self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the reporting radius. + function CARGO_SLINGLOAD:IsInRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + else + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + end + self:T( Distance ) + + if Distance <= self.ReportRadius then + return true + else + return false + end + end + + --- Respawn the CargoGroup. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:Respawn() + + self:F( { "Respawning" } ) + + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + + end + +end diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 2235407cb..01b1c64a0 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -553,10 +553,7 @@ end --- @param #DATABASE self function DATABASE:GetStaticUnitTemplate( StaticName ) local StaticTemplate = self.Templates.Statics[StaticName].UnitTemplate - StaticTemplate.SpawnCoalitionID = self.Templates.Statics[StaticName].CoalitionID - StaticTemplate.SpawnCategoryID = self.Templates.Statics[StaticName].CategoryID - StaticTemplate.SpawnCountryID = self.Templates.Statics[StaticName].CountryID - return StaticTemplate + return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID end diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 6772956e0..118b74b8c 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -81,14 +81,16 @@ SPAWNSTATIC = { -- @param #SPAWNSTATIC self -- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. -- @return #SPAWNSTATIC -function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1 +function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID ) --R2.1 local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC self:F( { SpawnTemplatePrefix } ) - local TemplateStatic = STATIC:FindByName( SpawnTemplatePrefix ) + local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticUnitTemplate( SpawnTemplatePrefix ) if TemplateStatic then self.SpawnTemplatePrefix = SpawnTemplatePrefix - self.CountryID = CountryID + self.CountryID = SpawnCountryID or CountryID + self.CategoryID = CategoryID + self.CoalitionID = CoalitionID self.SpawnIndex = 0 else error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) @@ -124,22 +126,28 @@ end function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3 self:F( { Heading, NewName } ) - local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID] - local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) - StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) - StaticTemplate.heading = ( Heading / 180 ) * math.pi + if StaticTemplate then - StaticTemplate.CountryID = nil - StaticTemplate.CoalitionID = nil - StaticTemplate.CategoryID = nil + local CountryID = self.CountryID + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] - local Static = coalition.addStaticObject( self.CountryID, StaticTemplate ) + StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) + StaticTemplate.heading = ( Heading / 180 ) * math.pi + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( CountryID, StaticTemplate ) + + self.SpawnIndex = self.SpawnIndex + 1 - self.SpawnIndex = self.SpawnIndex + 1 - - return Static + return Static + end + + return nil end @@ -153,30 +161,35 @@ end function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1 self:F( { PointVec2, Heading, NewName } ) - local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID] - local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) - StaticTemplate.x = PointVec2.x - StaticTemplate.y = PointVec2.z + if StaticTemplate then - StaticTemplate.units = nil - StaticTemplate.route = nil - StaticTemplate.groupId = nil + local CountryID = self.CountryID + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] + StaticTemplate.x = PointVec2.x + StaticTemplate.y = PointVec2.z - StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) - StaticTemplate.heading = ( Heading / 180 ) * math.pi + StaticTemplate.units = nil + StaticTemplate.route = nil + StaticTemplate.groupId = nil + + StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) + StaticTemplate.heading = ( Heading / 180 ) * math.pi + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( CountryID, StaticTemplate ) + + self.SpawnIndex = self.SpawnIndex + 1 - StaticTemplate.CountryID = nil - StaticTemplate.CoalitionID = nil - StaticTemplate.CategoryID = nil + return Static + end - local Static = coalition.addStaticObject( self.CountryID, StaticTemplate ) - - self.SpawnIndex = self.SpawnIndex + 1 - - return Static + return nil end --- Creates a new @{Static} from a @{Zone}. diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 78cedeb0c..efb21f018 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -259,10 +259,10 @@ do -- TASK_CARGO end if NotInDeployZones then if not TaskUnit:InAir() then - if Cargo:CanBoard() then + if Cargo:CanBoard() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) else - if Cargo:CanLoad() then + if Cargo:CanLoad() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) end end @@ -278,10 +278,10 @@ do -- TASK_CARGO if Cargo:IsLoaded() then if not TaskUnit:InAir() then - if Cargo:CanUnboard() then + if Cargo:CanUnboard() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime) else - if Cargo:CanUnload() then + if Cargo:CanUnload() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unload cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnloadCargo, self, Cargo ):SetTime(MenuTime) end end @@ -492,6 +492,7 @@ do -- TASK_CARGO self:__Board( -0.1 ) end end + --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit @@ -533,14 +534,6 @@ do -- TASK_CARGO self:Load( self.Cargo ) - -- TODO:I need to find a more decent solution for this. - Task:E( { CargoPickedUp = Task.CargoPickedUp } ) - if self.Cargo:IsAlive() then - if Task.CargoPickedUp then - Task:CargoPickedUp( TaskUnit, self.Cargo ) - end - end - end diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 2724ef8ed..6479037a9 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -134,7 +134,7 @@ function STATIC:ReSpawn( Coordinate, Heading ) -- todo: need to fix country - local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, country.id.USA ) + local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName ) end diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index d1328835d..c206b5416 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -36,6 +36,7 @@ Wrapper/Scenery.lua Cargo/Cargo.lua Cargo/CargoUnit.lua +Cargo/CargoSlingload.lua Cargo/CargoCrate.lua Cargo/CargoGroup.lua From 2ebd25d6778dfb4be7db441499fa3602d5c2d946 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 5 Apr 2018 19:54:24 +0200 Subject: [PATCH 030/170] Finish Cargo/FC/Csar --- Moose Development/Moose/Cargo/CargoSlingload.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 21ad7c7e9..a610e4b34 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -19,6 +19,7 @@ -- -- @module CargoCrate + do -- CARGO_SLINGLOAD --- Models the behaviour of cargo crates, which can only be slingloaded. From ed0c5b2264719c8b1a1833c67b2f5c83c50e01c4 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 5 Apr 2018 22:44:33 +0200 Subject: [PATCH 031/170] Added Range 1.0.3 Just copied from other branch. --- Moose Development/Moose/Functional/Range.lua | 66 +++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 3c946ea79..e3e3590cb 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -227,7 +227,7 @@ RANGE.id="RANGE | " --- Range script version. -- @field #number version -RANGE.version="1.0.1" +RANGE.version="1.0.3" --TODO list --TODO: Add statics for strafe pits. @@ -1390,6 +1390,9 @@ function RANGE:_CheckInZone(_unitName) else + -- Get current ammo. + local _ammo=self:_GetAmmo(_unitName) + -- Result. local _result = self.strafeStatus[_unitID] @@ -1403,9 +1406,19 @@ function RANGE:_CheckInZone(_unitName) else _result.text = "POOR PASS" end + + local shots=_result.ammo-_ammo + local accur=0 + if shots>0 then + accur=_result.hits/shots*100 + end + -- Message text. local _text=string.format("%s, %s with %d hits on target %s.", self:_myname(_unitName), _result.text, _result.hits, _result.zone.name) + if shots and accur then + _text=_text..string.format("\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur) + end -- Send message. self:_DisplayMessageToGroup(_unit, _text) @@ -1446,9 +1459,12 @@ function RANGE:_CheckInZone(_unitName) -- Player is inside zone. if unitinzone then + + -- Get ammo at the beginning of the run. + local _ammo=self:_GetAmmo(_unitName) -- Init strafe status for this player. - self.strafeStatus[_unitID] = {hits = 0, zone = _targetZone, time = 1, pastfoulline=false } + self.strafeStatus[_unitID] = {hits = 0, zone = _targetZone, time = 1, ammo=_ammo, pastfoulline=false } -- Rolling in! local _msg=string.format("%s, rolling in on strafe pit %s.", self:_myname(_unitName), _targetZone.name) @@ -1550,6 +1566,52 @@ end ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Helper Functions +--- Get the number of shells a unit currently has. +-- @param #RANGE self +-- @param #string unitname Name of the player unit. +-- @return Number of shells left +function RANGE:_GetAmmo(unitname) + self:F(unitname) + + -- Init counter. + local ammo=0 + + local unit, playername = self:_GetPlayerUnitAndName(unitname) + + if unit and playername then + + local has_ammo=false + + local ammotable=unit:GetAmmo() + self:T2({ammotable=ammotable}) + + if ammotable ~= nil then + + local weapons=#ammotable + self:T2(RANGE.id..string.format("Number of weapons %d.", weapons)) + + for w=1,weapons do + + local Nammo=ammotable[w]["count"] + local Tammo=ammotable[w]["desc"]["typeName"] + + -- We are specifically looking for shells here. + if string.match(Tammo, "shell") then + + -- Add up all shells + ammo=ammo+Nammo + + local text=string.format("Player %s has %d rounds ammo of type %s", playername, Nammo, Tammo) + self:T(RANGE.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + end + end + end + end + + return ammo +end + --- Mark targets on F10 map. -- @param #RANGE self -- @param #string _unitName Name of the player unit. From 269b52fd0eb7ab05314327700cebeb1ee71d7529 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 6 Apr 2018 21:28:43 +0200 Subject: [PATCH 032/170] Fixed slingload deploy problem. Fixed messaging. Now a message is shown when cargo reports itself when in LoadRange and when near, it will allow for loading of cargo. Fixed the perception that cargo can be boarded when loaded in an other carrier, which is totally wrong. --- Moose Development/Moose/Cargo/Cargo.lua | 234 ++++++++++++++---- Moose Development/Moose/Cargo/CargoCrate.lua | 51 ++-- Moose Development/Moose/Cargo/CargoGroup.lua | 43 +++- .../Moose/Cargo/CargoSlingload.lua | 52 ++-- Moose Development/Moose/Cargo/CargoUnit.lua | 2 +- .../Moose/Tasking/Task_CARGO.lua | 68 ++--- 6 files changed, 305 insertions(+), 145 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 2528b1b32..cdba0ec8f 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -224,6 +224,7 @@ do -- CARGO Slingloadable = false, Moveable = false, Containable = false, + Reported = {}, } --- @type CARGO.CargoObjects @@ -235,12 +236,13 @@ do -- CARGO -- @param #string Type -- @param #string Name -- @param #number Weight + -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO - function CARGO:New( Type, Name, Weight ) --R2.1 + function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1 local self = BASE:Inherit( self, FSM:New() ) -- #CARGO - self:F( { Type, Name, Weight } ) + self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) self:SetStartState( "UnLoaded" ) self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) @@ -267,6 +269,9 @@ do -- CARGO self.Moveable = false self.Containable = false + self.LoadRadius = LoadRadius or 500 + self.NearRadius = NearRadius or 25 + self:SetDeployed( false ) self.CargoScheduler = SCHEDULER:New() @@ -405,8 +410,9 @@ do -- CARGO end end - --- Set the cargo as deployed + --- Set the cargo as deployed. -- @param #CARGO self + -- @param #boolean Deployed true if the cargo is to be deployed. false or nil otherwise. function CARGO:SetDeployed( Deployed ) self.Deployed = Deployed end @@ -507,7 +513,86 @@ do -- CARGO end + --- Set the Load radius, which is the radius till when the Cargo can be loaded. + -- @param #CARGO self + -- @param #number LoadRadius The radius till Cargo can be loaded. + -- @return #CARGO + function CARGO:SetLoadRadius( LoadRadius ) + self.LoadRadius = LoadRadius or 150 + end + --- Get the Load radius, which is the radius till when the Cargo can be loaded. + -- @param #CARGO self + -- @return #number The radius till Cargo can be loaded. + function CARGO:GetLoadRadius() + return self.LoadRadius + end + + + + --- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded. + -- @param #CARGO self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the CargoGroup is within the loading radius. + function CARGO:IsInLoadRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.LoadRadius then + return true + end + end + + return false + end + + + --- Check if the Cargo can report itself to be Boarded or Loaded. + -- @param #CARGO self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the Cargo can report itself. + function CARGO:IsInReportRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.LoadRadius then + return true + end + end + + return false + end + + + --- Check if CargoCarrier is near the Cargo to be Loaded. + -- @param #CARGO self + -- @param Core.Point#POINT_VEC2 PointVec2 + -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). + -- @return #boolean + function CARGO:IsNear( PointVec2, NearRadius ) + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + + if self.CargoObject:IsAlive() then + --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:F( { CargoObjectName = self.CargoObject:GetName() } ) + self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) + self:F( { PointVec2 = PointVec2:GetVec2() } ) + local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + + if Distance <= NearRadius then + return true + end + end + + return false + end @@ -534,30 +619,6 @@ do -- CARGO end - --- Check if CargoCarrier is near the Cargo to be Loaded. - -- @param #CARGO self - -- @param Core.Point#POINT_VEC2 PointVec2 - -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - -- @return #boolean - function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) - - if self.CargoObject:IsAlive() then - --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:F( { CargoObjectName = self.CargoObject:GetName() } ) - self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) - self:F( { PointVec2 = PointVec2:GetVec2() } ) - local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - self:T( Distance ) - - if Distance <= NearRadius then - return true - end - end - - return false - end - --- Get the current PointVec2 of the cargo. -- @param #CARGO self -- @return Core.Point#POINT_VEC2 @@ -580,6 +641,85 @@ do -- CARGO self.Weight = Weight return self end + + --- Send a CC message to a @{Group}. + -- @param #CARGO self + -- @param #string Message + -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group. + -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. + function CARGO:MessageToGroup( Message, CarrierGroup, Name ) + + MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( CarrierGroup ) + + end + + --- Report to a Carrier Group. + -- @param #CARGO self + -- @param #string Action The string describing the action for the cargo. + -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to. + -- @return #CARGO + function CARGO:Report( ReportText, Action, CarrierGroup ) + + if not self.Reported[CarrierGroup] or not self.Reported[CarrierGroup][Action] then + self.Reported[CarrierGroup] = {} + self.Reported[CarrierGroup][Action] = true + self:MessageToGroup( ReportText, CarrierGroup ) + if self.ReportFlareColor then + if not self.Reported[CarrierGroup]["Flaring"] then + self:Flare( self.ReportFlareColor ) + self.Reported[CarrierGroup]["Flaring"] = true + end + end + if self.ReportSmokeColor then + if not self.Reported[CarrierGroup]["Smoking"] then + self:Smoke( self.ReportSmokeColor ) + self.Reported[CarrierGroup]["Smoking"] = true + end + end + end + end + + + --- Report to a Carrier Group with a Flaring signal. + -- @param #CARGO self + -- @param Utils#UTILS.FlareColor FlareColor the color of the flare. + -- @return #CARGO + function CARGO:ReportFlare( FlareColor ) + + self.ReportFlareColor = FlareColor + end + + + --- Report to a Carrier Group with a Smoking signal. + -- @param #CARGO self + -- @param Utils#UTILS.SmokeColor SmokeColor the color of the smoke. + -- @return #CARGO + function CARGO:ReportSmoke( SmokeColor ) + + self.ReportSmokeColor = SmokeColor + end + + + --- Reset the reporting for a Carrier Group. + -- @param #CARGO self + -- @param #string Action The string describing the action for the cargo. + -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to. + -- @return #CARGO + function CARGO:ReportReset( Action, CarrierGroup ) + + self.Reported[CarrierGroup][Action] = nil + end + + --- Reset all the reporting for a Carrier Group. + -- @param #CARGO self + -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to. + -- @return #CARGO + function CARGO:ReportResetAll( CarrierGroup ) + + self.Reported[CarrierGroup] = nil + end + + end -- CARGO @@ -600,16 +740,13 @@ do -- CARGO_REPRESENTABLE -- @param #string Type -- @param #string Name -- @param #number Weight - -- @param #number ReportRadius (optional) + -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPRESENTABLE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE + self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) - self.ReportRadius = ReportRadius or 500 - self.NearRadius = NearRadius or 25 - return self end @@ -661,14 +798,12 @@ do -- CARGO_REPORTABLE -- @param #string Type -- @param #string Name -- @param #number Weight - -- @param #number ReportRadius (optional) + -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_REPORTABLE - function CARGO_REPORTABLE:New( Type, Name, Weight, ReportRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE - self:F( { Type, Name, Weight, ReportRadius } ) - - self.ReportRadius = ReportRadius or 1000 + function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE + self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) return self end @@ -680,19 +815,10 @@ do -- CARGO_REPORTABLE -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name ) - local Prefix = Name and "@ " .. Name .. ": " or "@ " .. TaskGroup:GetCallsign() .. ": " - Message = Prefix .. Message - MESSAGE:New( Message, 20, "Cargo: " .. self:GetName() ):ToGroup( TaskGroup ) + MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( TaskGroup ) end - --- Get the Report radius, which is the radius when the Cargo is reporting itself. - -- @param #CARGO_REPORTABLE self - -- @return #number The range till Cargo reports itself. - function CARGO_REPORTABLE:GetBoardingRange() - return self.ReportRadius - end - end @@ -717,12 +843,12 @@ do -- CARGO_PACKAGE -- @param #string Type -- @param #string Name -- @param #number Weight --- @param #number ReportRadius (optional) +-- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_PACKAGE -function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_PACKAGE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) +function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_PACKAGE + self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) self:T( CargoCarrier ) self.CargoCarrier = CargoCarrier diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 1f083a010..44ef41af6 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -23,7 +23,7 @@ do -- CARGO_CRATE --- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters. -- @type CARGO_CRATE - -- @extends #CARGO_REPRESENTABLE + -- @extends Cargo.Cargo#CARGO_REPRESENTABLE --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} -- @@ -42,11 +42,11 @@ do -- CARGO_CRATE -- @param Wrapper.Static#STATIC CargoStatic -- @param #string Type -- @param #string Name - -- @param #number ReportRadius (optional) + -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_CRATE - function CARGO_CRATE:New( CargoStatic, Type, Name, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, ReportRadius, NearRadius ) ) -- #CARGO_CRATE + function CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE self:F( { Type, Name, NearRadius } ) self.CargoObject = CargoStatic @@ -134,6 +134,27 @@ do -- CARGO_CRATE return false end + --- Check if Cargo Crate is in the radius for the Cargo to be Boarded or Loaded. + -- @param #CARGO self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the Cargo Crate is within the loading radius. + function CARGO_CRATE:IsInLoadRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.NearRadius then + return true + end + end + + return false + end + + + --- Get the current Coordinate of the CargoGroup. -- @param #CARGO_CRATE self -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. @@ -188,28 +209,6 @@ do -- CARGO_CRATE end - --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. - -- @param #CARGO_CRATE self - -- @param Core.Point#Coordinate Coordinate - -- @return #boolean true if the CargoGroup is within the reporting radius. - function CARGO_CRATE:IsInRadius( Coordinate ) - self:F( { Coordinate } ) - - local Distance = 0 - if self:IsLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) - else - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - end - self:T( Distance ) - - if Distance <= self.ReportRadius then - return true - else - return false - end - end - --- Respawn the CargoGroup. -- @param #CARGO_CRATE self function CARGO_CRATE:Respawn() diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 2a5f8fee5..07806b45c 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -23,7 +23,7 @@ do -- CARGO_GROUP --- @type CARGO_GROUP - -- @extends #CARGO_REPORTABLE + -- @extends Cargo.Cargo#CARGO_REPORTABLE -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. -- @field #string GroupName The name of the CargoGroup. @@ -45,12 +45,12 @@ do -- CARGO_GROUP -- @param Wrapper.Group#GROUP CargoGroup -- @param #string Type -- @param #string Name --- @param #number ReportRadius (optional) +-- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_GROUP -function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, ReportRadius } ) +function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius ) ) -- #CARGO_GROUP + self:F( { Type, Name, LoadRadius } ) self.CargoSet = SET_CARGO:New() @@ -455,11 +455,11 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) return nil end - --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. + --- Check if Cargo Group is in the radius for the Cargo to be Boarded. -- @param #CARGO_GROUP self -- @param Core.Point#Coordinate Coordinate - -- @return #boolean true if the CargoGroup is within the reporting radius. - function CARGO_GROUP:IsInRadius( Coordinate ) + -- @return #boolean true if the Cargo Group is within the load radius. + function CARGO_GROUP:IsInLoadRadius( Coordinate ) self:F( { Coordinate } ) local Cargo = self.CargoSet:GetFirst() -- #CARGO @@ -473,7 +473,7 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) end self:T( Distance ) - if Distance <= self.ReportRadius then + if Distance <= self.LoadRadius then return true else return false @@ -484,6 +484,31 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) end + + --- Check if Cargo Group is in the report radius. + -- @param #CARGO_GROUP self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the Cargo Group is within the report radius. + function CARGO_GROUP:IsInReportRadius( Coordinate ) + self:F( { Coordinate } ) + + local Cargo = self.CargoSet:GetFirst() -- #CARGO + + if Cargo then + local Distance = 0 + if Cargo:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.LoadRadius then + return true + end + end + end + + return nil + + end + --- Respawn the CargoGroup. -- @param #CARGO_GROUP self function CARGO_GROUP:Respawn() diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index a610e4b34..91f69f873 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -24,7 +24,7 @@ do -- CARGO_SLINGLOAD --- Models the behaviour of cargo crates, which can only be slingloaded. -- @type CARGO_SLINGLOAD - -- @extends #CARGO_REPRESENTABLE + -- @extends Cargo.Cargo#CARGO_REPRESENTABLE --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} -- @@ -42,11 +42,11 @@ do -- CARGO_SLINGLOAD -- @param Wrapper.Static#STATIC CargoStatic -- @param #string Type -- @param #string Name - -- @param #number ReportRadius (optional) + -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_SLINGLOAD - function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, ReportRadius, NearRadius ) ) -- #CARGO_SLINGLOAD + function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_SLINGLOAD self:F( { Type, Name, NearRadius } ) self.CargoObject = CargoStatic @@ -90,6 +90,28 @@ do -- CARGO_SLINGLOAD return false end + + --- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded. + -- @param #CARGO_SLINGLOAD self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the Cargo Slingload is within the loading radius. + function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate ) + self:F( { Coordinate } ) + + local Distance = 0 + if self:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.NearRadius then + return true + end + end + + return false + end + + + --- Get the current Coordinate of the CargoGroup. -- @param #CARGO_SLINGLOAD self -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. @@ -144,28 +166,6 @@ do -- CARGO_SLINGLOAD end - --- Check if CargoGroup is in the ReportRadius for the Cargo to be Loaded. - -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#Coordinate Coordinate - -- @return #boolean true if the CargoGroup is within the reporting radius. - function CARGO_SLINGLOAD:IsInRadius( Coordinate ) - self:F( { Coordinate } ) - - local Distance = 0 - if self:IsLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) - else - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - end - self:T( Distance ) - - if Distance <= self.ReportRadius then - return true - else - return false - end - end - --- Respawn the CargoGroup. -- @param #CARGO_SLINGLOAD self function CARGO_SLINGLOAD:Respawn() diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index ba9c17f61..5f6b4e941 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -44,7 +44,7 @@ do -- CARGO_UNIT -- @param #string Type -- @param #string Name -- @param #number Weight - -- @param #number ReportRadius (optional) + -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_UNIT function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index efb21f018..101399783 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -230,7 +230,7 @@ do -- TASK_CARGO Task.SetCargo:ForEachCargo( - --- @param Core.Cargo#CARGO Cargo + --- @param Cargo.Cargo#CARGO Cargo function( Cargo ) if Cargo:IsAlive() then @@ -250,7 +250,7 @@ do -- TASK_CARGO if Cargo:IsUnLoaded() then if CargoItemCount <= Task.CargoLimit then - if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then local NotInDeployZones = true for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do if Cargo:IsInZone( DeployZone ) then @@ -260,20 +260,50 @@ do -- TASK_CARGO if NotInDeployZones then if not TaskUnit:InAir() then if Cargo:CanBoard() == true then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then + Cargo:Report( "Reporting for boarding at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "board", TaskUnit:GetGroup() ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + else + Cargo:Report( "Reporting at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + end else if Cargo:CanLoad() == true then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) + if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then + Cargo:Report( "Reporting for loading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "load", TaskUnit:GetGroup() ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) + else + Cargo:Report( "Reporting at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + end end end TaskUnit.Menu:SetTime( MenuTime ) + else + Cargo:ReportResetAll( TaskUnit:GetGroup() ) end end else MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Pickup cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime) TaskUnit.Menu:SetTime( MenuTime ) + Cargo:ReportResetAll( TaskUnit:GetGroup() ) end end + -- Cargo in deployzones are flagged as deployed. + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if Cargo:IsInZone( DeployZone ) then + if not Cargo:IsDeployed() then + Cargo:SetDeployed( true ) + -- TODO:I need to find a more decent solution for this. + Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } ) + Task:E( { CargoIsAlive = Cargo:IsAlive() and "true" or "false" } ) + if Cargo:IsAlive() then + if Task.CargoDeployed then + Task:CargoDeployed( TaskUnit, Cargo, DeployZone ) + end + end + end + end + end + end if Cargo:IsLoaded() then @@ -303,7 +333,7 @@ do -- TASK_CARGO TaskUnit.Menu:Remove( MenuTime ) - self:__SelectAction( -15 ) + self:__SelectAction( -5 ) end @@ -441,7 +471,7 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if self.Cargo:IsAlive() then - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if self.Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then self:__Land( -10, Action ) else @@ -465,7 +495,7 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if self.Cargo:IsAlive() then - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if self.Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then self:__Land( -0.1, Action ) else @@ -506,7 +536,7 @@ do -- TASK_CARGO end if self.Cargo:IsAlive() then - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if self.Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then --- ABORT the boarding. Split group if any and go back to select action. else @@ -649,26 +679,6 @@ do -- TASK_CARGO end end TaskUnit:RemoveCargo( Cargo ) - - local NotInDeployZones = true - for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if Cargo:IsInZone( DeployZone ) then - NotInDeployZones = false - end - end - - if NotInDeployZones == false then - Cargo:SetDeployed( true ) - end - - -- TODO:I need to find a more decent solution for this. - Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } ) - Task:E( { CargoIsAlive = Cargo:IsAlive() and "true" or "false" } ) - if Cargo:IsAlive() then - if Task.CargoDeployed then - Task:CargoDeployed( TaskUnit, Cargo, self.DeployZone ) - end - end self:Planned() self:__SelectAction( 1 ) @@ -739,7 +749,7 @@ do -- TASK_CARGO local ActRouteCargo = ProcessUnit:GetProcess( "RoutingToPickup", "RouteToPickupPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT ActRouteCargo:Reset() ActRouteCargo:SetCoordinate( Cargo:GetCoordinate() ) - ActRouteCargo:SetRange( Cargo:GetBoardingRange() ) + ActRouteCargo:SetRange( Cargo:GetLoadRadius() ) ActRouteCargo:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Cargo " .. Cargo:GetName(), TaskUnit.Menu ) ActRouteCargo:Start() return self From a247f56c7e8fed690884e284dfb48671bd1dec01 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 7 Apr 2018 10:18:52 +0200 Subject: [PATCH 033/170] Progress on AI_CARGO_TROOPS --- .../Moose/AI/AI_Cargo_Troops.lua | 170 ++++++++++++++---- Moose Development/Moose/Cargo/Cargo.lua | 14 +- Moose Development/Moose/Cargo/CargoUnit.lua | 72 ++++---- Moose Development/Moose/Core/Zone.lua | 8 + Moose Development/Moose/Wrapper/Group.lua | 9 +- .../Moose/Wrapper/Identifiable.lua | 20 +++ Moose Development/Moose/Wrapper/Object.lua | 2 + 7 files changed, 215 insertions(+), 80 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 754409aeb..2051fa22d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -24,19 +24,16 @@ AI_CARGO_TROOPS = { --- Creates a new AI_CARGO_TROOPS object. -- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup +-- @param #number CombatRadius -- @return #AI_CARGO_TROOPS function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( ) ) -- #AI_CARGO_TROOPS - self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT - self.CargoGroup = CargoGroup -- Core.Cargo#CARGO_GROUP + self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP self.CombatRadius = CombatRadius - - self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, CombatRadius ) - self.Coalition = self.CargoCarrier:GetCoalition() - - self:SetControllable( CargoCarrier ) self:SetStartState( "UnLoaded" ) @@ -50,14 +47,91 @@ function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) self:AddTransition( "*", "Guard", "Guarding" ) + + self:AddTransition( "*", "Destroyed", "Destroyed" ) self:__Monitor( 1 ) - self:__Load( 1 ) + + self:SetCarrier( CargoCarrier ) return self end +--- Set the Carrier. +-- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @return #AI_CARGO_TROOPS +function AI_CARGO_TROOPS:SetCarrier( CargoCarrier ) + + self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT + self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_TROOPS", self ) + + CargoCarrier:HandleEvent( EVENTS.Dead ) + CargoCarrier:HandleEvent( EVENTS.Hit ) + + function CargoCarrier:OnEventDead( EventData ) + self:F({"dead"}) + local AICargoTroops = self:GetState( self, "AI_CARGO_TROOPS" ) + self:F({AICargoTroops=AICargoTroops}) + if AICargoTroops then + self:F({}) + if not AICargoTroops:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + AICargoTroops:Destroyed() + end + end + end + + function CargoCarrier:OnEventHit( EventData ) + self:F({"hit"}) + local AICargoTroops = self:GetState( self, "AI_CARGO_TROOPS" ) + if AICargoTroops then + self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) + if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + AICargoTroops:Unload() + end + end + end + + self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius ) + self.Coalition = self.CargoCarrier:GetCoalition() + + self:SetControllable( CargoCarrier ) + + self:Guard() + + return self +end + + +--- Find a free Carrier within a range. +-- @param #AI_CARGO_TROOPS self +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Radius +-- @return Wrapper.Unit#UNIT NewCarrier +function AI_CARGO_TROOPS:FindCarrier( Coordinate, Radius ) + + local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) + CoordinateZone:Scan( { Object.Category.UNIT } ) + for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do + local NearUnit = UNIT:Find( DCSUnit ) + self:F({NearUnit=NearUnit}) + if not NearUnit:GetState( NearUnit, "AI_CARGO_TROOPS" ) then + local Attributes = NearUnit:GetDesc() + self:F({Desc=Attributes}) + if NearUnit:HasAttribute( "Trucks" ) then + self:SetCarrier( NearUnit ) + break + end + end + end + +end + + + --- Follow Infantry to the Carrier. -- @param #AI_CARGO_TROOPS self -- @param #AI_CARGO_TROOPS Me @@ -68,40 +142,44 @@ function AI_CARGO_TROOPS:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } ) - -- We check if the Cargo is near to the CargoCarrier. - if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then + --if self:Is( "Following" ) then - -- The Cargo does not need to follow the Carrier. - Me:Guard() + if CargoCarrier:IsAlive() then + -- We check if the Cargo is near to the CargoCarrier. + if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then - else + -- The Cargo does not need to follow the Carrier. + Me:Guard() - self:F( { InfantryGroup = InfantryGroup:GetName() } ) - - if InfantryGroup:IsAlive() then - + else + self:F( { InfantryGroup = InfantryGroup:GetName() } ) - - local Waypoints = {} - - -- Calculate the new Route. - local FromCoord = InfantryGroup:GetCoordinate() - local FromGround = FromCoord:WaypointGround( 10, "Diamond" ) - self:F({FromGround=FromGround}) - table.insert( Waypoints, FromGround ) - - local ToCoord = CargoCarrier:GetCoordinate() - local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) - self:F({ToGround=ToGround}) - table.insert( Waypoints, ToGround ) - - local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_TROOPS.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) - - self:F({Waypoints = Waypoints}) - local Waypoint = Waypoints[#Waypoints] - InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. - InfantryGroup:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. + if InfantryGroup:IsAlive() then + + self:F( { InfantryGroup = InfantryGroup:GetName() } ) + + local Waypoints = {} + + -- Calculate the new Route. + local FromCoord = InfantryGroup:GetCoordinate() + local FromGround = FromCoord:WaypointGround( 10, "Diamond" ) + self:F({FromGround=FromGround}) + table.insert( Waypoints, FromGround ) + + local ToCoord = CargoCarrier:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 ) + local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) + self:F({ToGround=ToGround}) + table.insert( Waypoints, ToGround ) + + local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_TROOPS.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. + + InfantryGroup:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. + end end end end @@ -132,6 +210,22 @@ function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) self:Follow() end end + if self:Is( "Following" ) then + local Distance = Coordinate:Get2DDistance( self.CargoGroup:GetCoordinate() ) + self:F( { Distance = Distance } ) + if Distance > 40 then + CargoCarrier:RouteStop() + self.CarrierStopped = true + else + if self.CarrierStopped then + if self.CargoGroup:IsNear( CargoCarrier, 10 ) then + CargoCarrier:RouteResume() + self.CarrierStopped = nil + end + end + end + end + end self.CarrierCoordinate = CargoCarrier:GetCoordinate() end @@ -149,7 +243,7 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() self:__Board( 10 ) - self.CargoGroup:Board( CargoCarrier, 100 ) + self.CargoGroup:Board( CargoCarrier, 10 ) end end diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index cdba0ec8f..eb44217a3 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -325,7 +325,7 @@ do -- CARGO -- @param #CARGO self function CARGO:Destroy() if self.CargoObject then - self.CargoObject:Destroy() + self.CargoObject:Destroy( false ) end self:Destroyed() end @@ -576,21 +576,23 @@ do -- CARGO -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + self:F2( { PointVec2 = PointVec2, NearRadius = NearRadius } ) if self.CargoObject:IsAlive() then --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:F( { CargoObjectName = self.CargoObject:GetName() } ) - self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) - self:F( { PointVec2 = PointVec2:GetVec2() } ) + --self:F( { CargoObjectName = self.CargoObject:GetName() } ) + --self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) + --self:F( { PointVec2 = PointVec2:GetVec2() } ) local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - self:T( Distance ) + --self:F( Distance ) if Distance <= NearRadius then + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } ) return true end end + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } ) return false end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 5f6b4e941..2ba33aa4b 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -23,7 +23,7 @@ do -- CARGO_UNIT --- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded. -- @type CARGO_UNIT - -- @extends #CARGO_REPRESENTABLE + -- @extends Cargo.Cargo#CARGO_REPRESENTABLE --- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE} -- @@ -82,42 +82,48 @@ do -- CARGO_UNIT if not self:IsDestroyed() then local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - - - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) - local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) - local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) - --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) - - ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) - self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) - self.CargoCarrier = nil + if CargoCarrier:IsAlive() then - local Points = {} - - -- From - Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) - - -- To - Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - + + local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - self:__UnBoarding( 1, ToPointVec2, NearRadius ) + + -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 + local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) + local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) + local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) + --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) + + ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) + self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) + self.CargoCarrier = nil + + local Points = {} + + -- From + Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) + + -- To + Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 1 ) + + + self:__UnBoarding( 1, ToPointVec2, NearRadius ) + end + else + -- the Carrier is dead. This cargo is dead too! + self:Destroyed() end end end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 72317d2ba..8c05d8a14 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -603,6 +603,7 @@ function ZONE_RADIUS:Scan( ObjectCategories ) self.ScanData = {} self.ScanData.Coalitions = {} self.ScanData.Scenery = {} + self.ScanData.Units = {} local ZoneCoord = self:GetCoordinate() local ZoneRadius = self:GetRadius() @@ -625,6 +626,7 @@ function ZONE_RADIUS:Scan( ObjectCategories ) (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then local CoalitionDCSUnit = ZoneObject:getCoalition() self.ScanData.Coalitions[CoalitionDCSUnit] = true + self.ScanData.Units[ZoneObject] = ZoneObject self:F( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } ) end if ObjectCategory == Object.Category.SCENERY then @@ -643,6 +645,12 @@ function ZONE_RADIUS:Scan( ObjectCategories ) end +function ZONE_RADIUS:GetScannedUnits() + + return self.ScanData.Units +end + + function ZONE_RADIUS:CountScannedCoalitions() local Count = 0 diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 26062ea09..23fd5da1a 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -239,14 +239,17 @@ end -- Note that this destroy method also raises a destroy event at run-time. -- So all event listeners will catch the destroy event of this DCS Group. -- @param #GROUP self -function GROUP:Destroy() +-- @param #boolean GenerateEvent +function GROUP:Destroy( GenerateEvent ) self:F2( self.GroupName ) local DCSGroup = self:GetDCSObject() if DCSGroup then - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - self:CreateEventCrash( timer.getTime(), UnitData ) + if not GenerateEvent then + for Index, UnitData in pairs( DCSGroup:getUnits() ) do + self:CreateEventCrash( timer.getTime(), UnitData ) + end end USERFLAG:New( self:GetName() ):Set( 100 ) DCSGroup:destroy() diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index baa83eedb..edd123665 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -229,6 +229,26 @@ function IDENTIFIABLE:GetDesc() return nil end +--- Check if the Object has the attribute. +-- @param #IDENTIFIABLE self +-- @param #string AttributeName The attribute name. +-- @return #boolean true if the attribute exists. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:HasAttribute( AttributeName ) + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableHasAttribute = DCSIdentifiable:hasAttribute( AttributeName ) + self:T2( IdentifiableHasAttribute ) + return IdentifiableHasAttribute + end + + self:F( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + --- Gets the CallSign of the IDENTIFIABLE, which is a blank by default. -- @param #IDENTIFIABLE self -- @return #string The CallSign of the IDENTIFIABLE. diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index fc3c11126..29901fd4b 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -91,3 +91,5 @@ end + + From 7735120f25b18a54326c85a12d2928de81c8f014 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 7 Apr 2018 14:21:34 +0200 Subject: [PATCH 034/170] Progress on AI_CARGO_TROOPS --- Moose Development/Moose/Cargo/CargoUnit.lua | 53 +++++++++++-------- Moose Development/Moose/Core/Set.lua | 13 +++++ .../Moose/Wrapper/Controllable.lua | 4 +- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 2ba33aa4b..5ac185277 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -231,7 +231,11 @@ do -- CARGO_UNIT local NearRadius = NearRadius or 25 self.CargoInAir = self.CargoObject:InAir() - + + local Desc = self.CargoObject:GetDesc() + local MaxSpeed = Desc.speedMaxOffRoad + local TypeName = Desc.typeName + self:T( self.CargoInAir ) -- Only move the group to the carrier when the cargo is not in the air @@ -240,28 +244,33 @@ do -- CARGO_UNIT if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then self:Load( CargoCarrier, NearRadius, ... ) else - local Speed = 90 - local Angle = 180 - local Distance = 5 + if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then + self:Load( CargoCarrier, NearRadius, ... ) + else + + local Speed = 90 + local Angle = 180 + local Distance = 5 + + NearRadius = NearRadius or 25 - NearRadius = NearRadius or 25 - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - self:__Boarding( -1, CargoCarrier, NearRadius ) - self.RunCount = 0 + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 2 ) + self:__Boarding( -1, CargoCarrier, NearRadius ) + self.RunCount = 0 + end end end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 939973fd1..58c24bcce 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4131,6 +4131,19 @@ function SET_CARGO:New() --R2.1 return self end + +--- (R2.1) Add CARGO to SET_CARGO. +-- @param Core.Set#SET_CARGO self +-- @param Cargo.Cargo#CARGO Cargo A single cargo. +-- @return self +function SET_CARGO:AddCargo( Cargo ) --R2.4 + + self:Add( Cargo:GetName(), Cargo ) + + return self +end + + --- (R2.1) Add CARGOs to SET_CARGO. -- @param Core.Set#SET_CARGO self -- @param #string AddCargoNames A single name or an array of CARGO names. diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 1847a16cd..f5b414e60 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1892,7 +1892,7 @@ end -- @param #CONTROLLABLE self -- @return #CONTROLLABLE function CONTROLLABLE:RouteStop() - self:F2() + self:F("RouteStop") local CommandStop = self:CommandStopRoute( true ) self:SetCommand( CommandStop ) @@ -1903,7 +1903,7 @@ end -- @param #CONTROLLABLE self -- @return #CONTROLLABLE function CONTROLLABLE:RouteResume() - self:F2() + self:F("RouteResume") local CommandResume = self:CommandStopRoute( false ) self:SetCommand( CommandResume ) From b1ecdc727c98ca17f758a7d0d58b1df91a291a32 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 7 Apr 2018 19:00:18 +0200 Subject: [PATCH 035/170] Faster menu and fix for Disembark loaded engineers in other helicopter. --- Moose Development/Moose/Cargo/Cargo.lua | 8 ++++++++ Moose Development/Moose/Tasking/Task_CARGO.lua | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index eb44217a3..cacd5fa64 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -384,6 +384,14 @@ do -- CARGO return self:Is( "Loaded" ) end + --- Check if cargo is loaded. + -- @param #CARGO self + -- @param Wrapper.Unit#UNIT Carrier + -- @return #boolean true if loaded + function CARGO:IsLoadedInCarrier( Carrier ) + return self.CargoCarrier and self.CargoCarrier:GetName() == Carrier:GetName() + end + --- Check if cargo is unloaded. -- @param #CARGO self -- @return #boolean true if unloaded diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 101399783..933413ebc 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -306,7 +306,7 @@ do -- TASK_CARGO end - if Cargo:IsLoaded() then + if Cargo:IsLoaded() == true and Cargo:IsLoadedInCarrier( TaskUnit ) == true then if not TaskUnit:InAir() then if Cargo:CanUnboard() == true then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime) @@ -333,7 +333,7 @@ do -- TASK_CARGO TaskUnit.Menu:Remove( MenuTime ) - self:__SelectAction( -5 ) + self:__SelectAction( -1 ) end From 303f5cb571fc3d6193402553efb699df49f39f54 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 7 Apr 2018 23:36:09 +0200 Subject: [PATCH 036/170] RANGE v1.1.0 - Missiles are now tracked. - Statics can now be used for strafe pits. - Statics are automatically recognized. - More user functions to add bomb or strafe targets. - Bomb targets are allowed to move. - Bomb targets can automatically move randomly inside the range zone. - Improved trace output. - Documentation updated. --- Moose Development/Moose/Functional/Range.lua | 783 ++++++++++++++----- 1 file changed, 569 insertions(+), 214 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index e3e3590cb..9748e89d6 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -16,12 +16,12 @@ -- -- ## Features -- --- * Bomb and rocket impact point from closest range target is measured and distance reported to the player. --- * Number of hits on strafing passes are counted. +-- * Impact points of bombs, rockets and missils are recorded and distance to closest range target is measured and reported to the player. +-- * Number of hits on strafing passes are counted and reported. Also the percentage of hits w.r.t fired shots is evaluated. -- * Results of all bombing and strafing runs are stored and top 10 results can be displayed. -- * Range targets can be marked by smoke. -- * Range can be illuminated by illumination bombs for night practices. --- * Rocket or bomb impact points can be marked by smoke. +-- * Bomb, rocket and missile impact points can be marked by smoke. -- * Direct hits on targets can trigger flares. -- * Smoke and flare colors can be adjusted for each player via radio menu. -- * Range information and weather report at the range can be reported via radio menu. @@ -55,8 +55,9 @@ -- @field #string ClassName Name of the Class. -- @field #boolean Debug If true, debug info is send as messages on the screen. -- @field #string rangename Name of the range. --- @field Core.Point#COORDINATE location Coordinate of the range. --- @field #number rangeradius Radius of range defining its total size for e.g. smoking bomb impact points and sending radio messages. Default 10 km. +-- @field Core.Point#COORDINATE location Coordinate of the range location. +-- @field #number rangeradius Radius of range defining its total size for e.g. smoking bomb impact points and sending radio messages. Default 5 km. +-- @field Core.Zone#ZONE rangezone MOOSE zone object of the range. For example, no bomb impacts are smoked if bombs fall outside of the range zone. -- @field #table strafeTargets Table of strafing targets. -- @field #table bombingTargets Table of targets to bomb. -- @field #number nbombtargets Number of bombing targets. @@ -79,14 +80,17 @@ -- @field #number scorebombdistance Distance from closest target up to which bomb hits are counted. Default 1000 m. -- @field #number TdelaySmoke Time delay in seconds between impact of bomb and starting the smoke. Default 3 seconds. -- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true. +-- @field #boolean trackbombs If true (default), all bomb types are tracked and impact point to closest bombing target is evaluated. +-- @field #boolean trackrockets If true (default), all rocket types are tracked and impact point to closest bombing target is evaluated. +-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated. -- @extends Core.Base#BASE ---# RANGE class, extends @{Base#BASE} -- The RANGE class enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. -- The parameter "rangename" defindes the name of the range. It has to be unique since this is also the name displayed in the radio menu. -- --- Generally, a range consits of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated. --- For bombing targets, the distance from the impact point of the bomb or rocket to the closest range target is measured and tabulated. +-- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated. +-- For bombing targets, the distance from the impact point of the bomb, rocket or missile to the closest range target is measured and tabulated. -- Each player can display his best results via a function in the radio menu or see the best best results from all players. -- -- When all targets have been defined in the script, the range is started by the @{#RANGE.Start}() command. @@ -101,31 +105,34 @@ -- ## Strafe Pits -- Each strafe pit can consist of multiple targets. Often one findes two or three strafe targets next to each other. -- --- A strafe pit can be added to the range by the @{#RANGE.AddStrafepit}(unitnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline) function. +-- A strafe pit can be added to the range by the @{#RANGE.AddStrafepit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function. -- --- The first parameter defines the target. This has to be given as a lua table which contains the unit names of the targets as defined in the mission editor. +-- * The first parameter *targetnames* defines the target or targets. This has to be given as a lua table which contains the names of @{Unit} or @{Static} objects defined in the mission editor. +-- * In order to perform a valid pass on the strafe pit, the pilot has to begin his run from the correct direction. Therefore, an "approach box" is defined in front +-- of the strafe targets. The parameters *boxlength* and *boxwidth* define the size of the box while the parameter *heading* defines its direction. +-- If the parameter *heading* is passed as **nil**, the heading is automatically taken from the heading of the first target unit as defined in the ME. +-- The parameter *inverseheading* turns the heading around by 180 degrees. This is sometimes useful, since the default heading of strafe target units point in the +-- wrong/opposite direction. +-- * The parameter *goodpass* defines the number of hits a pilot has to achive during a run to be judged as a "good" pass. +-- * The last parameter *foulline* sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted! -- --- In order to perform a valid pass on the strafe pit, the pilot has to begin his run from the correct direction. Therefore, an "approach box" is defined in front --- of the strafe targets. The parameters "boxlength" and "boxwidth" define the size of the box while the parameter "heading" defines its direction. --- If the parameter heading is passed as **nil**, the heading is automatically taken from the heading of the first target unit as defined in the ME. --- The parameter "inverseheading" turns the heading around by 180 degrees. This is sometimes useful, since the default heading of strafe target units point in the --- wrong/opposite direction. --- --- The parameter "goodpass" defines the number of hits a pilot has to achive during a run to be judges as a good pass. --- --- The last parameter "foulline" sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted. +-- Another function to add a strafe pit is @{#RANGE.AddStrafePitGroup}(*group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*). Here, +-- the first parameter *group* is a MOOSE @{Group} object and **all** units in this group define **one** strafe pit. -- -- Finally, a valid approach has to be performed below a certain maximum altitude. The default is 914 meters (3000 ft) AGL. This is a parameter valid for all -- strafing pits of the range and can be adjusted by the @{#RANGE.SetMaxStrafeAlt}(maxalt) function. -- -- ## Bombing targets --- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(unitnames goodhitrange,static) function. +-- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(targetnames, goodhitrange, randommove) function. -- --- The first parameter "unitnames" has to be a lua table, which contains the names of the units as defined in the mission editor. --- --- The parameter "goodhitrange" specifies the radius around the target. If a bomb or rocket falls at a distance smaller than this number, the hit is considered to be "good". --- --- The final (optional) parameter "static" can be enabled (set to true) if static bomb targets are used rather than alive units. +-- * The first parameter *targetnames* has to be a lua table, which contains the names of @{Unit} and/or @{Static} objects defined in the mission editor. +-- Note that the @{Range} logic **automatically** determines, if a name belongs to a @{Unit} or @{Static} object now. +-- * The (optional) parameter *goodhitrange* specifies the radius around the target. If a bomb or rocket falls at a distance smaller than this number, the hit is considered to be "good". +-- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone. +-- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired. +-- +-- Another possibility to add bombing targets is the @{#RANGE.AddBombingTargetGroup}(*group, goodhitrange, randommove*) function. Here the parameter *group* is a MOOSE @{Group} object +-- and **all** units in this group are defined as bombing targets. -- -- ## Fine Tuning -- Many range parameters have good default values. However, the mission designer can change these settings easily with the supplied user functions: @@ -138,6 +145,9 @@ -- * @{#RANGE.SetStrafeTargetSmokeColor}() sets the color used to smoke strafe targets. -- * @{#RANGE.SetStrafePitSmokeColor}() sets the color used to smoke strafe pit approach boxes. -- * @{#RANGE.SetSmokeTimeDelay}() sets the time delay between smoking bomb/rocket impact points after impact. +-- * @{#RANGE.TrackBombsON}() or @{#RANGE.TrackBombsOFF}() can be used to enable/disable tracking and evaluating of all bomb types a player fires. +-- * @{#RANGE.TrackRocketsON}() or @{#RANGE.TrackRocketsOFF}() can be used to enable/disable tracking and evaluating of all rocket types a player fires. +-- * @{#RANGE.TrackMissilesON}() or @{#RANGE.TrackMissilesOFF}() can be used to enable/disable tracking and evaluating of all missile types a player fires. -- -- ## Radio Menu -- Each range gets a radio menu with various submenus where each player can adjust his individual settings or request information about the range or his scores. @@ -155,11 +165,11 @@ -- ## Examples -- -- ### Goldwater Range --- This example shows hot to set up the Barry M. Goldwater range. It consists of two strafe pits each has two targets plus three bombing targets. +-- This example shows hot to set up the [Barry M. Goldwater range](https://en.wikipedia.org/wiki/Barry_M._Goldwater_Air_Force_Range). +-- It consists of two strafe pits each has two targets plus three bombing targets. -- --- The [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is used in this example. --- --- -- Strafe pits. Each pit can consist of multiple targets. Here we have two pits and each of the pits has two targets. These are names of the corresponding units defined in the ME. +-- -- Strafe pits. Each pit can consist of multiple targets. Here we have two pits and each of the pits has two targets. +-- -- These are names of the corresponding units defined in the ME. -- local strafepit_left={"GWR Strafe Pit Left 1", "GWR Strafe Pit Left 2"} -- local strafepit_right={"GWR Strafe Pit Right 1", "GWR Strafe Pit Right 2"} -- @@ -167,16 +177,15 @@ -- local bombtargets={"GWR Bomb Target Circle Left", "GWR Bomb Target Circle Right", "GWR Bomb Target Hard"} -- -- -- Create a range object. --- local GoldwaterRange=RANGE:New("Goldwater Range") +-- GoldwaterRange=RANGE:New("Goldwater Range") -- --- -- Distance between foul line and strafe target. Note that this could also be done manually by simply measuring the distance between the target and the foul line in the ME. --- local strafe=UNIT:FindByName("GWR Strafe Pit Left 1") --- local foul=UNIT:FindByName("GWR Foul Line Left") --- local fouldist=strafe:GetCoordinate():Get2DDistance(foul:GetCoordinate()) +-- -- Distance between strafe target and foul line. You have to specify the names of the unit or static objects. +-- -- Note that this could also be done manually by simply measuring the distance between the target and the foul line in the ME. +-- GoldwaterRange:GetFoullineDistance("GWR Strafe Pit Left 1", "GWR Foul Line Left") -- -- -- Add strafe pits. Each pit (left and right) consists of two targets. -- GoldwaterRange:AddStrafePit(strafepit_left, 3000, 300, nil, true, 20, fouldist) --- GoldwaterRange:AddStrafePit(strafepit_right, 3000, 300, nil, true, 20, fouldist) +-- GoldwaterRange:AddStrafePit(strafepit_right, nil, nil, nil, true, nil, fouldist) -- -- -- Add bombing targets. A good hit is if the bomb falls less then 50 m from the target. -- GoldwaterRange:AddBombingTargets(bombtargets, 50) @@ -184,6 +193,24 @@ -- -- Start range. -- GoldwaterRange:Start() -- +-- The [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is (implicitly) used in this example. +-- +-- ## Debugging +-- +-- In case you have problems, it is always a good idea to have a look at your DCS log file. You find it in your "Saved Games" folder, so for example in +-- C:\Users\\Saved Games\DCS\Logs\dcs.log +-- All output concerning the RANGE class should have the string "RANGE" in the corresponding line. +-- +-- The verbosity of the output can be increased by adding the following lines to your script: +-- +-- BASE:TraceOnOff(true) +-- BASE:TraceLevel(1) +-- BASE:TraceClass("RANGE") +-- +-- To get even more output you can increase the trace level to 2 or even 3, c.f. @{BASE} for more details. +-- +-- The function @{#RANGE.DebugON}() can be used to send messages on screen. It also smokes all defined strafe and bombing targets, the strafe pit approach boxes and the range zone. +-- -- -- -- @field #RANGE @@ -192,7 +219,8 @@ RANGE={ Debug=false, rangename=nil, location=nil, - rangeradius=10000, + rangeradius=5000, + rangezone=nil, strafeTargets={}, bombingTargets={}, nbombtargets=0, @@ -215,8 +243,32 @@ RANGE={ scorebombdistance=1000, TdelaySmoke=3.0, eventmoose=true, + trackbombs=true, + trackrockets=true, + trackmissiles=true, } +--- Default range parameters. +-- @list Defaults +RANGE.Defaults={ + goodhitrange=25, + strafemaxalt=914, + dtBombtrack=0.005, + Tmsg=30, + ndisplayresult=10, + rangeradius=5000, + TdelaySmoke=3.0, + boxlength=3000, + boxwidth=300, + goodpass=20, + goodhitrange=25, + foulline=610, +} + +--- Global list of all defined range names. +-- @field #table Names +RANGE.Names={} + --- Main radio menu. -- @field #table MenuF10 RANGE.MenuF10={} @@ -227,10 +279,13 @@ RANGE.id="RANGE | " --- Range script version. -- @field #number version -RANGE.version="1.0.3" +RANGE.version="1.1.0" ---TODO list ---TODO: Add statics for strafe pits. +--TODO list: +--TODO: Add custom weapons, which can be specified by the user. +--TODO: Check if units are still alive. +--DONE: Add statics for strafe pits. +--DONE: Add missiles. --DONE: Convert env.info() to self:T() --DONE: Add user functions. --DONE: Rename private functions, i.e. start with _functionname. @@ -251,6 +306,7 @@ function RANGE:New(rangename) local self=BASE:Inherit(self, BASE:New()) -- #RANGE -- Get range name. + --TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu. self.rangename=rangename or "Practice Range" -- Debug info. @@ -274,9 +330,10 @@ function RANGE:Start() local _count=0 for _,_target in pairs(self.bombingTargets) do _count=_count+1 - --_target.name + + -- Get range location. if _location==nil then - _location=_target.point --Core.Point#COORDINATE + _location=_target.target:GetCoordinate() --Core.Point#COORDINATE end end self.nbombtargets=_count @@ -285,6 +342,7 @@ function RANGE:Start() _count=0 for _,_target in pairs(self.strafeTargets) do _count=_count+1 + for _,_unit in pairs(_target.targets) do if _location==nil then _location=_unit:GetCoordinate() @@ -293,13 +351,20 @@ function RANGE:Start() end self.nstrafetargets=_count - -- Location of the range. We simply take the first unit/target we find. - self.location=_location + -- Location of the range. We simply take the first unit/target we find if it was not explicitly specified by the user. + if self.location==nil then + self.location=_location + end if self.location==nil then local text=string.format("ERROR! No range location found. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets) self:E(RANGE.id..text) - return nil + return + end + + -- Define a MOOSE zone of the range. + if self.rangezone==nil then + self.rangezone=ZONE_RADIUS:New(self.rangename, {x=self.location.x, y=self.location.z}, self.rangeradius) end -- Starting range. @@ -311,9 +376,6 @@ function RANGE:Start() if self.eventmoose then -- Events are handled my MOOSE. self:T(RANGE.id.."Events are handled by MOOSE.") - --self:HandleEvent(EVENTS.Birth, self._OnBirth) - --self:HandleEvent(EVENTS.Hit, self._OnHit) - --self:HandleEvent(EVENTS.Shot, self._OnShot) self:HandleEvent(EVENTS.Birth) self:HandleEvent(EVENTS.Hit) self:HandleEvent(EVENTS.Shot) @@ -323,6 +385,28 @@ function RANGE:Start() world.addEventHandler(self) end + -- Make bomb target move randomly within the range zone. + for _,_target in pairs(self.bombingTargets) do + + -- Check if it is a static object. + local _static=self:_CheckStatic(_target.target:GetName()) + + if _target.move and _static==false and _target.speed>1 then + local unit=_target.target --Wrapper.Unit#UNIT + _target.target:PatrolZones({self.rangezone}, _target.speed*0.75, "Off road") + end + + end + + -- Debug mode: smoke all targets and range zone. + if self.Debug then + self:_MarkTargetsOnMap() + self:_SmokeBombTargets() + self:_SmokeStrafeTargets() + self:_SmokeStrafeTargetBoxes() + self.rangezone:SmokeZone(SMOKECOLOR.White) + end + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -332,35 +416,50 @@ end -- @param #RANGE self -- @param #number maxalt Maximum altitude AGL in meters. Default is 914 m= 3000 ft. function RANGE:SetMaxStrafeAlt(maxalt) - self.strafemaxalt=maxalt or 914 + self.strafemaxalt=maxalt or RANGE.Defaults.strafemaxalt end --- Set time interval for tracking bombs. A smaller time step increases accuracy but needs more CPU time. -- @param #RANGE self -- @param #number dt Time interval in seconds. Default is 0.005 s. function RANGE:SetBombtrackTimestep(dt) - self.dtBombtrack=dt or 0.005 + self.dtBombtrack=dt or RANGE.Defaults.dtBombtrack end --- Set time how long (most) messages are displayed. -- @param #RANGE self -- @param #number time Time in seconds. Default is 30 s. function RANGE:SetMessageTimeDuration(time) - self.Tmsg=time or 30 + self.Tmsg=time or RANGE.Defaults.Tmsg end --- Set max number of player results that are displayed. -- @param #RANGE self -- @param #number nmax Number of results. Default is 10. function RANGE:SetDisplayedMaxPlayerResults(nmax) - self.ndisplayresult=nmax or 10 + self.ndisplayresult=nmax or RANGE.Defaults.ndisplayresult end --- Set range radius. Defines the area in which e.g. bomb impacts are smoked. -- @param #RANGE self --- @param #number radius Radius in km. Default 10 km. +-- @param #number radius Radius in km. Default 5 km. function RANGE:SetRangeRadius(radius) - self.rangeradius=radius*1000 or 10000 + self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius +end + +--- Set range location. If this is not done, one (random) unit position of the range is used to determine the center of the range. +-- @param #RANGE self +-- @param Core.Point#COORDINATE coordinate Coordinate of the center of the range. +function RANGE:SetRangeLocation(coordinate) + self.location=coordinate +end + +--- Set range zone. For example, no bomb impact points are smoked if a bomb falls outside of this zone. +-- If a zone is not explicitly specified, the range zone is determined by its location and radius. +-- @param #RANGE self +-- @param Core.Zone#ZONE zone MOOSE zone defining the range perimeters. +function RANGE:SetRangeLocation(zone) + self.rangezone=zone end --- Set smoke color for marking bomb targets. By default bomb targets are marked by red smoke. @@ -388,7 +487,7 @@ end -- @param #RANGE self -- @param #number delay Time delay in seconds. Default is 3 seconds. function RANGE:SetSmokeTimeDelay(delay) - self.TdelaySmoke=delay or 3.0 + self.TdelaySmoke=delay or RANGE.Defaults.TdelaySmoke end --- Enable debug modus. @@ -403,24 +502,60 @@ function RANGE:DebugOFF() self.Debug=false end +--- Enables tracking of all bomb types. Note that this is the default setting. +-- @param #RANGE self +function RANGE:TrackBombsON() + self.trackbombs=true +end + +--- Disables tracking of all bomb types. +-- @param #RANGE self +function RANGE:TrackBombsOFF() + self.trackbombs=false +end + +--- Enables tracking of all rocket types. Note that this is the default setting. +-- @param #RANGE self +function RANGE:TrackRocketsON() + self.trackrockets=true +end + +--- Disables tracking of all rocket types. +-- @param #RANGE self +function RANGE:TrackRocketsOFF() + self.trackrockets=false +end + +--- Enables tracking of all missile types. Note that this is the default setting. +-- @param #RANGE self +function RANGE:TrackMissilesON() + self.trackmissiles=true +end + +--- Disables tracking of all missile types. +-- @param #RANGE self +function RANGE:TrackMissilesOFF() + self.trackmissiles=false +end + --- Add new strafe pit. For a strafe pit, hits from guns are counted. One pit can consist of several units. -- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading. -- Furthermore, the player must not be too high and fly in the direction of the pit to make a valid target apporoach. -- @param #RANGE self --- @param #table unitnames Table of unit names defining the strafe targets. The first target in the list determines the approach zone (heading and box). +-- @param #table targetnames Table of unit or static names defining the strafe targets. The first target in the list determines the approach zone (heading and box). -- @param #number boxlength (Optional) Length of the approach box in meters. Default is 3000 m. -- @param #number boxwidth (Optional) Width of the approach box in meters. Default is 300 m. -- @param #number heading (Optional) Approach heading in Degrees. Default is heading of the unit as defined in the mission editor. -- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false. -- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20. -- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line. -function RANGE:AddStrafePit(unitnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline) - self:F({unitnames=unitnames, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline}) +function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline) + self:F({targetnames=targetnames, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline}) -- Create table if necessary. - if type(unitnames) ~= "table" then - unitnames={unitnames} + if type(targetnames) ~= "table" then + targetnames={targetnames} end -- Make targets @@ -428,11 +563,34 @@ function RANGE:AddStrafePit(unitnames, boxlength, boxwidth, heading, inversehead local center=nil --Wrapper.Unit#UNIT local ntargets=0 - for _i,_name in ipairs(unitnames) do + for _i,_name in ipairs(targetnames) do - self:T(RANGE.id..string.format("Adding strafe target #%d %s", _i, _name)) - local unit=UNIT:FindByName(_name) + -- Check if we have a static or unit object. + local _isstatic=self:_CheckStatic(_name) + + local unit=nil + if _isstatic==true then + -- Add static object. + self:T(RANGE.id..string.format("Adding STATIC object %s as strafe target #%d.", _name, _i)) + unit=STATIC:FindByName(_name, false) + + elseif _isstatic==false then + + -- Add unit object. + self:T(RANGE.id..string.format("Adding UNIT object %s as strafe target #%d.", _name, _i)) + unit=UNIT:FindByName(_name) + + else + + -- Neither unit nor static object with this name could be found. + local text=string.format("ERROR! Could not find ANY strafe target object with name %s.", _name) + self:E(RANGE.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + + end + + -- Add object to targets. if unit then table.insert(_targets, unit) -- Define center as the first unit we find @@ -440,17 +598,21 @@ function RANGE:AddStrafePit(unitnames, boxlength, boxwidth, heading, inversehead center=unit end ntargets=ntargets+1 - else - local text=string.format("ERROR! Could not find strafe target with name %s.", _name) - self:E(RANGE.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug) end end + + -- Check if at least one target could be found. + if ntargets==0 then + local text=string.format("ERROR! No strafe target could be found when calling RANGE:AddStrafePit() for range %s", self.rangename) + self:E(RANGE.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + return + end -- Approach box dimensions. - local l=boxlength or 3000 - local w=(boxwidth or 300)/2 + local l=boxlength or RANGE.Defaults.boxlength + local w=(boxwidth or RANGE.Defaults.boxwidth)/2 -- Heading: either manually entered or automatically taken from unit heading. local heading=heading or center:GetHeading() @@ -469,10 +631,10 @@ function RANGE:AddStrafePit(unitnames, boxlength, boxwidth, heading, inversehead end -- Number of hits called a "good" pass. - local goodpass=goodpass or 20 + goodpass=goodpass or RANGE.Defaults.goodpass -- Foule line distance. - local foulline=foulline or 610 + foulline=foulline or RANGE.Defaults.foulline -- Coordinate of the range. local Ccenter=center:GetCoordinate() @@ -499,96 +661,195 @@ function RANGE:AddStrafePit(unitnames, boxlength, boxwidth, heading, inversehead --_polygon:BoundZone() -- Add zone to table. - table.insert(self.strafeTargets, {name=_name, polygon=_polygon, goodPass=goodpass, targets=_targets, foulline=foulline, smokepoints=p, heading=heading}) + table.insert(self.strafeTargets, {name=_name, polygon=_polygon, coordinate= Ccenter, goodPass=goodpass, targets=_targets, foulline=foulline, smokepoints=p, heading=heading}) -- Debug info - local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, boxlength, boxwidth, goodpass, foulline) + local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, l, w, goodpass, foulline) self:T(RANGE.id..text) MESSAGE:New(text, 5):ToAllIf(self.Debug) end ---- Add bombing target(s) to range. --- @param #RANGE self --- @param #table unitnames Table containing the unit names acting as bomb targets. --- @param #number goodhitrange (Optional) Max distance from target unit (in meters) which is considered as a good hit. Default is 25 m. --- @param #boolean static (Optional) Target is static. Default false. -function RANGE:AddBombingTargets(unitnames, goodhitrange, static) - self:F({unitnames=unitnames, goodhitrange=goodhitrange, static=static}) - -- Create a table if necessary. - if type(unitnames) ~= "table" then - unitnames={unitnames} - end - - if static == nil or static == false then - static=false - else - static=true - end - - -- Default range is 25 m. - goodhitrange=goodhitrange or 25 - - for _,name in pairs(unitnames) do - local _unit - local _static +--- Add all units of a group as one new strafe target pit. +-- For a strafe pit, hits from guns are counted. One pit can consist of several units. +-- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading. +-- Furthermore, the player must not be too high and fly in the direction of the pit to make a valid target apporoach. +-- @param #RANGE self +-- @param Wrapper.Group#GROUP group MOOSE group of unit names defining the strafe target pit. The first unit in the group determines the approach zone (heading and box). +-- @param #number boxlength (Optional) Length of the approach box in meters. Default is 3000 m. +-- @param #number boxwidth (Optional) Width of the approach box in meters. Default is 300 m. +-- @param #number heading (Optional) Approach heading in Degrees. Default is heading of the unit as defined in the mission editor. +-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false. +-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20. +-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line. +function RANGE:AddStrafePitGroup(group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline) + self:F({group=group, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline}) + + if group and group:IsAlive() then - if static then - - -- Add static object. Workaround since cargo objects are not yet in database because DCS function does not add those. - local _DCSstatic=StaticObject.getByName(name) - if _DCSstatic and _DCSstatic:isExist() then - self:T(RANGE.id..string.format("Adding DCS static to database. Name = %s.", name)) - _DATABASE:AddStatic(name) - else - self:E(RANGE.id..string.format("ERROR! DCS static DOES NOT exist! Name = %s.", name)) - end - - -- Now we can find it... - _static=STATIC:FindByName(name) - if _static then - self:AddBombingTargetUnit(_static, goodhitrange) - self:T(RANGE.id..string.format("Adding static bombing target %s with hit range %d.", name, goodhitrange)) - else - self:E(RANGE.id..string.format("ERROR! Cound not find static bombing target %s.", name)) - end - - else + -- Get units of group. + local _units=group:GetUnits() - _unit=UNIT:FindByName(name) - if _unit then - self:AddBombingTargetUnit(_unit, goodhitrange) - self:T(RANGE.id..string.format("Adding bombing target %s with hit range %d.", name, goodhitrange)) - else - self:E(RANGE.id..string.format("ERROR! Could not find bombing target %s.", name)) + -- Make table of unit names. + local _names={} + for _,_unit in ipairs(_units) do + + local _unit=_unit --Wrapper.Unit#UNIT + + if _unit and _unit:IsAlive() then + local _name=_unit:GetName() + table.insert(_names,_name) end end + + -- Add strafe pit. + self:AddStrafePit(_names, boxlength, boxwidth, heading, inverseheading, goodpass, foulline) + end +end + +--- Add bombing target(s) to range. +-- @param #RANGE self +-- @param #table targetnames Table containing names of unit or static objects serving as bomb targets. +-- @param #number goodhitrange (Optional) Max distance from target unit (in meters) which is considered as a good hit. Default is 25 m. +-- @param #boolean randommove If true, unit will move randomly within the range. Default is false. +function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove) + self:F({targetnames=targetnames, goodhitrange=goodhitrange, randommove=randommove}) + + -- Create a table if necessary. + if type(targetnames) ~= "table" then + targetnames={targetnames} + end + + -- Default range is 25 m. + goodhitrange=goodhitrange or RANGE.Defaults.goodhitrange + + for _,name in pairs(targetnames) do + + -- Check if we have a static or unit object. + local _isstatic=self:_CheckStatic(name) + + if _isstatic==true then + local _static=STATIC:FindByName(name) + self:T2(RANGE.id..string.format("Adding static bombing target %s with hit range %d.", name, goodhitrange, false)) + self:AddBombingTargetUnit(_static, goodhitrange) + elseif _isstatic==false then + local _unit=UNIT:FindByName(name) + self:T2(RANGE.id..string.format("Adding unit bombing target %s with hit range %d.", name, goodhitrange, randommove)) + self:AddBombingTargetUnit(_unit, goodhitrange) + else + self:E(RANGE.id..string.format("ERROR! Could not find bombing target %s.", name)) + end + end end ---- Add a unit as bombing target. +--- Add a unit or static object as bombing target. -- @param #RANGE self --- @param Wrapper.Unit#UNIT unit Unit of the strafe target. +-- @param Wrapper.Positionable#POSITIONABLE unit Positionable (unit or static) of the strafe target. -- @param #number goodhitrange Max distance from unit which is considered as a good hit. -function RANGE:AddBombingTargetUnit(unit, goodhitrange) - self:F({unit=unit, goodhitrange=goodhitrange}) +-- @param #boolean randommove If true, unit will move randomly within the range. Default is false. +function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove) + self:F({unit=unit, goodhitrange=goodhitrange, randommove=randommove}) - local coord=unit:GetCoordinate() + -- Get name of positionable. local name=unit:GetName() - -- Default range is 25 m. - goodhitrange=goodhitrange or 25 + -- Check if we have a static or unit object. + local _isstatic=self:_CheckStatic(name) - -- Create a zone around the unit. - local Vec2=coord:GetVec2() - local Rzone=ZONE_RADIUS:New(name, Vec2, goodhitrange) + -- Default range is 25 m. + goodhitrange=goodhitrange or RANGE.Defaults.goodhitrange + + -- Set randommove to false if it was not specified. + if randommove==nil or _isstatic==true then + randommove=false + end + + -- Debug or error output. + if _isstatic==true then + self:T(RANGE.id..string.format("Adding STATIC bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring(randommove))) + elseif _isstatic==false then + self:T(RANGE.id..string.format("Adding UNIT bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring(randommove))) + else + self:E(RANGE.id..string.format("ERROR! No bombing target with name %s could be found. Carefully check all UNIT and STATIC names defined in the mission editor!", name)) + end + + -- Get max speed of unit in km/h. + local speed=0 + if _isstatic==false then + speed=self:_GetSpeed(unit) + end -- Insert target to table. - table.insert(self.bombingTargets, {name=name, point=coord, zone=Rzone, target=unit, goodhitrange=goodhitrange}) + table.insert(self.bombingTargets, {name=name, target=unit, goodhitrange=goodhitrange, move=randommove, speed=speed}) end +--- Add all units of a group as bombing targets. +-- @param #RANGE self +-- @param Wrapper.Group#GROUP group Group of bombing targets. +-- @param #number goodhitrange Max distance from unit which is considered as a good hit. +-- @param #boolean randommove If true, unit will move randomly within the range. Default is false. +function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove) + self:F({group=group, goodhitrange=goodhitrange, randommove=randommove}) + + if group then + + local _units=group:GetUnits() + + for _,_unit in pairs(_units) do + if _unit and _unit:IsAlive() then + self:AddBombingTargetUnit(_unit, goodhitrange, randommove) + end + end + end + +end + +--- Measures the foule line distance between two unit or static objects. +-- @param #RANGE self +-- @param #string namepit Name of the strafe pit target object. +-- @param #string namefoulline Name of the fould line distance marker object. +-- @return #number Foul line distance in meters. +function RANGE:GetFoullineDistance(namepit, namefoulline) + self:F({namepit=namepit, namefoulline=namefoulline}) + + -- Check if we have units or statics. + local _staticpit=self:_CheckStatic(namepit) + local _staticfoul=self:_CheckStatic(namefoulline) + + -- Get the unit or static pit object. + local pit=nil + if _staticpit==true then + pit=STATIC:FindByName(namepit, false) + elseif _staticpit==false then + pit=UNIT:FindByName(namepit) + else + self:E(RANGE.id..string.format("ERROR! Pit object %s could not be found in GetFoullineDistance function. Check the name in the ME.", namepit)) + end + + -- Get the unit or static foul line object. + local foul=nil + if _staticfoul==true then + foul=STATIC:FindByName(namefoulline, false) + elseif _staticfoul==false then + foul=UNIT:FindByName(namefoulline) + else + self:E(RANGE.id..string.format("ERROR! Foul line object %s could not be found in GetFoullineDistance function. Check the name in the ME.", namefoulline)) + end + + -- Get the distance between the two objects. + local fouldist=0 + if pit~=nil and foul~=nil then + fouldist=pit:GetCoordinate():Get2DDistance(foul:GetCoordinate()) + else + self:E(RANGE.id..string.format("ERROR! Foul line distance could not be determined. Check pit object name %s and foul line object name %s in the ME.", namepit, namefoulline)) + end + + self:T(RANGE.id..string.format("Foul line distance = %.1f m.", fouldist)) + return fouldist +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Event Handling @@ -600,11 +861,11 @@ function RANGE:onEvent(Event) self:F3(Event) if Event == nil or Event.initiator == nil then - self:T2("Skipping onEvent. Event or Event.initiator unknown.") + self:T3("Skipping onEvent. Event or Event.initiator unknown.") return true end if Unit.getByName(Event.initiator:getName()) == nil then - self:T2("Skipping onEvent. Initiator unit name unknown.") + self:T3("Skipping onEvent. Initiator unit name unknown.") return true end @@ -646,19 +907,16 @@ function RANGE:onEvent(Event) -- Call event Birth function. if Event.id==world.event.S_EVENT_BIRTH and _playername then self:OnEventBirth(EventData) - --self:_OnBirth(EventData) end -- Call event Shot function. if Event.id==world.event.S_EVENT_SHOT and _playername and Event.weapon then self:OnEventShot(EventData) - --self:_OnShot(EventData) end -- Call event Hit function. if Event.id==world.event.S_EVENT_HIT and _playername and DCStgtunit then self:OnEventHit(EventData) - --self:_OnHit(EventData) end end @@ -668,7 +926,6 @@ end -- @param #RANGE self -- @param Core.Event#EVENTDATA EventData function RANGE:OnEventBirth(EventData) ---function RANGE:_OnBirth(EventData) self:F({eventbirth = EventData}) local _unitName=EventData.IniUnitName @@ -690,6 +947,8 @@ function RANGE:OnEventBirth(EventData) self:T(RANGE.id..text) MESSAGE:New(text, 5):ToAllIf(self.Debug) + self:_GetAmmo(_unitName) + -- Reset current strafe status. self.strafeStatus[_uid] = nil @@ -717,7 +976,6 @@ end -- @param #RANGE self -- @param Core.Event#EVENTDATA EventData function RANGE:OnEventHit(EventData) ---function RANGE:_OnHit(EventData) self:F({eventhit = EventData}) -- Debug info. @@ -733,7 +991,7 @@ function RANGE:OnEventHit(EventData) end -- Unit ID - local _unitID = _unit:GetID() + local _unitID = _unit:GetID() -- Target local target = EventData.TgtUnit @@ -743,7 +1001,7 @@ function RANGE:OnEventHit(EventData) local _currentTarget = self.strafeStatus[_unitID] -- Player has rolled in on a strafing target. - if _currentTarget then + if _currentTarget and target:IsAlive() then local playerPos = _unit:GetCoordinate() local targetPos = target:GetCoordinate() @@ -752,7 +1010,7 @@ function RANGE:OnEventHit(EventData) for _,_target in pairs(_currentTarget.zone.targets) do -- Check the the target is the same that was actually hit. - if _target:GetName() == targetname then + if _target and _target:IsAlive() and _target:GetName() == targetname then -- Get distance between player and target. local dist=playerPos:Get2DDistance(targetPos) @@ -768,7 +1026,7 @@ function RANGE:OnEventHit(EventData) else -- Too close to the target. if _currentTarget.pastfoulline==false and _unit and _playername then - local _d=_currentTarget.zone.foulline + local _d=_currentTarget.zone.foulline local text=string.format("%s, Invalid hit!\nYou already passed foul line distance of %d m for target %s.", self:_myname(_unitName), _d, targetname) self:_DisplayMessageToGroup(_unit, text, 10) self:T2(RANGE.id..text) @@ -781,15 +1039,17 @@ function RANGE:OnEventHit(EventData) end -- Bombing Targets - for _,_target in pairs(self.bombingTargets) do + for _,_bombtarget in pairs(self.bombingTargets) do + + local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE -- Check if one of the bomb targets was hit. - if _target.name == targetname then + if _target and _target:IsAlive() and _bombtarget.name == targetname then if _unit and _playername then - local playerPos = _unit:GetCoordinate() - local targetPos = target:GetCoordinate() + -- Position of target. + local targetPos = _target:GetCoordinate() -- Message to player. --local text=string.format("%s, direct hit on target %s.", self:_myname(_unitName), targetname) @@ -809,7 +1069,6 @@ end -- @param #RANGE self -- @param Core.Event#EVENTDATA EventData function RANGE:OnEventShot(EventData) ---function RANGE:_OnShot(EventData) self:F({eventshot = EventData}) -- Weapon data. @@ -818,13 +1077,23 @@ function RANGE:OnEventShot(EventData) local _weaponName = _weaponStrArray[#_weaponStrArray] -- Debug info. - self:T3(RANGE.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) - self:T3(RANGE.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) - self:T3(RANGE.id.."EVENT SHOT: Weapon type = ".._weapon) - self:T3(RANGE.id.."EVENT SHOT: Weapon name = ".._weaponName) + self:T(RANGE.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) + self:T(RANGE.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) + self:T(RANGE.id.."EVENT SHOT: Weapon type = ".._weapon) + self:T(RANGE.id.."EVENT SHOT: Weapon name = ".._weaponName) - -- Monitor only bombs and rockets. - if (string.match(_weapon, "weapons.bombs") or string.match(_weapon, "weapons.nurs")) then + -- Special cases: + local _viggen=string.match(_weapon, "ROBOT") or string.match(_weapon, "RB75") or string.match(_weapon, "BK90") or string.match(_weapon, "RB15") or string.match(_weapon, "RB04") + + -- Tracking conditions for bombs, rockets and missiles. + local _bombs=string.match(_weapon, "weapons.bombs") + local _rockets=string.match(_weapon, "weapons.nurs") + local _missiles=string.match(_weapon, "weapons.missiles") or _viggen + + -- Check if any condition applies here. + local _track = (_bombs and self.trackbombs) or (_rockets and self.trackrockets) or (_missiles and self.trackmissiles) + + if _track then -- Weapon local _ordnance = EventData.weapon @@ -887,11 +1156,15 @@ function RANGE:OnEventShot(EventData) -- Loop over defined bombing targets. for _,_bombtarget in pairs(self.bombingTargets) do - -- Distance between bomb and target. - local _temp = impactcoord:Get2DDistance(_bombtarget.point) - - -- Find closest target to last known position of the bomb. - if _distance == nil or _temp < _distance then + local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + + if _target and _target:IsAlive() then + + -- Distance between bomb and target. + local _temp = impactcoord:Get2DDistance(_target:GetCoordinate()) + + -- Find closest target to last known position of the bomb. + if _distance == nil or _temp < _distance then _distance = _temp _closetTarget = _bombtarget if _distance <= 0.5*_bombtarget.goodhitrange then @@ -903,6 +1176,8 @@ function RANGE:OnEventShot(EventData) else _hitquality = "POOR" end + + end end end @@ -1335,7 +1610,7 @@ end -- @param #RANGE self -- @param #string _unitName Name of player unit. function RANGE:_CheckInZone(_unitName) - self:F(_unitName) + self:F2(_unitName) -- Get player unit and name. local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) @@ -1364,7 +1639,7 @@ function RANGE:_CheckInZone(_unitName) -- Debug output local text=string.format("Checking stil in zone. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _unitName, _playername, tostring(unitinzone), unitalt, deltaheading) - self:T(RANGE.id..text) + self:T2(RANGE.id..text) -- Check if player is in strafe zone and below max alt. if unitinzone then @@ -1407,13 +1682,13 @@ function RANGE:_CheckInZone(_unitName) _result.text = "POOR PASS" end + -- Calculate accuracy of run. Number of hits wrt number of rounds fired. local shots=_result.ammo-_ammo local accur=0 if shots>0 then accur=_result.hits/shots*100 end - - + -- Message text. local _text=string.format("%s, %s with %d hits on target %s.", self:_myname(_unitName), _result.text, _result.hits, _result.zone.name) if shots and accur then @@ -1455,7 +1730,7 @@ function RANGE:_CheckInZone(_unitName) -- Debug info. local text=string.format("Checking zone %s. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _targetZone.name, _unitName, _playername, tostring(unitinzone), unitalt, deltaheading) - self:T(RANGE.id..text) + self:T2(RANGE.id..text) -- Player is inside zone. if unitinzone then @@ -1509,7 +1784,7 @@ function RANGE:_AddF10Commands(_unitName) -- Enable switch so we don't do this twice. self.MenuAddedTo[_gid] = true - -- Main F10 menu: F10/On the Range + -- Main F10 menu: F10/On the Range// if RANGE.MenuF10[_gid] == nil then RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range") end @@ -1517,40 +1792,39 @@ function RANGE:_AddF10Commands(_unitName) local _statsPath = missionCommands.addSubMenuForGroup(_gid, "Statistics", _rangePath) local _markPath = missionCommands.addSubMenuForGroup(_gid, "Mark Targets", _rangePath) local _settingsPath = missionCommands.addSubMenuForGroup(_gid, "My Settings", _rangePath) - -- F10/On the Range/My Settings/ + -- F10/On the Range//My Settings/ local _mysmokePath = missionCommands.addSubMenuForGroup(_gid, "Smoke Color", _settingsPath) local _myflarePath = missionCommands.addSubMenuForGroup(_gid, "Flare Color", _settingsPath) - --TODO: Convert to MOOSE menu. - -- F10/On the Range/Mark Targets/ + -- F10/On the Range//Mark Targets/ missionCommands.addCommandForGroup(_gid, "Mark On Map", _markPath, self._MarkTargetsOnMap, self, _unitName) missionCommands.addCommandForGroup(_gid, "Illuminate Range", _markPath, self._IlluminateBombTargets, self, _unitName) missionCommands.addCommandForGroup(_gid, "Smoke Strafe Pits", _markPath, self._SmokeStrafeTargetBoxes, self, _unitName) missionCommands.addCommandForGroup(_gid, "Smoke Strafe Tgts", _markPath, self._SmokeStrafeTargets, self, _unitName) missionCommands.addCommandForGroup(_gid, "Smoke Bomb Tgts", _markPath, self._SmokeBombTargets, self, _unitName) - -- F10/On the Range/Stats/ + -- F10/On the Range//Stats/ missionCommands.addCommandForGroup(_gid, "All Strafe Results", _statsPath, self._DisplayStrafePitResults, self, _unitName) missionCommands.addCommandForGroup(_gid, "All Bombing Results", _statsPath, self._DisplayBombingResults, self, _unitName) missionCommands.addCommandForGroup(_gid, "My Strafe Results", _statsPath, self._DisplayMyStrafePitResults, self, _unitName) missionCommands.addCommandForGroup(_gid, "My Bomb Results", _statsPath, self._DisplayMyBombingResults, self, _unitName) missionCommands.addCommandForGroup(_gid, "Reset All Stats", _statsPath, self._ResetRangeStats, self, _unitName) - -- F10/On the Range/My Settings/Smoke Color/ + -- F10/On the Range//My Settings/Smoke Color/ missionCommands.addCommandForGroup(_gid, "Blue Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Blue) missionCommands.addCommandForGroup(_gid, "Green Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Green) missionCommands.addCommandForGroup(_gid, "Orange Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Orange) missionCommands.addCommandForGroup(_gid, "Red Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Red) missionCommands.addCommandForGroup(_gid, "White Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.White) - -- F10/On the Range/My Settings/Flare Color/ + -- F10/On the Range//My Settings/Flare Color/ missionCommands.addCommandForGroup(_gid, "Green Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Green) missionCommands.addCommandForGroup(_gid, "Red Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Red) missionCommands.addCommandForGroup(_gid, "White Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.White) missionCommands.addCommandForGroup(_gid, "Yellow Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Yellow) - -- F10/On the Range/My Settings/ + -- F10/On the Range//My Settings/ missionCommands.addCommandForGroup(_gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName) missionCommands.addCommandForGroup(_gid, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName) missionCommands.addCommandForGroup(_gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName) - -- F10/On the Range/ + -- F10/On the Range// missionCommands.addCommandForGroup(_gid, "Range Information", _rangePath, self._DisplayRangeInfo, self, _unitName) missionCommands.addCommandForGroup(_gid, "Weather Report", _rangePath, self._DisplayRangeWeather, self, _unitName) end @@ -1571,7 +1845,7 @@ end -- @param #string unitname Name of the player unit. -- @return Number of shells left function RANGE:_GetAmmo(unitname) - self:F(unitname) + self:F2(unitname) -- Init counter. local ammo=0 @@ -1603,7 +1877,11 @@ function RANGE:_GetAmmo(unitname) local text=string.format("Player %s has %d rounds ammo of type %s", playername, Nammo, Tammo) self:T(RANGE.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + else + local text=string.format("Player %s has %d ammo of type %s", playername, Nammo, Tammo) + self:T(RANGE.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) end end end @@ -1619,31 +1897,45 @@ function RANGE:_MarkTargetsOnMap(_unitName) self:F(_unitName) -- Get group. - local group=UNIT:FindByName(_unitName):GetGroup() - - if group then + local group=nil + if _unitName then + group=UNIT:FindByName(_unitName):GetGroup() + end - -- Mark bomb targets. - for _,_target in pairs(self.bombingTargets) do - local coord=_target.point --Core.Point#COORDINATE - coord:MarkToGroup("Bomb target ".._target.name, group) - end - - -- Mark strafe targets. - for _,_strafepit in pairs(self.strafeTargets) do - for _,_target in pairs(_strafepit.targets) do - local coord=_target:GetCoordinate() --Core.Point#COORDINATE - coord:MarkToGroup("Strafe target ".._target:GetName(), group) + -- Mark bomb targets. + for _,_bombtarget in pairs(self.bombingTargets) do + local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + if _target and _target:IsAlive() then + local coord=_target:GetCoordinate() --Core.Point#COORDINATE + if group then + coord:MarkToGroup("Bomb target ".._bombtarget.name, group) + else + coord:MarkToAll("Bomb target ".._bombtarget.name) end end - - if _unitName then - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - local text=string.format("%s, %s, range targets are now marked on F10 map.", self.rangename, _playername) - self:_DisplayMessageToGroup(_unit, text, 5) - end - end + + -- Mark strafe targets. + for _,_strafepit in pairs(self.strafeTargets) do + for _,_target in pairs(_strafepit.targets) do + local _target=_target --Wrapper.Positionable#POSITIONABLE + if _target and _target:IsAlive() then + local coord=_target:GetCoordinate() --Core.Point#COORDINATE + if group then + coord:MarkToGroup("Strafe target ".._target:GetName(), group) + else + coord:MarkToAll("Strafe target ".._target:GetName()) + end + end + end + end + + if _unitName then + local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local text=string.format("%s, %s, range targets are now marked on F10 map.", self.rangename, _playername) + self:_DisplayMessageToGroup(_unit, text, 5) + end + end --- Illuminate targets. Fires illumination bombs at one random bomb and one random strafe target at a random altitude between 400 and 800 m. @@ -1655,9 +1947,12 @@ function RANGE:_IlluminateBombTargets(_unitName) -- All bombing target coordinates. local bomb={} - for _,_target in pairs(self.bombingTargets) do - local coord=_target.point --Core.Point#COORDINATE - table.insert(bomb, coord) + for _,_bombtarget in pairs(self.bombingTargets) do + local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + if _target and _target:IsAlive() then + local coord=_target:GetCoordinate() --Core.Point#COORDINATE + table.insert(bomb, coord) + end end if #bomb>0 then @@ -1671,8 +1966,11 @@ function RANGE:_IlluminateBombTargets(_unitName) for _,_strafepit in pairs(self.strafeTargets) do for _,_target in pairs(_strafepit.targets) do - local coord=_target:GetCoordinate() --Core.Point#COORDINATE - table.insert(strafe, coord) + local _target=_target --Wrapper.Positionable#POSITIONABLE + if _target and _target:IsAlive() then + local coord=_target:GetCoordinate() --Core.Point#COORDINATE + table.insert(strafe, coord) + end end end @@ -1803,9 +2101,12 @@ end function RANGE:_SmokeBombTargets(unitname) self:F(unitname) - for _,_target in pairs(self.bombingTargets) do - local coord = _target.point --Core.Point#COORDINATE - coord:Smoke(self.BombSmokeColor) + for _,_bombtarget in pairs(self.bombingTargets) do + local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + if _target and _target:IsAlive() then + local coord = _target:GetCoordinate() --Core.Point#COORDINATE + coord:Smoke(self.BombSmokeColor) + end end if unitname then @@ -1823,10 +2124,7 @@ function RANGE:_SmokeStrafeTargets(unitname) self:F(unitname) for _,_target in pairs(self.strafeTargets) do - for _,_unit in pairs(_target.targets) do - local coord = _unit:GetCoordinate() --Core.Point#COORDINATE - coord:Smoke(self.StrafeSmokeColor) - end + _target.coordinate:Smoke(self.StrafeSmokeColor) end if unitname then @@ -1939,6 +2237,63 @@ function RANGE:_flarecolor2text(color) return txt end +--- Checks if a static object with a certain name exists. It also added it to the MOOSE data base, if it is not already in there. +-- @param #RANGE self +-- @param #string name Name of the potential static object. +-- @return #boolean Returns true if a static with this name exists. Retruns false if a unit with this name exists. Returns nil if neither unit or static exist. +function RANGE:_CheckStatic(name) + self:F2(name) + + -- Get DCS static object. + local _DCSstatic=StaticObject.getByName(name) + + if _DCSstatic and _DCSstatic:isExist() then + + --Static does exist at least in DCS. Check if it also in the MOOSE DB. + local _MOOSEstatic=STATIC:FindByName(name, false) + + -- If static is not yet in MOOSE DB, we add it. Can happen for cargo statics! + if not _MOOSEstatic then + self:T(RANGE.id..string.format("Adding DCS static to MOOSE database. Name = %s.", name)) + _DATABASE:AddStatic(name) + end + + return true + else + self:T3(RANGE.id..string.format("No static object with name %s exists.", name)) + end + + -- Check if a unit has this name. + if UNIT:FindByName(name) then + return false + else + self:T3(RANGE.id..string.format("No unit object with name %s exists.", name)) + end + + -- If not unit or static exist, we return nil. + return nil +end + +--- Get max speed of controllable. +-- @param #RANGE self +-- @param Wrapper.Controllable#CONTROLLABLE controllable +-- @return Maximum speed in km/h. +function RANGE:_GetSpeed(controllable) + self:F2(controllable) + + -- Get DCS descriptors + local desc=controllable:GetDesc() + + -- Get speed + local speed=0 + if desc then + speed=desc.speedMax*3.6 + self:T({speed=speed}) + end + + return speed +end + --- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. -- @param #RANGE self -- @param #string _unitName Name of the player unit. @@ -1946,7 +2301,7 @@ end -- @return #string Name of the player. -- @return nil If player does not exist. function RANGE:_GetPlayerUnitAndName(_unitName) - self:F(_unitName) + self:F2(_unitName) if _unitName ~= nil then @@ -1958,7 +2313,7 @@ function RANGE:_GetPlayerUnitAndName(_unitName) local playername=DCSunit:getPlayerName() local unit=UNIT:Find(DCSunit) - self:T({DCSunit=DCSunit, unit=unit, playername=playername}) + self:T2({DCSunit=DCSunit, unit=unit, playername=playername}) if DCSunit and unit and playername then return unit, playername end @@ -1975,7 +2330,7 @@ end -- @param #RANGE self -- @param #string unitname Name of the player unit. function RANGE:_myname(unitname) - self:F(unitname) + self:F2(unitname) local unit=UNIT:FindByName(unitname) local pname=unit:GetPlayerName() @@ -1984,13 +2339,13 @@ function RANGE:_myname(unitname) return string.format("%s (%s)", csign, pname) end ---- http://stackoverflow.com/questions/1426954/split-string-in-lua +--- Split string. Cf http://stackoverflow.com/questions/1426954/split-string-in-lua -- @param #RANGE self -- @param #string str Sting to split. -- @param #string sep Speparator for split. -- @return #table Split text. function RANGE:_split(str, sep) - self:F({str=str, sep=sep}) + self:F2({str=str, sep=sep}) local result = {} local regex = ("([^%s]+)"):format(sep) From af23aa3b794a364cbb7d91d7bc99bfcdf040ce5a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 8 Apr 2018 11:01:46 +0200 Subject: [PATCH 037/170] -- Lots of fixes done. Especially on the - Messaging - Menu system - Crashing DCS - Routing --- Moose Development/Moose/Actions/Act_Route.lua | 17 ++-- Moose Development/Moose/Cargo/Cargo.lua | 56 +++++++++++-- Moose Development/Moose/Cargo/CargoCrate.lua | 2 +- Moose Development/Moose/Cargo/CargoGroup.lua | 1 + .../Moose/Cargo/CargoSlingload.lua | 6 ++ Moose Development/Moose/Core/Event.lua | 6 ++ Moose Development/Moose/Core/Fsm.lua | 4 + .../Moose/Tasking/Task_CARGO.lua | 80 +++++++++++-------- Moose Development/Moose/Wrapper/Unit.lua | 3 + 9 files changed, 131 insertions(+), 44 deletions(-) diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index e50c3ffcc..cbf089140 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -123,16 +123,21 @@ do -- ACT_ROUTE --- Set a Cancel Menu item. -- @param #ACT_ROUTE self -- @return #ACT_ROUTE - function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu, MenuTime ) + function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu ) - MENU_GROUP_COMMAND:New( + local MenuTime = timer.getTime() + 1 + + self.CancelMenuGroupCommand = MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, self.MenuCancel, self - ):SetTime(MenuTime) - + ):SetTime( MenuTime ) + + ParentMenu:SetTime( MenuTime ) + ParentMenu:Remove( MenuTime ) + return self end @@ -206,7 +211,9 @@ do -- ACT_ROUTE function ACT_ROUTE:MenuCancel() - self:Cancel() + self:F("Cancelled") + self.CancelMenuGroupCommand:Remove() + self:__Cancel( 1 ) end --- Task Events diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index cacd5fa64..09fac4fc3 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -258,7 +258,6 @@ do -- CARGO self:AddTransition( "*", "Destroyed", "Destroyed" ) self:AddTransition( "*", "Respawn", "UnLoaded" ) - self.Type = Type self.Name = Name self.Weight = Weight or 0 @@ -268,6 +267,9 @@ do -- CARGO self.Slingloadable = false self.Moveable = false self.Containable = false + self.LoadAction = "" + + self.CargoLimit = 0 self.LoadRadius = LoadRadius or 500 self.NearRadius = NearRadius or 25 @@ -293,6 +295,12 @@ do -- CARGO return CargoFound end + --- Check if the cargo can be Slingloaded. + -- @param #CARGO self + function CARGO:CanSlingload() + return false + end + --- Check if the cargo can be Boarded. -- @param #CARGO self function CARGO:CanBoard() @@ -317,9 +325,6 @@ do -- CARGO return true end - - - --- Destroy the cargo. -- @param #CARGO self @@ -354,13 +359,26 @@ do -- CARGO function CARGO:GetCount() return 1 end - + --- Get the type of the Cargo. -- @param #CARGO self -- @return #string The type of the Cargo. function CARGO:GetType() return self.Type end + + + --- Get the coalition of the Cargo. + -- @param #CARGO self + -- @return Coalition + function CARGO:GetCoalition() + if self:IsLoaded() then + return self.CargoCarrier:GetCoalition() + else + return self.CargoObject:GetCoalition() + end + end + --- Get the current coordinates of the Cargo. -- @param #CARGO self @@ -792,6 +810,32 @@ do -- CARGO_REPRESENTABLE return self end + --- Send a message to a @{Group} through a communication channel near the cargo. + -- @param #CARGO_REPRESENTABLE self + -- @param #string Message + -- @param Wrapper.Group#GROUP TaskGroup + -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. + function CARGO_REPRESENTABLE:MessageToGroup( Message, TaskGroup, Name ) + + local CoordinateZone = ZONE_RADIUS:New( "Zone" , self:GetCoordinate():GetVec2(), 500 ) + CoordinateZone:Scan( { Object.Category.UNIT } ) + for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do + local NearUnit = UNIT:Find( DCSUnit ) + self:F({NearUnit=NearUnit}) + local NearUnitCoalition = NearUnit:GetCoalition() + local CargoCoalition = self:GetCoalition() + if NearUnitCoalition == CargoCoalition then + local Attributes = NearUnit:GetDesc() + self:F({Desc=Attributes}) + if NearUnit:HasAttribute( "Trucks" ) then + MESSAGE:New( Message, 20, NearUnit:GetCallsign() .. " reporting - Cargo " .. self:GetName() ):ToGroup( TaskGroup ) + break + end + end + end + + end + end -- CARGO_REPRESENTABLE @@ -825,7 +869,7 @@ do -- CARGO_REPORTABLE -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name ) - MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( TaskGroup ) + MESSAGE:New( Message, 20, "Cargo " .. self:GetName() .. " reporting" ):ToGroup( TaskGroup ) end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 44ef41af6..b4a61a58b 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -50,7 +50,7 @@ do -- CARGO_CRATE self:F( { Type, Name, NearRadius } ) self.CargoObject = CargoStatic - + self:T( self.ClassName ) -- Cargo objects are added to the _DATABASE and SET_CARGO objects. diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 07806b45c..57ec3a0af 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -95,6 +95,7 @@ function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius ) self:SetWeight( WeightGroup ) + self.CargoLimit = 10 self:T( { "Weight Cargo", WeightGroup } ) diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 91f69f873..5e979d93c 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -66,6 +66,12 @@ do -- CARGO_SLINGLOAD end + --- Check if the cargo can be Slingloaded. + -- @param #CARGO self + function CARGO:CanSlingload() + return true + end + --- Check if the cargo can be Boarded. -- @param #CARGO_SLINGLOAD self function CARGO_SLINGLOAD:CanBoard() diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index a21911627..c68fec80b 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -174,6 +174,7 @@ EVENT = { ClassName = "EVENT", ClassID = 0, + MissionEnd = false, } world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000 @@ -748,8 +749,13 @@ function EVENT:onEvent( Event ) if self and self.Events and self.Events[Event.id] and + self.MissionEnd == false and ( Event.initiator ~= nil or ( Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit ) ) then + if Event.id and Event.id == EVENTS.MissionEnd then + self.MissionEnd = true + end + if Event.initiator then Event.IniObjectCategory = Event.initiator:getCategory() diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 0c49c79e3..efcea3aee 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -724,6 +724,10 @@ do -- FSM return self.current end + function FSM:GetCurrentState() + return self.current + end + function FSM:Is( State ) return self.current == State diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 933413ebc..a6a723054 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -174,17 +174,17 @@ do -- TASK_CARGO Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) - Fsm:AddTransition( { "Planned", "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Loaded", "UnLoaded", "Landed", "Boarding" }, "SelectAction", "*" ) + Fsm:AddTransition( { "Planned", "Assigned", "Cancelled", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Loaded", "UnLoaded", "Landed", "Boarding" }, "SelectAction", "*" ) Fsm:AddTransition( "*", "RouteToPickup", "RoutingToPickup" ) Fsm:AddProcess ( "RoutingToPickup", "RouteToPickupPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtPickup", Cancelled = "CancelRouteToPickup" } ) Fsm:AddTransition( "Arrived", "ArriveAtPickup", "ArrivedAtPickup" ) - Fsm:AddTransition( "Cancelled", "CancelRouteToPickup", "WaitingForCommand" ) + Fsm:AddTransition( "Cancelled", "CancelRouteToPickup", "Cancelled" ) Fsm:AddTransition( "*", "RouteToDeploy", "RoutingToDeploy" ) Fsm:AddProcess ( "RoutingToDeploy", "RouteToDeployZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtDeploy", Cancelled = "CancelRouteToDeploy" } ) Fsm:AddTransition( "Arrived", "ArriveAtDeploy", "ArrivedAtDeploy" ) - Fsm:AddTransition( "Cancelled", "CancelRouteToDeploy", "WaitingForCommand" ) + Fsm:AddTransition( "Cancelled", "CancelRouteToDeploy", "Cancelled" ) Fsm:AddTransition( { "ArrivedAtPickup", "ArrivedAtDeploy", "Landing" }, "Land", "Landing" ) Fsm:AddTransition( "Landing", "Landed", "Landed" ) @@ -249,7 +249,7 @@ do -- TASK_CARGO self:F( { CargoUnloaded = Cargo:IsUnLoaded(), CargoLoaded = Cargo:IsLoaded(), CargoItemCount = CargoItemCount } ) if Cargo:IsUnLoaded() then - if CargoItemCount <= Task.CargoLimit then + if CargoItemCount < 1 then if Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then local NotInDeployZones = true for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do @@ -261,18 +261,26 @@ do -- TASK_CARGO if not TaskUnit:InAir() then if Cargo:CanBoard() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then - Cargo:Report( "Reporting for boarding at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "board", TaskUnit:GetGroup() ) + Cargo:Report( "ready for boarding at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "board", TaskUnit:GetGroup() ) MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) else - Cargo:Report( "Reporting at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + Cargo:Report( "Board at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) end else if Cargo:CanLoad() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then - Cargo:Report( "Reporting for loading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "load", TaskUnit:GetGroup() ) + Cargo:Report( "ready for loading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "load", TaskUnit:GetGroup() ) MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) else - Cargo:Report( "Reporting at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + Cargo:Report( "Load at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + end + else + if Cargo:CanSlingload() == true then + if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then + Cargo:Report( "ready for slingloading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "slingload", TaskUnit:GetGroup() ) + else + Cargo:Report( "Slingload at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + end end end end @@ -282,9 +290,13 @@ do -- TASK_CARGO end end else - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Pickup cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime) - TaskUnit.Menu:SetTime( MenuTime ) - Cargo:ReportResetAll( TaskUnit:GetGroup() ) + if self:Is( "RoutingToPickup" ) then + else + self:F("route menu set") + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Pickup cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime) + TaskUnit.Menu:SetTime( MenuTime ) + Cargo:ReportResetAll( TaskUnit:GetGroup() ) + end end end -- Cargo in deployzones are flagged as deployed. @@ -405,7 +417,6 @@ do -- TASK_CARGO function Fsm:onafterArriveAtPickup( TaskUnit, Task ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if self.Cargo:IsAlive() then - self.Cargo:Smoke( Task:GetSmokeColor(), 15 ) if TaskUnit:IsAir() then Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() ) self:__Land( -0.1, "Pickup" ) @@ -422,6 +433,7 @@ do -- TASK_CARGO function Fsm:onafterCancelRouteToPickup( TaskUnit, Task ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + Task:GetMission():GetCommandCenter():MessageToGroup( "Cancelled routing to Cargo " .. self.Cargo:GetName(), TaskUnit:GetGroup() ) self:__SelectAction( -0.1 ) end @@ -459,6 +471,7 @@ do -- TASK_CARGO function Fsm:onafterCancelRouteToDeploy( TaskUnit, Task ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + Task:GetMission():GetCommandCenter():MessageToGroup( "Cancelled routing to deploy zone " .. self.DeployZone:GetName(), TaskUnit:GetGroup() ) self:__SelectAction( -0.1 ) end @@ -518,8 +531,7 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if Cargo and Cargo:IsAlive() then - self.Cargo = Cargo -- Core.Cargo#CARGO_GROUP - self:__Board( -0.1 ) + self:__Board( -0.1, Cargo ) end end @@ -527,22 +539,22 @@ do -- TASK_CARGO --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task - function Fsm:onafterBoard( TaskUnit, Task ) + function Fsm:onafterBoard( TaskUnit, Task, From, Event, To, Cargo ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - function self.Cargo:OnEnterLoaded( From, Event, To, TaskUnit, TaskProcess ) + function Cargo:OnEnterLoaded( From, Event, To, TaskUnit, TaskProcess ) self:F({From, Event, To, TaskUnit, TaskProcess }) - TaskProcess:__Boarded( 0.1 ) + TaskProcess:__Boarded( 0.1, self ) end - if self.Cargo:IsAlive() then - if self.Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then + if Cargo:IsAlive() then + if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then --- ABORT the boarding. Split group if any and go back to select action. else - self.Cargo:MessageToGroup( "Boarding ...", TaskUnit:GetGroup() ) - if not self.Cargo:IsBoarding() then - self.Cargo:Board( TaskUnit, 20, self ) + Cargo:MessageToGroup( "Boarding ...", TaskUnit:GetGroup() ) + if not Cargo:IsBoarding() then + Cargo:Board( TaskUnit, 20, self ) end end else @@ -555,14 +567,14 @@ do -- TASK_CARGO --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task - function Fsm:onafterBoarded( TaskUnit, Task ) + function Fsm:onafterBoarded( TaskUnit, Task, From, Event, To, Cargo ) local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) - - self.Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() ) - self:Load( self.Cargo ) + Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() ) + + self:__Load( -0.1, Cargo ) end @@ -570,16 +582,18 @@ do -- TASK_CARGO --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task - function Fsm:onafterLoad( TaskUnit, Task, From, Event, To, Cargo ) + function Fsm:onenterLoaded( TaskUnit, Task, From, Event, To, Cargo ) local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) if not Cargo:IsLoaded() then Cargo:Load( TaskUnit ) - TaskUnit:AddCargo( Cargo ) end + Cargo:MessageToGroup( "Loaded ...", TaskUnit:GetGroup() ) + TaskUnit:AddCargo( Cargo ) + self:__SelectAction( 1 ) -- TODO:I need to find a more decent solution for this. @@ -640,9 +654,9 @@ do -- TASK_CARGO if self.Cargo:IsAlive() then self.Cargo:MessageToGroup( "UnBoarding ...", TaskUnit:GetGroup() ) if DeployZone then - self.Cargo:UnBoard( DeployZone:GetPointVec2(), 400, self ) + self.Cargo:UnBoard( DeployZone:GetCoordinate():GetRandomCoordinateInRadius( 25, 10 ), 400, self ) else - self.Cargo:UnBoard( TaskUnit:GetPointVec2():AddX(60), 400, self ) + self.Cargo:UnBoard( TaskUnit:GetCoordinate():GetRandomCoordinateInRadius( 25, 10 ), 400, self ) end end end @@ -673,9 +687,9 @@ do -- TASK_CARGO if not Cargo:IsUnLoaded() then if DeployZone then - Cargo:UnLoad( DeployZone:GetPointVec2(), 400, self ) + Cargo:UnLoad( DeployZone:GetCoordinate():GetRandomCoordinateInRadius( 25, 10 ), 400, self ) else - Cargo:UnLoad( TaskUnit:GetPointVec2():AddX(60), 400, self ) + Cargo:UnLoad( TaskUnit:GetCoordinate():GetRandomCoordinateInRadius( 25, 10 ), 400, self ) end end TaskUnit:RemoveCargo( Cargo ) @@ -752,6 +766,7 @@ do -- TASK_CARGO ActRouteCargo:SetRange( Cargo:GetLoadRadius() ) ActRouteCargo:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Cargo " .. Cargo:GetName(), TaskUnit.Menu ) ActRouteCargo:Start() + return self end @@ -769,6 +784,7 @@ do -- TASK_CARGO ActRouteDeployZone:SetZone( DeployZone ) ActRouteDeployZone:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Deploy Zone" .. DeployZone:GetName(), TaskUnit.Menu ) ActRouteDeployZone:Start() + return self end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 219705f85..ed536a603 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -326,6 +326,9 @@ function UNIT:GetCallsign() if DCSUnit then local UnitCallSign = DCSUnit:getCallsign() + if UnitCallSign == "" then + UnitCallSign = DCSUnit:getName() + end return UnitCallSign end From 31f0bb9fef3d1bdff7d4cac40f306e820be47be3 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 8 Apr 2018 13:33:18 +0200 Subject: [PATCH 038/170] Adding events for Deployed and PickedUp. --- .../Moose/Tasking/Task_CARGO.lua | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index a6a723054..ece266d49 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -167,6 +167,61 @@ do -- TASK_CARGO self.DeployZones = {} -- setmetatable( {}, { __mode = "v" } ) -- weak table on value + self:AddTransition( "*", "Deployed", "*" ) + + --- Deployed Handler OnBefore for Type + -- @function [parent=#Type] OnBeforeDeployed + -- @param #Type self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- Deployed Handler OnAfter for Type + -- @function [parent=#Type] OnAfterDeployed + -- @param #Type self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- Deployed Trigger for Type + -- @function [parent=#Type] Deployed + -- @param #Type self + + --- Deployed Asynchronous Trigger for Type + -- @function [parent=#Type] __Deployed + -- @param #Type self + -- @param #number Delay + + + self:AddTransition( "*", "PickedUp", "*" ) + + --- PickedUp Handler OnBefore for Type + -- @function [parent=#Type] OnBeforePickedUp + -- @param #Type self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- PickedUp Handler OnAfter for Type + -- @function [parent=#Type] OnAfterPickedUp + -- @param #Type self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- PickedUp Trigger for Type + -- @function [parent=#Type] PickedUp + -- @param #Type self + + --- PickedUp Asynchronous Trigger for Type + -- @function [parent=#Type] __PickedUp + -- @param #Type self + -- @param #number Delay + + + local Fsm = self:GetUnitProcess() From 8b8fcaaacddac424ccc43d5f104ce4f5e40269d6 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 8 Apr 2018 18:59:42 +0200 Subject: [PATCH 039/170] # Conflicts: # Moose Development/Moose/Tasking/Task_CARGO.lua --- Moose Development/Moose/Cargo/Cargo.lua | 2 +- Moose Development/Moose/Cargo/CargoCrate.lua | 22 +++++++++++++++- .../Moose/Cargo/CargoSlingload.lua | 20 ++++++++++++++ .../Moose/Tasking/Task_CARGO.lua | 26 ++++++++----------- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 09fac4fc3..52ad16b29 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -561,7 +561,7 @@ do -- CARGO -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the CargoGroup is within the loading radius. function CARGO:IsInLoadRadius( Coordinate ) - self:F( { Coordinate } ) + self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index b4a61a58b..1edd1c167 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -134,12 +134,32 @@ do -- CARGO_CRATE return false end + --- Check if Cargo Crate is in the radius for the Cargo to be reported. + -- @param #CARGO self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the Cargo Crate is within the report radius. + function CARGO_CRATE:IsInReportRadius( Coordinate ) + self:F( { Coordinate, LoadRadius = self.LoadRadius } ) + + local Distance = 0 + if self:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.LoadRadius then + return true + end + end + + return false + end + + --- Check if Cargo Crate is in the radius for the Cargo to be Boarded or Loaded. -- @param #CARGO self -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Crate is within the loading radius. function CARGO_CRATE:IsInLoadRadius( Coordinate ) - self:F( { Coordinate } ) + self:F( { Coordinate, LoadRadius = self.NearRadius } ) local Distance = 0 if self:IsUnLoaded() then diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 5e979d93c..f8be5c183 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -97,6 +97,26 @@ do -- CARGO_SLINGLOAD end + --- Check if Cargo Crate is in the radius for the Cargo to be reported. + -- @param #CARGO_SLINGLOAD self + -- @param Core.Point#Coordinate Coordinate + -- @return #boolean true if the Cargo Crate is within the report radius. + function CARGO_SLINGLOAD:IsInReportRadius( Coordinate ) + self:F( { Coordinate, LoadRadius = self.LoadRadius } ) + + local Distance = 0 + if self:IsUnLoaded() then + Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + if Distance <= self.LoadRadius then + return true + end + end + + return false + end + + --- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded. -- @param #CARGO_SLINGLOAD self -- @param Core.Point#Coordinate Coordinate diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index ece266d49..055604c9c 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -457,7 +457,7 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if Cargo:IsAlive() then - self.Cargo = Cargo -- Core.Cargo#CARGO + self.Cargo = Cargo -- Cargo.Cargo#CARGO Task:SetCargoPickup( self.Cargo, TaskUnit ) self:__RouteToPickupPoint( -0.1 ) end @@ -539,7 +539,7 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if self.Cargo:IsAlive() then - if self.Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then + if self.Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then self:__Land( -10, Action ) else @@ -548,9 +548,9 @@ do -- TASK_CARGO end else if Action == "Pickup" then - self:__RouteToPickupZone( -0.1 ) + self:__RouteToPickup( -0.1, self.Cargo ) else - self:__RouteToDeployZone( -0.1 ) + self:__RouteToDeploy( -0.1, self.Cargo ) end end end @@ -563,7 +563,7 @@ do -- TASK_CARGO self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if self.Cargo:IsAlive() then - if self.Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then + if self.Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then self:__Land( -0.1, Action ) else @@ -571,9 +571,9 @@ do -- TASK_CARGO end else if Action == "Pickup" then - self:__RouteToPickupZone( -0.1 ) + self:__RouteToPickup( -0.1, self.Cargo ) else - self:__RouteToDeployZone( -0.1 ) + self:__RouteToDeploy( -0.1, self.Cargo ) end end end @@ -624,6 +624,8 @@ do -- TASK_CARGO -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterBoarded( TaskUnit, Task, From, Event, To, Cargo ) + self:F( { Cargo = Cargo } ) + local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) @@ -639,6 +641,8 @@ do -- TASK_CARGO -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onenterLoaded( TaskUnit, Task, From, Event, To, Cargo ) + self:F( { Cargo = Cargo } ) + local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) @@ -651,14 +655,6 @@ do -- TASK_CARGO self:__SelectAction( 1 ) - -- TODO:I need to find a more decent solution for this. - Task:E( { CargoPickedUp = Task.CargoPickedUp } ) - if Cargo:IsAlive() then - if Task.CargoPickedUp then - Task:CargoPickedUp( TaskUnit, Cargo ) - end - end - end From a95afe995610a1d53babcaa74794d1546b196868 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 8 Apr 2018 22:36:58 +0200 Subject: [PATCH 040/170] # Conflicts: # Moose Development/Moose/Tasking/Task_CARGO.lua --- .../Moose/Tasking/Task_CARGO.lua | 2 ++ .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 26 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 055604c9c..7976fe39e 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -643,6 +643,8 @@ do -- TASK_CARGO self:F( { Cargo = Cargo } ) + self:F( { Cargo = Cargo } ) + local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index ca96b2d87..11c9feede 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -429,17 +429,17 @@ do -- TASK_CARGO_DISPATCHER --- Add a Transport task to transport cargo from fixed locations to a deployment zone. -- @param #TASK_CARGO_DISPATCHER self - -- @param #string TransportTaskName (optional) The name of the transport task. + -- @param #string TaskName (optional) The name of the transport task. -- @param Core.SetCargo#SET_CARGO SetCargo The SetCargo to be transported. -- @param #string Briefing The briefing of the task transport to be shown to the player. -- @return #TASK_CARGO_DISPATCHER -- @usage -- -- -- Add a Transport task to transport cargo of different types to a Transport Deployment Zone. - function TASK_CARGO_DISPATCHER:AddTransportTask( TransportTaskName, SetCargo, Briefing ) + function TASK_CARGO_DISPATCHER:AddTransportTask( TaskName, SetCargo, Briefing ) self.TransportCount = self.TransportCount + 1 - local TaskName = string.format( ( TransportTaskName or "Transport" ) .. ".%03d", self.TransportCount ) + local TaskName = string.format( ( TaskName or "Transport" ) .. ".%03d", self.TransportCount ) self.Transport[TaskName] = {} self.Transport[TaskName].SetCargo = SetCargo @@ -452,13 +452,15 @@ do -- TASK_CARGO_DISPATCHER --- Define one deploy zone for the Transport tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param #string TransportTaskName (optional) The name of the Transport task. + -- @param #string TaskName (optional) The name of the Transport task. -- @param TransportDeployZone A Transport deploy zone. -- @return #TASK_CARGO_DISPATCHER - function TASK_CARGO_DISPATCHER:SetTransportDeployZone( TransportTaskName, TransportDeployZone ) + function TASK_CARGO_DISPATCHER:SetTransportDeployZone( TaskName, TransportDeployZone ) - if TransportTaskName then - self.Transport[TransportTaskName].DeployZones = { TransportDeployZone } + if self.Transport[TaskName] then + self.Transport[TaskName].DeployZones = { TransportDeployZone } + else + error( "TaskName does not exist" ) end return self @@ -467,14 +469,16 @@ do -- TASK_CARGO_DISPATCHER --- Define the deploy zones for the Transport tasks. -- @param #TASK_CARGO_DISPATCHER self - -- @param #string TransportTaskName (optional) The name of the Transport task. + -- @param #string TaskName (optional) The name of the Transport task. -- @param TransportDeployZones A list of the Transport deploy zones. -- @return #TASK_CARGO_DISPATCHER -- - function TASK_CARGO_DISPATCHER:SetTransportDeployZones( TransportTaskName, TransportDeployZones ) + function TASK_CARGO_DISPATCHER:SetTransportDeployZones( TaskName, TransportDeployZones ) - if TransportTaskName then - self.Transport[TransportTaskName].DeployZones = TransportDeployZones + if self.Transport[TaskName] then + self.Transport[TaskName].DeployZones = TransportDeployZones + else + error( "TaskName does not exist" ) end return self From 86cc1f81b68d58caec0b24e18b1da09ac99f1743 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 8 Apr 2018 22:38:45 +0200 Subject: [PATCH 041/170] Finish Cargo/FC/Transport --- Moose Development/Moose/Tasking/Task_CARGO.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 7976fe39e..2cb400dd8 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -645,6 +645,8 @@ do -- TASK_CARGO self:F( { Cargo = Cargo } ) + self:F( { Cargo = Cargo } ) + local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) From 4eb596f5bf8644258b40caab4ebafe6f8bdfc8e2 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 9 Apr 2018 12:56:11 +0200 Subject: [PATCH 042/170] Finish Cargo/FC/Transport --- .../Moose/Tasking/Task_CARGO.lua | 324 ++++-------------- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 11 + .../Moose/Tasking/Task_Cargo_Transport.lua | 77 +---- .../Moose/Wrapper/Controllable.lua | 2 +- Moose Development/Moose/Wrapper/Group.lua | 4 +- 5 files changed, 91 insertions(+), 327 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 2cb400dd8..56d0619fe 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -23,7 +23,7 @@ -- -- === -- --- @module Task_Cargo +-- @module Tasking.Task_Cargo do -- TASK_CARGO @@ -167,60 +167,50 @@ do -- TASK_CARGO self.DeployZones = {} -- setmetatable( {}, { __mode = "v" } ) -- weak table on value - self:AddTransition( "*", "Deployed", "*" ) + self:AddTransition( "*", "CargoDeployed", "*" ) - --- Deployed Handler OnBefore for Type - -- @function [parent=#Type] OnBeforeDeployed - -- @param #Type self + --- CargoDeployed Handler OnBefore for TASK_CARGO + -- @function [parent=#TASK_CARGO] OnBeforeCargoDeployed + -- @param #TASK_CARGO self -- @param #string From -- @param #string Event -- @param #string To + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. -- @return #boolean - --- Deployed Handler OnAfter for Type - -- @function [parent=#Type] OnAfterDeployed - -- @param #Type self + --- CargoDeployed Handler OnAfter for TASK_CARGO + -- @function [parent=#TASK_CARGO] OnAfterCargoDeployed + -- @param #TASK_CARGO self -- @param #string From -- @param #string Event -- @param #string To - - --- Deployed Trigger for Type - -- @function [parent=#Type] Deployed - -- @param #Type self - - --- Deployed Asynchronous Trigger for Type - -- @function [parent=#Type] __Deployed - -- @param #Type self - -- @param #number Delay - - - self:AddTransition( "*", "PickedUp", "*" ) + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. + -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - --- PickedUp Handler OnBefore for Type - -- @function [parent=#Type] OnBeforePickedUp - -- @param #Type self + + self:AddTransition( "*", "CargoPickedUp", "*" ) + + --- CargoPickedUp Handler OnBefore for TASK_CARGO + -- @function [parent=#TASK_CARGO] OnBeforeCargoPickedUp + -- @param #TASK_CARGO self -- @param #string From -- @param #string Event -- @param #string To + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. -- @return #boolean - --- PickedUp Handler OnAfter for Type - -- @function [parent=#Type] OnAfterPickedUp - -- @param #Type self + --- CargoPickedUp Handler OnAfter for TASK_CARGO + -- @function [parent=#TASK_CARGO] OnAfterCargoPickedUp + -- @param #TASK_CARGO self -- @param #string From -- @param #string Event -- @param #string To - - --- PickedUp Trigger for Type - -- @function [parent=#Type] PickedUp - -- @param #Type self - - --- PickedUp Asynchronous Trigger for Type - -- @function [parent=#Type] __PickedUp - -- @param #Type self - -- @param #number Delay - - + -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. + -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. local Fsm = self:GetUnitProcess() @@ -302,6 +292,7 @@ do -- TASK_CARGO -- end self:F( { CargoUnloaded = Cargo:IsUnLoaded(), CargoLoaded = Cargo:IsLoaded(), CargoItemCount = CargoItemCount } ) + Task:E( { TaskDeployZones = Task.DeployZones, TaskName = Task:GetName() } ) if Cargo:IsUnLoaded() then if CargoItemCount < 1 then @@ -354,18 +345,18 @@ do -- TASK_CARGO end end end + -- Cargo in deployzones are flagged as deployed. for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + Task:E( { DeployZone = DeployZone } ) if Cargo:IsInZone( DeployZone ) then - if not Cargo:IsDeployed() then + Task:E( { CargoIsDeployed = Task.CargoDeployed and "true" or "false" } ) + if Cargo:IsDeployed() == false then Cargo:SetDeployed( true ) - -- TODO:I need to find a more decent solution for this. - Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } ) + -- Now we call a callback method to handle the CargoDeployed event. Task:E( { CargoIsAlive = Cargo:IsAlive() and "true" or "false" } ) if Cargo:IsAlive() then - if Task.CargoDeployed then - Task:CargoDeployed( TaskUnit, Cargo, DeployZone ) - end + Task:CargoDeployed( TaskUnit, Cargo, DeployZone ) end end end @@ -538,17 +529,28 @@ do -- TASK_CARGO function Fsm:onafterLand( TaskUnit, Task, From, Event, To, Action ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - if self.Cargo:IsAlive() then - if self.Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then - if TaskUnit:InAir() then - self:__Land( -10, Action ) + if Action == "Pickup" then + if self.Cargo:IsAlive() then + if self.Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then + if TaskUnit:InAir() then + self:__Land( -10, Action ) + else + Task:GetMission():GetCommandCenter():MessageToGroup( "Landed at pickup location...", TaskUnit:GetGroup() ) + self:__Landed( -0.1, Action ) + end else - Task:GetMission():GetCommandCenter():MessageToGroup( "Landed ...", TaskUnit:GetGroup() ) - self:__Landed( -0.1, Action ) - end - else - if Action == "Pickup" then self:__RouteToPickup( -0.1, self.Cargo ) + end + end + else + if TaskUnit:IsAlive() then + if TaskUnit:IsInZone( self.DeployZone ) then + if TaskUnit:InAir() then + self:__Land( -10, Action ) + else + Task:GetMission():GetCommandCenter():MessageToGroup( "Landed at deploy zone " .. self.DeployZone:GetName(), TaskUnit:GetGroup() ) + self:__Landed( -0.1, Action ) + end else self:__RouteToDeploy( -0.1, self.Cargo ) end @@ -562,16 +564,26 @@ do -- TASK_CARGO function Fsm:onafterLanded( TaskUnit, Task, From, Event, To, Action ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - if self.Cargo:IsAlive() then - if self.Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then - if TaskUnit:InAir() then - self:__Land( -0.1, Action ) + if Action == "Pickup" then + if self.Cargo:IsAlive() then + if self.Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then + if TaskUnit:InAir() then + self:__Land( -0.1, Action ) + else + self:__SelectAction( -0.1 ) + end else - self:__SelectAction( -0.1 ) - end - else - if Action == "Pickup" then self:__RouteToPickup( -0.1, self.Cargo ) + end + end + else + if TaskUnit:IsAlive() then + if TaskUnit:IsInZone( self.DeployZone ) then + if TaskUnit:InAir() then + self:__Land( -10, Action ) + else + self:__SelectAction( -0.1 ) + end else self:__RouteToDeploy( -0.1, self.Cargo ) end @@ -624,8 +636,6 @@ do -- TASK_CARGO -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onafterBoarded( TaskUnit, Task, From, Event, To, Cargo ) - self:F( { Cargo = Cargo } ) - local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) @@ -641,12 +651,6 @@ do -- TASK_CARGO -- @param Tasking.Task_Cargo#TASK_CARGO Task function Fsm:onenterLoaded( TaskUnit, Task, From, Event, To, Cargo ) - self:F( { Cargo = Cargo } ) - - self:F( { Cargo = Cargo } ) - - self:F( { Cargo = Cargo } ) - local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) @@ -657,7 +661,9 @@ do -- TASK_CARGO Cargo:MessageToGroup( "Loaded ...", TaskUnit:GetGroup() ) TaskUnit:AddCargo( Cargo ) - self:__SelectAction( 1 ) + --Task:CargoPickedUp( TaskUnit, Cargo ) + + self:SelectAction( ) end @@ -967,183 +973,3 @@ do -- TASK_CARGO end -do -- TASK_CARGO_TRANSPORT - - --- The TASK_CARGO_TRANSPORT class - -- @type TASK_CARGO_TRANSPORT - -- @extends #TASK_CARGO - TASK_CARGO_TRANSPORT = { - ClassName = "TASK_CARGO_TRANSPORT", - } - - --- Instantiates a new TASK_CARGO_TRANSPORT. - -- @param #TASK_CARGO_TRANSPORT self - -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. - -- @param #string TaskName The name of the Task. - -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. - -- @param #string TaskBriefing The Cargo Task briefing. - -- @return #TASK_CARGO_TRANSPORT self - function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) - local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_TRANSPORT - self:F() - - Mission:AddTask( self ) - - - -- Events - - self:AddTransition( "*", "CargoPickedUp", "*" ) - self:AddTransition( "*", "CargoDeployed", "*" ) - - self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) - - --- OnBefore Transition Handler for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - - --- Synchronous Event Trigger for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] CargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - - --- Asynchronous Event Trigger for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param #number Delay The delay in seconds. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - - --- OnBefore Transition Handler for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - - --- Synchronous Event Trigger for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] CargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - - --- Asynchronous Event Trigger for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param #number Delay The delay in seconds. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - - local Fsm = self:GetUnitProcess() - - local CargoReport = REPORT:New( "Transport Cargo. The following cargo needs to be transported including initial positions:") - - SetCargo:ForEachCargo( - --- @param Core.Cargo#CARGO Cargo - function( Cargo ) - local CargoType = Cargo:GetType() - local CargoName = Cargo:GetName() - local CargoCoordinate = Cargo:GetCoordinate() - CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) - end - ) - - self:SetBriefing( - TaskBriefing or - CargoReport:Text() - ) - - - return self - end - - function TASK_CARGO_TRANSPORT:ReportOrder( ReportGroup ) - - return 0 - end - - - --- - -- @param #TASK_CARGO_TRANSPORT self - -- @return #boolean - function TASK_CARGO_TRANSPORT:IsAllCargoTransported() - - local CargoSet = self:GetCargoSet() - local Set = CargoSet:GetSet() - - local DeployZones = self:GetDeployZones() - - local CargoDeployed = true - - -- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ). - for CargoID, CargoData in pairs( Set ) do - local Cargo = CargoData -- Core.Cargo#CARGO - - self:F( { Cargo = Cargo:GetName(), CargoDeployed = Cargo:IsDeployed() } ) - - if Cargo:IsDeployed() then - --- -- Loop the DeployZones set for the TASK_CARGO_TRANSPORT. --- for DeployZoneID, DeployZone in pairs( DeployZones ) do --- --- -- If all cargo is in one of the deploy zones, then all is good. --- self:T( { Cargo.CargoObject } ) --- if Cargo:IsInZone( DeployZone ) == false then --- CargoDeployed = false --- end --- end - else - CargoDeployed = false - end - end - - self:F( { CargoDeployed = CargoDeployed } ) - - return CargoDeployed - end - - --- @param #TASK_CARGO_TRANSPORT self - function TASK_CARGO_TRANSPORT:onafterGoal( TaskUnit, From, Event, To ) - local CargoSet = self.CargoSet - - if self:IsAllCargoTransported() then - self:Success() - end - - self:__Goal( -10 ) - end - -end - diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 11c9feede..bdac4b931 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -449,6 +449,17 @@ do -- TASK_CARGO_DISPATCHER return self end + + --- Add a Transport task to transport cargo from fixed locations to a deployment zone. + -- @param #TASK_CARGO_DISPATCHER self + -- @param #string TaskName (optional) The name of the transport task. + -- @return Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT + function TASK_CARGO_DISPATCHER:GetTransportTask( TaskName ) + + self:ManageTasks() + return self.Transport[TaskName] and self.Transport[TaskName].Task + end + --- Define one deploy zone for the Transport tasks. -- @param #TASK_CARGO_DISPATCHER self diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index 0deff06e4..611eefa49 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -3,6 +3,7 @@ -- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) -- -- === +-- @module do -- TASK_CARGO_TRANSPORT @@ -28,82 +29,6 @@ do -- TASK_CARGO_TRANSPORT Mission:AddTask( self ) - - -- Events - - self:AddTransition( "*", "CargoPickedUp", "*" ) - self:AddTransition( "*", "CargoDeployed", "*" ) - - self:F( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } ) - - --- OnBefore Transition Handler for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - - --- Synchronous Event Trigger for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] CargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - - --- Asynchronous Event Trigger for Event CargoPickedUp. - -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoPickedUp - -- @param #TASK_CARGO_TRANSPORT self - -- @param #number Delay The delay in seconds. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - - --- OnBefore Transition Handler for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] OnAfterCargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - - --- Synchronous Event Trigger for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] CargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - - --- Asynchronous Event Trigger for Event CargoDeployed. - -- @function [parent=#TASK_CARGO_TRANSPORT] __CargoDeployed - -- @param #TASK_CARGO_TRANSPORT self - -- @param #number Delay The delay in seconds. - -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. - -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - local Fsm = self:GetUnitProcess() local CargoReport = REPORT:New( "Transport Cargo. The following cargo needs to be transported including initial positions:") diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index f5b414e60..2d6551fd2 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Controllable +-- @module Wrapper.Controllable diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 23fd5da1a..609b1aa91 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -23,7 +23,7 @@ -- -- === -- --- @module Group +-- @module Wrapper.Group --- @type GROUP @@ -1143,6 +1143,8 @@ function GROUP:Respawn( Template, Reset ) self:ResetEvents() + return self + end From a6889be6762245097120c44163ebef997c0ec1fa Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 9 Apr 2018 13:30:33 +0200 Subject: [PATCH 043/170] # Conflicts: # Moose Development/Moose/Tasking/Task_CARGO.lua --- Moose Development/Moose/Tasking/Task_CARGO.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 56d0619fe..278354142 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -649,7 +649,7 @@ do -- TASK_CARGO --- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task - function Fsm:onenterLoaded( TaskUnit, Task, From, Event, To, Cargo ) + function Fsm:onafterLoad( TaskUnit, Task, From, Event, To, Cargo ) local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) @@ -661,9 +661,9 @@ do -- TASK_CARGO Cargo:MessageToGroup( "Loaded ...", TaskUnit:GetGroup() ) TaskUnit:AddCargo( Cargo ) - --Task:CargoPickedUp( TaskUnit, Cargo ) + Task:CargoPickedUp( TaskUnit, Cargo ) - self:SelectAction( ) + self:SelectAction( -1 ) end From 1beb34231eaf6099c76c1d4817386d04e0a3a475 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 9 Apr 2018 13:38:32 +0200 Subject: [PATCH 044/170] Getting rid of an old annoyance. --- Moose Development/Moose/Wrapper/Client.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 71e2066cb..dcf44d8d8 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -182,7 +182,6 @@ function CLIENT:ShowBriefing() if self.ClientBriefing then Briefing = Briefing .. self.ClientBriefing end - Briefing = Briefing .. " Press [LEFT ALT]+[B] to view the complete mission briefing." self:Message( Briefing, 60, "Briefing" ) end From ffe4d9a1439c25de8ba4050e21b60991664c746f Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 10 Apr 2018 20:02:40 +0200 Subject: [PATCH 045/170] Finish Cargo/FC/Transport --- Moose Development/Moose/Actions/Act_Route.lua | 9 +- Moose Development/Moose/Cargo/Cargo.lua | 17 ++ Moose Development/Moose/Cargo/CargoCrate.lua | 61 ++++++- Moose Development/Moose/Cargo/CargoGroup.lua | 154 ++++++++---------- .../Moose/Cargo/CargoSlingload.lua | 51 +++++- Moose Development/Moose/Cargo/CargoUnit.lua | 4 +- Moose Development/Moose/Core/Event.lua | 10 ++ Moose Development/Moose/Core/Menu.lua | 17 ++ Moose Development/Moose/Core/Set.lua | 10 +- Moose Development/Moose/Core/SpawnStatic.lua | 70 ++++++++ Moose Development/Moose/Tasking/Task.lua | 82 ++++++++-- .../Moose/Tasking/Task_CARGO.lua | 68 ++++---- Moose Development/Moose/Wrapper/Static.lua | 15 +- Moose Development/Moose/Wrapper/Unit.lua | 22 +-- 14 files changed, 434 insertions(+), 156 deletions(-) diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index cbf089140..8a0d53b0f 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -123,9 +123,7 @@ do -- ACT_ROUTE --- Set a Cancel Menu item. -- @param #ACT_ROUTE self -- @return #ACT_ROUTE - function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu ) - - local MenuTime = timer.getTime() + 1 + function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu, MenuTime, MenuTag ) self.CancelMenuGroupCommand = MENU_GROUP_COMMAND:New( MenuGroup, @@ -133,10 +131,11 @@ do -- ACT_ROUTE ParentMenu, self.MenuCancel, self - ):SetTime( MenuTime ) + ):SetTime( MenuTime ):SetTag( MenuTag ) ParentMenu:SetTime( MenuTime ) - ParentMenu:Remove( MenuTime ) + + ParentMenu:Remove( MenuTime, MenuTag ) return self end diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 52ad16b29..b7f52ee4e 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -257,6 +257,7 @@ do -- CARGO self:AddTransition( "*", "Damaged", "Damaged" ) self:AddTransition( "*", "Destroyed", "Destroyed" ) self:AddTransition( "*", "Respawn", "UnLoaded" ) + self:AddTransition( "*", "Reset", "UnLoaded" ) self.Type = Type self.Name = Name @@ -747,6 +748,22 @@ do -- CARGO self.Reported[CarrierGroup] = nil end + --- Respawn the cargo when destroyed + -- @param #CARGO self + -- @param #boolean RespawnDestroyed + function CARGO:RespawnOnDestroyed( RespawnDestroyed ) + + if RespawnDestroyed then + self.onenterDestroyed = function( self ) + self:Respawn() + end + else + self.onenterDestroyed = nil + end + + end + + end -- CARGO diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 1edd1c167..104e26438 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -65,6 +65,33 @@ do -- CARGO_CRATE return self end + --- @param #CARGO_CRATE self + -- @param Core.Event#EVENTDATA EventData + function CARGO_CRATE:OnEventCargoDead( EventData ) + + local Destroyed = false + + if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then + if self.CargoObject:GetName() == EventData.IniUnitName then + Destroyed = true + end + else + if self:IsLoaded() then + local CarrierName = self.CargoCarrier:GetName() + if CarrierName == EventData.IniDCSUnitName then + MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() + Destroyed = true + self.CargoCarrier:ClearCargo() + end + end + end + + if Destroyed then + self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } ) + self:Destroyed() + end + + end --- Enter UnLoaded State. @@ -90,7 +117,7 @@ do -- CARGO_CRATE -- Respawn the group... if self.CargoObject then - self.CargoObject:ReSpawn( ToPointVec2, 0 ) + self.CargoObject:ReSpawnAt( ToPointVec2, 0 ) self.CargoCarrier = nil end @@ -228,15 +255,39 @@ do -- CARGO_CRATE return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) end - --- Respawn the CargoGroup. -- @param #CARGO_CRATE self function CARGO_CRATE:Respawn() - self:F( { "Respawning" } ) + self:F( { "Respawning crate " .. self:GetName() } ) + + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event. + self:__Reset( -0.1 ) + end + + + end + + + --- Respawn the CargoGroup. + -- @param #CARGO_CRATE self + function CARGO_CRATE:onafterReset() + + self:F( { "Reset crate " .. self:GetName() } ) + + + -- Respawn the group... + if self.CargoObject then + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + self.CargoCarrier = nil + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + end - self:SetDeployed( false ) - self:SetStartState( "UnLoaded" ) end diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 57ec3a0af..4ad076362 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -38,82 +38,82 @@ do -- CARGO_GROUP ClassName = "CARGO_GROUP", } ---- CARGO_GROUP constructor. --- This make a new CARGO_GROUP from a @{Group} object. --- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. --- @param #CARGO_GROUP self --- @param Wrapper.Group#GROUP CargoGroup --- @param #string Type --- @param #string Name --- @param #number LoadRadius (optional) --- @param #number NearRadius (optional) --- @return #CARGO_GROUP -function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, LoadRadius } ) - - self.CargoSet = SET_CARGO:New() + --- CARGO_GROUP constructor. + -- This make a new CARGO_GROUP from a @{Group} object. + -- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. + -- @param #CARGO_GROUP self + -- @param Wrapper.Group#GROUP CargoGroup + -- @param #string Type + -- @param #string Name + -- @param #number LoadRadius (optional) + -- @param #number NearRadius (optional) + -- @return #CARGO_GROUP + function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius ) ) -- #CARGO_GROUP + self:F( { Type, Name, LoadRadius } ) - self:SetDeployed( false ) - - local WeightGroup = 0 - - self.GroupName = CargoGroup:GetName() - self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) - - CargoGroup:Destroy() - - -- We iterate through the group template and for each unit in the template, we create a new group with one unit. - for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do + self.CargoSet = SET_CARGO:New() - local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - local GroupName = env.getValueDictByKey( GroupTemplate.name ) + self:SetDeployed( false ) - -- We create a new group object with one unit... - -- First we prepare the template... - GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID - GroupTemplate.groupId = nil - GroupTemplate.units = {} - GroupTemplate.units[1] = UnitTemplate - local UnitName = UnitTemplate.name .. "#CARGO" - GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" - - - -- Then we register the new group in the database - local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + local WeightGroup = 0 - -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) + self.GroupName = CargoGroup:GetName() + self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) - -- And we register the spawned unit as part of the CargoSet. - local Unit = UNIT:FindByName( UnitName ) - --local WeightUnit = Unit:GetDesc().massEmpty - --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) - self.CargoSet:Add( UnitName, CargoUnit ) + CargoGroup:Destroy() + + -- We iterate through the group template and for each unit in the template, we create a new group with one unit. + for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + local GroupName = env.getValueDictByKey( GroupTemplate.name ) + + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.groupId = nil + GroupTemplate.units = {} + GroupTemplate.units[1] = UnitTemplate + local UnitName = UnitTemplate.name .. "#CARGO" + GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" + + + -- Then we register the new group in the database + local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + + -- And we register the spawned unit as part of the CargoSet. + local Unit = UNIT:FindByName( UnitName ) + --local WeightUnit = Unit:GetDesc().massEmpty + --WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) + self.CargoSet:Add( UnitName, CargoUnit ) + end + + + self:SetWeight( WeightGroup ) + self.CargoLimit = 10 + + self:T( { "Weight Cargo", WeightGroup } ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) + + return self end - - self:SetWeight( WeightGroup ) - self.CargoLimit = 10 - - self:T( { "Weight Cargo", WeightGroup } ) - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) - - self:SetEventPriority( 4 ) - - return self -end - ---- @param #CARGO_GROUP self --- @param Core.Event#EVENTDATA EventData -function CARGO_GROUP:OnEventCargoDead( EventData ) + --- @param #CARGO_GROUP self + -- @param Core.Event#EVENTDATA EventData + function CARGO_GROUP:OnEventCargoDead( EventData ) local Destroyed = false @@ -364,22 +364,6 @@ function CARGO_GROUP:OnEventCargoDead( EventData ) end - --- Respawn the cargo when destroyed - -- @param #CARGO_GROUP self - -- @param #boolean RespawnDestroyed - function CARGO_GROUP:RespawnOnDestroyed( RespawnDestroyed ) - self:F({"In function RespawnOnDestroyed"}) - if RespawnDestroyed then - self.onenterDestroyed = function( self ) - self:F("IN FUNCTION") - self:Respawn() - end - else - self.onenterDestroyed = nil - end - - end - --- Get the current Coordinate of the CargoGroup. -- @param #CARGO_GROUP self -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index f8be5c183..04626385b 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -64,6 +64,26 @@ do -- CARGO_SLINGLOAD return self end + + + --- @param #CARGO_SLINGLOAD self + -- @param Core.Event#EVENTDATA EventData + function CARGO_SLINGLOAD:OnEventCargoDead( EventData ) + + local Destroyed = false + + if self:IsDestroyed() or self:IsUnLoaded() then + if self.CargoObject:GetName() == EventData.IniUnitName then + Destroyed = true + end + end + + if Destroyed then + self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } ) + self:Destroyed() + end + + end --- Check if the cargo can be Slingloaded. @@ -196,10 +216,35 @@ do -- CARGO_SLINGLOAD -- @param #CARGO_SLINGLOAD self function CARGO_SLINGLOAD:Respawn() - self:F( { "Respawning" } ) + self:F( { "Respawning slingload " .. self:GetName() } ) + + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event. + self:__Reset( -0.1 ) + end + + + end + + + --- Respawn the CargoGroup. + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:onafterReset() + + self:F( { "Reset slingload " .. self:GetName() } ) + + + -- Respawn the group... + if self.CargoObject then + self:SetDeployed( false ) + self:SetStartState( "UnLoaded" ) + self.CargoCarrier = nil + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + end - self:SetDeployed( false ) - self:SetStartState( "UnLoaded" ) end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 5ac185277..70a42b6c8 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -103,7 +103,7 @@ do -- CARGO_UNIT -- Respawn the group... if self.CargoObject then - self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) + self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading ) self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) self.CargoCarrier = nil @@ -207,7 +207,7 @@ do -- CARGO_UNIT -- Respawn the group... if self.CargoObject then - self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 ) + self.CargoObject:ReSpawnAt( ToPointVec2, 0 ) self.CargoCarrier = nil end diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index c68fec80b..dd26c3bf6 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -794,6 +794,16 @@ function EVENT:onEvent( Event ) Event.IniTypeName = Event.IniDCSUnit:getTypeName() end + if Event.IniObjectCategory == Object.Category.CARGO then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName ) + Event.IniCoalition = Event.IniDCSUnit:getCoalition() + Event.IniCategory = Event.IniDCSUnit:getDesc().category + Event.IniTypeName = Event.IniDCSUnit:getTypeName() + end + if Event.IniObjectCategory == Object.Category.SCENERY then Event.IniDCSUnit = Event.initiator Event.IniDCSUnitName = Event.IniDCSUnit:getName() diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 9bb30be21..5ee9f9fff 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -213,6 +213,7 @@ do -- MENU_BASE self.Menus = {} self.MenuCount = 0 self.MenuTime = timer.getTime() + self.MenuRemoveParent = false if self.ParentMenu then self.ParentMenu.Menus = self.ParentMenu.Menus or {} @@ -226,14 +227,30 @@ do -- MENU_BASE if self.ParentMenu then self.ParentMenu.Menus = self.ParentMenu.Menus or {} self.ParentMenu.Menus[MenuText] = Menu + self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1 end end function MENU_BASE:ClearParentMenu( MenuText ) if self.ParentMenu and self.ParentMenu.Menus[MenuText] then self.ParentMenu.Menus[MenuText] = nil + self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1 + if self.ParentMenu.MenuCount == 0 then + --self.ParentMenu:Remove() + end end end + + --- Sets a @{Menu} to remove automatically the parent menu when the menu removed is the last child menu of that parent @{Menu}. + -- @param #MENU_BASE self + -- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}. + -- @return #MENU_BASE + function MENU_BASE:SetRemoveParent( RemoveParent ) + self:F( { RemoveParent } ) + self.MenuRemoveParent = RemoveParent + return self + end + --- Gets a @{Menu} from a parent @{Menu} -- @param #MENU_BASE self diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 58c24bcce..48973c2b2 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -173,7 +173,7 @@ end -- @param Core.Base#BASE Object -- @return Core.Base#BASE The added BASE Object. function SET_BASE:Add( ObjectName, Object ) - self:F3( { ObjectName = ObjectName, Object = Object } ) + self:F( { ObjectName = ObjectName, Object = Object } ) -- Ensure that the existing element is removed from the Set before a new one is inserted to the Set if self.Set[ObjectName] then @@ -4349,7 +4349,7 @@ function SET_CARGO:IsIncludeObject( MCargo ) --R2.1 MCargoCoalition = true end end - self:T( { "Evaluated Coalition", MCargoCoalition } ) + self:F( { "Evaluated Coalition", MCargoCoalition } ) MCargoInclude = MCargoInclude and MCargoCoalition end @@ -4361,7 +4361,7 @@ function SET_CARGO:IsIncludeObject( MCargo ) --R2.1 MCargoType = true end end - self:T( { "Evaluated Type", MCargoType } ) + self:F( { "Evaluated Type", MCargoType } ) MCargoInclude = MCargoInclude and MCargoType end @@ -4373,7 +4373,7 @@ function SET_CARGO:IsIncludeObject( MCargo ) --R2.1 MCargoPrefix = true end end - self:T( { "Evaluated Prefix", MCargoPrefix } ) + self:F( { "Evaluated Prefix", MCargoPrefix } ) MCargoInclude = MCargoInclude and MCargoPrefix end end @@ -4387,6 +4387,8 @@ end -- @param Core.Event#EVENTDATA EventData function SET_CARGO:OnEventNewCargo( EventData ) --R2.1 + self:F( { "New Cargo", EventData } ) + if EventData.Cargo then if EventData.Cargo and self:IsIncludeObject( EventData.Cargo ) then self:Add( EventData.Cargo.Name , EventData.Cargo ) diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 118b74b8c..1f5b8a97a 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -118,6 +118,7 @@ function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, return self end + --- Creates a new @{Static} at the original position. -- @param #SPAWNSTATIC self -- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360. @@ -192,6 +193,75 @@ function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1 return nil end + +--- Creates the original @{Static} at a POINT_VEC2. +-- @param #SPAWNSTATIC self +-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static. +-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360. +-- @param #string (optional) The name of the new static. +-- @return #SPAWNSTATIC +function SPAWNSTATIC:ReSpawn() + + local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) + + if StaticTemplate then + + local CountryID = self.CountryID + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] + + StaticTemplate.units = nil + StaticTemplate.route = nil + StaticTemplate.groupId = nil + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( CountryID, StaticTemplate ) + + return Static + end + + return nil +end + + +--- Creates the original @{Static} at a POINT_VEC2. +-- @param #SPAWNSTATIC self +-- @param Core.Point#COORDINATE Coordinate The 2D coordinate where to spawn the static. +-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360. +-- @return #SPAWNSTATIC +function SPAWNSTATIC:ReSpawnAt( Coordinate, Heading ) + + local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) + + if StaticTemplate then + + local CountryID = self.CountryID + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] + + StaticTemplate.x = Coordinate.x + StaticTemplate.y = Coordinate.z + + StaticTemplate.units = nil + StaticTemplate.route = nil + StaticTemplate.groupId = nil + + StaticTemplate.heading = Heading and ( ( Heading / 180 ) * math.pi ) or StaticTemplate.heading + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( CountryID, StaticTemplate ) + + return Static + end + + return nil +end + + --- Creates a new @{Static} from a @{Zone}. -- @param #SPAWNSTATIC self -- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static. diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index e8ae381a1..4a4677053 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -597,7 +597,9 @@ function TASK:UnAssignFromUnit( TaskUnit ) self:F( TaskUnit:GetName() ) self:RemoveStateMachine( TaskUnit ) - + + -- If a Task Control Menu had been set, then this will be removed. + self:RemoveTaskControlMenu( TaskUnit ) return self end @@ -779,15 +781,16 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime ) local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString ) local TaskName = string.format( "%s", self:GetName() ) - local MissionMenu = Mission:GetMenu( TaskGroup ) --- local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime ) --- local MissionMenu = Mission:GetMenu( TaskGroup ) - - self.MenuAssigned = self.MenuAssigned or {} - self.MenuAssigned[TaskGroup] = MENU_GROUP_DELAYED:New( TaskGroup, string.format( "Assigned Task %s", TaskName ), MissionMenu ):SetTime( MenuTime ):SetTag( "Tasking" ) - local TaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Abort Task" ), self.MenuAssigned[TaskGroup], self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) - local MarkMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Mark Task Location on Map" ), self.MenuAssigned[TaskGroup], self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) - local TaskTypeMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Report Task Details" ), self.MenuAssigned[TaskGroup], self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) + for UnitName, TaskUnit in pairs( TaskGroup:GetUnits() ) do + local TaskUnit = TaskUnit -- Wrapper.Unit#UNIT + if TaskUnit then + local MenuControl = self:GetTaskControlMenu( TaskUnit ) + local TaskControl = MENU_GROUP:New( TaskGroup, "Control Task", MenuControl ):SetTime( MenuTime ):SetTag( "Tasking" ) + local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Task" ), TaskControl, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) + local MarkMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskControl, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) + local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Details" ), TaskControl, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) + end + end return self end @@ -1595,3 +1598,62 @@ do -- Additional Task Scoring and Task Progress end end + +do -- Task Control Menu + + -- The Task Control Menu is a menu attached to the task at the main menu to quickly be able to do actions in the task. + -- The Task Control Menu can only be shown when the task is assigned to the player. + -- The Task Control Menu is linked to the process executing the task, so no task menu can be set to the main static task definition. + + --- Init Task Control Menu + -- @param #TASK self + -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @return Task Control Menu Refresh ID + function TASK:InitTaskControlMenu( TaskUnit ) + + self.TaskControlMenuTime = timer.getTime() + + return self.TaskControlMenuTime + end + + --- Get Task Control Menu + -- @param #TASK self + -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @return Core.Menu#MENU_GROUP TaskControlMenu The Task Control Menu + function TASK:GetTaskControlMenu( TaskUnit, TaskName ) + + TaskName = TaskName or "" + + if not self.TaskControlMenu then + self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Assigned Task " .. TaskUnit:GetPlayerName() .. " - " .. self:GetName() .. " " .. TaskName ):SetTime( self.TaskControlMenuTime ) + else + self.TaskControlMenu:SetTime( self.TaskControlMenuTime ) + end + + return self.TaskControlMenu + end + + --- Remove Task Control Menu + -- @param #TASK self + -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + function TASK:RemoveTaskControlMenu( TaskUnit ) + + if self.TaskControlMenu then + self.TaskControlMenu:Remove() + self.TaskControlMenu = nil + end + end + + --- Refresh Task Control Menu + -- @param #TASK self + -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @param MenuTime The refresh time that was used to refresh the Task Control Menu items. + -- @param MenuTag The tag. + function TASK:RefreshTaskControlMenu( TaskUnit, MenuTime, MenuTag ) + + if self.TaskControlMenu then + self.TaskControlMenu:Remove( MenuTime, MenuTag ) + end + end + +end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 278354142..a6ab41fc3 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -257,17 +257,17 @@ do -- TASK_CARGO --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit - -- @param Tasking.Task_CARGO#TASK_CARGO Task + -- @param #TASK_CARGO Task function Fsm:onafterSelectAction( TaskUnit, Task ) local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) - local MenuTime = timer.getTime() + local MenuTime = Task:InitTaskControlMenu( TaskUnit ) + + local MenuControl = Task:GetTaskControlMenu( TaskUnit ) - TaskUnit.Menu = MENU_GROUP:New( TaskUnit:GetGroup(), Task:GetName() .. " @ " .. TaskUnit:GetName() ) - local CargoItemCount = TaskUnit:CargoItemCount() --Task:GetMission():GetCommandCenter():MessageToGroup( "Cargo in carrier: " .. CargoItemCount, TaskUnit:GetGroup() ) @@ -284,7 +284,7 @@ do -- TASK_CARGO -- MENU_GROUP_COMMAND:New( -- TaskUnit:GetGroup(), -- "Cancel Route " .. Cargo.Name, --- TaskUnit.Menu, +-- MenuControl, -- self.MenuRouteToPickupCancel, -- self, -- Cargo @@ -294,6 +294,8 @@ do -- TASK_CARGO self:F( { CargoUnloaded = Cargo:IsUnLoaded(), CargoLoaded = Cargo:IsLoaded(), CargoItemCount = CargoItemCount } ) Task:E( { TaskDeployZones = Task.DeployZones, TaskName = Task:GetName() } ) + local TaskGroup = TaskUnit:GetGroup() + if Cargo:IsUnLoaded() then if CargoItemCount < 1 then if Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then @@ -308,7 +310,8 @@ do -- TASK_CARGO if Cargo:CanBoard() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then Cargo:Report( "ready for boarding at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "board", TaskUnit:GetGroup() ) - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime) + local BoardMenu = MENU_GROUP:New( TaskGroup, "Board cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, BoardMenu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() else Cargo:Report( "Board at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) end @@ -316,7 +319,8 @@ do -- TASK_CARGO if Cargo:CanLoad() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then Cargo:Report( "ready for loading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "load", TaskUnit:GetGroup() ) - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Load cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime) + local LoadMenu = MENU_GROUP:New( TaskGroup, "Load cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, LoadMenu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() else Cargo:Report( "Load at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) end @@ -330,17 +334,14 @@ do -- TASK_CARGO end end end - TaskUnit.Menu:SetTime( MenuTime ) else Cargo:ReportResetAll( TaskUnit:GetGroup() ) end end else - if self:Is( "RoutingToPickup" ) then - else - self:F("route menu set") - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Pickup cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime) - TaskUnit.Menu:SetTime( MenuTime ) + if not Cargo:IsDeployed() == true then + local RouteToPickupMenu = MENU_GROUP:New( TaskGroup, "Route to pickup cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, RouteToPickupMenu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() Cargo:ReportResetAll( TaskUnit:GetGroup() ) end end @@ -367,20 +368,22 @@ do -- TASK_CARGO if Cargo:IsLoaded() == true and Cargo:IsLoadedInCarrier( TaskUnit ) == true then if not TaskUnit:InAir() then if Cargo:CanUnboard() == true then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime) + local UnboardMenu = MENU_GROUP:New( TaskGroup, "Unboard cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, UnboardMenu, self.MenuUnboardCargo, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() else if Cargo:CanUnload() == true then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unload cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnloadCargo, self, Cargo ):SetTime(MenuTime) + local UnloadMenu = MENU_GROUP:New( TaskGroup, "Unload cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, UnloadMenu, self.MenuUnloadCargo, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() end end - TaskUnit.Menu:SetTime( MenuTime ) end - -- Deployzones are optional zones that can be selected to request routing information. - for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if not Cargo:IsInZone( DeployZone ) then - MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Deploy cargo at " .. DeployZoneName, TaskUnit.Menu, self.MenuRouteToDeploy, self, DeployZone ):SetTime(MenuTime) - TaskUnit.Menu:SetTime( MenuTime ) - end + end + + -- Deployzones are optional zones that can be selected to request routing information. + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if not Cargo:IsInZone( DeployZone ) then + local RouteToDeployMenu = MENU_GROUP:New( TaskGroup, "Route to deploy cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) + MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Zone " .. DeployZoneName, RouteToDeployMenu, self.MenuRouteToDeploy, self, DeployZone ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() end end end @@ -388,8 +391,7 @@ do -- TASK_CARGO end ) - TaskUnit.Menu:Remove( MenuTime ) - + Task:RefreshTaskControlMenu( TaskUnit, MenuTime, "Cargo" ) self:__SelectAction( -1 ) @@ -399,11 +401,13 @@ do -- TASK_CARGO --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit - -- @param Tasking.Task_Cargo#TASK_CARGO Task + -- @param #TASK_CARGO Task function Fsm:OnLeaveWaitingForCommand( TaskUnit, Task ) self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - TaskUnit.Menu:Remove() + --local MenuControl = Task:GetTaskControlMenu( TaskUnit ) + + --MenuControl:Remove() end function Fsm:MenuBoardCargo( Cargo ) @@ -820,12 +824,15 @@ do -- TASK_CARGO self:F({Cargo, TaskUnit}) local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local MenuTime = self:InitTaskControlMenu( TaskUnit ) + local MenuControl = self:GetTaskControlMenu( TaskUnit ) local ActRouteCargo = ProcessUnit:GetProcess( "RoutingToPickup", "RouteToPickupPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT ActRouteCargo:Reset() ActRouteCargo:SetCoordinate( Cargo:GetCoordinate() ) ActRouteCargo:SetRange( Cargo:GetLoadRadius() ) - ActRouteCargo:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Cargo " .. Cargo:GetName(), TaskUnit.Menu ) + ActRouteCargo:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Cargo " .. Cargo:GetName(), MenuControl, MenuTime, "Cargo" ) ActRouteCargo:Start() return self @@ -840,10 +847,13 @@ do -- TASK_CARGO local ProcessUnit = self:GetUnitProcess( TaskUnit ) + local MenuTime = self:InitTaskControlMenu( TaskUnit ) + local MenuControl = self:GetTaskControlMenu( TaskUnit ) + local ActRouteDeployZone = ProcessUnit:GetProcess( "RoutingToDeploy", "RouteToDeployZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE ActRouteDeployZone:Reset() ActRouteDeployZone:SetZone( DeployZone ) - ActRouteDeployZone:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Deploy Zone" .. DeployZone:GetName(), TaskUnit.Menu ) + ActRouteDeployZone:SetMenuCancel( TaskUnit:GetGroup(), "Cancel Routing to Deploy Zone" .. DeployZone:GetName(), MenuControl, MenuTime, "Cargo" ) ActRouteDeployZone:Start() return self @@ -970,6 +980,8 @@ do -- TASK_CARGO return 0 end + + end diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 6479037a9..2e5318f68 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -130,12 +130,21 @@ end -- @param #UNIT self -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param #number Heading The heading of the unit respawn. -function STATIC:ReSpawn( Coordinate, Heading ) +function STATIC:SpawnAt( Coordinate, Heading ) - - -- todo: need to fix country local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName ) end + +--- Respawn the @{Unit} using a (tweaked) template of the parent Group. +-- @param #UNIT self +-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. +-- @param #number Heading The heading of the unit respawn. +function STATIC:ReSpawn() + + local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) + + SpawnStatic:ReSpawn() +end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index ed536a603..fe4b8cca0 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -189,9 +189,9 @@ end -- * Then it will respawn the re-modelled group. -- -- @param #UNIT self --- @param Dcs.DCSTypes#Vec3 SpawnVec3 The position where to Spawn the new Unit at. +-- @param Core.Point#COORDINATE Coordinate The position where to Spawn the new Unit at. -- @param #number Heading The heading of the unit respawn. -function UNIT:ReSpawn( SpawnVec3, Heading ) +function UNIT:ReSpawnAt( Coordinate, Heading ) self:T( self:Name() ) local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) @@ -203,8 +203,8 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) if SpawnGroup then local Vec3 = SpawnGroup:GetVec3() - SpawnGroupTemplate.x = SpawnVec3.x - SpawnGroupTemplate.y = SpawnVec3.z + SpawnGroupTemplate.x = Coordinate.x + SpawnGroupTemplate.y = Coordinate.z self:F( #SpawnGroupTemplate.units ) for UnitID, UnitData in pairs( SpawnGroup:GetUnits() ) do @@ -227,9 +227,9 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) SpawnGroupTemplate.units[UnitTemplateID].unitId = nil if UnitTemplateData.name == self:Name() then self:T("Adjusting") - SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y - SpawnGroupTemplate.units[UnitTemplateID].x = SpawnVec3.x - SpawnGroupTemplate.units[UnitTemplateID].y = SpawnVec3.z + SpawnGroupTemplate.units[UnitTemplateID].alt = Coordinate.y + SpawnGroupTemplate.units[UnitTemplateID].x = Coordinate.x + SpawnGroupTemplate.units[UnitTemplateID].y = Coordinate.z SpawnGroupTemplate.units[UnitTemplateID].heading = Heading self:F( { UnitTemplateID, SpawnGroupTemplate.units[UnitTemplateID], SpawnGroupTemplate.units[UnitTemplateID] } ) else @@ -344,18 +344,18 @@ end function UNIT:GetPlayerName() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSObject() + local DCSUnit = self:GetDCSObject() -- Dcs.DCSUnit#Unit if DCSUnit then local PlayerName = DCSUnit:getPlayerName() - if PlayerName == nil then - PlayerName = "" + if PlayerName == nil or PlayerName == "" then + PlayerName = "Player" .. DCSUnit:getID() end return PlayerName end - return nil + return nil end From 1ae1b9abd72b605c8cb7640dbdfaed160a9697ac Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 11 Apr 2018 09:14:12 +0200 Subject: [PATCH 046/170] Ready for another test session. --- Moose Development/Moose/Cargo/Cargo.lua | 13 +++++-- Moose Development/Moose/Cargo/CargoCrate.lua | 29 ++++++++++++-- Moose Development/Moose/Cargo/CargoGroup.lua | 20 ++++++++++ .../Moose/Cargo/CargoSlingload.lua | 24 +++++++++++- Moose Development/Moose/Cargo/CargoUnit.lua | 18 +++++++++ Moose Development/Moose/Core/Event.lua | 14 ++++++- Moose Development/Moose/Core/Set.lua | 38 +++++++++++++++---- Moose Development/Moose/Core/SpawnStatic.lua | 5 --- Moose Development/Moose/Tasking/Task.lua | 2 +- Moose Development/Moose/Tasking/TaskInfo.lua | 12 +++--- .../Moose/Tasking/Task_CARGO.lua | 21 +++++----- Moose Development/Moose/Wrapper/Object.lua | 4 +- Moose Development/Moose/Wrapper/Static.lua | 17 +++++++-- 13 files changed, 172 insertions(+), 45 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index b7f52ee4e..6e327bf5a 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -268,8 +268,7 @@ do -- CARGO self.Slingloadable = false self.Moveable = false self.Containable = false - self.LoadAction = "" - + self.CargoLimit = 0 self.LoadRadius = LoadRadius or 500 @@ -369,6 +368,14 @@ do -- CARGO end + --- Get the transportation method of the Cargo. + -- @param #CARGO self + -- @return #string The transportation method of the Cargo. + function CARGO:GetTransportationMethod() + return self.TransportationMethod + end + + --- Get the coalition of the Cargo. -- @param #CARGO self -- @return Coalition @@ -802,7 +809,7 @@ do -- CARGO_REPRESENTABLE -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects. self:F( { CargoName = self:GetName() } ) - _EVENTDISPATCHER:CreateEventDeleteCargo( self ) + --_EVENTDISPATCHER:CreateEventDeleteCargo( self ) return self end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 104e26438..89bd95c6d 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -49,7 +49,7 @@ do -- CARGO_CRATE local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE self:F( { Type, Name, NearRadius } ) - self.CargoObject = CargoStatic + self.CargoObject = CargoStatic -- Wrapper.Static#STATIC self:T( self.ClassName ) @@ -73,7 +73,9 @@ do -- CARGO_CRATE if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then if self.CargoObject:GetName() == EventData.IniUnitName then - Destroyed = true + if not self.NoDestroy then + Destroyed = true + end end else if self:IsLoaded() then @@ -90,7 +92,7 @@ do -- CARGO_CRATE self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } ) self:Destroyed() end - + end @@ -145,7 +147,10 @@ do -- CARGO_CRATE -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). if self.CargoObject then self:T("Destroying") + self.NoDestroy = true self.CargoObject:Destroy() + --local Coordinate = self.CargoObject:GetCoordinate():GetRandomCoordinateInRadius( 50, 20 ) + --self.CargoObject:ReSpawnAt( Coordinate, 0 ) end end @@ -290,6 +295,24 @@ do -- CARGO_CRATE end + + --- Get the transportation method of the Cargo. + -- @param #CARGO_CRATE self + -- @return #string The transportation method of the Cargo. + function CARGO_CRATE:GetTransportationMethod() + if self:IsLoaded() then + return "for unloading" + else + if self:IsUnLoaded() then + return "for loading" + else + if self:IsDeployed() then + return "delivered" + end + end + end + return "" + end end diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 4ad076362..32dd2a886 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -584,4 +584,24 @@ do -- CARGO_GROUP end + --- Get the transportation method of the Cargo. + -- @param #CARGO_GROUP self + -- @return #string The transportation method of the Cargo. + function CARGO_GROUP:GetTransportationMethod() + if self:IsLoaded() then + return "for unboarding" + else + if self:IsUnLoaded() then + return "for boarding" + else + if self:IsDeployed() then + return "delivered" + end + end + end + return "" + end + + + end -- CARGO_GROUP diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 04626385b..e8ed5d5cb 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -74,7 +74,9 @@ do -- CARGO_SLINGLOAD if self:IsDestroyed() or self:IsUnLoaded() then if self.CargoObject:GetName() == EventData.IniUnitName then - Destroyed = true + if not self.NoDestroy then + Destroyed = true + end end end @@ -247,5 +249,23 @@ do -- CARGO_SLINGLOAD end - + + --- Get the transportation method of the Cargo. + -- @param #CARGO_SLINGLOAD self + -- @return #string The transportation method of the Cargo. + function CARGO_SLINGLOAD:GetTransportationMethod() + if self:IsLoaded() then + return "for sling loading" + else + if self:IsUnLoaded() then + return "for sling loading" + else + if self:IsDeployed() then + return "delivered" + end + end + end + return "" + end + end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 70a42b6c8..7086035bb 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -370,4 +370,22 @@ do -- CARGO_UNIT end end + --- Get the transportation method of the Cargo. + -- @param #CARGO_UNIT self + -- @return #string The transportation method of the Cargo. + function CARGO_UNIT:GetTransportationMethod() + if self:IsLoaded() then + return "for unboarding" + else + if self:IsUnLoaded() then + return "for boarding" + else + if self:IsDeployed() then + return "delivered" + end + end + end + return "" + end + end -- CARGO_UNIT diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index dd26c3bf6..b7004d42f 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -744,7 +744,7 @@ function EVENT:onEvent( Event ) local EventMeta = _EVENTMETA[Event.id] - --self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ... + self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ... if self and self.Events and @@ -888,7 +888,7 @@ function EVENT:onEvent( Event ) -- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do - + --if Event.IniObjectCategory ~= Object.Category.STATIC then -- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } ) --end @@ -1037,6 +1037,16 @@ function EVENT:onEvent( Event ) end end end + + -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. + -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. + -- And this is a problem because it will remove all entries from the SET_CARGOs. + -- To prevent this from happening, the Cargo object has a flag NoDestroy. + -- When true, the SET_CARGO won't Remove the Cargo object from the set. + -- But we need to switch that flag off after the event handlers have been called. + if Event.id == EVENTS.DeleteCargo then + Event.Cargo.NoDestroy = nil + end else self:T( { EventMeta.Text, Event } ) end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 48973c2b2..eb950115a 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -149,6 +149,7 @@ end -- @param #SET_BASE self -- @param #string ObjectName function SET_BASE:Remove( ObjectName ) + self:F( { ObjectName = ObjectName, Object = Object } ) local Object = self.Set[ObjectName] @@ -313,10 +314,6 @@ function SET_BASE:_FilterStart() end end - self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) - self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) - self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) - -- Follow alive players and clients --self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) --self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit ) @@ -935,6 +932,9 @@ function SET_GROUP:FilterStart() if _DATABASE then self:_FilterStart() + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) end @@ -1643,6 +1643,9 @@ do -- SET_UNIT if _DATABASE then self:_FilterStart() + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) end return self @@ -2559,6 +2562,9 @@ do -- SET_STATIC if _DATABASE then self:_FilterStart() + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) end return self @@ -3200,6 +3206,9 @@ function SET_CLIENT:FilterStart() if _DATABASE then self:_FilterStart() + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) end return self @@ -3599,6 +3608,9 @@ function SET_PLAYER:FilterStart() if _DATABASE then self:_FilterStart() + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) end return self @@ -4270,10 +4282,9 @@ function SET_CARGO:FilterStart() --R2.1 if _DATABASE then self:_FilterStart() + self:HandleEvent( EVENTS.NewCargo ) + self:HandleEvent( EVENTS.DeleteCargo ) end - - self:HandleEvent( EVENTS.NewCargo ) - self:HandleEvent( EVENTS.DeleteCargo ) return self end @@ -4405,7 +4416,18 @@ function SET_CARGO:OnEventDeleteCargo( EventData ) --R2.1 if EventData.Cargo then local Cargo = _DATABASE:FindCargo( EventData.Cargo.Name ) if Cargo and Cargo.Name then - self:Remove( Cargo.Name ) + + -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. + -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. + -- And this is a problem because it will remove all entries from the SET_CARGOs. + -- To prevent this from happening, the Cargo object has a flag NoDestroy. + -- When true, the SET_CARGO won't Remove the Cargo object from the set. + -- This flag is switched off after the event handlers have been called in the EVENT class. + self:F( { CargoNoDestroy=Cargo.NoDestroy } ) + if Cargo.NoDestroy then + else + self:Remove( Cargo.Name ) + end end end end diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 1f5b8a97a..8019902af 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -238,15 +238,10 @@ function SPAWNSTATIC:ReSpawnAt( Coordinate, Heading ) if StaticTemplate then local CountryID = self.CountryID - local CountryName = _DATABASE.COUNTRY_NAME[CountryID] StaticTemplate.x = Coordinate.x StaticTemplate.y = Coordinate.z - StaticTemplate.units = nil - StaticTemplate.route = nil - StaticTemplate.groupId = nil - StaticTemplate.heading = Heading and ( ( Heading / 180 ) * math.pi ) or StaticTemplate.heading StaticTemplate.CountryID = nil diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 4a4677053..e31cb0c6b 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -1502,7 +1502,7 @@ function TASK:ReportDetails( ReportGroup ) local PlayerReport = REPORT:New() for PlayerName, PlayerGroup in pairs( PlayerNames ) do - PlayerReport:Add( "Group " .. PlayerGroup:GetCallsign() .. ": " .. PlayerName ) + PlayerReport:Add( "Players group " .. PlayerGroup:GetCallsign() .. ": " .. PlayerName ) end local Players = PlayerReport:Text() diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index bf75bcf5a..2a3c150c3 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -249,17 +249,15 @@ end function TASKINFO:AddCargoSet( SetCargo, Order, Detail, Keep ) local CargoReport = REPORT:New() + CargoReport:Add( "" ) SetCargo:ForEachCargo( - --- @param Core.Cargo#CARGO Cargo + --- @param Cargo.Cargo#CARGO Cargo function( Cargo ) - local CargoType = Cargo:GetType() - local CargoName = Cargo:GetName() - local CargoCoordinate = Cargo:GetCoordinate() - CargoReport:Add( string.format( '"%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) ) + CargoReport:Add( string.format( ' - %s (%s) %s - status %s ', Cargo:GetName(), Cargo:GetType(), Cargo:GetTransportationMethod(), Cargo:GetCurrentState() ) ) end ) - self:AddInfo( "CargoSet", CargoReport:Text(), Order, Detail, Keep ) + self:AddInfo( "Cargo", CargoReport:Text(), Order, Detail, Keep ) return self end @@ -319,7 +317,7 @@ function TASKINFO:Report( Report, Detail, ReportGroup ) local Coordinate = Data.Data -- Core.Point#COORDINATE Text = Coordinate:ToStringWind( ReportGroup:GetUnit(1), nil, self ) end - if Key == "CargoSet" then + if Key == "Cargo" then local DataText = Data.Data -- #string Text = DataText end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index a6ab41fc3..970da6af5 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -309,27 +309,27 @@ do -- TASK_CARGO if not TaskUnit:InAir() then if Cargo:CanBoard() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then - Cargo:Report( "ready for boarding at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "board", TaskUnit:GetGroup() ) + Cargo:Report( "Ready for boarding.", "board", TaskUnit:GetGroup() ) local BoardMenu = MENU_GROUP:New( TaskGroup, "Board cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, BoardMenu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() else - Cargo:Report( "Board at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + Cargo:Report( "Board at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() .. "." ), "reporting", TaskUnit:GetGroup() ) end else if Cargo:CanLoad() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then - Cargo:Report( "ready for loading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "load", TaskUnit:GetGroup() ) + Cargo:Report( "Ready for loading.", "load", TaskUnit:GetGroup() ) local LoadMenu = MENU_GROUP:New( TaskGroup, "Load cargo", MenuControl ):SetTime( MenuTime ):SetTag( "Cargo" ) MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), Cargo.Name, LoadMenu, self.MenuLoadCargo, self, Cargo ):SetTime(MenuTime):SetTag("Cargo"):SetRemoveParent() else - Cargo:Report( "Load at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + Cargo:Report( "Load at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ) .. " within " .. Cargo.NearRadius .. ".", "reporting", TaskUnit:GetGroup() ) end else if Cargo:CanSlingload() == true then if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then - Cargo:Report( "ready for slingloading at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "slingload", TaskUnit:GetGroup() ) + Cargo:Report( "Ready for slingloading.", "slingload", TaskUnit:GetGroup() ) else - Cargo:Report( "Slingload at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ), "reporting", TaskUnit:GetGroup() ) + Cargo:Report( "Slingload at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() .. "." ), "reporting", TaskUnit:GetGroup() ) end end end @@ -643,7 +643,7 @@ do -- TASK_CARGO local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) - Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() ) + Cargo:MessageToGroup( "Boarded cargo " .. Cargo:GetName(), TaskUnit:GetGroup() ) self:__Load( -0.1, Cargo ) @@ -662,7 +662,7 @@ do -- TASK_CARGO Cargo:Load( TaskUnit ) end - Cargo:MessageToGroup( "Loaded ...", TaskUnit:GetGroup() ) + Cargo:MessageToGroup( "Loaded cargo " .. Cargo:GetName(), TaskUnit:GetGroup() ) TaskUnit:AddCargo( Cargo ) Task:CargoPickedUp( TaskUnit, Cargo ) @@ -736,7 +736,7 @@ do -- TASK_CARGO local TaskUnitName = TaskUnit:GetName() self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) - self.Cargo:MessageToGroup( "UnBoarded ...", TaskUnit:GetGroup() ) + self.Cargo:MessageToGroup( "UnBoarded cargo " .. self.Cargo:GetName(), TaskUnit:GetGroup() ) self:Unload( self.Cargo ) end @@ -759,6 +759,8 @@ do -- TASK_CARGO end TaskUnit:RemoveCargo( Cargo ) + Cargo:MessageToGroup( "Unloaded cargo " .. Cargo:GetName(), TaskUnit:GetGroup() ) + self:Planned() self:__SelectAction( 1 ) end @@ -970,7 +972,6 @@ do -- TASK_CARGO function TASK_CARGO:UpdateTaskInfo( DetectedItem ) if self:IsStatePlanned() or self:IsStateAssigned() then - self.TaskInfo:AddTaskName( 0, "MSOD" ) self.TaskInfo:AddCargoSet( self.SetCargo, 10, "SOD", true ) end end diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index 29901fd4b..656031e78 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -73,6 +73,7 @@ end --- Destroys the OBJECT. -- @param #OBJECT self +-- @return #boolean true if the object is destroyed. -- @return #nil The DCS Unit is not existing or alive. function OBJECT:Destroy() @@ -80,7 +81,8 @@ function OBJECT:Destroy() if DCSObject then --BASE:CreateEventCrash( timer.getTime(), DCSObject ) - DCSObject:destroy() + DCSObject:destroy( false ) + return true end BASE:E( { "Cannot Destroy", Name = self.ObjectName, Class = self:GetClassName() } ) diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 2e5318f68..ad53a16dd 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -138,13 +138,24 @@ function STATIC:SpawnAt( Coordinate, Heading ) end ---- Respawn the @{Unit} using a (tweaked) template of the parent Group. +--- Respawn the @{Unit} at the same location with the same properties. +-- This is useful to respawn a cargo after it has been destroyed. -- @param #UNIT self --- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. --- @param #number Heading The heading of the unit respawn. function STATIC:ReSpawn() local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) SpawnStatic:ReSpawn() end + + +--- Respawn the @{Unit} at a defined Coordinate with an optional heading. +-- @param #UNIT self +-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. +-- @param #number Heading The heading of the unit respawn. +function STATIC:ReSpawnAt( Coordinate, Heading ) + + local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) + + SpawnStatic:ReSpawnAt( Coordinate, Heading ) +end From faa934ffce8ca95a77a421be7853149d54837a56 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 11 Apr 2018 17:00:11 +0200 Subject: [PATCH 047/170] Fixed stuff for multi player --- Moose Development/Moose/Cargo/Cargo.lua | 6 +++--- Moose Development/Moose/Cargo/CargoCrate.lua | 16 +++++++--------- Moose Development/Moose/Cargo/CargoUnit.lua | 4 ++-- Moose Development/Moose/Core/Menu.lua | 2 +- Moose Development/Moose/Tasking/Task.lua | 6 +----- Moose Development/Moose/Tasking/Task_CARGO.lua | 2 +- Moose Development/Moose/Wrapper/Positionable.lua | 2 +- 7 files changed, 16 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 6e327bf5a..199f211a2 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -610,7 +610,7 @@ do -- CARGO -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - self:F2( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + --self:F2( { PointVec2 = PointVec2, NearRadius = NearRadius } ) if self.CargoObject:IsAlive() then --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) @@ -621,12 +621,12 @@ do -- CARGO --self:F( Distance ) if Distance <= NearRadius then - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } ) + --self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } ) return true end end - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } ) + --self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } ) return false end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 89bd95c6d..18c49a4db 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -51,8 +51,6 @@ do -- CARGO_CRATE self.CargoObject = CargoStatic -- Wrapper.Static#STATIC - self:T( self.ClassName ) - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. _EVENTDISPATCHER:CreateEventNewCargo( self ) @@ -103,7 +101,7 @@ do -- CARGO_CRATE -- @param #string To -- @param Core.Point#POINT_VEC2 function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) + --self:F( { ToPointVec2, From, Event, To } ) local Angle = 180 local Speed = 10 @@ -140,7 +138,7 @@ do -- CARGO_CRATE -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier ) - self:F( { From, Event, To, CargoCarrier } ) + --self:F( { From, Event, To, CargoCarrier } ) self.CargoCarrier = CargoCarrier @@ -171,12 +169,12 @@ do -- CARGO_CRATE -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_CRATE:IsInReportRadius( Coordinate ) - self:F( { Coordinate, LoadRadius = self.LoadRadius } ) + --self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:T( Distance ) + --self:T( Distance ) if Distance <= self.LoadRadius then return true end @@ -191,12 +189,12 @@ do -- CARGO_CRATE -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Crate is within the loading radius. function CARGO_CRATE:IsInLoadRadius( Coordinate ) - self:F( { Coordinate, LoadRadius = self.NearRadius } ) + --self:F( { Coordinate, LoadRadius = self.NearRadius } ) local Distance = 0 if self:IsUnLoaded() then Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:T( Distance ) + --self:T( Distance ) if Distance <= self.NearRadius then return true end @@ -212,7 +210,7 @@ do -- CARGO_CRATE -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. -- @return #nil There is no valid Cargo in the CargoGroup. function CARGO_CRATE:GetCoordinate() - self:F() + --self:F() return self.CargoObject:GetCoordinate() end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 7086035bb..318852cb1 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -285,7 +285,7 @@ do -- CARGO_UNIT -- @param Wrapper.Client#CLIENT CargoCarrier -- @param #number NearRadius function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + --self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then @@ -338,7 +338,7 @@ do -- CARGO_UNIT -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + --self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) local Speed = 90 local Angle = 180 diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 5ee9f9fff..a435f16cb 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -246,7 +246,7 @@ do -- MENU_BASE -- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}. -- @return #MENU_BASE function MENU_BASE:SetRemoveParent( RemoveParent ) - self:F( { RemoveParent } ) + --self:F( { RemoveParent } ) self.MenuRemoveParent = RemoveParent return self end diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index e31cb0c6b..d1dde22ed 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -1624,11 +1624,7 @@ do -- Task Control Menu TaskName = TaskName or "" - if not self.TaskControlMenu then - self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Assigned Task " .. TaskUnit:GetPlayerName() .. " - " .. self:GetName() .. " " .. TaskName ):SetTime( self.TaskControlMenuTime ) - else - self.TaskControlMenu:SetTime( self.TaskControlMenuTime ) - end + self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Assigned Task " .. TaskUnit:GetPlayerName() .. " - " .. self:GetName() .. " " .. TaskName ):SetTime( self.TaskControlMenuTime ) return self.TaskControlMenu end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 970da6af5..4f1473e7f 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -329,7 +329,7 @@ do -- TASK_CARGO if Cargo:IsInLoadRadius( TaskUnit:GetPointVec2() ) then Cargo:Report( "Ready for slingloading.", "slingload", TaskUnit:GetGroup() ) else - Cargo:Report( "Slingload at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() .. "." ), "reporting", TaskUnit:GetGroup() ) + Cargo:Report( "Slingload at " .. Cargo:GetCoordinate():ToString( TaskUnit:GetGroup() ) .. ".", "reporting", TaskUnit:GetGroup() ) end end end diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index b36a2d88b..b28bb5933 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -129,7 +129,7 @@ function POSITIONABLE:GetPointVec2() local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) - self:T( PositionablePointVec2 ) + --self:F( PositionablePointVec2 ) return PositionablePointVec2 end From 9cea486fdc31bffc610eee3bb6d20290b6a9f5f6 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 11 Apr 2018 17:09:59 +0200 Subject: [PATCH 048/170] Progress --- Moose Development/Moose/Cargo/CargoSlingload.lua | 16 +++++++--------- Moose Development/Moose/Wrapper/Client.lua | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index e8ed5d5cb..1cfa043f1 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -51,8 +51,6 @@ do -- CARGO_SLINGLOAD self.CargoObject = CargoStatic - self:T( self.ClassName ) - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. _EVENTDISPATCHER:CreateEventNewCargo( self ) @@ -124,7 +122,7 @@ do -- CARGO_SLINGLOAD -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_SLINGLOAD:IsInReportRadius( Coordinate ) - self:F( { Coordinate, LoadRadius = self.LoadRadius } ) + --self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then @@ -144,7 +142,7 @@ do -- CARGO_SLINGLOAD -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Slingload is within the loading radius. function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate ) - self:F( { Coordinate } ) + --self:F( { Coordinate } ) local Distance = 0 if self:IsUnLoaded() then @@ -165,7 +163,7 @@ do -- CARGO_SLINGLOAD -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. -- @return #nil There is no valid Cargo in the CargoGroup. function CARGO_SLINGLOAD:GetCoordinate() - self:F() + --self:F() return self.CargoObject:GetCoordinate() end @@ -195,7 +193,7 @@ do -- CARGO_SLINGLOAD -- @param #CARGO_SLINGLOAD self -- @param Core.Point#COORDINATE Coordinate function CARGO_SLINGLOAD:RouteTo( Coordinate ) - self:F( {Coordinate = Coordinate } ) + --self:F( {Coordinate = Coordinate } ) end @@ -208,7 +206,7 @@ do -- CARGO_SLINGLOAD -- @return #boolean The Cargo is near to the Carrier. -- @return #nil The Cargo is not near to the Carrier. function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius ) - self:F( {NearRadius = NearRadius } ) + --self:F( {NearRadius = NearRadius } ) return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) end @@ -218,7 +216,7 @@ do -- CARGO_SLINGLOAD -- @param #CARGO_SLINGLOAD self function CARGO_SLINGLOAD:Respawn() - self:F( { "Respawning slingload " .. self:GetName() } ) + --self:F( { "Respawning slingload " .. self:GetName() } ) -- Respawn the group... @@ -235,7 +233,7 @@ do -- CARGO_SLINGLOAD -- @param #CARGO_SLINGLOAD self function CARGO_SLINGLOAD:onafterReset() - self:F( { "Reset slingload " .. self:GetName() } ) + --self:F( { "Reset slingload " .. self:GetName() } ) -- Respawn the group... diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index dcf44d8d8..0d98f5092 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -181,8 +181,8 @@ function CLIENT:ShowBriefing() local Briefing = "" if self.ClientBriefing then Briefing = Briefing .. self.ClientBriefing + self:Message( Briefing, 60, "Briefing" ) end - self:Message( Briefing, 60, "Briefing" ) end return self From dcc42b8e62db9040331430c9236213cbe80963ca Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 11 Apr 2018 23:24:13 +0200 Subject: [PATCH 049/170] Fixes --- Moose Development/Moose/Cargo/Cargo.lua | 4 +-- Moose Development/Moose/Cargo/CargoGroup.lua | 28 +++++++++---------- .../Moose/Cargo/CargoSlingload.lua | 2 +- Moose Development/Moose/Core/Fsm.lua | 4 ++- Moose Development/Moose/Tasking/Task.lua | 13 +++++---- .../Moose/Tasking/Task_CARGO.lua | 4 +-- 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 199f211a2..2cf5be78e 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -637,12 +637,12 @@ do -- CARGO -- @param Core.Zone#ZONE_BASE Zone -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. function CARGO:IsInZone( Zone ) - self:F( { Zone } ) + --self:F( { Zone } ) if self:IsLoaded() then return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) else - self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) + --self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) if self.CargoObject:GetSize() ~= 0 then return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) else diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 32dd2a886..ab7addf54 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -150,7 +150,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) + --self:F( { CargoCarrier.UnitName, From, Event, To } ) local NearRadius = NearRadius or 25 @@ -175,7 +175,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) - self:F( { From, Event, To, CargoCarrier, ...} ) + --self:F( { From, Event, To, CargoCarrier, ...} ) if From == "UnLoaded" then -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. @@ -196,7 +196,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) + --self:F( { CargoCarrier.UnitName, From, Event, To } ) local NearRadius = NearRadius or 100 @@ -259,7 +259,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( {From, Event, To, ToPointVec2, NearRadius } ) + --self:F( {From, Event, To, ToPointVec2, NearRadius } ) NearRadius = NearRadius or 25 @@ -293,7 +293,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) + --self:F( { From, Event, To, ToPointVec2, NearRadius } ) --local NearRadius = NearRadius or 25 @@ -330,7 +330,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) + --self:F( { From, Event, To, ToPointVec2, NearRadius } ) --local NearRadius = NearRadius or 25 @@ -346,7 +346,7 @@ do -- CARGO_GROUP -- @param #string From -- @param #string To function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) - self:F( { From, Event, To, ToPointVec2 } ) + --self:F( { From, Event, To, ToPointVec2 } ) if From == "Loaded" then @@ -410,7 +410,7 @@ do -- CARGO_GROUP -- @param #CARGO_GROUP self -- @param Core.Point#COORDINATE Coordinate function CARGO_GROUP:RouteTo( Coordinate ) - self:F( {Coordinate = Coordinate } ) + --self:F( {Coordinate = Coordinate } ) -- For each Cargo within the CargoSet, route each object to the Coordinate self.CargoSet:ForEach( @@ -429,7 +429,7 @@ do -- CARGO_GROUP -- @return #boolean The Cargo is near to the Carrier. -- @return #nil The Cargo is not near to the Carrier. function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) - self:F( {NearRadius = NearRadius } ) + --self:F( {NearRadius = NearRadius } ) local Cargo = self.CargoSet:GetFirst() -- #CARGO @@ -445,7 +445,7 @@ do -- CARGO_GROUP -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Group is within the load radius. function CARGO_GROUP:IsInLoadRadius( Coordinate ) - self:F( { Coordinate } ) + --self:F( { Coordinate } ) local Cargo = self.CargoSet:GetFirst() -- #CARGO @@ -456,7 +456,7 @@ do -- CARGO_GROUP else Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) end - self:T( Distance ) + --self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -475,7 +475,7 @@ do -- CARGO_GROUP -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Group is within the report radius. function CARGO_GROUP:IsInReportRadius( Coordinate ) - self:F( { Coordinate } ) + --self:F( { Coordinate } ) local Cargo = self.CargoSet:GetFirst() -- #CARGO @@ -483,7 +483,7 @@ do -- CARGO_GROUP local Distance = 0 if Cargo:IsUnLoaded() then Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) - self:T( Distance ) + --self:T( Distance ) if Distance <= self.LoadRadius then return true end @@ -572,7 +572,7 @@ do -- CARGO_GROUP -- @return #boolean **true** if the first element of the CargoGroup is in the Zone -- @return #boolean **false** if there is no element of the CargoGroup in the Zone. function CARGO_GROUP:IsInZone( Zone ) - self:F( { Zone } ) + --self:F( { Zone } ) local Cargo = self.CargoSet:GetFirst() -- #CARGO diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 1cfa043f1..b1ea35246 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -127,7 +127,7 @@ do -- CARGO_SLINGLOAD local Distance = 0 if self:IsUnLoaded() then Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:T( Distance ) + --self:T( Distance ) if Distance <= self.LoadRadius then return true end diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index efcea3aee..dc2dec440 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -934,7 +934,9 @@ do -- FSM_PROCESS if self[handler] then self:F3( "Calling " .. handler ) self._EventSchedules[EventName] = nil - local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler ) + if self.Controllable and self.Controllable:IsAlive() == true then + local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler ) + end return Value --return self[handler]( self, self.Controllable, unpack( params ) ) end diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index d1dde22ed..564e6b4bd 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -688,7 +688,8 @@ function TASK:SetMenu( MenuTime ) --R2.1 Mission Reports and Task Reports added. self:F( { self:GetName(), MenuTime } ) --self.SetGroup:Flush() - for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetAliveSet() ) do + --for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetAliveSet() ) do + for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetSet() ) do local TaskGroup = TaskGroupData -- Wrapper.Group#GROUP if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then @@ -1444,11 +1445,13 @@ function TASK:GetPlayerCount() --R2.1 Get a count of the players. local PlayerCount = 0 -- Loop each Unit active in the Task, and find Player Names. - for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetAliveSet() ) do + for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP - if self:IsGroupAssigned( PlayerGroup ) then - local PlayerNames = PlayerGroup:GetPlayerNames() - PlayerCount = PlayerCount + #PlayerNames + if PlayerGroup:IsAlive() == true then + if self:IsGroupAssigned( PlayerGroup ) then + local PlayerNames = PlayerGroup:GetPlayerNames() + PlayerCount = PlayerCount + #PlayerNames + end end end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 4f1473e7f..12cabd80e 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -291,8 +291,7 @@ do -- TASK_CARGO -- ):SetTime(MenuTime) -- end - self:F( { CargoUnloaded = Cargo:IsUnLoaded(), CargoLoaded = Cargo:IsLoaded(), CargoItemCount = CargoItemCount } ) - Task:E( { TaskDeployZones = Task.DeployZones, TaskName = Task:GetName() } ) + --self:F( { CargoUnloaded = Cargo:IsUnLoaded(), CargoLoaded = Cargo:IsLoaded(), CargoItemCount = CargoItemCount } ) local TaskGroup = TaskUnit:GetGroup() @@ -349,7 +348,6 @@ do -- TASK_CARGO -- Cargo in deployzones are flagged as deployed. for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - Task:E( { DeployZone = DeployZone } ) if Cargo:IsInZone( DeployZone ) then Task:E( { CargoIsDeployed = Task.CargoDeployed and "true" or "false" } ) if Cargo:IsDeployed() == false then From fea2f55fbbea65d4351399b0727308b5f2ab2c73 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 12 Apr 2018 13:59:55 +0200 Subject: [PATCH 050/170] Lots of optimizations --- Moose Development/Moose/Actions/Act_Route.lua | 7 +- .../Moose/Cargo/CargoSlingload.lua | 2 - Moose Development/Moose/Core/Database.lua | 4 +- Moose Development/Moose/Core/Event.lua | 2 +- Moose Development/Moose/Core/Fsm.lua | 215 +++++++++++------- Moose Development/Moose/Core/Point.lua | 14 +- Moose Development/Moose/Core/Set.lua | 5 +- .../Moose/Functional/Detection.lua | 49 ++-- .../Moose/Tasking/CommandCenter.lua | 2 +- Moose Development/Moose/Tasking/Mission.lua | 4 +- Moose Development/Moose/Tasking/Task.lua | 67 +++--- .../Moose/Tasking/Task_CARGO.lua | 8 - Moose Development/Moose/Wrapper/Client.lua | 2 +- .../Moose/Wrapper/Controllable.lua | 2 +- Moose Development/Moose/Wrapper/Group.lua | 45 +++- Moose Development/Moose/Wrapper/Unit.lua | 22 +- 16 files changed, 261 insertions(+), 189 deletions(-) diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index 8a0d53b0f..3a4806468 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -244,10 +244,8 @@ do -- ACT_ROUTE -- @param #string From -- @param #string To function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To ) - self:F( { "BeforeRoute 1", self.DisplayCount, self.DisplayInterval } ) if ProcessUnit:IsAlive() then - self:F( "BeforeRoute 2" ) local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic if self.DisplayCount >= self.DisplayInterval then self:T( { HasArrived = HasArrived } ) @@ -259,8 +257,6 @@ do -- ACT_ROUTE self.DisplayCount = self.DisplayCount + 1 end - self:T( { DisplayCount = self.DisplayCount } ) - if HasArrived then self:__Arrive( 1 ) else @@ -343,7 +339,7 @@ do -- ACT_ROUTE_POINT -- @param #ACT_ROUTE_POINT self -- @param #number Range The Range to consider the arrival. Default is 10000 meters. function ACT_ROUTE_POINT:SetRange( Range ) - self:F2( { self.Range } ) + self:F2( { Range } ) self.Range = Range or 10000 end @@ -351,6 +347,7 @@ do -- ACT_ROUTE_POINT -- @param #ACT_ROUTE_POINT self -- @return #number The Range to consider the arrival. Default is 10000 meters. function ACT_ROUTE_POINT:GetRange() + self:F2( { self.Range } ) return self.Range end diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index b1ea35246..642fde94f 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -127,7 +127,6 @@ do -- CARGO_SLINGLOAD local Distance = 0 if self:IsUnLoaded() then Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - --self:T( Distance ) if Distance <= self.LoadRadius then return true end @@ -147,7 +146,6 @@ do -- CARGO_SLINGLOAD local Distance = 0 if self:IsUnLoaded() then Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:T( Distance ) if Distance <= self.NearRadius then return true end diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 01b1c64a0..b160fdfda 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -719,7 +719,7 @@ function DATABASE:_EventOnBirth( Event ) Event.IniGroup = self:FindGroup( Event.IniDCSGroupName ) local PlayerName = Event.IniUnit:GetPlayerName() self:E( { "PlayerName:", PlayerName } ) - if PlayerName ~= "" then + if PlayerName then self:E( { "Player Joined:", PlayerName } ) if not self.PLAYERS[PlayerName] then self:AddPlayer( Event.IniUnitName, PlayerName ) @@ -788,7 +788,7 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event ) if Event.IniUnit then if Event.IniObjectCategory == 1 then local PlayerName = Event.IniUnit:GetPlayerName() - if self.PLAYERS[PlayerName] then + if PlayerName and self.PLAYERS[PlayerName] then self:E( { "Player Left:", PlayerName } ) local Settings = SETTINGS:Set( PlayerName ) Settings:RemovePlayerMenu( Event.IniUnit ) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index b7004d42f..fafd2d2c5 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -744,7 +744,7 @@ function EVENT:onEvent( Event ) local EventMeta = _EVENTMETA[Event.id] - self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ... + --self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ... if self and self.Events and diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index dc2dec440..12b25179a 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -337,7 +337,7 @@ do -- FSM --- Creates a new FSM object. -- @param #FSM self -- @return #FSM - function FSM:New( FsmT ) + function FSM:New() -- Inherits from BASE self = BASE:Inherit( self, BASE:New() ) @@ -557,8 +557,9 @@ do -- FSM end - function FSM:_call_handler( handler, params, EventName ) + function FSM:_call_handler( step, trigger, params, EventName ) + local handler = step .. trigger local ErrorHandler = function( errmsg ) env.info( "Error in SCHEDULER function:" .. errmsg ) @@ -569,64 +570,99 @@ do -- FSM return errmsg end if self[handler] then - self:T2( "Calling " .. handler ) + self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] ) self._EventSchedules[EventName] = nil local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler ) return Value end end + --- @param #FSM self function FSM._handler( self, EventName, ... ) - local Can, to = self:can( EventName ) + local Can, To = self:can( EventName ) - if to == "*" then - to = self.current + if To == "*" then + To = self.current end if Can then - local from = self.current - local params = { from, EventName, to, ... } + local From = self.current + local Params = { From, EventName, To, ... } - if self.Controllable then - self:T( "FSM Transition for " .. self.Controllable.ControllableName .. " :" .. self.current .. " --> " .. EventName .. " --> " .. to ) + + if self["onleave".. From] or + self["OnLeave".. From] or + self["onbefore".. EventName] or + self["OnBefore".. EventName] or + self["onafter".. EventName] or + self["OnAfter".. EventName] or + self["onenter".. To] or + self["OnEnter".. To] + then + if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then + self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName ) + return false + else + if self:_call_handler( "OnBefore", EventName, Params, EventName ) == false then + self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** OnBefore" .. EventName ) + return false + else + if self:_call_handler( "onleave", From, Params, EventName ) == false then + self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onleave" .. From ) + return false + else + if self:_call_handler( "OnLeave", From, Params, EventName ) == false then + self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** OnLeave" .. From ) + return false + end + end + end + end else - self:T( "FSM Transition:" .. self.current .. " --> " .. EventName .. " --> " .. to ) - end + local ClassName = self:GetClassName() + if ClassName == "FSM" then + self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To ) + end - if ( self:_call_handler("onbefore" .. EventName, params, EventName ) == false ) - or ( self:_call_handler("OnBefore" .. EventName, params, EventName ) == false ) - or ( self:_call_handler("onleave" .. from, params, EventName ) == false ) - or ( self:_call_handler("OnLeave" .. from, params, EventName ) == false ) then - self:T( "Cancel Transition" ) - return false + if ClassName == "FSM_TASK" then + self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.TaskName ) + end + + if ClassName == "FSM_CONTROLLABLE" then + self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " ) + end + + if ClassName == "FSM_PROCESS" then + self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " ) + end end - self.current = to + self.current = To local execute = true - local subtable = self:_gosub( from, EventName ) + local subtable = self:_gosub( From, EventName ) for _, sub in pairs( subtable ) do --if sub.nextevent then -- self:F2( "nextevent = " .. sub.nextevent ) -- self[sub.nextevent]( self ) --end - self:T( "calling sub start event: " .. sub.StartEvent ) + self:T( "*** FSM *** Sub *** " .. sub.StartEvent ) sub.fsm.fsmparent = self sub.fsm.ReturnEvents = sub.ReturnEvents sub.fsm[sub.StartEvent]( sub.fsm ) execute = false end - local fsmparent, Event = self:_isendstate( to ) + local fsmparent, Event = self:_isendstate( To ) if fsmparent and Event then - self:F2( { "end state: ", fsmparent, Event } ) - self:_call_handler("onenter" .. to, params, EventName ) - self:_call_handler("OnEnter" .. to, params, EventName ) - self:_call_handler("onafter" .. EventName, params, EventName ) - self:_call_handler("OnAfter" .. EventName, params, EventName ) - self:_call_handler("onstatechange", params, EventName ) + self:T( "*** FSM *** End *** " .. Event ) + self:_call_handler("onenter", To, Params, EventName ) + self:_call_handler("OnEnter", To, Params, EventName ) + self:_call_handler("onafter", EventName, Params, EventName ) + self:_call_handler("OnAfter", EventName, Params, EventName ) + self:_call_handler("onstate", "change", Params, EventName ) fsmparent[Event]( fsmparent ) execute = false end @@ -634,18 +670,17 @@ do -- FSM if execute then -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! --if from ~= to then - self:_call_handler("onenter" .. to, params, EventName ) - self:_call_handler("OnEnter" .. to, params, EventName ) + self:_call_handler("onenter", To, Params, EventName ) + self:_call_handler("OnEnter", To, Params, EventName ) --end - self:_call_handler("onafter" .. EventName, params, EventName ) - self:_call_handler("OnAfter" .. EventName, params, EventName ) + self:_call_handler("onafter", EventName, Params, EventName ) + self:_call_handler("OnAfter", EventName, Params, EventName ) - self:_call_handler("onstatechange", params, EventName ) + self:_call_handler("onstate", "change", Params, EventName ) end else - self:T( "Cannot execute transition." ) - self:T( { From = self.current, Event = EventName, To = to, Can = Can } ) + self:T( "*** FSM *** NO Transition *** " .. self.current .. " --> " .. EventName .. " --> ? " ) end return nil @@ -691,17 +726,16 @@ do -- FSM function FSM:_isendstate( Current ) local FSMParent = self.fsmparent if FSMParent and self.endstates[Current] then - self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } ) + --self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } ) FSMParent.current = Current local ParentFrom = FSMParent.current - self:T( ParentFrom ) - self:T( self.ReturnEvents ) + --self:T( { ParentFrom, self.ReturnEvents } ) local Event = self.ReturnEvents[Current] - self:T( { ParentFrom, Event, self.ReturnEvents } ) + --self:T( { Event } ) if Event then return FSMParent, Event else - self:T( { "Could not find parent event name for state ", ParentFrom } ) + --self:T( { "Could not find parent event name for state ", ParentFrom } ) end end @@ -773,10 +807,10 @@ do -- FSM_CONTROLLABLE -- @param #table FSMT Finite State Machine Table -- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs. -- @return #FSM_CONTROLLABLE - function FSM_CONTROLLABLE:New( FSMT, Controllable ) + function FSM_CONTROLLABLE:New( Controllable ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Core.Fsm#FSM_CONTROLLABLE + local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE if Controllable then self:SetControllable( Controllable ) @@ -859,7 +893,9 @@ do -- FSM_CONTROLLABLE return self.Controllable end - function FSM_CONTROLLABLE:_call_handler( handler, params, EventName ) + function FSM_CONTROLLABLE:_call_handler( step, trigger, params, EventName ) + + local handler = step .. trigger local ErrorHandler = function( errmsg ) @@ -872,7 +908,7 @@ do -- FSM_CONTROLLABLE end if self[handler] then - self:F3( "Calling " .. handler ) + self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** TaskUnit: " .. self.Controllable:GetName() ) self._EventSchedules[EventName] = nil local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler ) return Value @@ -909,9 +945,9 @@ do -- FSM_PROCESS local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS --self:F( Controllable ) - + self:Assign( Controllable, Task ) - + return self end @@ -919,7 +955,9 @@ do -- FSM_PROCESS self:T( "No Initialisation" ) end - function FSM_PROCESS:_call_handler( handler, params, EventName ) + function FSM_PROCESS:_call_handler( step, trigger, params, EventName ) + + local handler = step .. trigger local ErrorHandler = function( errmsg ) @@ -932,7 +970,9 @@ do -- FSM_PROCESS end if self[handler] then - self:F3( "Calling " .. handler ) + if handler ~= "onstatechange" then + self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable:GetName() ) + end self._EventSchedules[EventName] = nil if self.Controllable and self.Controllable:IsAlive() == true then local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler ) @@ -952,7 +992,7 @@ do -- FSM_PROCESS local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS NewFsm:Assign( Controllable, Task ) - + -- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS NewFsm:Init( self ) @@ -1043,21 +1083,21 @@ do -- FSM_PROCESS -- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP. --- Send a message of the @{Task} to the Group of the Unit. --- @param #FSM_PROCESS self -function FSM_PROCESS:Message( Message ) - self:F( { Message = Message } ) - - local CC = self:GetCommandCenter() - local TaskGroup = self.Controllable:GetGroup() + -- @param #FSM_PROCESS self + function FSM_PROCESS:Message( Message ) + self:F( { Message = Message } ) - local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit - PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets. - local Callsign = self.Controllable:GetCallsign() - local Prefix = Callsign and " @ " .. Callsign .. PlayerName or "" - - Message = Prefix .. ": " .. Message - CC:MessageToGroup( Message, TaskGroup ) -end + local CC = self:GetCommandCenter() + local TaskGroup = self.Controllable:GetGroup() + + local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit + PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets. + local Callsign = self.Controllable:GetCallsign() + local Prefix = Callsign and " @ " .. Callsign .. PlayerName or "" + + Message = Prefix .. ": " .. Message + CC:MessageToGroup( Message, TaskGroup ) + end @@ -1078,14 +1118,16 @@ end return self end - function FSM_PROCESS:onenterAssigned( ProcessUnit ) - self:T( "Assign" ) +-- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To ) +-- +-- if From( "Planned" ) then +-- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To ) +-- self.Task:Assign() +-- end +-- end - self.Task:Assign() - end - - function FSM_PROCESS:onenterFailed( ProcessUnit ) - self:T( "Failed" ) + function FSM_PROCESS:onenterFailed( ProcessUnit, Task, From, Event, To ) + self:T( "*** FSM *** Failed *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To ) self.Task:Fail() end @@ -1097,14 +1139,17 @@ end -- @param #string Event -- @param #string From -- @param #string To - function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To, Dummy ) - self:T( { ProcessUnit:GetName(), From, Event, To, Dummy, self:IsTrace() } ) + function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To ) - if self:IsTrace() then - --MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() + if From ~= To then + self:T( "*** FSM *** Change *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To ) end - self:T( { Scores = self._Scores, To = To } ) +-- if self:IsTrace() then +-- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() +-- self:F2( { Scores = self._Scores, To = To } ) +-- end + -- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects... if self._Scores[To] then @@ -1139,22 +1184,23 @@ do -- FSM_TASK --- Creates a new FSM_TASK object. -- @param #FSM_TASK self - -- @param #table FSMT - -- @param Tasking.Task#TASK Task - -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #string TaskName The name of the task. -- @return #FSM_TASK - function FSM_TASK:New( FSMT ) + function FSM_TASK:New( TaskName ) - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( FSMT ) ) -- Core.Fsm#FSM_TASK + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_TASK self["onstatechange"] = self.OnStateChange + self.TaskName = TaskName return self end - function FSM_TASK:_call_handler( handler, params, EventName ) + function FSM_TASK:_call_handler( step, trigger, params, EventName ) + local handler = step .. trigger + if self[handler] then - self:T( "Calling " .. handler ) + self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.TaskName ) self._EventSchedules[EventName] = nil return self[handler]( self, unpack( params ) ) end @@ -1216,9 +1262,10 @@ do -- FSM_SET return self.Controllable end - function FSM_SET:_call_handler( handler, params, EventName ) + function FSM_SET:_call_handler( step, trigger, params, EventName ) + local handler = step .. trigger if self[handler] then - self:T( "Calling " .. handler ) + self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] ) self._EventSchedules[EventName] = nil return self[handler]( self, self.Set, unpack( params ) ) end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0bb49c265..de1a81cfc 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1289,7 +1289,7 @@ do -- COORDINATE -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings ) -- R2.2 - self:F( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } ) + self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS @@ -1318,7 +1318,7 @@ do -- COORDINATE -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringA2G( Controllable, Settings ) -- R2.2 - self:F( { Controllable = Controllable and Controllable:GetName() } ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS @@ -1353,7 +1353,7 @@ do -- COORDINATE -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringA2A( Controllable, Settings ) -- R2.2 - self:F( { Controllable = Controllable and Controllable:GetName() } ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS @@ -1393,7 +1393,7 @@ do -- COORDINATE -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToString( Controllable, Settings, Task ) -- R2.2 - self:F( { Controllable = Controllable and Controllable:GetName() } ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS @@ -1442,7 +1442,7 @@ do -- COORDINATE -- @return #string The pressure text in the configured measurement system. function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3 - self:F( { Controllable = Controllable and Controllable:GetName() } ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS @@ -1458,7 +1458,7 @@ do -- COORDINATE -- @return #string The wind text in the configured measurement system. function COORDINATE:ToStringWind( Controllable, Settings ) -- R2.3 - self:F( { Controllable = Controllable and Controllable:GetName() } ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS @@ -1474,7 +1474,7 @@ do -- COORDINATE -- @return #string The temperature text in the configured measurement system. function COORDINATE:ToStringTemperature( Controllable, Settings ) -- R2.3 - self:F( { Controllable = Controllable and Controllable:GetName() } ) + self:F2( { Controllable = Controllable and Controllable:GetName() } ) local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index eb950115a..a59d82909 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -149,7 +149,7 @@ end -- @param #SET_BASE self -- @param #string ObjectName function SET_BASE:Remove( ObjectName ) - self:F( { ObjectName = ObjectName, Object = Object } ) + self:F2( { ObjectName = ObjectName } ) local Object = self.Set[ObjectName] @@ -158,7 +158,6 @@ function SET_BASE:Remove( ObjectName ) if Key == ObjectName then table.remove( self.Index, Index ) self.Set[ObjectName] = nil - self:Flush(self) break end end @@ -174,7 +173,7 @@ end -- @param Core.Base#BASE Object -- @return Core.Base#BASE The added BASE Object. function SET_BASE:Add( ObjectName, Object ) - self:F( { ObjectName = ObjectName, Object = Object } ) + self:F2( { ObjectName = ObjectName, Object = Object } ) -- Ensure that the existing element is removed from the Set before a new one is inserted to the Set if self.Set[ObjectName] then diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 98f7cb024..02122a437 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -510,7 +510,6 @@ do -- DETECTION_BASE -- @param #string Event The Event string. -- @param #string To The To State string. function DETECTION_BASE:onafterDetect(From,Event,To) - self:F( { From, Event, To } ) local DetectDelay = 0.1 self.DetectionCount = 0 @@ -533,7 +532,6 @@ do -- DETECTION_BASE -- @param #string To The To State string. -- @param Wrapper.Group#GROUP DetectionGroup The Group detecting. function DETECTION_BASE:onafterDetectionGroup( From, Event, To, DetectionGroup, DetectionTimeStamp ) - self:F( { From, Event, To } ) self.DetectionRun = self.DetectionRun + 1 @@ -541,7 +539,7 @@ do -- DETECTION_BASE if DetectionGroup:IsAlive() then - self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } ) + --self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } ) local DetectionGroupName = DetectionGroup:GetName() local DetectionUnit = DetectionGroup:GetUnit(1) @@ -557,7 +555,7 @@ do -- DETECTION_BASE self.DetectDLINK ) - self:F( DetectedTargets ) + --self:F( DetectedTargets ) for DetectionObjectID, Detection in pairs( DetectedTargets ) do local DetectedObject = Detection.object -- Dcs.DCSWrapper.Object#Object @@ -574,7 +572,7 @@ do -- DETECTION_BASE self.DetectDLINK ) - self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } ) + --self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } ) -- Only process if the target is visible. Detection also returns invisible units. --if Detection.visible == true then @@ -596,7 +594,7 @@ do -- DETECTION_BASE local DetectedUnitCategory = DetectedObject:getDesc().category - self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } ) + --self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } ) -- Calculate Acceptance @@ -644,7 +642,7 @@ do -- DETECTION_BASE local DistanceProbability = 1 - DistanceProbabilityReversed DistanceProbability = DistanceProbability * 30 / 300 local Probability = math.random() -- Selects a number between 0 and 1 - self:T( { Probability, DistanceProbability } ) + --self:T( { Probability, DistanceProbability } ) if Probability > DistanceProbability then DetectionAccepted = false end @@ -660,7 +658,7 @@ do -- DETECTION_BASE AlphaAngleProbability = AlphaAngleProbability * 30 / 300 local Probability = math.random() -- Selects a number between 0 and 1 - self:T( { Probability, AlphaAngleProbability } ) + --self:T( { Probability, AlphaAngleProbability } ) if Probability > AlphaAngleProbability then DetectionAccepted = false end @@ -677,7 +675,7 @@ do -- DETECTION_BASE if ZoneObject:IsPointVec2InZone( DetectedObjectVec2 ) == true then local Probability = math.random() -- Selects a number between 0 and 1 - self:T( { Probability, ZoneProbability } ) + --self:T( { Probability, ZoneProbability } ) if Probability > ZoneProbability then DetectionAccepted = false break @@ -702,7 +700,7 @@ do -- DETECTION_BASE self.DetectedObjects[DetectedObjectName].Distance = Distance self.DetectedObjects[DetectedObjectName].DetectionTimeStamp = DetectionTimeStamp - self:F( { DetectedObject = self.DetectedObjects[DetectedObjectName] } ) + --self:F( { DetectedObject = self.DetectedObjects[DetectedObjectName] } ) local DetectedUnit = UNIT:FindByName( DetectedObjectName ) @@ -716,7 +714,7 @@ do -- DETECTION_BASE --end end - self:T2( self.DetectedObjects ) + --self:T2( self.DetectedObjects ) end if HasDetectedObjects then @@ -726,7 +724,6 @@ do -- DETECTION_BASE end if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then - self:T( "--> Create Detection Sets" ) -- First check if all DetectedObjects were detected. -- This is important. When there are DetectedObjects in the list, but were not detected, @@ -766,7 +763,6 @@ do -- DETECTION_BASE local DetectedSet = DetectedItem.Set if DetectedSet:Count() == 0 then - self:F3( { DetectedItemID = DetectedItemID } ) self:RemoveDetectedItem( DetectedItemID ) end @@ -778,8 +774,7 @@ do -- DETECTION_BASE -- @param #string UnitName The UnitName that needs to be forgotten from the DetectionItem Sets. -- @return #DETECTION_BASE function DETECTION_BASE:ForgetDetectedUnit( UnitName ) - self:F2() - + local DetectedItems = self:GetDetectedItems() for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do @@ -796,7 +791,6 @@ do -- DETECTION_BASE -- @param #DETECTION_BASE self -- @return #DETECTION_BASE function DETECTION_BASE:CreateDetectionItems() - self:F2() self:F( "Error, in DETECTION_BASE class..." ) return self @@ -1179,8 +1173,7 @@ do -- DETECTION_BASE -- @param Dcs.DCSUnit#Unit.Category Category The category of the unit. -- @return #boolean true if there are friendlies nearby function DETECTION_BASE:IsFriendliesNearBy( DetectedItem, Category ) - - self:F( { "FriendliesNearBy Test", DetectedItem.FriendliesNearBy } ) + --self:F( { "FriendliesNearBy Test", DetectedItem.FriendliesNearBy } ) return ( DetectedItem.FriendliesNearBy and DetectedItem.FriendliesNearBy[Category] ~= nil ) or false end @@ -1237,7 +1230,7 @@ do -- DETECTION_BASE --- Background worker function to determine if there are friendlies nearby ... -- @param #DETECTION_BASE self function DETECTION_BASE:ReportFriendliesNearBy( TargetData ) - self:F( { "Search Friendlies", DetectedItem = TargetData.DetectedItem } ) + --self:F( { "Search Friendlies", DetectedItem = TargetData.DetectedItem } ) local DetectedItem = TargetData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem local DetectedSet = TargetData.DetectedItem.Set @@ -1286,7 +1279,7 @@ do -- DETECTION_BASE if FoundUnitInReportSetGroup == true then -- If the recce was part of the friendlies found, then check if the recce is part of the allowed friendly unit prefixes. for PrefixID, Prefix in pairs( self.FriendlyPrefixes or {} ) do - self:F( { "Friendly Prefix:", Prefix = Prefix } ) + --self:F( { "Friendly Prefix:", Prefix = Prefix } ) -- In case a match is found (so a recce unit name is part of the friendly prefixes), then report that recce to be part of the friendlies. -- This is important if CAP planes (so planes using their own radar) to be scanning for targets as part of the EWR network. -- But CAP planes are also attackers, so they need to be considered friendlies too! @@ -1298,7 +1291,7 @@ do -- DETECTION_BASE end end - self:F( { "Friendlies near Target:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) + --self:F( { "Friendlies near Target:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then local FriendlyUnit = UNIT:Find( FoundDCSUnit ) @@ -1313,7 +1306,7 @@ do -- DETECTION_BASE local Distance = DetectedUnitCoord:Get2DDistance( FriendlyUnit:GetCoordinate() ) DetectedItem.FriendliesDistance = DetectedItem.FriendliesDistance or {} DetectedItem.FriendliesDistance[Distance] = FriendlyUnit - self:T( { "Friendlies Found:", FriendlyUnitName = FriendlyUnitName, Distance = Distance, FriendlyUnitCategory = FriendlyUnitCategory, FriendliesCategory = self.FriendliesCategory } ) + --self:F( { "Friendlies Found:", FriendlyUnitName = FriendlyUnitName, Distance = Distance, FriendlyUnitCategory = FriendlyUnitCategory, FriendliesCategory = self.FriendliesCategory } ) return true end @@ -1355,6 +1348,9 @@ do -- DETECTION_BASE end ) end + + self:F( { Friendlies = DetectedItem.FriendliesNearBy, Players = DetectedItem.PlayersNearBy } ) + end end @@ -1886,7 +1882,6 @@ do -- DETECTION_UNITS -- @param #DETECTION_UNITS self -- @return #DETECTION_UNITS self function DETECTION_UNITS:CreateDetectionItems() - self:F2( #self.DetectedObjects ) -- Loop the current detected items, and check if each object still exists and is detected. @@ -2137,7 +2132,6 @@ do -- DETECTION_TYPES -- @param #DETECTION_TYPES self -- @return #DETECTION_TYPES self function DETECTION_TYPES:CreateDetectionItems() - self:F2( #self.DetectedObjects ) -- Loop the current detected items, and check if each object still exists and is detected. @@ -2525,10 +2519,9 @@ do -- DETECTION_AREAS -- @param #DETECTION_AREAS self -- @return #DETECTION_AREAS self function DETECTION_AREAS:CreateDetectionItems() - self:F2() - self:T( "Checking Detected Items for new Detected Units ..." ) + self:T2( "Checking Detected Items for new Detected Units ..." ) -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. -- Regroup when needed, split groups when needed. for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do @@ -2537,8 +2530,7 @@ do -- DETECTION_AREAS if DetectedItem then - self:T( { "Detected Item ID:", DetectedItemID } ) - + self:T2( { "Detected Item ID: ", DetectedItemID } ) local DetectedSet = DetectedItem.Set @@ -2667,7 +2659,6 @@ do -- DETECTION_AREAS local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem if DetectedItem then - self:T( "Detection Area #" .. DetectedItem.ID ) local DetectedSet = DetectedItem.Set if not self:IsDetectedObjectIdentified( DetectedObject ) and DetectedUnit:IsInZone( DetectedItem.Zone ) then self:IdentifyDetectedObject( DetectedObject ) diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index e521f63df..3f581ec62 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -171,7 +171,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) end ) - -- Handle when a player leaves a slot and goes back to spectators ... + -- Handle when a player crashes ... -- The PlayerUnit will be UnAssigned from the Task. -- When there is no Unit left running the Task, the Task goes into Abort... self:HandleEvent( EVENTS.Crash, diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 441b463aa..0d872a85b 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -443,11 +443,11 @@ do -- Group Assignment local MissionGroupName = MissionGroup:GetName() if self.AssignedGroups[MissionGroupName] == MissionGroup then - self:T( { "Mission is assigned to:", MissionGroup:GetName() } ) + self:T2( { "Mission is assigned to:", MissionGroup:GetName() } ) return true end - self:T( { "Mission is not assigned to:", MissionGroup:GetName() } ) + self:T2( { "Mission is not assigned to:", MissionGroup:GetName() } ) return false end diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 564e6b4bd..562b9413d 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -161,7 +161,7 @@ TASK = { -- @return #TASK self function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) - local self = BASE:Inherit( self, FSM_TASK:New() ) -- Tasking.Task#TASK + local self = BASE:Inherit( self, FSM_TASK:New( TaskName ) ) -- Tasking.Task#TASK self:SetStartState( "Planned" ) self:AddTransition( "Planned", "Assign", "Assigned" ) @@ -622,9 +622,11 @@ function TASK:MessageToGroups( Message ) local Mission = self:GetMission() local CC = Mission:GetCommandCenter() - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do - local TaskGroup = TaskGroup -- Wrapper.Group#GROUP - CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() ) + for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do + TaskGroup = TaskGroup -- Wrapper.Group#GROUP + if TaskGroup:IsAlive() == true then + CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() ) + end end end @@ -634,10 +636,11 @@ end function TASK:SendBriefingToAssignedGroups() self:F2() - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do - - if self:IsGroupAssigned( TaskGroup ) then - TaskGroup:Message( self.TaskBriefing, 60 ) + for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if TaskGroup:IsAlive() then + if self:IsGroupAssigned( TaskGroup ) then + TaskGroup:Message( self.TaskBriefing, 60 ) + end end end end @@ -648,9 +651,11 @@ end function TASK:UnAssignFromGroups() self:F2() - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do - if self:IsGroupAssigned(TaskGroup) then - self:UnAssignFromGroup( TaskGroup ) + for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if TaskGroup:IsAlive() == true then + if self:IsGroupAssigned(TaskGroup) then + self:UnAssignFromGroup( TaskGroup ) + end end end end @@ -663,13 +668,15 @@ end function TASK:HasAliveUnits() self:F() - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do - if self:IsStateAssigned() then - if self:IsGroupAssigned( TaskGroup ) then - for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do - if TaskUnit:IsAlive() then - self:T( { HasAliveUnits = true } ) - return true + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if TaskGroup:IsAlive() == true then + if self:IsStateAssigned() then + if self:IsGroupAssigned( TaskGroup ) then + for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do + if TaskUnit:IsAlive() then + self:T( { HasAliveUnits = true } ) + return true + end end end end @@ -782,7 +789,7 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime ) local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString ) local TaskName = string.format( "%s", self:GetName() ) - for UnitName, TaskUnit in pairs( TaskGroup:GetUnits() ) do + for UnitName, TaskUnit in pairs( TaskGroup:GetPlayerUnits() ) do local TaskUnit = TaskUnit -- Wrapper.Unit#UNIT if TaskUnit then local MenuControl = self:GetTaskControlMenu( TaskUnit ) @@ -803,10 +810,12 @@ end function TASK:RemoveMenu( MenuTime ) self:F( { self:GetName(), MenuTime } ) - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do - local TaskGroup = TaskGroup -- Wrapper.Group#GROUP - if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then - self:RefreshMenus( TaskGroup, MenuTime ) + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if TaskGroup:IsAlive() == true then + local TaskGroup = TaskGroup -- Wrapper.Group#GROUP + if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then + self:RefreshMenus( TaskGroup, MenuTime ) + end end end end @@ -1467,12 +1476,14 @@ function TASK:GetPlayerNames() --R2.1 Get a map of the players. local PlayerNameMap = {} -- Loop each Unit active in the Task, and find Player Names. - for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetAliveSet() ) do + for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP - if self:IsGroupAssigned( PlayerGroup ) then - local PlayerNames = PlayerGroup:GetPlayerNames() - for PlayerNameID, PlayerName in pairs( PlayerNames ) do - PlayerNameMap[PlayerName] = PlayerGroup + if PlayerGroup:IsAlive() == true then + if self:IsGroupAssigned( PlayerGroup ) then + local PlayerNames = PlayerGroup:GetPlayerNames() + for PlayerNameID, PlayerName in pairs( PlayerNames ) do + PlayerNameMap[PlayerName] = PlayerGroup + end end end end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 12cabd80e..4d523aba9 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -261,17 +261,9 @@ do -- TASK_CARGO function Fsm:onafterSelectAction( TaskUnit, Task ) local TaskUnitName = TaskUnit:GetName() - - self:F( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } ) - local MenuTime = Task:InitTaskControlMenu( TaskUnit ) - local MenuControl = Task:GetTaskControlMenu( TaskUnit ) - local CargoItemCount = TaskUnit:CargoItemCount() - - --Task:GetMission():GetCommandCenter():MessageToGroup( "Cargo in carrier: " .. CargoItemCount, TaskUnit:GetGroup() ) - Task.SetCargo:ForEachCargo( diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 0d98f5092..4ccfe98d4 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -179,7 +179,7 @@ function CLIENT:ShowBriefing() if not self.ClientBriefingShown then self.ClientBriefingShown = true local Briefing = "" - if self.ClientBriefing then + if self.ClientBriefing and self.ClientBriefing ~= "" then Briefing = Briefing .. self.ClientBriefing self:Message( Briefing, 60, "Briefing" ) end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 2d6551fd2..0b68255c5 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2223,7 +2223,7 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad local DetectionRWR = ( DetectRWR and DetectRWR == true ) and Controller.Detection.RWR or nil local DetectionDLINK = ( DetectDLINK and DetectDLINK == true ) and Controller.Detection.DLINK or nil - self:T( { DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK } ) + self:T2( { DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK } ) return self:_GetController():getDetectedTargets( DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK ) end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 609b1aa91..2705eb51a 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -352,13 +352,39 @@ function GROUP:GetUnits() return nil end + + +--- Returns a list of @{Unit} objects of the @{Group} that are occupied by a player. +-- @param #GROUP self +-- @return #list The list of player occupied @{Unit} objects of the @{Group}. +function GROUP:GetPlayerUnits() + self:F2( { self.GroupName } ) + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local DCSUnits = DCSGroup:getUnits() + local Units = {} + for Index, UnitData in pairs( DCSUnits ) do + local PlayerUnit = UNIT:Find( UnitData ) + if PlayerUnit:GetPlayerName() then + Units[#Units+1] = PlayerUnit + end + end + self:T3( Units ) + return Units + end + + return nil +end + + --- Returns the UNIT wrapper class with number UnitNumber. -- If the underlying DCS Unit does not exist, the method will return nil. . -- @param #GROUP self -- @param #number UnitNumber The number of the UNIT wrapper class to be returned. -- @return Wrapper.Unit#UNIT The UNIT wrapper class. function GROUP:GetUnit( UnitNumber ) - self:E( { self.GroupName, UnitNumber } ) + self:F3( { self.GroupName, UnitNumber } ) local DCSGroup = self:GetDCSObject() @@ -378,7 +404,7 @@ end -- @param #number UnitNumber The number of the DCS Unit to be returned. -- @return Dcs.DCSWrapper.Unit#Unit The DCS Unit. function GROUP:GetDCSUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) + self:F3( { self.GroupName, UnitNumber } ) local DCSGroup = self:GetDCSObject() @@ -396,7 +422,7 @@ end -- @param #GROUP self -- @return #number The DCS Group size. function GROUP:GetSize() - self:F2( { self.GroupName } ) + self:F3( { self.GroupName } ) local DCSGroup = self:GetDCSObject() if DCSGroup then @@ -419,7 +445,7 @@ end -- @param #GROUP self -- @return #number The DCS Group initial size. function GROUP:GetInitialSize() - self:F2( { self.GroupName } ) + self:F3( { self.GroupName } ) local DCSGroup = self:GetDCSObject() if DCSGroup then @@ -1382,6 +1408,8 @@ do -- Players -- @return #nil The group has no players function GROUP:GetPlayerNames() + local HasPlayers = false + local PlayerNames = {} local Units = self:GetUnits() @@ -1391,11 +1419,16 @@ do -- Players if PlayerName and PlayerName ~= "" then PlayerNames = PlayerNames or {} table.insert( PlayerNames, PlayerName ) + HasPlayers = true end end + + if HasPlayers == true then + self:F2( PlayerNames ) + return PlayerNames + end - self:F2( PlayerNames ) - return PlayerNames + return nil end end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index fe4b8cca0..ebc041a7c 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -349,9 +349,21 @@ function UNIT:GetPlayerName() if DCSUnit then local PlayerName = DCSUnit:getPlayerName() + -- TODO - Workaround for DCS-BUG-3 if PlayerName == nil or PlayerName == "" then - PlayerName = "Player" .. DCSUnit:getID() + local PlayerCategory = DCSUnit:getDesc().category + if PlayerCategory == Unit.Category.GROUND_UNIT or PlayerCategory == Unit.Category.SHIP then + PlayerName = "Player" .. DCSUnit:getID() + end end +-- -- Good code +-- if PlayerName == nil then +-- PlayerName = nil +-- else +-- if PlayerName == "" then +-- PlayerName = "Player" .. DCSUnit:getID() +-- end +-- end return PlayerName end @@ -638,12 +650,9 @@ function UNIT:GetThreatLevel() if Descriptor then local Attributes = Descriptor.attributes - self:T( Attributes ) if self:IsGround() then - self:T( "Ground" ) - local ThreatLevels = { "Unarmed", "Infantry", @@ -680,8 +689,6 @@ function UNIT:GetThreatLevel() if self:IsAir() then - self:T( "Air" ) - local ThreatLevels = { "Unarmed", "Tanker", @@ -714,8 +721,6 @@ function UNIT:GetThreatLevel() if self:IsShip() then - self:T( "Ship" ) - --["Aircraft Carriers"] = {"Heavy armed ships",}, --["Cruisers"] = {"Heavy armed ships",}, --["Destroyers"] = {"Heavy armed ships",}, @@ -753,7 +758,6 @@ function UNIT:GetThreatLevel() end end - self:T2( ThreatLevel ) return ThreatLevel, ThreatText end From 3e6017c0d5d9650b709ecaef3bed58b0f4b232f5 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 12 Apr 2018 20:03:44 +0200 Subject: [PATCH 051/170] Task Assignment --- .../Moose/Actions/Act_Assign.lua | 61 +++++++++---------- Moose Development/Moose/Core/Fsm.lua | 14 +++++ .../Moose/Tasking/CommandCenter.lua | 49 ++++++++++++--- Moose Development/Moose/Tasking/Mission.lua | 30 ++++++--- Moose Development/Moose/Tasking/Task.lua | 55 +++++++++-------- .../Moose/Tasking/Task_CARGO.lua | 6 +- .../Moose/Wrapper/Positionable.lua | 10 +-- 7 files changed, 144 insertions(+), 81 deletions(-) diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 930810ee2..6b2652a59 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -155,8 +155,7 @@ do -- ACT_ASSIGN_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) - self:F( { ProcessUnit, From, Event, To } ) + function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To ) self:__Assign( 1 ) end @@ -167,11 +166,8 @@ do -- ACT_ASSIGN_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To ) - self:F( { ProcessUnit, From, Event, To } ) + function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To ) - local ProcessGroup = ProcessUnit:GetGroup() - self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() ) end @@ -192,36 +188,26 @@ do -- ACT_ASSIGN_MENU_ACCEPT --- Init. -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param #string TaskName -- @param #string TaskBriefing -- @return #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing ) + function ACT_ASSIGN_MENU_ACCEPT:New( TaskBriefing ) -- Inherits from BASE local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT - self.TaskName = TaskName self.TaskBriefing = TaskBriefing return self end - function ACT_ASSIGN_MENU_ACCEPT:Init( FsmAssign ) - - self.TaskName = FsmAssign.TaskName - self.TaskBriefing = FsmAssign.TaskBriefing - end - - + --- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param #string TaskName -- @param #string TaskBriefing -- @return #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing ) + function ACT_ASSIGN_MENU_ACCEPT:Init( TaskBriefing ) self.TaskBriefing = TaskBriefing - self.TaskName = TaskName return self end @@ -232,30 +218,31 @@ do -- ACT_ASSIGN_MENU_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) - self:F( { ProcessUnit, From, Event, To } ) + function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To ) - self:GetCommandCenter():MessageTypeToGroup( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", ProcessUnit:GetGroup(), MESSAGE.Type.Information ) + self:GetCommandCenter():MessageToGroup( "Task " .. self.Task:GetName() .. " has been assigned to you and your group!\nRead the briefing and use the Radio Menu (F10) to accept the task.\nYou have 2 minutes to accept, or the task assignment will be cancelled!", ProcessUnit:GetGroup(), 120 ) local ProcessGroup = ProcessUnit:GetGroup() + + self.Menu = MENU_GROUP:New( ProcessGroup, "Accept task " .. self.Task:GetName() ) + self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.Task:GetName(), self.Menu, self.MenuAssign, self ) + self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.Task:GetName(), self.Menu, self.MenuReject, self ) - self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" ) - self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self ) - self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self ) + self:__Reject( 120, ProcessUnit ) end --- Menu function. -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuAssign() + function ACT_ASSIGN_MENU_ACCEPT:MenuAssign( ProcessUnit, Task, From, Event, To ) - self:__Assign( 1 ) + self:__Assign( -1 ) end --- Menu function. -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuReject() + function ACT_ASSIGN_MENU_ACCEPT:MenuReject( ProcessUnit, Task, From, Event, To ) - self:__Reject( 1 ) + self:__Reject( -1 ) end --- StateMachine callback function @@ -264,8 +251,7 @@ do -- ACT_ASSIGN_MENU_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To ) - self:F( { ProcessUnit.UnitNameFrom, Event, To } ) + function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, Task, From, Event, To ) self.Menu:Remove() end @@ -282,7 +268,18 @@ do -- ACT_ASSIGN_MENU_ACCEPT self.Menu:Remove() --TODO: need to resolve this problem ... it has to do with the events ... --self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event - ProcessUnit:Destroy() + self.Task:Abort() + end + + --- StateMachine callback function + -- @param #ACT_ASSIGN_ACCEPT self + -- @param Wrapper.Unit#UNIT ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIGN_MENU_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To ) + + self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() ) end end -- ACT_ASSIGN_MENU_ACCEPT diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 12b25179a..4e959004f 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -441,6 +441,8 @@ do -- FSM -- @return #table function FSM:GetProcesses() + self:F( { Processes = self._Processes } ) + return self._Processes or {} end @@ -455,6 +457,18 @@ do -- FSM error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" ) end + function FSM:SetProcess( From, Event, Fsm ) + + for ProcessID, Process in pairs( self:GetProcesses() ) do + if Process.From == From and Process.Event == Event then + Process.fsm = Fsm + return true + end + end + + error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" ) + end + --- Adds an End state. function FSM:AddEndState( State ) diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 3f581ec62..217721d53 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -86,7 +86,7 @@ COMMANDCENTER = { -- @return #COMMANDCENTER function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, BASE:New() ) -- #COMMANDCENTER self.CommandCenterPositionable = CommandCenterPositionable self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName() @@ -241,7 +241,7 @@ end -- @return #list function COMMANDCENTER:GetMissions() - return self.Missions + return self.Missions or {} end --- Add a MISSION to be governed by the HQ command center. @@ -330,7 +330,7 @@ end --- Sets the menu structure of the Missions governed by the HQ command center. -- @param #COMMANDCENTER self function COMMANDCENTER:SetMenu() - self:F() + self:F2() local MenuTime = timer.getTime() for MissionID, Mission in pairs( self:GetMissions() or {} ) do @@ -339,7 +339,7 @@ function COMMANDCENTER:SetMenu() end for MissionID, Mission in pairs( self:GetMissions() or {} ) do - local Mission = Mission -- Tasking.Mission#MISSION + Mission = Mission -- Tasking.Mission#MISSION Mission:RemoveMenu( MenuTime ) end @@ -348,10 +348,43 @@ end --- Gets the commandcenter menu structure governed by the HQ command center. -- @param #COMMANDCENTER self -- @return Core.Menu#MENU_COALITION -function COMMANDCENTER:GetMenu() - return self.CommandCenterMenu +function COMMANDCENTER:GetMenu( TaskGroup ) + + self.CommandCenterMenus = self.CommandCenterMenus or {} + if not self.CommandCenterMenus[TaskGroup] then + local CommandCenterText = self:GetText() + local CommandCenterMenu = MENU_GROUP:New( TaskGroup, CommandCenterText ) + self.CommandCenterMenus[TaskGroup] = CommandCenterMenu + local AssignTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Assign Task", CommandCenterMenu, self.AssignRandomTask, self, TaskGroup ) + end + return self.CommandCenterMenus[TaskGroup] end + +--- Assigns a random task to a TaskGroup. +-- @param #COMMANDCENTER self +-- @return #COMMANDCENTER +function COMMANDCENTER:AssignRandomTask( TaskGroup ) + + local Tasks = {} + + for MissionID, Mission in pairs( self:GetMissions() ) do + local Mission = Mission -- Tasking.Mission#MISSION + local MissionTasks = Mission:GetGroupTasks( TaskGroup ) + for MissionTaskName, MissionTask in pairs( MissionTasks or {} ) do + Tasks[#Tasks+1] = MissionTask + end + end + + local Task = Tasks[ math.random( 1, #Tasks ) ] -- Tasking.Task#TASK + + Task:SetAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) ) + + Task:AssignToGroup( TaskGroup ) + +end + + --- Checks of the COMMANDCENTER has a GROUP. -- @param #COMMANDCENTER self -- @param Wrapper.Group#GROUP @@ -407,7 +440,7 @@ function COMMANDCENTER:MessageToCoalition( Message ) local CCCoalition = self:GetPositionable():GetCoalition() --TODO: Fix coalition bug! - self:GetPositionable():MessageToCoalition( Message, 15, CCCoalition ) + self:GetPositionable():MessageToCoalition( Message, 15, CCCoalition, self:GetShortText() ) end @@ -421,7 +454,7 @@ function COMMANDCENTER:MessageTypeToCoalition( Message, MessageType ) local CCCoalition = self:GetPositionable():GetCoalition() --TODO: Fix coalition bug! - self:GetPositionable():MessageTypeToCoalition( Message, MessageType, CCCoalition ) + self:GetPositionable():MessageTypeToCoalition( Message, MessageType, CCCoalition, self:GetShortText() ) end diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 0d872a85b..ca2723b5e 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -524,18 +524,13 @@ end function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure local CommandCenter = self:GetCommandCenter() - local CommandCenterMenu = CommandCenter:GetMenu() + local CommandCenterMenu = CommandCenter:GetMenu( TaskGroup ) - --local MissionMenu = CommandCenterMenu:GetMenu( MissionName ) - self.MissionGroupMenu = self.MissionGroupMenu or {} self.MissionGroupMenu[TaskGroup] = self.MissionGroupMenu[TaskGroup] or {} local GroupMenu = self.MissionGroupMenu[TaskGroup] - local CommandCenterText = CommandCenter:GetText() - CommandCenterMenu = MENU_GROUP:New( TaskGroup, CommandCenterText ) - local MissionText = self:GetText() self.MissionMenu = MENU_GROUP:New( TaskGroup, MissionText, CommandCenterMenu ) @@ -564,7 +559,7 @@ end -- @param #string TaskName The Name of the @{Task} within the @{Mission}. -- @return Tasking.Task#TASK The Task -- @return #nil Returns nil if no task was found. -function MISSION:GetTask( TaskName ) +function MISSION:GetTask( TaskName ) self:F( { TaskName } ) return self.Tasks[TaskName] @@ -1005,9 +1000,28 @@ end -- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) function MISSION:GetTasks() - return self.Tasks + return self.Tasks or {} end +--- Get the relevant tasks of a TaskGroup. +-- @param #MISSION +-- @param Wrapper.Group#GROUP TaskGroup +-- @return #list +function MISSION:GetGroupTasks( TaskGroup ) + + local Tasks = {} + + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + if Task:HasGroup( TaskGroup ) then + Tasks[#Tasks+1] = Task + end + end + + return Tasks +end + + --- Reports the briefing. -- @param #MISSION self -- @param Wrapper.Group#GROUP ReportGroup The group to which the report needs to be sent. diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 562b9413d..946ad9bca 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -169,10 +169,16 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) self:AddTransition( "Assigned", "Success", "Success" ) self:AddTransition( "Assigned", "Hold", "Hold" ) self:AddTransition( "Assigned", "Fail", "Failed" ) - self:AddTransition( "Assigned", "Abort", "Aborted" ) + self:AddTransition( { "Planned", "Assigned" }, "Abort", "Aborted" ) self:AddTransition( "Assigned", "Cancel", "Cancelled" ) self:AddTransition( "Assigned", "Goal", "*" ) + self.Fsm = {} + + local Fsm = self:GetUnitProcess() + Fsm:SetStartState( "Planned" ) + Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) + --- Goal Handler OnBefore for TASK -- @function [parent=#TASK] OnBeforeGoal -- @param #TASK self @@ -216,7 +222,6 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) self:F( "New TASK " .. TaskName ) self.Processes = {} - self.Fsm = {} self.Mission = Mission self.CommandCenter = Mission:GetCommandCenter() @@ -229,7 +234,6 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) self:SetBriefing( TaskBriefing ) - self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New() self.TaskInfo = TASKINFO:New( self ) @@ -246,7 +250,8 @@ function TASK:GetUnitProcess( TaskUnit ) if TaskUnit then return self:GetStateMachine( TaskUnit ) else - return self.FsmTemplate + self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New() + return self.FsmTemplate end end @@ -500,6 +505,16 @@ end do -- Group Assignment + --- @param #TASK self + -- @param Actions.Act_Assign#ACT_ASSIGN AcceptClass + function TASK:SetAssignMethod( AcceptClass ) + + local ProcessTemplate = self:GetUnitProcess() + + ProcessTemplate:SetProcess( "Planned", "Accept", AcceptClass ) -- Actions.Act_Assign#ACT_ASSIGN + end + + --- Assign the @{Task} to a @{Group}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup @@ -739,21 +754,14 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime ) local Mission = self:GetMission() local MissionName = Mission:GetName() - local CommandCenter = Mission:GetCommandCenter() - local CommandCenterMenu = CommandCenter:GetMenu() + local MissionMenu = Mission:GetMenu( TaskGroup ) local TaskType = self:GetType() local TaskPlayerCount = self:GetPlayerCount() local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount ) --- local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString ) local TaskText = string.format( "%s", self:GetName() ) local TaskName = string.format( "%s", self:GetName() ) - local MissionMenu = Mission:GetMenu( TaskGroup ) - --local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime ) - - --local MissionMenu = Mission:GetMenu( TaskGroup ) - self.MenuPlanned = self.MenuPlanned or {} self.MenuPlanned[TaskGroup] = MENU_GROUP_DELAYED:New( TaskGroup, "Join Planned Task", MissionMenu, Mission.MenuReportTasksPerStatus, Mission, TaskGroup, "Planned" ):SetTime( MenuTime ):SetTag( "Tasking" ) local TaskTypeMenu = MENU_GROUP_DELAYED:New( TaskGroup, TaskType, self.MenuPlanned[TaskGroup] ):SetTime( MenuTime ):SetTag( "Tasking" ) @@ -778,11 +786,6 @@ end function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime ) self:F( { TaskGroup:GetName(), MenuTime } ) - local Mission = self:GetMission() - local MissionName = Mission:GetName() - local CommandCenter = Mission:GetCommandCenter() - local CommandCenterMenu = CommandCenter:GetMenu() - local TaskType = self:GetType() local TaskPlayerCount = self:GetPlayerCount() local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount ) @@ -831,9 +834,6 @@ function TASK:RefreshMenus( TaskGroup, MenuTime ) local Mission = self:GetMission() local MissionName = Mission:GetName() - local CommandCenter = Mission:GetCommandCenter() - local CommandCenterMenu = CommandCenter:GetMenu() - local MissionMenu = Mission:GetMenu( TaskGroup ) local TaskName = self:GetName() @@ -865,7 +865,6 @@ function TASK:RemoveAssignedMenuForGroup( TaskGroup ) local Mission = self:GetMission() local MissionName = Mission:GetName() - local MissionMenu = Mission:GetMenu( TaskGroup ) if MissionMenu then @@ -1223,12 +1222,16 @@ function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName ) --- This test is required, because the state transition will be fired also when the state does not change in case of an event. if From ~= "Assigned" then - self:F( { From, Event, To, PlayerUnit:GetName(), PlayerName } ) - self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is assigned." ) - + local PlayerNames = self:GetPlayerNames() + local PlayerText = REPORT:New() + for PlayerName, TaskName in pairs( PlayerNames ) do + PlayerText:Add( PlayerName ) + end + + self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is assigned to players " .. PlayerText:Text(",") .. ". Good Luck!" ) + -- Set the total Progress to be achieved. - self:SetGoalTotal() -- Polymorphic to set the initial goal total! if self.Dispatcher then @@ -1244,7 +1247,7 @@ function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName ) self:SetMenu() self:F( { "--> Task Assigned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } ) - self:F( { "--> Task Player Names", PlayerNames = self:GetPlayerNames() } ) + self:F( { "--> Task Player Names", PlayerNames = PlayerNames } ) end end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 4d523aba9..0d2a5d869 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -215,9 +215,9 @@ do -- TASK_CARGO local Fsm = self:GetUnitProcess() - Fsm:SetStartState( "Planned" ) - - Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) +-- Fsm:SetStartState( "Planned" ) +-- +-- Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) Fsm:AddTransition( { "Planned", "Assigned", "Cancelled", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Loaded", "UnLoaded", "Landed", "Boarding" }, "SelectAction", "*" ) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index b28bb5933..2a6605bb9 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -538,10 +538,11 @@ end -- @param #string Message The message text -- @param Dcs.DCSTYpes#Duration Duration The duration of the message. -- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message. -function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition ) +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, Name ) self:F2( { Message, Duration } ) - local Name = "" + local Name = Name or "" local DCSObject = self:GetDCSObject() if DCSObject then @@ -558,10 +559,11 @@ end -- @param #string Message The message text -- @param Core.Message#MESSAGE.Type MessageType The message type that determines the duration. -- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message. -function POSITIONABLE:MessageTypeToCoalition( Message, MessageType, MessageCoalition ) +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageTypeToCoalition( Message, MessageType, MessageCoalition, Name ) self:F2( { Message, MessageType } ) - local Name = "" + local Name = Name or "" local DCSObject = self:GetDCSObject() if DCSObject then From 25ae0c3d1570396653b3563d029b3ced7b95e281 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 13 Apr 2018 09:56:00 +0200 Subject: [PATCH 052/170] Finish this feature. --- .../Moose/Actions/Act_Assign.lua | 31 +++--- Moose Development/Moose/Core/Menu.lua | 8 +- .../Moose/Tasking/CommandCenter.lua | 102 +++++++++++++++++- Moose Development/Moose/Tasking/Mission.lua | 24 +++-- Moose Development/Moose/Tasking/Task.lua | 93 ++++++++++++---- Moose Development/Moose/Wrapper/Group.lua | 20 ++++ Moose Development/Moose/Wrapper/Unit.lua | 2 +- 7 files changed, 228 insertions(+), 52 deletions(-) diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 6b2652a59..0bb843ab1 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -220,29 +220,29 @@ do -- ACT_ASSIGN_MENU_ACCEPT -- @param #string To function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To ) - self:GetCommandCenter():MessageToGroup( "Task " .. self.Task:GetName() .. " has been assigned to you and your group!\nRead the briefing and use the Radio Menu (F10) to accept the task.\nYou have 2 minutes to accept, or the task assignment will be cancelled!", ProcessUnit:GetGroup(), 120 ) + self:GetCommandCenter():MessageToGroup( "Task " .. self.Task:GetName() .. " has been assigned to you and your group!\nRead the briefing and use the Radio Menu (F10) / Task ... CONFIRMATION menu to accept or reject the task.\nYou have 2 minutes to accept, or the task assignment will be cancelled!", ProcessUnit:GetGroup(), 120 ) - local ProcessGroup = ProcessUnit:GetGroup() + local TaskGroup = ProcessUnit:GetGroup() - self.Menu = MENU_GROUP:New( ProcessGroup, "Accept task " .. self.Task:GetName() ) - self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.Task:GetName(), self.Menu, self.MenuAssign, self ) - self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.Task:GetName(), self.Menu, self.MenuReject, self ) + self.Menu = MENU_GROUP:New( TaskGroup, "Task " .. self.Task:GetName() .. " CONFIRMATION" ) + self.MenuAcceptTask = MENU_GROUP_COMMAND:New( TaskGroup, "Accept task " .. self.Task:GetName(), self.Menu, self.MenuAssign, self, TaskGroup ) + self.MenuRejectTask = MENU_GROUP_COMMAND:New( TaskGroup, "Reject task " .. self.Task:GetName(), self.Menu, self.MenuReject, self, TaskGroup ) - self:__Reject( 120, ProcessUnit ) + self:__Reject( 120, TaskGroup ) end --- Menu function. -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuAssign( ProcessUnit, Task, From, Event, To ) + function ACT_ASSIGN_MENU_ACCEPT:MenuAssign( TaskGroup ) - self:__Assign( -1 ) + self:__Assign( -1, TaskGroup ) end --- Menu function. -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuReject( ProcessUnit, Task, From, Event, To ) + function ACT_ASSIGN_MENU_ACCEPT:MenuReject( TaskGroup ) - self:__Reject( -1 ) + self:__Reject( -1, TaskGroup ) end --- StateMachine callback function @@ -251,7 +251,7 @@ do -- ACT_ASSIGN_MENU_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, Task, From, Event, To ) + function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, Task, From, Event, To, TaskGroup ) self.Menu:Remove() end @@ -262,13 +262,13 @@ do -- ACT_ASSIGN_MENU_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To ) - self:F( { ProcessUnit.UnitName, From, Event, To } ) + function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, Task, From, Event, To, TaskGroup ) + self:F( { TaskGroup = TaskGroup } ) self.Menu:Remove() --TODO: need to resolve this problem ... it has to do with the events ... --self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event - self.Task:Abort() + self.Task:RejectGroup( TaskGroup ) end --- StateMachine callback function @@ -277,8 +277,9 @@ do -- ACT_ASSIGN_MENU_ACCEPT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To ) + function ACT_ASSIGN_MENU_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To, TaskGroup ) + --self.Task:AssignToGroup( TaskGroup ) self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() ) end diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index a435f16cb..65c0025cd 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -917,8 +917,8 @@ do self:RemoveSubMenus( MenuTime, MenuTag ) if not MenuTime or self.MenuTime ~= MenuTime then if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then - self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then + self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) end MENU_INDEX:ClearGroupMenu( self.Group, Path ) @@ -1009,8 +1009,8 @@ do if GroupMenu == self then if not MenuTime or self.MenuTime ~= MenuTime then if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then - self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then + self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) end MENU_INDEX:ClearGroupMenu( self.Group, Path ) @@ -1150,8 +1150,8 @@ do self:RemoveSubMenus( MenuTime, MenuTag ) if not MenuTime or self.MenuTime ~= MenuTime then if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then - self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then + self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) end MENU_INDEX:ClearGroupMenu( self.Group, Path ) @@ -1261,8 +1261,8 @@ do if GroupMenu == self then if not MenuTime or self.MenuTime ~= MenuTime then if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then - self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then + self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) end MENU_INDEX:ClearGroupMenu( self.Group, Path ) diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 217721d53..1e4452bec 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -91,6 +91,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) self.CommandCenterPositionable = CommandCenterPositionable self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName() self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition() + + self.AutoAssignTasks = false self.Missions = {} @@ -350,13 +352,23 @@ end -- @return Core.Menu#MENU_COALITION function COMMANDCENTER:GetMenu( TaskGroup ) + local MenuTime = timer.getTime() + self.CommandCenterMenus = self.CommandCenterMenus or {} - if not self.CommandCenterMenus[TaskGroup] then - local CommandCenterText = self:GetText() - local CommandCenterMenu = MENU_GROUP:New( TaskGroup, CommandCenterText ) - self.CommandCenterMenus[TaskGroup] = CommandCenterMenu - local AssignTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Assign Task", CommandCenterMenu, self.AssignRandomTask, self, TaskGroup ) + local CommandCenterMenu + + local CommandCenterText = self:GetText() + CommandCenterMenu = MENU_GROUP:New( TaskGroup, CommandCenterText ):SetTime(MenuTime) + self.CommandCenterMenus[TaskGroup] = CommandCenterMenu + + if self.AutoAssignTasks == false then + local AutoAssignTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Assign Task On", CommandCenterMenu, self.SetAutoAssignTasks, self, true ):SetTime(MenuTime):SetTag("AutoTask") + local AssignTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Assign Task", CommandCenterMenu, self.AssignRandomTask, self, TaskGroup ):SetTime(MenuTime):SetTag("AutoTask") + else + local AutoAssignTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Assign Task Off", CommandCenterMenu, self.SetAutoAssignTasks, self, false ):SetTime(MenuTime):SetTag("AutoTask") end + CommandCenterMenu:Remove( MenuTime, "AutoTask" ) + return self.CommandCenterMenus[TaskGroup] end @@ -385,6 +397,86 @@ function COMMANDCENTER:AssignRandomTask( TaskGroup ) end +--- Automatically assigns tasks to all TaskGroups. +-- @param #COMMANDCENTER self +-- @param #boolean AutoAssign true for ON and false or nil for OFF. +-- @return #COMMANDCENTER +function COMMANDCENTER:SetAutoAssignTasks( AutoAssign ) + + self.AutoAssignTasks = AutoAssign or false + + local GroupSet = self:AddGroups() + + for GroupID, TaskGroup in pairs( GroupSet:GetSet() ) do + local TaskGroup = TaskGroup -- Wrapper.Group#GROUP + self:GetMenu( TaskGroup ) + end + + if self.AutoAssignTasks == true then + self:ScheduleRepeat( 10, 30, 0, nil, self.AssignTasks, self ) + else + self:ScheduleStop( self.AssignTasks ) + end + +end + + +--- Automatically assigns tasks to all TaskGroups. +-- @param #COMMANDCENTER self +function COMMANDCENTER:AssignTasks() + + local GroupSet = self:AddGroups() + + for GroupID, TaskGroup in pairs( GroupSet:GetSet() ) do + local TaskGroup = TaskGroup -- Wrapper.Group#GROUP + + if self:IsGroupAssigned( TaskGroup ) then + else + -- Only groups with planes or helicopters will receive automatic tasks. + -- TODO Workaround DCS-BUG-3 - https://github.com/FlightControl-Master/MOOSE/issues/696 + if TaskGroup:IsAir() then + self:AssignRandomTask( TaskGroup ) + end + end + end +end + + +--- Get all the Groups active within the command center. +-- @param #COMMANDCENTER self +-- @return Core.Set#SET_GROUP +function COMMANDCENTER:AddGroups() + + local GroupSet = SET_GROUP:New() + + for MissionID, Mission in pairs( self.Missions ) do + local Mission = Mission -- Tasking.Mission#MISSION + GroupSet = Mission:AddGroups( GroupSet ) + end + + return GroupSet +end + + +--- Checks of the TaskGroup has a Task. +-- @param #COMMANDCENTER self +-- @return #boolean +function COMMANDCENTER:IsGroupAssigned( TaskGroup ) + + local Assigned = false + + for MissionID, Mission in pairs( self.Missions ) do + local Mission = Mission -- Tasking.Mission#MISSION + if Mission:IsGroupAssigned( TaskGroup ) then + Assigned = true + break + end + end + + return Assigned +end + + --- Checks of the COMMANDCENTER has a GROUP. -- @param #COMMANDCENTER self -- @param Wrapper.Group#GROUP diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index ca2723b5e..86ba1d410 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -377,24 +377,30 @@ function MISSION:GetScoring() return self.Scoring end ---- Get the groups for which TASKS are given in the mission +--- Gets the groups for which TASKS are given in the mission -- @param #MISSION self +-- @param Core.Set#SET_GROUP GroupSet -- @return Core.Set#SET_GROUP function MISSION:GetGroups() - local SetGroup = SET_GROUP:New() + return self:AddGroups() + +end + +--- Adds the groups for which TASKS are given in the mission +-- @param #MISSION self +-- @param Core.Set#SET_GROUP GroupSet +-- @return Core.Set#SET_GROUP +function MISSION:AddGroups( GroupSet ) + + GroupSet = GroupSet or SET_GROUP:New() for TaskID, Task in pairs( self:GetTasks() ) do local Task = Task -- Tasking.Task#TASK - local GroupSet = Task:GetGroups() - GroupSet:ForEachGroup( - function( TaskGroup ) - SetGroup:Add( TaskGroup, TaskGroup ) - end - ) + GroupSet = Task:AddGroups( GroupSet ) end - return SetGroup + return GroupSet end diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 946ad9bca..4203dc08a 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -215,6 +215,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) self:AddTransition( "*", "PlayerCrashed", "*" ) self:AddTransition( "*", "PlayerAborted", "*" ) + self:AddTransition( "*", "PlayerRejected", "*" ) self:AddTransition( "*", "PlayerDead", "*" ) self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" ) self:AddTransition( "*", "TimeOut", "Cancelled" ) @@ -300,34 +301,61 @@ function TASK:JoinUnit( PlayerUnit, PlayerGroup ) return PlayerUnitAdded end ---- Abort a PlayerUnit from a Task. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. +--- A group rejecting a planned task. -- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. +-- @param Wrapper.Group#GROUP PlayerGroup The group rejecting the task. -- @return #TASK -function TASK:AbortGroup( PlayerGroup ) - self:F( { PlayerGroup = PlayerGroup } ) +function TASK:RejectGroup( PlayerGroup ) local PlayerGroups = self:GetGroups() -- Is the PlayerGroup part of the PlayerGroups? if PlayerGroups:IsIncludeObject( PlayerGroup ) then - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. + -- Check if the PlayerGroup is already assigned or is planned to be assigned to the Task. + -- If yes, the PlayerGroup is aborted from the Task. -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. - if self:IsStateAssigned() then + if self:IsStatePlanned() then + + local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup ) + if IsGroupAssigned then + local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName() + self:GetMission():GetCommandCenter():MessageToGroup( "Task " .. self:GetName() .. " has been rejected! We will select another task.", PlayerGroup ) + self:UnAssignFromGroup( PlayerGroup ) + + self:PlayerRejected( PlayerGroup:GetUnit(1) ) + end + + end + end + + return self +end + + +--- A group aborting the task. +-- @param #TASK self +-- @param Wrapper.Group#GROUP PlayerGroup The group aborting the task. +-- @return #TASK +function TASK:AbortGroup( PlayerGroup ) + + local PlayerGroups = self:GetGroups() + + -- Is the PlayerGroup part of the PlayerGroups? + if PlayerGroups:IsIncludeObject( PlayerGroup ) then + + -- Check if the PlayerGroup is already assigned or is planned to be assigned to the Task. + -- If yes, the PlayerGroup is aborted from the Task. + -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. + if self:IsStateAssigned() then + local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup ) - self:F( { IsGroupAssigned = IsGroupAssigned } ) if IsGroupAssigned then local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName() - --self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() ) self:UnAssignFromGroup( PlayerGroup ) - --self:Abort() -- Now check if the task needs to go to hold... -- It will go to hold, if there are no players in the mission... - PlayerGroups:Flush( self ) local IsRemaining = false for GroupName, AssignedGroup in pairs( PlayerGroups:GetSet() or {} ) do @@ -352,11 +380,10 @@ function TASK:AbortGroup( PlayerGroup ) return self end ---- A PlayerUnit crashed in a Task. Abort the Player. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. + +--- A group crashing and thus aborting from the task. -- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. +-- @param Wrapper.Group#GROUP PlayerGroup The group aborting the task. -- @return #TASK function TASK:CrashGroup( PlayerGroup ) self:F( { PlayerGroup = PlayerGroup } ) @@ -418,9 +445,29 @@ end -- @param #TASK self -- @return Core.Set#SET_GROUP function TASK:GetGroups() + return self.SetGroup end + +--- Gets the SET_GROUP assigned to the TASK. +-- @param #TASK self +-- @param Core.Set#SET_GROUP GroupSet +-- @return Core.Set#SET_GROUP +function TASK:AddGroups( GroupSet ) + + GroupSet = GroupSet or SET_GROUP:New() + + self.SetGroup:ForEachGroup( + --- @param Wrapper.Group#GROUP GroupSet + function( GroupItem ) + GroupSet:Add( GroupItem:GetName(), GroupItem) + end + ) + + return GroupSet +end + do -- Group Assignment --- Returns if the @{Task} is assigned to the Group. @@ -797,7 +844,9 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime ) if TaskUnit then local MenuControl = self:GetTaskControlMenu( TaskUnit ) local TaskControl = MENU_GROUP:New( TaskGroup, "Control Task", MenuControl ):SetTime( MenuTime ):SetTag( "Tasking" ) - local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Task" ), TaskControl, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) + if self:IsStateAssigned() then + local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Task" ), TaskControl, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) + end local MarkMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskControl, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Details" ), TaskControl, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) end @@ -1289,6 +1338,7 @@ function TASK:onenterAborted( From, Event, To ) end + --- FSM function for a TASK -- @param #TASK self -- @param #string From @@ -1641,7 +1691,14 @@ do -- Task Control Menu TaskName = TaskName or "" - self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Assigned Task " .. TaskUnit:GetPlayerName() .. " - " .. self:GetName() .. " " .. TaskName ):SetTime( self.TaskControlMenuTime ) + local TaskGroup = TaskUnit:GetGroup() + local TaskPlayerCount = TaskGroup:GetPlayerCount() + + if TaskPlayerCount <= 1 then + self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Task " .. self:GetName() .. " control" ):SetTime( self.TaskControlMenuTime ) + else + self.TaskControlMenu = MENU_GROUP:New( TaskUnit:GetGroup(), "Task " .. self:GetName() .. " control for " .. TaskUnit:GetPlayerName() ):SetTime( self.TaskControlMenuTime ) + end return self.TaskControlMenu end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 2705eb51a..be59a7723 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -1430,6 +1430,26 @@ do -- Players return nil end + + + --- Get the active player count in the group. + -- @param #GROUP self + -- @return #number The amount of players. + function GROUP:GetPlayerCount() + + local PlayerCount = 0 + + local Units = self:GetUnits() + for UnitID, UnitData in pairs( Units or {} ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + local PlayerName = Unit:GetPlayerName() + if PlayerName and PlayerName ~= "" then + PlayerCount = PlayerCount + 1 + end + end + + return PlayerCount + end end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index ebc041a7c..2734279bd 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -349,7 +349,7 @@ function UNIT:GetPlayerName() if DCSUnit then local PlayerName = DCSUnit:getPlayerName() - -- TODO - Workaround for DCS-BUG-3 + -- TODO Workaround DCS-BUG-3 - https://github.com/FlightControl-Master/MOOSE/issues/696 if PlayerName == nil or PlayerName == "" then local PlayerCategory = DCSUnit:getDesc().category if PlayerCategory == Unit.Category.GROUND_UNIT or PlayerCategory == Unit.Category.SHIP then From 47dd73a37751d1fec11338da87ba467777ccb5db Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 13 Apr 2018 12:22:39 +0200 Subject: [PATCH 053/170] Fixes --- Moose Development/Moose/Functional/Scoring.lua | 2 +- Moose Development/Moose/Tasking/Task.lua | 3 ++- Moose Development/Moose/Tasking/Task_A2A.lua | 11 +++++++++-- Moose Development/Moose/Tasking/Task_A2G.lua | 15 ++++++++++++--- Moose Development/Moose/Tasking/Task_CARGO.lua | 11 +++++++++++ .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 3 ++- .../Moose/Tasking/Task_Cargo_Transport.lua | 2 +- 7 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index cab7839ae..2ca3fd71a 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -858,7 +858,7 @@ function SCORING:OnEventBirth( Event ) if Event.IniUnit then if Event.IniObjectCategory == 1 then local PlayerName = Event.IniUnit:GetPlayerName() - if PlayerName ~= "" then + if PlayerName then self:_AddPlayerFromUnit( Event.IniUnit ) self:SetScoringMenu( Event.IniGroup ) end diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 4203dc08a..d854431a5 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -177,7 +177,8 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) local Fsm = self:GetUnitProcess() Fsm:SetStartState( "Planned" ) - Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) + Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "Assigned", Rejected = "Reject" } ) + Fsm:AddTransition( "Assigned", "Assigned", "*" ) --- Goal Handler OnBefore for TASK -- @function [parent=#TASK] OnBeforeGoal diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index 4db992c40..0ebc3551a 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -62,8 +62,6 @@ do -- TASK_A2A local Fsm = self:GetUnitProcess() - Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "RouteToRendezVous", Rejected = "Reject" } ) - Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" ) Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } ) Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } ) @@ -84,6 +82,15 @@ do -- TASK_A2A Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) Fsm:AddTransition( "Failed", "Fail", "Failed" ) + + ---- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #TASK_CARGO Task + function Fsm:OnLeaveAssigned( TaskUnit, Task ) + self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + + self:SelectAction() + end --- Test -- @param #FSM_PROCESS self diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 6ecb4ce78..6b3f28986 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -61,9 +61,6 @@ do -- TASK_A2G local Fsm = self:GetUnitProcess() - - Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "RouteToRendezVous", Rejected = "Reject" } ) - Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" ) Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } ) Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } ) @@ -84,6 +81,18 @@ do -- TASK_A2G Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) Fsm:AddTransition( "Failed", "Fail", "Failed" ) + + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_A2G#TASK_A2G Task + function Fsm:onafterAssigned( TaskUnit, Task ) + self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + -- Determine the first Unit from the self.RendezVousSetUnit + + self:RouteToRendezVous() + end --- Test -- @param #FSM_PROCESS self diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 0d2a5d869..47ff9a6ee 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -252,6 +252,17 @@ do -- TASK_CARGO Fsm:AddTransition( "Deployed", "Success", "Success" ) Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) Fsm:AddTransition( "Failed", "Fail", "Failed" ) + + + ---- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #TASK_CARGO Task + function Fsm:OnAfterAssigned( TaskUnit, Task ) + self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + + self:SelectAction() + end + --- diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index bdac4b931..7b3967d5e 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -439,6 +439,7 @@ do -- TASK_CARGO_DISPATCHER function TASK_CARGO_DISPATCHER:AddTransportTask( TaskName, SetCargo, Briefing ) self.TransportCount = self.TransportCount + 1 + local TaskName = string.format( ( TaskName or "Transport" ) .. ".%03d", self.TransportCount ) self.Transport[TaskName] = {} @@ -446,7 +447,7 @@ do -- TASK_CARGO_DISPATCHER self.Transport[TaskName].Briefing = Briefing self.Transport[TaskName].Task = nil - return self + return TaskName end diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index 611eefa49..21e296860 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -10,7 +10,7 @@ do -- TASK_CARGO_TRANSPORT --- The TASK_CARGO_TRANSPORT class -- @type TASK_CARGO_TRANSPORT - -- @extends Tasking.Task_Cargo#TASK_CARGO + -- @extends Tasking.Task_CARGO#TASK_CARGO TASK_CARGO_TRANSPORT = { ClassName = "TASK_CARGO_TRANSPORT", } From b33dd94fa0d8d887254e223edb6579cc5d8ae5fd Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 13 Apr 2018 13:57:47 +0200 Subject: [PATCH 054/170] Fixed a bug in Spawn regarding spawning with templates. --- Moose Development/Moose/Core/Spawn.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 1e4640a62..5797ce1d0 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1880,7 +1880,10 @@ function SPAWN:_GetTemplate( SpawnTemplatePrefix ) local SpawnTemplate = nil - SpawnTemplate = routines.utils.deepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template ) + local Template = _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template + self:F( { Template = Template } ) + + SpawnTemplate = UTILS.DeepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template ) if SpawnTemplate == nil then error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) @@ -1902,11 +1905,12 @@ end function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - if not self.SpawnTemplate then - self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) - end +-- if not self.SpawnTemplate then +-- self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) +-- end - local SpawnTemplate = self.SpawnTemplate + local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + --local SpawnTemplate = self.SpawnTemplate SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) SpawnTemplate.groupId = nil @@ -1999,7 +2003,7 @@ function SPAWN:_RandomizeTemplate( SpawnIndex ) if self.SpawnRandomizeTemplate then self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ] self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) - self.SpawnGroups[SpawnIndex].SpawnTemplate.route = routines.utils.deepCopy( self.SpawnTemplate.route ) + self.SpawnGroups[SpawnIndex].SpawnTemplate.route = UTILS.DeepCopy( self.SpawnTemplate.route ) self.SpawnGroups[SpawnIndex].SpawnTemplate.x = self.SpawnTemplate.x self.SpawnGroups[SpawnIndex].SpawnTemplate.y = self.SpawnTemplate.y self.SpawnGroups[SpawnIndex].SpawnTemplate.start_time = self.SpawnTemplate.start_time From f01b2c9149c83039685d40ee01b6042cd3e938ae Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 13 Apr 2018 20:35:38 +0200 Subject: [PATCH 055/170] Finish Cargo/AI_Cargo_APC --- .../{AI_Cargo_Troops.lua => AI_Cargo_APC.lua} | 80 +++---- .../Moose/AI/AI_Cargo_Helicopter.lua | 209 ++++++++++++++++++ Moose Setup/Moose.files | 3 +- 3 files changed, 251 insertions(+), 41 deletions(-) rename Moose Development/Moose/AI/{AI_Cargo_Troops.lua => AI_Cargo_APC.lua} (81%) create mode 100644 Moose Development/Moose/AI/AI_Cargo_Helicopter.lua diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua similarity index 81% rename from Moose Development/Moose/AI/AI_Cargo_Troops.lua rename to Moose Development/Moose/AI/AI_Cargo_APC.lua index 2051fa22d..2c34615cd 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -6,9 +6,9 @@ -- -- === -- --- @module AI_Cargo_Troops +-- @module AI_Cargo_APC ---- @type AI_CARGO_TROOPS +--- @type AI_CARGO_APC -- @extends Core.Fsm#FSM_CONTROLLABLE @@ -16,21 +16,21 @@ -- -- === -- --- @field #AI_CARGO_TROOPS -AI_CARGO_TROOPS = { - ClassName = "AI_CARGO_TROOPS", +-- @field #AI_CARGO_APC +AI_CARGO_APC = { + ClassName = "AI_CARGO_APC", Coordinate = nil -- Core.Point#COORDINATE, } ---- Creates a new AI_CARGO_TROOPS object. --- @param #AI_CARGO_TROOPS self +--- Creates a new AI_CARGO_APC object. +-- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup -- @param #number CombatRadius --- @return #AI_CARGO_TROOPS -function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) +-- @return #AI_CARGO_APC +function AI_CARGO_APC:New( CargoCarrier, CargoGroup, CombatRadius ) - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( ) ) -- #AI_CARGO_TROOPS + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_APC self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP self.CombatRadius = CombatRadius @@ -59,20 +59,20 @@ end --- Set the Carrier. --- @param #AI_CARGO_TROOPS self +-- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier --- @return #AI_CARGO_TROOPS -function AI_CARGO_TROOPS:SetCarrier( CargoCarrier ) +-- @return #AI_CARGO_APC +function AI_CARGO_APC:SetCarrier( CargoCarrier ) self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT - self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_TROOPS", self ) + self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self ) CargoCarrier:HandleEvent( EVENTS.Dead ) CargoCarrier:HandleEvent( EVENTS.Hit ) function CargoCarrier:OnEventDead( EventData ) self:F({"dead"}) - local AICargoTroops = self:GetState( self, "AI_CARGO_TROOPS" ) + local AICargoTroops = self:GetState( self, "AI_CARGO_APC" ) self:F({AICargoTroops=AICargoTroops}) if AICargoTroops then self:F({}) @@ -85,7 +85,7 @@ function AI_CARGO_TROOPS:SetCarrier( CargoCarrier ) function CargoCarrier:OnEventHit( EventData ) self:F({"hit"}) - local AICargoTroops = self:GetState( self, "AI_CARGO_TROOPS" ) + local AICargoTroops = self:GetState( self, "AI_CARGO_APC" ) if AICargoTroops then self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then @@ -107,18 +107,18 @@ end --- Find a free Carrier within a range. --- @param #AI_CARGO_TROOPS self +-- @param #AI_CARGO_APC self -- @param Core.Point#COORDINATE Coordinate -- @param #number Radius -- @return Wrapper.Unit#UNIT NewCarrier -function AI_CARGO_TROOPS:FindCarrier( Coordinate, Radius ) +function AI_CARGO_APC:FindCarrier( Coordinate, Radius ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) CoordinateZone:Scan( { Object.Category.UNIT } ) for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do local NearUnit = UNIT:Find( DCSUnit ) self:F({NearUnit=NearUnit}) - if not NearUnit:GetState( NearUnit, "AI_CARGO_TROOPS" ) then + if not NearUnit:GetState( NearUnit, "AI_CARGO_APC" ) then local Attributes = NearUnit:GetDesc() self:F({Desc=Attributes}) if NearUnit:HasAttribute( "Trucks" ) then @@ -133,12 +133,12 @@ end --- Follow Infantry to the Carrier. --- @param #AI_CARGO_TROOPS self --- @param #AI_CARGO_TROOPS Me +-- @param #AI_CARGO_APC self +-- @param #AI_CARGO_APC Me -- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Group#GROUP InfantryGroup --- @return #AI_CARGO_TROOPS -function AI_CARGO_TROOPS:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) +-- @return #AI_CARGO_APC +function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } ) @@ -172,7 +172,7 @@ function AI_CARGO_TROOPS:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) self:F({ToGround=ToGround}) table.insert( Waypoints, ToGround ) - local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_TROOPS.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) + local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) self:F({Waypoints = Waypoints}) local Waypoint = Waypoints[#Waypoints] @@ -185,9 +185,9 @@ function AI_CARGO_TROOPS:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -235,9 +235,9 @@ function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterLoad( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -248,9 +248,9 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterBoard( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterBoard( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -264,9 +264,9 @@ function AI_CARGO_TROOPS:onafterBoard( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterLoaded( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -276,9 +276,9 @@ function AI_CARGO_TROOPS:onafterLoaded( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterUnload( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterUnload( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -289,9 +289,9 @@ function AI_CARGO_TROOPS:onafterUnload( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterUnboard( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -304,9 +304,9 @@ function AI_CARGO_TROOPS:onafterUnboard( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterUnloaded( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterUnloaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then @@ -318,9 +318,9 @@ function AI_CARGO_TROOPS:onafterUnloaded( CargoCarrier, From, Event, To ) end ---- @param #AI_CARGO_TROOPS self +--- @param #AI_CARGO_APC self -- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_TROOPS:onafterFollow( CargoCarrier, From, Event, To ) +function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) self:F( "Follow" ) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua new file mode 100644 index 000000000..bf6f3dfe6 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -0,0 +1,209 @@ +--- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo). +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Helicopter + +--- @type AI_CARGO_HELICOPTER +-- @extends Core.Fsm#FSM_CONTROLLABLE + + +--- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE} +-- +-- === +-- +-- @field #AI_CARGO_HELICOPTER +AI_CARGO_HELICOPTER = { + ClassName = "AI_CARGO_HELICOPTER", + Coordinate = nil -- Core.Point#COORDINATE, +} + +--- Creates a new AI_CARGO_HELICOPTER object. +-- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup +-- @param #number CombatRadius +-- @return #AI_CARGO_HELICOPTER +function AI_CARGO_HELICOPTER:New( CargoCarrier, CargoGroup ) + + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_HELICOPTER + + self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP + + self:SetStartState( "UnLoaded" ) + + self:AddTransition( "*", "Load", "Boarding" ) + self:AddTransition( "Boarding", "Board", "Boarding" ) + self:AddTransition( "Boarding", "Loaded", "Loaded" ) + self:AddTransition( "Loaded", "Unload", "Unboarding" ) + self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) + self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) + + self:AddTransition( "*", "Landed", "*" ) + + self:AddTransition( "*", "Destroyed", "Destroyed" ) + + self:__Monitor( 1 ) + + self:SetCarrier( CargoCarrier ) + + return self +end + + +--- Set the Carrier. +-- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @return #AI_CARGO_HELICOPTER +function AI_CARGO_HELICOPTER:SetCarrier( CargoCarrier ) + + self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT + self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_HELICOPTER", self ) + + CargoCarrier:HandleEvent( EVENTS.Dead ) + CargoCarrier:HandleEvent( EVENTS.Hit ) + CargoCarrier:HandleEvent( EVENTS.Land ) + + function CargoCarrier:OnEventDead( EventData ) + local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" ) + self:F({AICargoTroops=AICargoTroops}) + if AICargoTroops then + self:F({}) + if not AICargoTroops:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + AICargoTroops:Destroyed() + end + end + end + + + function CargoCarrier:OnEventHit( EventData ) + local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" ) + if AICargoTroops then + self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) + if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + AICargoTroops:Unload() + end + end + end + + + function CargoCarrier:OnEventLand( EventData ) + self:Landed() + end + + self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, 500 ) + self.Coalition = self.CargoCarrier:GetCoalition() + + self:SetControllable( CargoCarrier ) + + self:Guard() + + return self +end + + +--- Find a free Carrier within a range. +-- @param #AI_CARGO_HELICOPTER self +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Radius +-- @return Wrapper.Unit#UNIT NewCarrier +function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) + + local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) + CoordinateZone:Scan( { Object.Category.UNIT } ) + for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do + local NearUnit = UNIT:Find( DCSUnit ) + self:F({NearUnit=NearUnit}) + if not NearUnit:GetState( NearUnit, "AI_CARGO_HELICOPTER" ) then + local Attributes = NearUnit:GetDesc() + self:F({Desc=Attributes}) + if NearUnit:HasAttribute( "Trucks" ) then + self:SetCarrier( NearUnit ) + break + end + end + end + +end + + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_HELICOPTER:onafterLoad( CargoCarrier, From, Event, To ) + + if CargoCarrier and CargoCarrier:IsAlive() then + self:__Board( 10 ) + self.CargoGroup:Board( CargoCarrier, 10 ) + end + +end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_HELICOPTER:onafterBoard( CargoCarrier, From, Event, To ) + + if CargoCarrier and CargoCarrier:IsAlive() then + self:F({ IsLoaded = self.CargoGroup:IsLoaded() } ) + if not self.CargoGroup:IsLoaded() then + self:__Board( 10 ) + else + self:__Loaded( 1 ) + end + end + +end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_HELICOPTER:onafterLoaded( CargoCarrier, From, Event, To ) + + if CargoCarrier and CargoCarrier:IsAlive() then + CargoCarrier:RouteResume() + end + +end + + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_HELICOPTER:onafterUnload( CargoCarrier, From, Event, To ) + + if CargoCarrier and CargoCarrier:IsAlive() then + CargoCarrier:RouteStop() + self.CargoGroup:UnBoard( ) + self:__Unboard( 10 ) + end + +end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_HELICOPTER:onafterUnboard( CargoCarrier, From, Event, To ) + + if CargoCarrier and CargoCarrier:IsAlive() then + if not self.CargoGroup:IsUnLoaded() then + self:__Unboard( 10 ) + else + self:__Unloaded( 1 ) + end + end + +end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_HELICOPTER:onafterUnloaded( CargoCarrier, From, Event, To ) + + if CargoCarrier and CargoCarrier:IsAlive() then + self.CargoCarrier = CargoCarrier + end + +end + + diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index c206b5416..2f3d08e7c 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -66,7 +66,8 @@ AI/AI_Cap.lua AI/AI_Cas.lua AI/AI_Bai.lua AI/AI_Formation.lua -AI/AI_Cargo_Troops.lua +AI/AI_Cargo_APC.lua +AI/AI_Cargo_Helicopter.lua Actions/Act_Assign.lua Actions/Act_Route.lua From 5988ceec05a0a9c8d178dedf4504889b20b1cad0 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 13 Apr 2018 22:31:19 +0200 Subject: [PATCH 056/170] A new AI Cargo Helicopter class. --- .../Moose/AI/AI_Cargo_Helicopter.lua | 308 +++++++++++++++--- 1 file changed, 255 insertions(+), 53 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index bf6f3dfe6..05afee6a4 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -24,19 +24,22 @@ AI_CARGO_HELICOPTER = { --- Creates a new AI_CARGO_HELICOPTER object. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup +-- @param Wrapper.Unit#UNIT Helicopter +-- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_HELICOPTER -function AI_CARGO_HELICOPTER:New( CargoCarrier, CargoGroup ) +function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_HELICOPTER - self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP + self.CargoSet = CargoSet -- Cargo.CargoGroup#CARGO_GROUP - self:SetStartState( "UnLoaded" ) + self:SetStartState( "Unloaded" ) - self:AddTransition( "*", "Load", "Boarding" ) + self:AddTransition( "Unloaded", "Pickup", "*" ) + self:AddTransition( "Loaded", "Deploy", "*" ) + + self:AddTransition( "Unloaded", "Load", "Boarding" ) self:AddTransition( "Boarding", "Board", "Boarding" ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) @@ -47,9 +50,65 @@ function AI_CARGO_HELICOPTER:New( CargoCarrier, CargoGroup ) self:AddTransition( "*", "Destroyed", "Destroyed" ) - self:__Monitor( 1 ) + --- Pickup Handler OnBefore for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] OnBeforePickup + -- @param #AI_CARGO_HELICOPTER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + -- @return #boolean + + --- Pickup Handler OnAfter for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] OnAfterPickup + -- @param #AI_CARGO_HELICOPTER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + + --- Pickup Trigger for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] Pickup + -- @param #AI_CARGO_HELICOPTER self + -- @param Core.Point#COORDINATE Coordinate + + --- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] __Pickup + -- @param #AI_CARGO_HELICOPTER self + -- @param #number Delay + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Handler OnBefore for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] OnBeforeDeploy + -- @param #AI_CARGO_HELICOPTER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + -- @return #boolean + + --- Deploy Handler OnAfter for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] OnAfterDeploy + -- @param #AI_CARGO_HELICOPTER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Trigger for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] Deploy + -- @param #AI_CARGO_HELICOPTER self + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER + -- @function [parent=#AI_CARGO_HELICOPTER] __Deploy + -- @param #AI_CARGO_HELICOPTER self + -- @param Core.Point#COORDINATE Coordinate + -- @param #number Delay - self:SetCarrier( CargoCarrier ) + + + self:SetCarrier( Helicopter ) return self end @@ -57,52 +116,54 @@ end --- Set the Carrier. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Unit#UNIT Helicopter -- @return #AI_CARGO_HELICOPTER -function AI_CARGO_HELICOPTER:SetCarrier( CargoCarrier ) +function AI_CARGO_HELICOPTER:SetCarrier( Helicopter ) - self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT - self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_HELICOPTER", self ) + local AICargo = self - CargoCarrier:HandleEvent( EVENTS.Dead ) - CargoCarrier:HandleEvent( EVENTS.Hit ) - CargoCarrier:HandleEvent( EVENTS.Land ) + self.Helicopter = Helicopter -- Wrapper.Unit#UNIT + self.Helicopter:SetState( self.Helicopter, "AI_CARGO_HELICOPTER", self ) + + self.RoutePickup = false + self.RouteDeploy = false + + Helicopter:HandleEvent( EVENTS.Dead ) + Helicopter:HandleEvent( EVENTS.Hit ) + Helicopter:HandleEvent( EVENTS.Land ) - function CargoCarrier:OnEventDead( EventData ) + function Helicopter:OnEventDead( EventData ) local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" ) self:F({AICargoTroops=AICargoTroops}) if AICargoTroops then self:F({}) if not AICargoTroops:Is( "Loaded" ) then - -- There are enemies within combat range. Unload the CargoCarrier. + -- There are enemies within combat range. Unload the Helicopter. AICargoTroops:Destroyed() end end end - function CargoCarrier:OnEventHit( EventData ) + function Helicopter:OnEventHit( EventData ) local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" ) if AICargoTroops then self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then - -- There are enemies within combat range. Unload the CargoCarrier. + -- There are enemies within combat range. Unload the Helicopter. AICargoTroops:Unload() end end end - function CargoCarrier:OnEventLand( EventData ) - self:Landed() + function Helicopter:OnEventLand( EventData ) + AICargo:Landed() end - self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, 500 ) - self.Coalition = self.CargoCarrier:GetCoalition() + self.Coalition = self.Helicopter:GetCoalition() - self:SetControllable( CargoCarrier ) - - self:Guard() + self:SetControllable( Helicopter ) return self end @@ -132,25 +193,168 @@ function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) end +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT Helicopter +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) + + if Helicopter and Helicopter:IsAlive() then + + if self.RoutePickup == true then + self:Load( Helicopter:GetPointVec2() ) + self.RoutePickup = false + end + + if self.RouteDeploy == true then + self:Unload() + self.RouteDeploy = false + end + + end + +end + + --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_HELICOPTER:onafterLoad( CargoCarrier, From, Event, To ) +-- @param Wrapper.Unit#UNIT Helicopter +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed ) - if CargoCarrier and CargoCarrier:IsAlive() then - self:__Board( 10 ) - self.CargoGroup:Board( CargoCarrier, 10 ) + if Helicopter and Helicopter:IsAlive() then + + self.RoutePickup = true + + local Route = {} + + --- Calculate the target route point. + local CoordinateFrom = Helicopter:GetCoordinate() + local CoordinateTo = Coordinate + + --- Create a route point of type air. + local WaypointFrom = CoordinateFrom:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + Speed, + true + ) + + --- Create a route point of type air. + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + Speed, + true + ) + + Route[#Route+1] = WaypointFrom + Route[#Route+1] = WaypointTo + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Helicopter:WayPointInitialize( Route ) + + local Tasks = {} + + Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) + + -- Now route the helicopter + Helicopter:Route( Route, 0.5 ) + end + +end + + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT Helicopter +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed ) + + if Helicopter and Helicopter:IsAlive() then + + self.RouteDeploy = true + + local Route = {} + + --- Calculate the target route point. + local CoordinateFrom = Helicopter:GetCoordinate() + local CoordinateTo = Coordinate + + --- Create a route point of type air. + local WaypointFrom = CoordinateFrom:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + Speed, + true + ) + + --- Create a route point of type air. + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + Speed, + true + ) + + Route[#Route+1] = WaypointFrom + Route[#Route+1] = WaypointTo + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Helicopter:WayPointInitialize( Route ) + + local Tasks = {} + + Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) + + -- Now route the helicopter + Helicopter:Route( Route, 0.5 ) + end + +end + + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Unit#UNIT Helicopter +function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinate ) + + if Helicopter and Helicopter:IsAlive() then + + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + if Cargo:IsInLoadRadius( Coordinate ) then + self:__Board( 5 ) + Cargo:Board( Helicopter, 25 ) + self.Cargo = Cargo + break + end + end end end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_HELICOPTER:onafterBoard( CargoCarrier, From, Event, To ) +-- @param Wrapper.Unit#UNIT Helicopter +function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To ) - if CargoCarrier and CargoCarrier:IsAlive() then - self:F({ IsLoaded = self.CargoGroup:IsLoaded() } ) - if not self.CargoGroup:IsLoaded() then + if Helicopter and Helicopter:IsAlive() then + self:F({ IsLoaded = self.Cargo:IsLoaded() } ) + if not self.Cargo:IsLoaded() then self:__Board( 10 ) else self:__Loaded( 1 ) @@ -160,34 +364,32 @@ function AI_CARGO_HELICOPTER:onafterBoard( CargoCarrier, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_HELICOPTER:onafterLoaded( CargoCarrier, From, Event, To ) +-- @param Wrapper.Unit#UNIT Helicopter +function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteResume() + if Helicopter and Helicopter:IsAlive() then end end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_HELICOPTER:onafterUnload( CargoCarrier, From, Event, To ) +-- @param Wrapper.Unit#UNIT Helicopter +function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteStop() - self.CargoGroup:UnBoard( ) + if Helicopter and Helicopter:IsAlive() then + self.Cargo:UnBoard() self:__Unboard( 10 ) end end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_HELICOPTER:onafterUnboard( CargoCarrier, From, Event, To ) +-- @param Wrapper.Unit#UNIT Helicopter +function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To ) - if CargoCarrier and CargoCarrier:IsAlive() then - if not self.CargoGroup:IsUnLoaded() then + if Helicopter and Helicopter:IsAlive() then + if not self.Cargo:IsUnLoaded() then self:__Unboard( 10 ) else self:__Unloaded( 1 ) @@ -197,11 +399,11 @@ function AI_CARGO_HELICOPTER:onafterUnboard( CargoCarrier, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_HELICOPTER:onafterUnloaded( CargoCarrier, From, Event, To ) +-- @param Wrapper.Unit#UNIT Helicopter +function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To ) - if CargoCarrier and CargoCarrier:IsAlive() then - self.CargoCarrier = CargoCarrier + if Helicopter and Helicopter:IsAlive() then + self.Helicopter = Helicopter end end From 1444a613c5fb9f620e4bb9a922be5be16f091884 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 14 Apr 2018 12:02:48 +0200 Subject: [PATCH 057/170] New AI_Cargo_Airplane file --- .../Moose/AI/AI_Cargo_Airplane.lua | 338 ++++++++++++++++++ Moose Setup/Moose.files | 1 + 2 files changed, 339 insertions(+) create mode 100644 Moose Development/Moose/AI/AI_Cargo_Airplane.lua diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua new file mode 100644 index 000000000..0d8411544 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -0,0 +1,338 @@ +--- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo). +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Airplane + +--- @type AI_CARGO_AIRPLANE +-- @extends Core.Fsm#FSM_CONTROLLABLE + + +--- # AI\_CARGO\_AIRPLANE class, extends @{Core.Base@BASE} +-- +-- === +-- +-- @field #AI_CARGO_AIRPLANE +AI_CARGO_AIRPLANE = { + ClassName = "AI_CARGO_AIRPLANE", + Coordinate = nil -- Core.Point#COORDINATE, +} + +--- Creates a new AI_CARGO_AIRPLANE object. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +-- @param Core.Set#SET_CARGO CargoSet +-- @param #number CombatRadius +-- @return #AI_CARGO_AIRPLANE +function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) + + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_AIRPLANE + + self.CargoSet = CargoSet -- Cargo.CargoGroup#CARGO_GROUP + + self:SetStartState( "Unloaded" ) + + self:AddTransition( "Unloaded", "Pickup", "*" ) + self:AddTransition( "Loaded", "Deploy", "*" ) + + self:AddTransition( "Unloaded", "Load", "Boarding" ) + self:AddTransition( "Boarding", "Board", "Boarding" ) + self:AddTransition( "Boarding", "Loaded", "Loaded" ) + self:AddTransition( "Loaded", "Unload", "Unboarding" ) + self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) + self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) + + self:AddTransition( "*", "Landed", "*" ) + + self:AddTransition( "*", "Destroyed", "Destroyed" ) + + --- Pickup Handler OnBefore for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] OnBeforePickup + -- @param #AI_CARGO_AIRPLANE self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Wrapper.Airbase#AIRBASE Airbase + -- @return #boolean + + --- Pickup Handler OnAfter for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] OnAfterPickup + -- @param #AI_CARGO_AIRPLANE self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Wrapper.Airbase#AIRBASE Airbase + + --- Pickup Trigger for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] Pickup + -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Airbase#AIRBASE Airbase + + --- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] __Pickup + -- @param #AI_CARGO_AIRPLANE self + -- @param #number Delay + -- @param Wrapper.Airbase#AIRBASE Airbase + + --- Deploy Handler OnBefore for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy + -- @param #AI_CARGO_AIRPLANE self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Wrapper.Airbase#AIRBASE Airbase + -- @return #boolean + + --- Deploy Handler OnAfter for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] OnAfterDeploy + -- @param #AI_CARGO_AIRPLANE self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Wrapper.Airbase#AIRBASE Airbase + + --- Deploy Trigger for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] Deploy + -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Airbase#AIRBASE Airbase + + --- Deploy Asynchronous Trigger for AI_CARGO_AIRPLANE + -- @function [parent=#AI_CARGO_AIRPLANE] __Deploy + -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param #number Delay + + + self:SetCarrier( Airplane ) + + return self +end + + +--- Set the Carrier. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +-- @return #AI_CARGO_AIRPLANE +function AI_CARGO_AIRPLANE:SetCarrier( Airplane ) + + local AICargo = self + + self.Airplane = Airplane -- Wrapper.Unit#UNIT + self.Airplane:SetState( self.Airplane, "AI_CARGO_AIRPLANE", self ) + + self.RoutePickup = false + self.RouteDeploy = false + + Airplane:HandleEvent( EVENTS.Dead ) + Airplane:HandleEvent( EVENTS.Hit ) + Airplane:HandleEvent( EVENTS.EngineShutdown ) + + function Airplane:OnEventDead( EventData ) + local AICargoTroops = self:GetState( self, "AI_CARGO_AIRPLANE" ) + self:F({AICargoTroops=AICargoTroops}) + if AICargoTroops then + self:F({}) + if not AICargoTroops:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the Airplane. + AICargoTroops:Destroyed() + end + end + end + + + function Airplane:OnEventHit( EventData ) + local AICargoTroops = self:GetState( self, "AI_CARGO_AIRPLANE" ) + if AICargoTroops then + self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) + if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then + -- There are enemies within combat range. Unload the Airplane. + AICargoTroops:Unload() + end + end + end + + + function Airplane:OnEventEngineShutdown( EventData ) + AICargo:Landed() + end + + self.Coalition = self.Airplane:GetCoalition() + + self:SetControllable( Airplane ) + + return self +end + + +--- Find a free Carrier within a range. +-- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Airbase#AIRBASE Airbase +-- @param #number Radius +-- @return Wrapper.Unit#UNIT NewCarrier +function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius ) + + local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) + CoordinateZone:Scan( { Object.Category.UNIT } ) + for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do + local NearUnit = UNIT:Find( DCSUnit ) + self:F({NearUnit=NearUnit}) + if not NearUnit:GetState( NearUnit, "AI_CARGO_AIRPLANE" ) then + local Attributes = NearUnit:GetDesc() + self:F({Desc=Attributes}) + if NearUnit:HasAttribute( "Trucks" ) then + self:SetCarrier( NearUnit ) + break + end + end + end + +end + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +-- @param From +-- @param Event +-- @param To + -- @param Wrapper.Airbase#AIRBASE Airbase +-- @param #number Speed +function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) + + if Airplane and Airplane:IsAlive() then + + if self.RoutePickup == true then + self:Load( Airplane:GetPointVec2() ) + self.RoutePickup = false + end + + if self.RouteDeploy == true then + self:Unload() + self.RouteDeploy = false + end + + end + +end + + + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane +-- @param From +-- @param Event +-- @param To +-- @param Wrapper.Airbase#AIRBASE Airbase +-- @param #number Speed +function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed ) + + if Airplane and Airplane:IsAlive() then + + self.RoutePickup = true + + Airplane:RouteRTB( Airbase, Speed) + end + +end + + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +-- @param From +-- @param Event +-- @param To + -- @param Wrapper.Airbase#AIRBASE Airbase +-- @param #number Speed +function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Coordinate, Speed ) + + if Airplane and Airplane:IsAlive() then + + self.RouteDeploy = true + + Airplane:RouteRTB( Airbase, Speed) + end + +end + + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) + + if Airplane and Airplane:IsAlive() then + + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + if Cargo:IsInLoadRadius( Coordinate ) then + self:__Board( 5 ) + Cargo:Board( Airplane, 25 ) + self.Cargo = Cargo + break + end + end + end + +end + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) + + if Airplane and Airplane:IsAlive() then + self:F({ IsLoaded = self.Cargo:IsLoaded() } ) + if not self.Cargo:IsLoaded() then + self:__Board( 10 ) + else + self:__Loaded( 1 ) + end + end + +end + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) + + if Airplane and Airplane:IsAlive() then + end + +end + + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) + + if Airplane and Airplane:IsAlive() then + self.Cargo:UnBoard() + self:__Unboard( 10 ) + end + +end + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) + + if Airplane and Airplane:IsAlive() then + if not self.Cargo:IsUnLoaded() then + self:__Unboard( 10 ) + else + self:__Unloaded( 1 ) + end + end + +end + +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Unit#UNIT Airplane +function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) + + if Airplane and Airplane:IsAlive() then + self.Airplane = Airplane + end + +end + + diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index 2f3d08e7c..f909972b7 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -68,6 +68,7 @@ AI/AI_Bai.lua AI/AI_Formation.lua AI/AI_Cargo_APC.lua AI/AI_Cargo_Helicopter.lua +AI/AI_Cargo_Airplane.lua Actions/Act_Assign.lua Actions/Act_Route.lua From b9eab34d6ae25aeef23dcbbbb8eebe24c437d034 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 14 Apr 2018 13:45:00 +0200 Subject: [PATCH 058/170] WIP on AI_Cargo_Airplane --- .../Moose/AI/AI_Cargo_Airplane.lua | 40 +++++--- Moose Development/Moose/Core/Database.lua | 2 +- Moose Development/Moose/Wrapper/Group.lua | 96 ++++++++++++++++++- 3 files changed, 121 insertions(+), 17 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 0d8411544..679900301 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -24,7 +24,7 @@ AI_CARGO_AIRPLANE = { --- Creates a new AI_CARGO_AIRPLANE object. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane -- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_AIRPLANE @@ -115,13 +115,13 @@ end --- Set the Carrier. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane -- @return #AI_CARGO_AIRPLANE function AI_CARGO_AIRPLANE:SetCarrier( Airplane ) local AICargo = self - self.Airplane = Airplane -- Wrapper.Unit#UNIT + self.Airplane = Airplane -- Wrapper.Group#GROUP self.Airplane:SetState( self.Airplane, "AI_CARGO_AIRPLANE", self ) self.RoutePickup = false @@ -172,7 +172,7 @@ end -- @param #AI_CARGO_AIRPLANE self -- @param Wrapper.Airbase#AIRBASE Airbase -- @param #number Radius --- @return Wrapper.Unit#UNIT NewCarrier +-- @return Wrapper.Group#GROUP NewCarrier function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) @@ -193,7 +193,7 @@ function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius ) end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane -- @param From -- @param Event -- @param To @@ -228,9 +228,14 @@ end -- @param #number Speed function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed ) + if self.Airbase then + Airplane:RespawnAtAirbase( self.Airbase ) + end + if Airplane and Airplane:IsAlive() then self.RoutePickup = true + self.Airbase = Airbase Airplane:RouteRTB( Airbase, Speed) end @@ -239,26 +244,31 @@ end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane -- @param From -- @param Event -- @param To - -- @param Wrapper.Airbase#AIRBASE Airbase +-- @param Wrapper.Airbase#AIRBASE Airbase -- @param #number Speed -function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Coordinate, Speed ) +function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Speed ) + if self.Airbase then + Airplane:RespawnAtAirbase( self.Airbase ) + end + if Airplane and Airplane:IsAlive() then self.RouteDeploy = true + self.Airbase = Airbase - Airplane:RouteRTB( Airbase, Speed) + Airplane:RouteRTB( Airbase, Speed ) end end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) if Airplane and Airplane:IsAlive() then @@ -276,7 +286,7 @@ function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -291,7 +301,7 @@ function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -301,7 +311,7 @@ end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -312,7 +322,7 @@ function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -326,7 +336,7 @@ function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) end --- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Unit#UNIT Airplane +-- @param Wrapper.Group#GROUP Airplane function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index b160fdfda..6eb78eccc 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -688,7 +688,7 @@ function DATABASE:_RegisterAirbases() local DCSAirbaseName = DCSAirbase:getName() - self:E( { "Register Airbase:", DCSAirbaseName } ) + self:E( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } ) self:AddAirbase( DCSAirbaseName ) end end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index be59a7723..af83d6553 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -1141,7 +1141,7 @@ function GROUP:Respawn( Template, Reset ) else for UnitID, TemplateUnitData in pairs( Template.units ) do self:F( "Reset" ) - local GroupUnitVec3 = { x = TemplateUnitData.x, y = TemplateUnitData.alt, z = TemplateUnitData.z } + local GroupUnitVec3 = { x = TemplateUnitData.x, y = TemplateUnitData.alt, z = TemplateUnitData.y } if Zone then if self.InitRespawnRandomizePositionZone then GroupUnitVec3 = Zone:GetRandomVec3() @@ -1174,7 +1174,101 @@ function GROUP:Respawn( Template, Reset ) end +--- @param Wrapper.Group#GROUP self +function GROUP:RespawnAtAirbase( AirbaseRespawn, Takeoff, TakeoffAltitude ) -- R2.4 + self:F( { AirbaseRespawn, Takeoff, TakeoffAltitude } ) + local PointVec3 = AirbaseRespawn:GetPointVec3() + + Takeoff = Takeoff or SPAWN.Takeoff.Hot + + local SpawnTemplate = self:GetTemplate() + + if SpawnTemplate then + + local SpawnPoint = SpawnTemplate.route.points[1] + + -- These are only for ships. + SpawnPoint.linkUnit = nil + SpawnPoint.helipadId = nil + SpawnPoint.airdromeId = nil + + local AirbaseID = AirbaseRespawn:GetID() + local AirbaseCategory = AirbaseRespawn:GetDesc().category + self:F( { AirbaseCategory = AirbaseCategory, Ship = Airbase.Category.SHIP, Helipad = Airbase.Category.HELIPAD, Airdrome = Airbase.Category.AIRDROME } ) + + if AirbaseCategory == Airbase.Category.SHIP then + SpawnPoint.linkUnit = AirbaseID + SpawnPoint.helipadId = AirbaseID + elseif AirbaseCategory == Airbase.Category.HELIPAD then + SpawnPoint.linkUnit = AirbaseID + SpawnPoint.helipadId = AirbaseID + elseif AirbaseCategory == Airbase.Category.AIRDROME then + SpawnPoint.airdromeId = AirbaseID + end + + SpawnPoint.alt = 0 + + SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type + SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action + + + -- Translate the position of the Group Template to the Vec3. + for UnitID = 1, #SpawnTemplate.units do + self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + + -- These cause a lot of confusion. + local UnitTemplate = SpawnTemplate.units[UnitID] + + UnitTemplate.parking = 15 + UnitTemplate.parking_id = "30" + UnitTemplate.alt = 0 + + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnPoint.x + local BY = SpawnPoint.y + local TX = PointVec3.x + ( SX - BX ) + local TY = PointVec3.z + ( SY - BY ) + + UnitTemplate.x = TX + UnitTemplate.y = TY + + if Takeoff == GROUP.Takeoff.Air then + UnitTemplate.alt = PointVec3.y + ( TakeoffAltitude or 200 ) + --else + -- UnitTemplate.alt = PointVec3.y + 10 + end + self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) + end + + SpawnPoint.x = PointVec3.x + SpawnPoint.y = PointVec3.z + + if Takeoff == GROUP.Takeoff.Air then + SpawnPoint.alt = PointVec3.y + ( TakeoffAltitude or 200 ) + --else + -- SpawnPoint.alt = PointVec3.y + 10 + end + + SpawnTemplate.x = PointVec3.x + SpawnTemplate.y = PointVec3.z + + local GroupSpawned = self:Respawn( SpawnTemplate ) + + -- When spawned in the air, we need to generate a Takeoff Event + + if Takeoff == GROUP.Takeoff.Air then + for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do + SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 ) + end + end + + return GroupSpawned + end + + return nil +end --- Return the mission template of the group. From 3757eb06d9411267330ac24cec6ab8904b4dea9e Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 15 Apr 2018 04:41:52 +0200 Subject: [PATCH 059/170] Fixes for AI_CARGO_AIRPLANE --- .../Moose/AI/AI_Cargo_Airplane.lua | 128 ++++++++++++++++-- Moose Development/Moose/Core/Base.lua | 16 +++ Moose Development/Moose/Wrapper/Group.lua | 33 +++-- 3 files changed, 154 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 679900301..a55bf0d10 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -228,16 +228,10 @@ end -- @param #number Speed function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed ) - if self.Airbase then - Airplane:RespawnAtAirbase( self.Airbase ) - end - if Airplane and Airplane:IsAlive() then - + self:Route( Airplane, Airbase, Speed ) self.RoutePickup = true self.Airbase = Airbase - - Airplane:RouteRTB( Airbase, Speed) end end @@ -252,16 +246,10 @@ end -- @param #number Speed function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Speed ) - if self.Airbase then - Airplane:RespawnAtAirbase( self.Airbase ) - end - if Airplane and Airplane:IsAlive() then - + self:Route( Airplane, Airbase, Speed ) self.RouteDeploy = true self.Airbase = Airbase - - Airplane:RouteRTB( Airbase, Speed ) end end @@ -346,3 +334,115 @@ function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) end +--- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane +-- @param Wrapper.Airbase#AIRBASE Airbase +-- @param #number Speed +function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed ) + + if Airplane and Airplane:IsAlive() then + + local PointVec3 = Airplane:GetPointVec3() + + local Takeoff = SPAWN.Takeoff.Hot + + local Template = Airplane:GetTemplate() + + if Template then + + local Points = {} + + if self.Airbase then + + local FromWaypoint = Template.route.points[1] + + -- These are only for ships. + FromWaypoint.linkUnit = nil + FromWaypoint.helipadId = nil + FromWaypoint.airdromeId = nil + + local AirbaseID = self.Airbase:GetID() + local AirbaseCategory = self.Airbase:GetDesc().category + + FromWaypoint.airdromeId = AirbaseID + + FromWaypoint.alt = 0 + + FromWaypoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type + FromWaypoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action + + + -- Translate the position of the Group Template to the Vec3. + for UnitID = 1, #Template.units do + self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. Template.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. Template.units[UnitID].y ) + + -- These cause a lot of confusion. + local UnitTemplate = Template.units[UnitID] + + UnitTemplate.parking = 15 + UnitTemplate.parking_id = "1" + UnitTemplate.alt = 0 + + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = FromWaypoint.x + local BY = FromWaypoint.y + local TX = PointVec3.x + ( SX - BX ) + local TY = PointVec3.z + ( SY - BY ) + + UnitTemplate.x = TX + UnitTemplate.y = TY + + self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) + end + + FromWaypoint.x = PointVec3.x + FromWaypoint.y = PointVec3.z + + Points[#Points+1] = FromWaypoint + else + + local GroupPoint = Airplane:GetVec2() + local GroupVelocity = Airplane:GetUnit(1):GetDesc().speedMax + + local FromWaypoint = {} + FromWaypoint.x = GroupPoint.x + FromWaypoint.y = GroupPoint.y + FromWaypoint.type = "Turning Point" + FromWaypoint.action = "Turning Point" + FromWaypoint.speed = GroupVelocity + + Points[#Points+1] = FromWaypoint + end + + local AirbasePointVec2 = Airbase:GetPointVec2() + local ToWaypoint = AirbasePointVec2:WaypointAir( + POINT_VEC3.RoutePointAltType.BARO, + "Land", + "Landing", + Speed or Airplane:GetUnit(1):GetDesc().speedMax + ) + + ToWaypoint["airdromeId"] = Airbase:GetID() + ToWaypoint["speed_locked"] = true, + + self:F( ToWaypoint ) + + Points[#Points+1] = ToWaypoint + + Template.x = PointVec3.x + Template.y = PointVec3.z + + self:T3( Points ) + Template.route.points = Points + + --self:Respawn( Template ) + + local GroupSpawned = Airplane:Respawn( Template ) + + return GroupSpawned + end + + end + +end diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index f642d79b1..555786ab4 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -645,6 +645,22 @@ function BASE:CreateEventCrash( EventTime, Initiator ) world.onEvent( Event ) end +--- Creation of a Dead Event. +-- @param #BASE self +-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. +-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +function BASE:CreateEventDead( EventTime, Initiator ) + self:F( { EventTime, Initiator } ) + + local Event = { + id = world.event.S_EVENT_DEAD, + time = EventTime, + initiator = Initiator, + } + + world.onEvent( Event ) +end + --- Creation of a Takeoff Event. -- @param #BASE self -- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index af83d6553..c595a5dbb 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -236,19 +236,36 @@ function GROUP:IsAlive() end --- Destroys the DCS Group and all of its DCS Units. --- Note that this destroy method also raises a destroy event at run-time. --- So all event listeners will catch the destroy event of this DCS Group. +-- Note that this destroy method also can raise a destroy event at run-time. +-- So all event listeners will catch the destroy event of this group for each unit in the group. +-- To raise these events, provide the `GenerateEvent` parameter. -- @param #GROUP self --- @param #boolean GenerateEvent +-- @param #boolean GenerateEvent true if you want to generate a crash or dead event for each unit. +-- @usage +-- -- Air unit example: destroy the Helicopter and generate a S_EVENT_CRASH for each unit in the Helicopter group. +-- Helicopter = GROUP:FindByName( "Helicopter" ) +-- Helicopter:Destroy( true ) +-- @usage +-- -- Ground unit example: destroy the Tanks and generate a S_EVENT_DEAD for each unit in the Tanks group. +-- Tanks = GROUP:FindByName( "Tanks" ) +-- Tanks:Destroy( true ) +-- @usage +-- -- Ship unit example: destroy the Ship silently. +-- Ship = GROUP:FindByName( "Ship" ) +-- Ship:Destroy( true ) function GROUP:Destroy( GenerateEvent ) self:F2( self.GroupName ) local DCSGroup = self:GetDCSObject() if DCSGroup then - if not GenerateEvent then + if GenerateEvent and GenerateEvent == true then for Index, UnitData in pairs( DCSGroup:getUnits() ) do - self:CreateEventCrash( timer.getTime(), UnitData ) + if self:IsAir() then + self:CreateEventCrash( timer.getTime(), UnitData ) + else + self:CreateEventDead( timer.getTime(), UnitData ) + end end end USERFLAG:New( self:GetName() ):Set( 100 ) @@ -1394,7 +1411,7 @@ do -- Route methods -- @param #number Speed (optional) The Speed, if no Speed is given, the maximum Speed of the first unit is selected. -- @return #GROUP function GROUP:RouteRTB( RTBAirbase, Speed ) - self:F2( { RTBAirbase, Speed } ) + self:F( { RTBAirbase:GetName(), Speed } ) local DCSGroup = self:GetDCSObject() @@ -1435,9 +1452,7 @@ do -- Route methods Template.route.points = Points self:Respawn( Template ) - self:Route( Points ) - - self:Respawn(Template) + --self:Route( Points ) else self:ClearTasks() end From af050629aab4f401c186c4038fa429c33b84624a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 17 Apr 2018 06:25:40 +0200 Subject: [PATCH 060/170] Made it. Now cargo can be defined in the Mission Editor as #CARGO --- Moose Development/Moose/Cargo/Cargo.lua | 2 +- Moose Development/Moose/Core/Database.lua | 107 +++++++++++++++++----- Moose Development/Moose/Moose.lua | 2 + 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 2cf5be78e..446d58da4 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -610,7 +610,7 @@ do -- CARGO -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - --self:F2( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + --self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) if self.CargoObject:IsAlive() then --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 6eb78eccc..262175514 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -242,35 +242,96 @@ function DATABASE:FindAirbase( AirbaseName ) return AirbaseFound end ---- Adds a Cargo based on the Cargo Name in the DATABASE. --- @param #DATABASE self --- @param #string CargoName The name of the airbase -function DATABASE:AddCargo( Cargo ) - if not self.CARGOS[Cargo.Name] then - self.CARGOS[Cargo.Name] = Cargo + +do -- cargo + + --- Adds a Cargo based on the Cargo Name in the DATABASE. + -- @param #DATABASE self + -- @param #string CargoName The name of the airbase + function DATABASE:AddCargo( Cargo ) + + if not self.CARGOS[Cargo.Name] then + self.CARGOS[Cargo.Name] = Cargo + end end -end + + + --- Deletes a Cargo from the DATABASE based on the Cargo Name. + -- @param #DATABASE self + -- @param #string CargoName The name of the airbase + function DATABASE:DeleteCargo( CargoName ) + + self.CARGOS[CargoName] = nil + end + + --- Finds an CARGO based on the CargoName. + -- @param #DATABASE self + -- @param #string CargoName + -- @return Wrapper.Cargo#CARGO The found CARGO. + function DATABASE:FindCargo( CargoName ) + + local CargoFound = self.CARGOS[CargoName] + return CargoFound + end + + --- Checks if the Template name has a ~CARGO tag. + -- If yes, the group is a cargo. + -- @param #DATABASE self + -- @param #string TemplateName + -- @return #boolean + function DATABASE:IsCargo( TemplateName ) + TemplateName = env.getValueDictByKey( TemplateName ) + + local Cargo = TemplateName:match( "#(CARGO)" ) ---- Deletes a Cargo from the DATABASE based on the Cargo Name. --- @param #DATABASE self --- @param #string CargoName The name of the airbase -function DATABASE:DeleteCargo( CargoName ) + return Cargo and Cargo == "CARGO" + end - self.CARGOS[CargoName] = nil -end - ---- Finds an CARGO based on the CargoName. --- @param #DATABASE self --- @param #string CargoName --- @return Wrapper.Cargo#CARGO The found CARGO. -function DATABASE:FindCargo( CargoName ) - - local CargoFound = self.CARGOS[CargoName] - return CargoFound -end + --- Private method that registers new Static Templates within the DATABASE Object. + -- @param #DATABASE self + -- @return #DATABASE self + function DATABASE:RegisterCargos() + + for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do + if self:IsCargo( CargoGroupName ) then + local CargoInfo = CargoGroupName:match("~CARGO(.*)") + local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") + local CargoName = CargoGroupName:match("(.*)~CARGO") + local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") + local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") + local LoadRadius = CargoParam and CargoParam:match( "RR=([%a%d]+),?") + local NearRadius = CargoParam and CargoParam:match( "NR=([%a%d]+),?") + + CARGO_GROUP:New( CargoGroup, Type, Name or CargoName, LoadRadius, NearRadius ) + end + end + + for CargoStaticName, CargoStatic in pairs( self.STATICS ) do + if self:IsCargo( CargoStaticName ) then + local CargoInfo = CargoStaticName:match("~CARGO(.*)") + local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") + local CargoName = CargoStaticName:match("(.*)~CARGO") + local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") + local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?") + local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") + local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) + local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) + + if Category == "SLING" then + CARGO_SLINGLOAD:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius ) + else + if Category == "CRATE" then + CARGO_CRATE:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius ) + end + end + end + end + + end +end -- cargo --- Finds a CLIENT based on the ClientName. -- @param #DATABASE self diff --git a/Moose Development/Moose/Moose.lua b/Moose Development/Moose/Moose.lua index 5e1e394cc..6a748922a 100644 --- a/Moose Development/Moose/Moose.lua +++ b/Moose Development/Moose/Moose.lua @@ -13,3 +13,5 @@ _DATABASE = DATABASE:New() -- Core.Database#DATABASE _SETTINGS = SETTINGS:Set() _SETTINGS:SetPlayerMenuOn() +_DATABASE:RegisterCargos() + From 22976468736a8a102b454ae38825a363c84cf74e Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 20 Apr 2018 00:13:30 +0200 Subject: [PATCH 061/170] Range v1.1.1 Added strafe pit/bombing targets info --- Moose Development/Moose/Functional/Range.lua | 79 ++++++++++++++++++-- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 9748e89d6..937dc9002 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -279,7 +279,7 @@ RANGE.id="RANGE | " --- Range script version. -- @field #number version -RANGE.version="1.1.0" +RANGE.version="1.1.1" --TODO list: --TODO: Add custom weapons, which can be specified by the user. @@ -1537,6 +1537,73 @@ function RANGE:_DisplayRangeInfo(_unitname) end end +--- Display bombing target locations to player. +-- @param #RANGE self +-- @param #string _unitname Name of the player unit. +function RANGE:_DisplayBombTargets(_unitname) + self:F(_unitname) + + -- Get player unit and player name. + local _unit, _playername = self:_GetPlayerUnitAndName(_unitname) + + -- Check if we have a player. + if _unit and _playername then + + -- Player settings. + local _settings=_DATABASE:GetPlayerSettings(_playername) or _SETTINGS --Core.Settings#SETTINGS + + -- Message text. + local _text="Bomb Target Locations:" + + for _,_bombtarget in pairs(self.bombingTargets) do + local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + if _target and _target:IsAlive() then + + -- Core.Point#COORDINATE + local coord=_target:GetCoordinate() --Core.Point#COORDINATE + local mycoord=coord:ToStringA2G(_unit, _settings) + _text=_text..string.format("\n- %s: %s",_bombtarget.name, mycoord) + end + end + + self:_DisplayMessageToGroup(_unit,_text, nil, true) + end +end + +--- Display pit location and heading to player. +-- @param #RANGE self +-- @param #string _unitname Name of the player unit. +function RANGE:_DisplayStrafePits(_unitname) + self:F(_unitname) + + -- Get player unit and player name. + local _unit, _playername = self:_GetPlayerUnitAndName(_unitname) + + -- Check if we have a player. + if _unit and _playername then + + -- Player settings. + local _settings=_DATABASE:GetPlayerSettings(_playername) or _SETTINGS --Core.Settings#SETTINGS + + -- Message text. + local _text="Strafe Target Locations:" + + for _,_strafepit in pairs(self.strafeTargets) do + local _target=_strafepit --Wrapper.Positionable#POSITIONABLE + + -- Pit parameters. + local coord=_strafepit.coordinate --Core.Point#COORDINATE + local heading=_strafepit.heading + + local mycoord=coord:ToStringA2G(_unit, _settings) + _text=_text..string.format("\n- %s: %s - heading %03d",_strafepit.name, mycoord, heading) + end + + self:_DisplayMessageToGroup(_unit,_text, nil, true) + end +end + + --- Report weather conditions at range. Temperature, QFE pressure and wind data. -- @param #RANGE self -- @param #string _unitname Name of the player unit. @@ -1792,11 +1859,11 @@ function RANGE:_AddF10Commands(_unitName) local _statsPath = missionCommands.addSubMenuForGroup(_gid, "Statistics", _rangePath) local _markPath = missionCommands.addSubMenuForGroup(_gid, "Mark Targets", _rangePath) local _settingsPath = missionCommands.addSubMenuForGroup(_gid, "My Settings", _rangePath) + local _infoPath = missionCommands.addSubMenuForGroup(_gid, "Range Info", _rangePath) -- F10/On the Range//My Settings/ local _mysmokePath = missionCommands.addSubMenuForGroup(_gid, "Smoke Color", _settingsPath) local _myflarePath = missionCommands.addSubMenuForGroup(_gid, "Flare Color", _settingsPath) - --TODO: Convert to MOOSE menu. -- F10/On the Range//Mark Targets/ missionCommands.addCommandForGroup(_gid, "Mark On Map", _markPath, self._MarkTargetsOnMap, self, _unitName) missionCommands.addCommandForGroup(_gid, "Illuminate Range", _markPath, self._IlluminateBombTargets, self, _unitName) @@ -1824,9 +1891,11 @@ function RANGE:_AddF10Commands(_unitName) missionCommands.addCommandForGroup(_gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName) missionCommands.addCommandForGroup(_gid, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName) missionCommands.addCommandForGroup(_gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName) - -- F10/On the Range// - missionCommands.addCommandForGroup(_gid, "Range Information", _rangePath, self._DisplayRangeInfo, self, _unitName) - missionCommands.addCommandForGroup(_gid, "Weather Report", _rangePath, self._DisplayRangeWeather, self, _unitName) + -- F10/On the Range//Range Information + missionCommands.addCommandForGroup(_gid, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName) + missionCommands.addCommandForGroup(_gid, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName) + missionCommands.addCommandForGroup(_gid, "Bombing Targets", _infoPath, self._DisplayBombTargets, self, _unitName) + missionCommands.addCommandForGroup(_gid, "Strafe Pits", _infoPath, self._DisplayStrafePits, self, _unitName) end else self:T(RANGE.id.."Could not find group or group ID in AddF10Menu() function. Unit name: ".._unitName) From 462564cd01448282d8fc594fa31c4c5a0623840a Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 22 Apr 2018 23:55:21 +0200 Subject: [PATCH 062/170] PseudoATC and RANGE Range: corrected heading PseudoATC: lots of changes --- .../Moose/Functional/PseudoATC.lua | 279 +++++++++++++----- Moose Development/Moose/Functional/Range.lua | 7 + 2 files changed, 212 insertions(+), 74 deletions(-) diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 9e93073d6..6295fc646 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -13,7 +13,7 @@ -- -- * Report QFE or QNH pressures at nearby airbases. -- * Report wind direction and strength at airbases. --- * Report temperature at airbases +-- * Report temperature at airbases. -- * Report absolute bearing and range to nearest airports. -- * Report current altitude AGL of own aircraft. -- * Upon request, ATC reports altitude until touchdown. @@ -43,7 +43,7 @@ -- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** -- -- ==== --- @module PeusoATC +-- @module PseudoATC ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- PSEUDOATC class @@ -68,11 +68,12 @@ -- @field #PSEUDOATC PSEUDOATC={ ClassName = "PSEUDOATC", - Debug=true, + Debug=false, player={}, maxairport=9, mdur=30, mrefresh=120, + eventsmoose=true, } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -93,7 +94,7 @@ PSEUDOATC.id="PseudoATC | " --- PSEUDOATC version. -- @field #list PSEUDOATC.version={ - version = "0.5.0", + version = "0.6.0", print = true, } @@ -107,7 +108,7 @@ function PSEUDOATC:Start() local self=BASE:Inherit(self, BASE:New()) -- #PSEUDOATC -- Debug info - env.info(PSEUDOATC.id..string.format("Creating PseudoATC object. PseudoATC version %s", PSEUDOATC.version.version)) + self:E(PSEUDOATC.id..string.format("Creating PseudoATC object. PseudoATC version %s", PSEUDOATC.version.version)) -- Handle events. if self.eventsmoose then @@ -192,11 +193,13 @@ end -- @param #PSEUDOATC self -- @param Core.Event#EVENTDATA EventData function PSEUDOATC:_OnBirth(EventData) - env.info(PSEUDOATC.id.."PlayerEntered event caught my MOOSE.") + self:F({EventData=EventData}) + -- Get unit and player. local _unitName=EventData.IniUnitName local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + -- Check if a player entered. if _unit and _playername then self:PlayerEntered(_unit) end @@ -207,10 +210,13 @@ end -- @param #PSEUDOATC self -- @param Core.Event#EVENTDATA EventData function PSEUDOATC:_PlayerLeft(EventData) + self:F({EventData=EventData}) + -- Get unit and player. local _unitName=EventData.IniUnitName local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + -- Check if a player left. if _unit and _playername then self:PlayerLeft(_unit) end @@ -220,19 +226,22 @@ end -- @param #PSEUDOATC self -- @param Core.Event#EVENTDATA EventData function PSEUDOATC:_PlayerLanded(EventData) + self:F({EventData=EventData}) + -- Get unit, player and place. local _unitName=EventData.IniUnitName local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) local _base=EventData.Place local _baseName=EventData.PlaceName - if _unit and _playername and _base then + -- Call landed function. + if _unit and _playername and _base then self:PlayerLanded(_unit, _baseName) end end ----------------------------------------------------------------------------------------------------------------------------------------- --- Menu Functions +-- Event Functions --- Function called when a player enters a unit. -- @param #PSEUDOATC self @@ -240,6 +249,7 @@ end function PSEUDOATC:PlayerEntered(unit) self:F2({unit=unit}) + -- Get player info. local group=unit:GetGroup() --Wrapper.Group#GROUP local GID=group:GetID() local GroupName=group:GetName() @@ -259,10 +269,8 @@ function PSEUDOATC:PlayerEntered(unit) -- Info message. local text=string.format("Player %s entered unit %s of group %s. ID = %d", PlayerName, UnitName, GroupName, GID) - if self.Debug then - MESSAGE:New(text, 30):ToGroup(group) - env.info(PSEUDOATC.id..text) - end + self:T(PSEUDOATC.id..text) + MESSAGE:New(text, 30):ToAllIf(self.Debug) -- Create main F10 menu, i.e. "F10/Pseudo ATC" self.player[GID].menu_main=missionCommands.addSubMenuForGroup(GID, "Pseudo ATC") @@ -279,7 +287,6 @@ function PSEUDOATC:PlayerEntered(unit) -- Start scheduler to refresh the F10 menues. self.player[GID].scheduler, self.player[GID].schedulerid=SCHEDULER:New(nil, self.MenuRefresh, {self, GID}, self.mrefresh, self.mrefresh) - self:T2(self.player[GID]) end --- Function called when a player has landed. @@ -298,11 +305,9 @@ function PSEUDOATC:PlayerLanded(unit, place) local CallSign=self.player[id].callsign -- Debug message. - if self.Debug then - local text=string.format("Player %s (%s) from group %s with ID %d landed at %s", PlayerName, UnitName, GroupName, place) - MESSAGE:New(text,30):ToAll() - env.info(PSEUDOATC.id..text) - end + local text=string.format("Player %s (%s) from group %s with ID %d landed at %s", PlayerName, UnitName, GroupName, place) + self:T(PSEUDOATC.id..text) + MESSAGE:New(text, 30):ToAllIf(self.Debug) -- Stop altitude reporting timer if its activated. self:AltidudeStopTimer(id) @@ -326,25 +331,20 @@ function PSEUDOATC:PlayerLeft(unit) local id=group:GetID() -- Debug message. - if self.Debug then - local text=string.format("Player %s (%s) callsign %s of group %s just left.", self.player[id].playername, self.player[id].unitname, self.player[id].callsign, self.player[id].groupname) - MESSAGE:New(text,30):ToAll() - env.info(PSEUDOATC.id..text) - end + local text=string.format("Player %s (%s) callsign %s of group %s just left.", self.player[id].playername, self.player[id].unitname, self.player[id].callsign, self.player[id].groupname) + self:T(PSEUDOATC.id..text) + MESSAGE:New(text, 30):ToAllIf(self.Debug) -- Stop scheduler for menu updates if self.player[id].schedulerid then self.player[id].scheduler:Stop(self.player[id].schedulerid) - self.player[id].scheduler=nil - self.player[id].schedulerid=nil end - -- Remove main menu + -- Remove main menu. missionCommands.removeItem(self.player[id].menu_main) -- Remove player array. self.player[id]=nil - end ----------------------------------------------------------------------------------------------------------------------------------------- @@ -354,13 +354,12 @@ end -- @param #PSEUDOATC self. -- @param #number id Group id of player unit. function PSEUDOATC:MenuRefresh(id) - self:F(id) + self:F({id=id}) - if self.Debug then - local text=string.format("Refreshing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) - env.info(PSEUDOATC.id..text) - MESSAGE:New(text,30):ToAll() - end + -- Debug message. + local text=string.format("Refreshing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) + self:T(PSEUDOATC.id..text) + MESSAGE:New(text,30):ToAllIf(self.Debug) -- Clear menu. self:MenuClear(id) @@ -382,33 +381,27 @@ end function PSEUDOATC:MenuClear(id) self:F(id) - if self.Debug then - local text=string.format("Clearing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) - env.info(PSEUDOATC.id..text) - MESSAGE:New(text,30):ToAll() - end - - BASE:E(self.player[id].menu_airports) + -- Debug message. + local text=string.format("Clearing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) + self:T(PSEUDOATC.id..text) + MESSAGE:New(text,30):ToAllIf(self.Debug) + if self.player[id].menu_airports then for name,item in pairs(self.player[id].menu_airports) do - - if self.Debug then - env.info(PSEUDOATC.id..string.format("Deleting menu item %s for ID %d", name, id)) - BASE:E(item) - end + -- Debug message. + self:E(PSEUDOATC.id..string.format("Deleting menu item %s for ID %d", name, id)) + + -- Remove menu item. missionCommands.removeItemForGroup(id, self.player[id].menu_airports[name]) - --missionCommands.removeItemForGroup(id, item) end else - if self.Debug then - local text=string.format("no airports to clear menues") - env.info(PSEUDOATC.id..text) - end + self:T2(PSEUDOATC.id.."No airports to clear menus.") end + -- Remove if self.player[id].menu_aircraft then missionCommands.removeItemForGroup(id, self.player[id].menu_aircraft.main) end @@ -443,15 +436,15 @@ function PSEUDOATC:MenuAirports(id) self.player[id].menu_airports[name]=submenu -- Create menu reporting commands + missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, name) missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, name) missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, name) missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, name) missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, name) missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, name) - if self.Debug then - env.info(string.format(PSEUDOATC.id.."Creating airport menu item %s for ID %d", name, id)) - end + -- Debug message. + self:T(string.format(PSEUDOATC.id.."Creating airport menu item %s for ID %d", name, id)) end end @@ -469,9 +462,7 @@ function PSEUDOATC:MenuAircraft(id) local name=string.format("My Aircraft (%s)", callsign) -- Debug info. - if self.Debug then - env.info(PSEUDOATC.id..string.format("Creating menu item %s for ID %d", name,id)) - end + self:T(PSEUDOATC.id..string.format("Creating menu item %s for ID %d", name,id)) -- F10/PseudoATC/My Aircraft (callsign) self.player[id].menu_aircraft.main = missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) @@ -502,6 +493,7 @@ function PSEUDOATC:MenuAircraft(id) self.player[id].menu_aircraft_waypoints.pname=submenu -- Menu commands for each waypoint "F10/PseudoATC/My Aircraft (callsign)/Waypoints/Waypoint X/" + missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, pname) missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, pname) missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, pname) missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, pname) @@ -517,6 +509,75 @@ end ----------------------------------------------------------------------------------------------------------------------------------------- -- Reporting Functions +--- Weather Report. Report pressure QFE/QNH, temperature, wind at certain location +-- @param #PSEUDOATC self +-- @param #number id Group id to which the report is delivered. +-- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. +-- @param #string location Name of the location at which the pressure is measured. +function PSEUDOATC:ReportWeather(id, position, location) + self:F({id=id, position=position, location=location}) + + -- Player unit system settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + + local text=string.format("Local weather at %s:\n", location) + + -- Get pressure in hPa. + local Pqnh=position:GetPressure(0) -- Get pressure at sea level. + local Pqfe=position:GetPressure() -- Get pressure at (land) height of position. + + -- Unit conversion. + local _Pqnh=string.format("%.2f inHg", Pqnh * PSEUDOATC.unit.hPa2inHg) + local _Pqfe=string.format("%.2f inHg", Pqfe * PSEUDOATC.unit.hPa2inHg) + if settings:IsMetric() then + _Pqnh=string.format("%.1f mmHg", Pqnh * PSEUDOATC.unit.hPa2mmHg) + _Pqfe=string.format("%.1f mmHg", Pqfe * PSEUDOATC.unit.hPa2mmHg) + end + + -- Message text. + text=text..string.format("QFE %.1f hPa = %s.\n", Pqfe, _Pqfe) + text=text..string.format("QNH %.1f hPa = %s.\n", Pqnh, _Pqnh) + + --- convert celsius to fahrenheit + local function celsius2fahrenheit(degC) + return degC*1.8+32 + end + + -- Get temperature at position in degrees Celsius. + local T=position:GetTemperature() + + -- Correct unit system. + local _T=string.format('%d°F', celsius2fahrenheit(T)) + if settings:IsMetric() then + _T=string.format('%d°C', T) + end + + -- Message text. + local text=text..string.format("Temperature %s\n", _T) + + -- Get wind direction and speed. + local Dir,Vel=position:GetWind() + + -- Get Beaufort wind scale. + local Bn,Bd=UTILS.BeaufortScale(Vel) + + -- Formatted wind direction. + local Ds = string.format('%03d°', Dir) + + -- Velocity in player units. + local Vs=string.format('%.1f m/s', Vel) + if settings:IsImperial() then + Vs=string.format("%.1f knots", Vel*1.94384) + end + + -- Message text. + local text=text..string.format("Wind from %s at %s (%s).", Ds, Vs, Bd) + + -- Send message + self:_DisplayMessageToGroup(self.player[id].unit, text, self.mdur, true) + +end + --- Report pressure. -- @param #PSEUDOATC self -- @param #number id Group id to which the report is delivered. @@ -534,12 +595,20 @@ function PSEUDOATC:ReportPressure(id, Qcode, position, location) P=position:GetPressure() -- Get pressure at (land) height of position. end + -- Settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + -- Unit conversion. local P_inHg=P * PSEUDOATC.unit.hPa2inHg local P_mmHg=P * PSEUDOATC.unit.hPa2mmHg + + local P_set=string.format("%.2f inHg", P_inHg) + if settings:IsMetric() then + P_set=string.format("%.1f mmHg", P_mmHg) + end -- Message text. - local text=string.format("%s at %s: P = %.1f hPa = %.2f inHg = %.1f mmHg.", Qcode, location, P, P_inHg, P_mmHg) + local text=string.format("%s at %s: P = %.1f hPa = %s.", Qcode, location, P, P_set) -- Send message. MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) @@ -565,8 +634,17 @@ function PSEUDOATC:ReportTemperature(id, position, location) local Tc=string.format('%d°C', T) local Tf=string.format('%d°F', celsius2fahrenheit(T)) + -- Settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + + -- Correct unit system. + local _T=string.format('%d°F', celsius2fahrenheit(T)) + if settings:IsMetric() then + _T=string.format('%d°C', T) + end + -- Message text. - local text=string.format("Temperature at %s is %s = %s", location, Tc, Tf) + local text=string.format("Temperature at %s is %s", location, _T) -- Send message to player group. MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) @@ -589,8 +667,17 @@ function PSEUDOATC:ReportWind(id, position, location) -- Formatted wind direction. local Ds = string.format('%03d°', Dir) + -- Settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + + -- Velocity in player units. + local Vs=string.format('%.1f m/s', Vel) + if settings:IsImperial() then + Vs=string.format("%.1f knots", Vel*1.94384) + end + -- Message text. - local text=string.format("%s: Wind from %s at %.1f m/s (%s).", location, Ds, Vel, Bd) + local text=string.format("%s: Wind from %s at %s (%s).", location, Ds, Vs, Bd) -- Send message to player group. MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) @@ -614,10 +701,18 @@ function PSEUDOATC:ReportBR(id, position, location) local range=coord:Get2DDistance(position) -- Bearing string. - local Bs=string.format('%03d°', angle) + local Bs=string.format('%03d°', angle) + + -- Settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + + local Rs=string.format("%.1f km", range/1000) + if settings:IsImperial() then + Rs=string.format("%.1f NM", range/1000 * PSEUDOATC.unit.km2nm) + end -- Message text. - local text=string.format("%s: Bearing %s, Range %.1f km = %.1f NM.", location, Bs, range/1000, range/1000 * PSEUDOATC.unit.km2nm) + local text=string.format("%s: Bearing %s, Range %s.", location, Bs, Rs) -- Send message to player group. MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) @@ -627,11 +722,15 @@ end -- @param #PSEUDOATC self -- @param #number id Group id to the report is delivered. -- @param #number dt (Optional) Duration the message is displayed. +-- @param #boolean _clear (Optional) Clear previouse messages. -- @return #number Altuitude above ground. -function PSEUDOATC:ReportHeight(id, dt) +function PSEUDOATC:ReportHeight(id, dt, _clear) self:F({id=id, dt=dt}) local dt = dt or self.mdur + if _clear==nil then + _clear=false + end -- Return height [m] above ground level. local function get_AGL(p) @@ -647,11 +746,20 @@ function PSEUDOATC:ReportHeight(id, dt) local height=get_AGL(position) local callsign=unit:GetCallsign() + -- Settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + + local Hs=string.format("%d m", height) + if settings:IsMetric() then + Hs=string.format("%d ft", height*PSEUDOATC.unit.meter2feet) + end + -- Message text. - local text=string.format("%s: Your altitude is %d m = %d ft AGL.", callsign, height, height*PSEUDOATC.unit.meter2feet) + local _text=string.format("%s: Your altitude is %s AGL.", callsign, Hs) -- Send message to player group. - MESSAGE:New(text, dt):ToGroup(self.player[id].group) + --MESSAGE:New(text, dt):ToGroup(self.player[id].group) + self:_DisplayMessageToGroup(self.player[id].unit,_text, dt,_clear) -- Return height return height @@ -659,20 +767,18 @@ end ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Start DCS scheduler function. +--- Start altitude reporting scheduler. -- @param #PSEUDOATC self. -- @param #number id Group id of player unit. function PSEUDOATC:AltidudeStartTimer(id) self:F(id) -- Debug info. - if self.Debug then - env.info(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", id)) - end + self:T(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", id)) -- Start timer. --self.player[id].altimer=timer.scheduleFunction(self.ReportAltTouchdown, self, id, Tnow+2) - self.player[id].altimer, self.player[id].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, id, 0.1}, 1, 5) + self.player[id].altimer, self.player[id].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, id, 0.1, true}, 1, 5) end --- Stop/destroy DCS scheduler function for reporting altitude. @@ -681,9 +787,7 @@ end function PSEUDOATC:AltidudeStopTimer(id) -- Debug info. - if self.Debug then - env.info(PSEUDOATC.id..string.format("Stopping altitude report timer for player ID %d.", id)) - end + self:T(PSEUDOATC.id..string.format("Stopping altitude report timer for player ID %d.", id)) -- Stop timer. --timer.removeFunction(self.player[id].alttimer) @@ -752,9 +856,10 @@ function PSEUDOATC:_GetPlayerUnitAndName(_unitName) if _unitName ~= nil then local DCSunit=Unit.getByName(_unitName) local playername=DCSunit:getPlayerName() - local unit=UNIT:Find(DCSunit) - if DCSunit and unit and playername then + + if DCSunit and playername then + local unit=UNIT:Find(DCSunit) return unit, playername end end @@ -763,4 +868,30 @@ function PSEUDOATC:_GetPlayerUnitAndName(_unitName) end +--- Display message to group. +-- @param #PSEUDOATC self +-- @param Wrapper.Unit#UNIT _unit Player unit. +-- @param #string _text Message text. +-- @param #number _time Duration how long the message is displayed. +-- @param #boolean _clear Clear up old messages. +function PSEUDOATC:_DisplayMessageToGroup(_unit, _text, _time, _clear) + self:F({unit=_unit, text=_text, time=_time, clear=_clear}) + + _time=_time or self.Tmsg + if _clear==nil then + _clear=false + end + + -- Group ID. + local _gid=_unit:GetGroup():GetID() + + if _gid then + if _clear == true then + trigger.action.outTextForGroup(_gid, _text, _time, _clear) + else + trigger.action.outTextForGroup(_gid, _text, _time) + end + end + +end diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 937dc9002..a9ba91251 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -1594,6 +1594,13 @@ function RANGE:_DisplayStrafePits(_unitname) -- Pit parameters. local coord=_strafepit.coordinate --Core.Point#COORDINATE local heading=_strafepit.heading + + -- Turn heading around ==> approach heading. + if heading>180 then + heading=heading-180 + else + heading=heading+180 + end local mycoord=coord:ToStringA2G(_unit, _settings) _text=_text..string.format("\n- %s: %s - heading %03d",_strafepit.name, mycoord, heading) From c999389cda86d91ea07a8c39568ce8a62b1b838b Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 23 Apr 2018 06:51:49 +0200 Subject: [PATCH 063/170] Handler for unloading too. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 268 ++++++-- .../Moose/AI/AI_Cargo_Helicopter.lua | 35 +- Moose Development/Moose/Cargo/Cargo.lua | 20 +- Moose Development/Moose/Cargo/CargoCrate.lua | 6 +- Moose Development/Moose/Cargo/CargoGroup.lua | 20 +- .../Moose/Cargo/CargoSlingload.lua | 8 +- Moose Development/Moose/Cargo/CargoUnit.lua | 2 +- Moose Development/Moose/Core/Database.lua | 20 +- Moose Development/Moose/Core/Point.lua | 14 +- .../Moose/Wrapper/Controllable.lua | 645 +++++++++--------- 10 files changed, 600 insertions(+), 438 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 2c34615cd..68ffc7046 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -24,18 +24,21 @@ AI_CARGO_APC = { --- Creates a new AI_CARGO_APC object. -- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup +-- @param Wrapper.Group#GROUP CargoCarrier +-- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_APC -function AI_CARGO_APC:New( CargoCarrier, CargoGroup, CombatRadius ) +function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_APC - self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP + self.CargoSet = CargoSet -- Core.Set#SET_CARGO self.CombatRadius = CombatRadius - self:SetStartState( "UnLoaded" ) + self:SetStartState( "Unloaded" ) + + self:AddTransition( "Unloaded", "Pickup", "*" ) + self:AddTransition( "Loaded", "Deploy", "*" ) self:AddTransition( "*", "Load", "Boarding" ) self:AddTransition( "Boarding", "Board", "Boarding" ) @@ -46,10 +49,85 @@ function AI_CARGO_APC:New( CargoCarrier, CargoGroup, CombatRadius ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) - self:AddTransition( "*", "Guard", "Guarding" ) + self:AddTransition( "*", "Guard", "Unloaded" ) self:AddTransition( "*", "Destroyed", "Destroyed" ) + + --- Pickup Handler OnBefore for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnBeforePickup + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + -- @return #boolean + + --- Pickup Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterPickup + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + + --- Pickup Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] Pickup + -- @param #AI_CARGO_APC self + -- @param Core.Point#COORDINATE Coordinate + + --- Pickup Asynchronous Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] __Pickup + -- @param #AI_CARGO_APC self + -- @param #number Delay + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Handler OnBefore for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnBeforeDeploy + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + -- @return #boolean + + --- Deploy Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterDeploy + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] Deploy + -- @param #AI_CARGO_APC self + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Asynchronous Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] __Deploy + -- @param #AI_CARGO_APC self + -- @param Core.Point#COORDINATE Coordinate + -- @param #number Delay + + + --- Loaded Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterLoaded + -- @param #AI_CARGO_APC self + -- @param Wrapper.Group#GROUP APC + -- @param #string From + -- @param #string Event + -- @param #string To + + --- Unloaded Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterUnloaded + -- @param #AI_CARGO_APC self + -- @param Wrapper.Group#GROUP APC + -- @param #string From + -- @param #string Event + -- @param #string To + + self:__Monitor( 1 ) self:SetCarrier( CargoCarrier ) @@ -60,11 +138,11 @@ end --- Set the Carrier. -- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier -- @return #AI_CARGO_APC function AI_CARGO_APC:SetCarrier( CargoCarrier ) - self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT + self.CargoCarrier = CargoCarrier -- Wrapper.Group#GROUP self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self ) CargoCarrier:HandleEvent( EVENTS.Dead ) @@ -110,7 +188,7 @@ end -- @param #AI_CARGO_APC self -- @param Core.Point#COORDINATE Coordinate -- @param #number Radius --- @return Wrapper.Unit#UNIT NewCarrier +-- @return Wrapper.Group#GROUP NewCarrier function AI_CARGO_APC:FindCarrier( Coordinate, Radius ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) @@ -122,11 +200,12 @@ function AI_CARGO_APC:FindCarrier( Coordinate, Radius ) local Attributes = NearUnit:GetDesc() self:F({Desc=Attributes}) if NearUnit:HasAttribute( "Trucks" ) then - self:SetCarrier( NearUnit ) - break + return NearUnit:GetGroup() end end end + + return nil end @@ -135,7 +214,7 @@ end --- Follow Infantry to the Carrier. -- @param #AI_CARGO_APC self -- @param #AI_CARGO_APC Me --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier -- @param Wrapper.Group#GROUP InfantryGroup -- @return #AI_CARGO_APC function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) @@ -186,7 +265,7 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) @@ -195,32 +274,33 @@ function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) local Coordinate = CargoCarrier:GetCoordinate() self.Zone:Scan( { Object.Category.UNIT } ) if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - if self:Is( "Unloaded" ) or self:Is( "Guarding" ) or self:Is( "Following" ) then + if self:Is( "Unloaded" ) or self:Is( "Following" ) then -- There are no enemies within combat range. Load the CargoCarrier. - self:__Load( 1 ) + self:Load() end else if self:Is( "Loaded" ) then -- There are enemies within combat range. Unload the CargoCarrier. self:__Unload( 1 ) - end - end - if self:Is( "Guarding" ) then - if not self.CargoGroup:IsNear( CargoCarrier, 5 ) then - self:Follow() - end - end - if self:Is( "Following" ) then - local Distance = Coordinate:Get2DDistance( self.CargoGroup:GetCoordinate() ) - self:F( { Distance = Distance } ) - if Distance > 40 then - CargoCarrier:RouteStop() - self.CarrierStopped = true else - if self.CarrierStopped then - if self.CargoGroup:IsNear( CargoCarrier, 10 ) then - CargoCarrier:RouteResume() - self.CarrierStopped = nil + if self:Is( "Unloaded" ) then + if not self.Cargo:IsNear( CargoCarrier, 5 ) then + self:Follow() + end + end + if self:Is( "Following" ) then + local Distance = Coordinate:Get2DDistance( self.Cargo:GetCoordinate() ) + self:F( { Distance = Distance } ) + if Distance > 40 then + CargoCarrier:RouteStop() + self.CarrierStopped = true + else + if self.CarrierStopped then + if self.Cargo:IsNear( CargoCarrier, 10 ) then + CargoCarrier:RouteResume() + self.CarrierStopped = nil + end + end end end end @@ -236,66 +316,77 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_APC:onafterLoad( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC:onbeforeLoad( Carrier, From, Event, To ) + self:F( { Carrier, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteStop() - self:__Board( 10 ) - self.CargoGroup:Board( CargoCarrier, 10 ) + if Carrier and Carrier:IsAlive() then + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( Cargo ) + if Cargo:IsInLoadRadius( Carrier:GetCoordinate() ) then + self:F( "In radius" ) + Carrier:RouteStop() + self:__Board( 1, Cargo ) + Cargo:Board( Carrier:GetUnit(1), 25 ) + return true + end + end end + return false + end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_APC:onafterBoard( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC:onafterBoard( Carrier, From, Event, To, Cargo ) + self:F( { Carrier, From, Event, To, Cargo } ) - if CargoCarrier and CargoCarrier:IsAlive() then - self:F({ IsLoaded = self.CargoGroup:IsLoaded() } ) - if not self.CargoGroup:IsLoaded() then - self:__Board( 10 ) + if Carrier and Carrier:IsAlive() then + self:F({ IsLoaded = Cargo:IsLoaded() } ) + if not Cargo:IsLoaded() then + self:__Board( 10, Cargo ) else - self:__Loaded( 1 ) + self:__Loaded( 1, Cargo ) end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP CargoCarrier +function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To, Cargo ) + self:F( { CargoCarrier, From, Event, To, Cargo } ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteResume() + self.Cargo = Cargo end end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterUnload( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() - self.CargoGroup:UnBoard( ) + self.Cargo:UnBoard() self:__Unboard( 10 ) end end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then - if not self.CargoGroup:IsUnLoaded() then + if not self.Cargo:IsUnLoaded() then self:__Unboard( 10 ) else self:__Unloaded( 1 ) @@ -305,7 +396,7 @@ function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterUnloaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) @@ -319,13 +410,13 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) self:F( "Follow" ) if CargoCarrier and CargoCarrier:IsAlive() then - self.CargoGroup.CargoSet:ForEach( + self.Cargo.CargoSet:ForEach( --- @param Core.Cargo#CARGO Cargo function( Cargo ) self:F( { "Follow", Cargo.CargoObject:GetName() } ) @@ -339,3 +430,66 @@ function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) end + +--- @param #AI_CARGO_APC +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC._Pickup( Carrier ) + + Carrier:F( { "AI_CARGO_APC._Pickup:", Carrier:GetName() } ) + + if Carrier:IsAlive() then + Carrier:__Load( 1 ) + end +end + + +--- @param #AI_CARGO_APC +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC._Deploy( Carrier ) + + Carrier:F( { "AI_CARGO_APC._Deploy:", Carrier:GetName() } ) + + if Carrier:IsAlive() then + Carrier:__Unload( 1 ) + end +end + + + +--- @param #AI_CARGO_APC self +-- @param Wrapper.Group#GROUP Carrier +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_APC:onafterPickup( Carrier, From, Event, To, Coordinate, Speed ) + + if Carrier and Carrier:IsAlive() then + + self.RoutePickup = true + + Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + end + +end + + +--- @param #AI_CARGO_APC self +-- @param Wrapper.Group#GROUP Carrier +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_APC:onafterDeploy( Carrier, From, Event, To, Coordinate, Speed ) + + if Carrier and Carrier:IsAlive() then + + self.RouteDeploy = true + + Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + end + +end + diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 05afee6a4..ad502c322 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -24,7 +24,7 @@ AI_CARGO_HELICOPTER = { --- Creates a new AI_CARGO_HELICOPTER object. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_HELICOPTER @@ -116,13 +116,13 @@ end --- Set the Carrier. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @return #AI_CARGO_HELICOPTER function AI_CARGO_HELICOPTER:SetCarrier( Helicopter ) local AICargo = self - self.Helicopter = Helicopter -- Wrapper.Unit#UNIT + self.Helicopter = Helicopter -- Wrapper.Group#GROUP self.Helicopter:SetState( self.Helicopter, "AI_CARGO_HELICOPTER", self ) self.RoutePickup = false @@ -173,7 +173,7 @@ end -- @param #AI_CARGO_HELICOPTER self -- @param Core.Point#COORDINATE Coordinate -- @param #number Radius --- @return Wrapper.Unit#UNIT NewCarrier +-- @return Wrapper.Group#GROUP NewCarrier function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) @@ -183,18 +183,19 @@ function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) self:F({NearUnit=NearUnit}) if not NearUnit:GetState( NearUnit, "AI_CARGO_HELICOPTER" ) then local Attributes = NearUnit:GetDesc() - self:F({Desc=Attributes}) + self:F({Attributes=Attributes}) if NearUnit:HasAttribute( "Trucks" ) then - self:SetCarrier( NearUnit ) - break + return NearUnit:GetGroup() end end end + + return nil end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param From -- @param Event -- @param To @@ -221,7 +222,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param From -- @param Event -- @param To @@ -276,7 +277,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param From -- @param Event -- @param To @@ -331,7 +332,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinate ) if Helicopter and Helicopter:IsAlive() then @@ -339,7 +340,7 @@ function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinat for _, Cargo in pairs( self.CargoSet:GetSet() ) do if Cargo:IsInLoadRadius( Coordinate ) then self:__Board( 5 ) - Cargo:Board( Helicopter, 25 ) + Cargo:Board( Helicopter:GetUnit(1), 25 ) self.Cargo = Cargo break end @@ -349,7 +350,7 @@ function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinat end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -364,7 +365,7 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -374,7 +375,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -385,7 +386,7 @@ function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -399,7 +400,7 @@ function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 446d58da4..6c2bbe033 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -566,14 +566,14 @@ do -- CARGO --- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded. -- @param #CARGO self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the CargoGroup is within the loading radius. function CARGO:IsInLoadRadius( Coordinate ) self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -586,14 +586,14 @@ do -- CARGO --- Check if the Cargo can report itself to be Boarded or Loaded. -- @param #CARGO self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo can report itself. function CARGO:IsInReportRadius( Coordinate ) self:F( { Coordinate } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -606,18 +606,18 @@ do -- CARGO --- Check if CargoCarrier is near the Cargo to be Loaded. -- @param #CARGO self - -- @param Core.Point#POINT_VEC2 PointVec2 + -- @param Core.Point#COORDINATE Coordinate -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean - function CARGO:IsNear( PointVec2, NearRadius ) + function CARGO:IsNear( Coordinate, NearRadius ) --self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) if self.CargoObject:IsAlive() then - --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + --local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) --self:F( { CargoObjectName = self.CargoObject:GetName() } ) --self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) --self:F( { PointVec2 = PointVec2:GetVec2() } ) - local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) + local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) --self:F( Distance ) if Distance <= NearRadius then @@ -979,9 +979,9 @@ end function CARGO_PACKAGE:IsNear( CargoCarrier ) self:F() - local CargoCarrierPoint = CargoCarrier:GetPointVec2() + local CargoCarrierPoint = CargoCarrier:GetCoordinate() - local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() ) self:T( Distance ) if Distance <= self.NearRadius then diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 18c49a4db..7fc3a7293 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -166,14 +166,14 @@ do -- CARGO_CRATE --- Check if Cargo Crate is in the radius for the Cargo to be reported. -- @param #CARGO self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_CRATE:IsInReportRadius( Coordinate ) --self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) --self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -193,7 +193,7 @@ do -- CARGO_CRATE local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) --self:T( Distance ) if Distance <= self.NearRadius then return true diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index ab7addf54..d71c81a16 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -58,8 +58,9 @@ do -- CARGO_GROUP local WeightGroup = 0 - self.GroupName = CargoGroup:GetName() - self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) + local GroupName = CargoGroup:GetName() + local CargoName = GroupName:match("(.*)~CARGO") or GroupName + self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) ) CargoGroup:Destroy() @@ -67,11 +68,11 @@ do -- CARGO_GROUP for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - local GroupName = env.getValueDictByKey( GroupTemplate.name ) + --local GroupName = env.getValueDictByKey( GroupTemplate.name ) -- We create a new group object with one unit... -- First we prepare the template... - GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.name = CargoName .. "#CARGO#" .. UnitID GroupTemplate.groupId = nil GroupTemplate.units = {} GroupTemplate.units[1] = UnitTemplate @@ -442,7 +443,7 @@ do -- CARGO_GROUP --- Check if Cargo Group is in the radius for the Cargo to be Boarded. -- @param #CARGO_GROUP self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Group is within the load radius. function CARGO_GROUP:IsInLoadRadius( Coordinate ) --self:F( { Coordinate } ) @@ -452,12 +453,12 @@ do -- CARGO_GROUP if Cargo then local Distance = 0 if Cargo:IsLoaded() then - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoCarrier:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( Cargo.CargoCarrier:GetCoordinate() ) else - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) end - --self:T( Distance ) + self:F( { Distance = Distance, LoadRadius = self.LoadRadius } ) if Distance <= self.LoadRadius then return true else @@ -480,9 +481,10 @@ do -- CARGO_GROUP local Cargo = self.CargoSet:GetFirst() -- #CARGO if Cargo then + self:F( { Cargo } ) local Distance = 0 if Cargo:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) --self:T( Distance ) if Distance <= self.LoadRadius then return true diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 642fde94f..cb7898175 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -119,14 +119,14 @@ do -- CARGO_SLINGLOAD --- Check if Cargo Crate is in the radius for the Cargo to be reported. -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_SLINGLOAD:IsInReportRadius( Coordinate ) --self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) if Distance <= self.LoadRadius then return true end @@ -138,14 +138,14 @@ do -- CARGO_SLINGLOAD --- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded. -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Slingload is within the loading radius. function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate ) --self:F( { Coordinate } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) if Distance <= self.NearRadius then return true end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 318852cb1..d28d113a7 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -49,7 +49,7 @@ do -- CARGO_UNIT -- @return #CARGO_UNIT function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT - self:F( { Type, Name, Weight, NearRadius } ) + self:I( { Type, Name, Weight, NearRadius } ) self:T( CargoUnit ) self.CargoObject = CargoUnit diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 262175514..6173a355b 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -284,7 +284,7 @@ do -- cargo TemplateName = env.getValueDictByKey( TemplateName ) - local Cargo = TemplateName:match( "#(CARGO)" ) + local Cargo = TemplateName:match( "~(CARGO)" ) return Cargo and Cargo == "CARGO" end @@ -293,6 +293,7 @@ do -- cargo -- @param #DATABASE self -- @return #DATABASE self function DATABASE:RegisterCargos() + for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do if self:IsCargo( CargoGroupName ) then @@ -300,11 +301,12 @@ do -- cargo local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") local CargoName = CargoGroupName:match("(.*)~CARGO") local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") - local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") - local LoadRadius = CargoParam and CargoParam:match( "RR=([%a%d]+),?") - local NearRadius = CargoParam and CargoParam:match( "NR=([%a%d]+),?") + local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName + local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) + local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) - CARGO_GROUP:New( CargoGroup, Type, Name or CargoName, LoadRadius, NearRadius ) + self:F({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius ) end end @@ -315,15 +317,17 @@ do -- cargo local CargoName = CargoStaticName:match("(.*)~CARGO") local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?") - local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") + local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) if Category == "SLING" then - CARGO_SLINGLOAD:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius ) + self:F({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) else if Category == "CRATE" then - CARGO_CRATE:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius ) + self:F({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) end end end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index de1a81cfc..15d9cf436 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -274,21 +274,19 @@ do -- COORDINATE - --TODO: check this to replace - --- Calculate the distance from a reference @{DCSTypes#Vec2}. + --- Calculate the distance from a reference @{#COORDINATE}. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Vec2 Vec2Reference The reference @{DCSTypes#Vec2}. - -- @return Dcs.DCSTypes#Distance The distance from the reference @{DCSTypes#Vec2} in meters. - function COORDINATE:DistanceFromVec2( Vec2Reference ) - self:F2( Vec2Reference ) + -- @param #COORDINATE PointVec2Reference The reference @{#COORDINATE}. + -- @return Dcs.DCSTypes#Distance The distance from the reference @{#COORDINATE} in meters. + function COORDINATE:DistanceFromPointVec2( PointVec2Reference ) + self:F2( PointVec2Reference ) - local Distance = ( ( Vec2Reference.x - self.x ) ^ 2 + ( Vec2Reference.y - self.z ) ^2 ) ^0.5 + local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5 self:T2( Distance ) return Distance end - --- Add a Distance in meters from the COORDINATE orthonormal plane, with the given angle, and calculate the new COORDINATE. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 0b68255c5..c63a94af8 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1761,351 +1761,354 @@ function CONTROLLABLE:TaskRoute( Points ) return DCSTask end ---- (AIR + GROUND) Make the Controllable move to fly to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:RouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) +do -- Route methods - local ControllablePoint = self:GetUnit( 1 ):GetVec2() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.y - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - ---- (AIR + GROUND) Make the Controllable move to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:RouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local ControllableVec3 = self:GetUnit( 1 ):GetVec3() - - local PointFrom = {} - PointFrom.x = ControllableVec3.x - PointFrom.y = ControllableVec3.z - PointFrom.alt = ControllableVec3.y - PointFrom.alt_type = "BARO" - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.z - PointTo.alt = Point.y - PointTo.alt_type = "BARO" - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - - - ---- Make the controllable to follow a given route. --- @param #CONTROLLABLE self --- @param #table Route A table of Route Points. --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:Route( Route, DelaySeconds ) - self:F2( Route ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route. - self:SetTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1). - return self - end - - return nil -end - - ---- Stops the movement of the vehicle on the route. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE -function CONTROLLABLE:RouteStop() - self:F("RouteStop") + --- (AIR + GROUND) Make the Controllable move to fly to a given point. + -- @param #CONTROLLABLE self + -- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. + -- @param #number Speed The speed to travel. + -- @return #CONTROLLABLE self + function CONTROLLABLE:RouteToVec2( Point, Speed ) + self:F2( { Point, Speed } ) - local CommandStop = self:CommandStopRoute( true ) - self:SetCommand( CommandStop ) - -end - ---- Resumes the movement of the vehicle on the route. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE -function CONTROLLABLE:RouteResume() - self:F("RouteResume") + local ControllablePoint = self:GetUnit( 1 ):GetVec2() - local CommandResume = self:CommandStopRoute( false ) - self:SetCommand( CommandResume ) - -end - ---- Make the GROUND Controllable to drive towards a specific point. --- @param #CONTROLLABLE self --- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. --- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. --- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds ) - - local FromCoordinate = self:GetCoordinate() - - local FromWP = FromCoordinate:WaypointGround() - local ToWP = ToCoordinate:WaypointGround( Speed, Formation ) - - self:Route( { FromWP, ToWP }, DelaySeconds ) - - return self -end - ---- Make the GROUND Controllable to drive towards a specific point using (only) roads. --- @param #CONTROLLABLE self --- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. --- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:RouteGroundOnRoad( ToCoordinate, Speed, DelaySeconds ) - - -- Current coordinate. - local FromCoordinate = self:GetCoordinate() - - -- Formation is set to on road. - local Formation="On Road" - - -- Path on road from current position to destination coordinate. - local path=FromCoordinate:GetPathOnRoad(ToCoordinate) - - -- Route, ground waypoints along roads. - local route={} - table.insert(route, FromCoordinate:WaypointGround(Speed, Formation)) - - -- Convert coordinates to ground waypoints and insert into table. - for _, coord in ipairs(path) do - table.insert(route, coord:WaypointGround(Speed, Formation)) - end - - -- Add the final coordinate because the final coordinate in path is last point on road. - local dist=ToCoordinate:Get2DDistance(path[#path]) - if dist>10 then - table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee")) - end - - -- Route controllable to destination. - self:Route(route, DelaySeconds) - - return self -end - - ---- Make the AIR Controllable fly towards a specific point. --- @param #CONTROLLABLE self --- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. --- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type. --- @param Core.Point#COORDINATE.RoutePointType Type The route point type. --- @param Core.Point#COORDINATE.RoutePointAction Action The route point action. --- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds ) - - local FromCoordinate = self:GetCoordinate() - local FromWP = FromCoordinate:WaypointAir() - - local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed ) - - self:Route( { FromWP, ToWP }, DelaySeconds ) - - return self -end - - ---- (AIR + GROUND) Route the controllable to a given zone. --- The controllable final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param Core.Zone#ZONE Zone The zone where to route to. --- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. --- @param #number Speed The speed. --- @param Base#FORMATION Formation The formation string. -function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - local PointFrom = {} PointFrom.x = ControllablePoint.x PointFrom.y = ControllablePoint.y PointFrom.type = "Turning Point" - PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 - - + PointFrom.action = "Turning Point" + PointFrom.speed = Speed + PointFrom.speed_locked = true + PointFrom.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local PointTo = {} - local ZonePoint - - if Randomize then - ZonePoint = Zone:GetRandomVec2() - else - ZonePoint = Zone:GetVec2() - end - - PointTo.x = ZonePoint.x - PointTo.y = ZonePoint.y + PointTo.x = Point.x + PointTo.y = Point.y PointTo.type = "Turning Point" - - if Formation then - PointTo.action = Formation - else - PointTo.action = "Cone" - end - - if Speed then - PointTo.speed = Speed - else - PointTo.speed = 20 / 1.6 - end - + PointTo.action = "Fly Over Point" + PointTo.speed = Speed + PointTo.speed_locked = true + PointTo.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local Points = { PointFrom, PointTo } - + self:T3( Points ) - + self:Route( Points ) - + return self end - - return nil -end - ---- (GROUND) Route the controllable to a given Vec2. --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param #Vec2 Vec2 The Vec2 where to route to. --- @param #number Speed The speed. --- @param Base#FORMATION Formation The formation string. -function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - + + --- (AIR + GROUND) Make the Controllable move to a given point. + -- @param #CONTROLLABLE self + -- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. + -- @param #number Speed The speed to travel. + -- @return #CONTROLLABLE self + function CONTROLLABLE:RouteToVec3( Point, Speed ) + self:F2( { Point, Speed } ) + + local ControllableVec3 = self:GetUnit( 1 ):GetVec3() + local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y + PointFrom.x = ControllableVec3.x + PointFrom.y = ControllableVec3.z + PointFrom.alt = ControllableVec3.y + PointFrom.alt_type = "BARO" PointFrom.type = "Turning Point" - PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 - - + PointFrom.action = "Turning Point" + PointFrom.speed = Speed + PointFrom.speed_locked = true + PointFrom.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local PointTo = {} - - PointTo.x = Vec2.x - PointTo.y = Vec2.y + PointTo.x = Point.x + PointTo.y = Point.z + PointTo.alt = Point.y + PointTo.alt_type = "BARO" PointTo.type = "Turning Point" - - if Formation then - PointTo.action = Formation - else - PointTo.action = "Cone" - end - - if Speed then - PointTo.speed = Speed - else - PointTo.speed = 60 / 3.6 - end - + PointTo.action = "Fly Over Point" + PointTo.speed = Speed + PointTo.speed_locked = true + PointTo.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local Points = { PointFrom, PointTo } - + self:T3( Points ) - + self:Route( Points ) - + return self end + + + + --- Make the controllable to follow a given route. + -- @param #CONTROLLABLE self + -- @param #table Route A table of Route Points. + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:Route( Route, DelaySeconds ) + self:F2( Route ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route. + self:SetTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1). + return self + end + + return nil + end + + + --- Stops the movement of the vehicle on the route. + -- @param #CONTROLLABLE self + -- @return #CONTROLLABLE + function CONTROLLABLE:RouteStop() + self:F("RouteStop") + + local CommandStop = self:CommandStopRoute( true ) + self:SetCommand( CommandStop ) + + end + + --- Resumes the movement of the vehicle on the route. + -- @param #CONTROLLABLE self + -- @return #CONTROLLABLE + function CONTROLLABLE:RouteResume() + self:F("RouteResume") + + local CommandResume = self:CommandStopRoute( false ) + self:SetCommand( CommandResume ) + + end + + --- Make the GROUND Controllable to drive towards a specific point. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds ) + + local FromCoordinate = self:GetCoordinate() + + local FromWP = FromCoordinate:WaypointGround() + local ToWP = ToCoordinate:WaypointGround( Speed, Formation ) + + self:Route( { FromWP, ToWP }, DelaySeconds ) + + return self + end + + --- Make the GROUND Controllable to drive towards a specific point using (only) roads. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteGroundOnRoad( ToCoordinate, Speed, DelaySeconds ) + + -- Current coordinate. + local FromCoordinate = self:GetCoordinate() + + -- Formation is set to on road. + local Formation="On Road" + + -- Path on road from current position to destination coordinate. + local path=FromCoordinate:GetPathOnRoad(ToCoordinate) + + -- Route, ground waypoints along roads. + local route={} + table.insert(route, FromCoordinate:WaypointGround(Speed, Formation)) + + -- Convert coordinates to ground waypoints and insert into table. + for _, coord in ipairs(path) do + table.insert(route, coord:WaypointGround(Speed, Formation)) + end + + -- Add the final coordinate because the final coordinate in path is last point on road. + local dist=ToCoordinate:Get2DDistance(path[#path]) + if dist>10 then + table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee")) + end + + -- Route controllable to destination. + self:Route(route, DelaySeconds) + + return self + end + + + --- Make the AIR Controllable fly towards a specific point. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type. + -- @param Core.Point#COORDINATE.RoutePointType Type The route point type. + -- @param Core.Point#COORDINATE.RoutePointAction Action The route point action. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds ) + + local FromCoordinate = self:GetCoordinate() + local FromWP = FromCoordinate:WaypointAir() + + local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed ) + + self:Route( { FromWP, ToWP }, DelaySeconds ) + + return self + end + + + --- (AIR + GROUND) Route the controllable to a given zone. + -- The controllable final destination point can be randomized. + -- A speed can be given in km/h. + -- A given formation can be given. + -- @param #CONTROLLABLE self + -- @param Core.Zone#ZONE Zone The zone where to route to. + -- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. + -- @param #number Speed The speed. + -- @param Base#FORMATION Formation The formation string. + function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) + self:F2( Zone ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local ControllablePoint = self:GetVec2() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.y + PointFrom.type = "Turning Point" + PointFrom.action = Formation or "Cone" + PointFrom.speed = 20 / 1.6 + + + local PointTo = {} + local ZonePoint + + if Randomize then + ZonePoint = Zone:GetRandomVec2() + else + ZonePoint = Zone:GetVec2() + end + + PointTo.x = ZonePoint.x + PointTo.y = ZonePoint.y + PointTo.type = "Turning Point" + + if Formation then + PointTo.action = Formation + else + PointTo.action = "Cone" + end + + if Speed then + PointTo.speed = Speed + else + PointTo.speed = 20 / 1.6 + end + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self + end + + return nil + end + + --- (GROUND) Route the controllable to a given Vec2. + -- A speed can be given in km/h. + -- A given formation can be given. + -- @param #CONTROLLABLE self + -- @param #Vec2 Vec2 The Vec2 where to route to. + -- @param #number Speed The speed. + -- @param Base#FORMATION Formation The formation string. + function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local ControllablePoint = self:GetVec2() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.y + PointFrom.type = "Turning Point" + PointFrom.action = Formation or "Cone" + PointFrom.speed = 20 / 1.6 + + + local PointTo = {} + + PointTo.x = Vec2.x + PointTo.y = Vec2.y + PointTo.type = "Turning Point" + + if Formation then + PointTo.action = Formation + else + PointTo.action = "Cone" + end + + if Speed then + PointTo.speed = Speed + else + PointTo.speed = 60 / 3.6 + end + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self + end + + return nil + end - return nil -end - +end -- Route methods -- Commands From 7dbc9436ed64fcc2b41632b7e0aa31949dfd7b00 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 24 Apr 2018 00:29:09 +0200 Subject: [PATCH 064/170] PseudoATC restructured menu --- .../Moose/Functional/PseudoATC.lua | 85 ++++++++++--------- Moose Development/Moose/Functional/Range.lua | 3 + 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 6295fc646..3d17615a7 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -70,7 +70,7 @@ PSEUDOATC={ ClassName = "PSEUDOATC", Debug=false, player={}, - maxairport=9, + maxairport=10, mdur=30, mrefresh=120, eventsmoose=true, @@ -231,8 +231,16 @@ function PSEUDOATC:_PlayerLanded(EventData) -- Get unit, player and place. local _unitName=EventData.IniUnitName local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) - local _base=EventData.Place - local _baseName=EventData.PlaceName + local _base=nil + local _baseName=nil + if EventData.place then + _base=EventData.place + _baseName=EventData.place:getName() + end +-- if EventData.subplace then +-- local _subPlace=EventData.subplace +-- local _subPlaceName=EventData.subplace:getName() +-- end -- Call landed function. if _unit and _playername and _base then @@ -300,12 +308,13 @@ function PSEUDOATC:PlayerLanded(unit, place) local group=unit:GetGroup() local id=group:GetID() local PlayerName=self.player[id].playername - local UnitName=self.player[id].playername + local Callsign=self.player[id].callsign + local UnitName=self.player[id].unitname local GroupName=self.player[id].groupname local CallSign=self.player[id].callsign -- Debug message. - local text=string.format("Player %s (%s) from group %s with ID %d landed at %s", PlayerName, UnitName, GroupName, place) + local text=string.format("Player %s (%s) from group %s (ID %d) landed at %s", PlayerName, UnitName, GroupName, id, place) self:T(PSEUDOATC.id..text) MESSAGE:New(text, 30):ToAllIf(self.Debug) @@ -368,26 +377,28 @@ function PSEUDOATC:MenuRefresh(id) self:LocalAirports(id) -- Create submenu My Positon. - self:MenuAircraft(id) + --self:MenuAircraft(id) -- Create submenu airports. self:MenuAirports(id) end ---- Clear player menues. +--- Clear player menus. -- @param #PSEUDOATC self. -- @param #number id Group id of player unit. function PSEUDOATC:MenuClear(id) self:F(id) -- Debug message. - local text=string.format("Clearing menues for player %s in group %s.", self.player[id].playername, self.player[id].groupname) + local text=string.format("Clearing menus for player %s in group %s.", self.player[id].playername, self.player[id].groupname) self:T(PSEUDOATC.id..text) MESSAGE:New(text,30):ToAllIf(self.Debug) if self.player[id].menu_airports then + missionCommands.removeItemForGroup(id, self.player[id].menu_airports) + --[[ for name,item in pairs(self.player[id].menu_airports) do -- Debug message. @@ -396,7 +407,7 @@ function PSEUDOATC:MenuClear(id) -- Remove menu item. missionCommands.removeItemForGroup(id, self.player[id].menu_airports[name]) end - + ]] else self:T2(PSEUDOATC.id.."No airports to clear menus.") end @@ -407,7 +418,7 @@ function PSEUDOATC:MenuClear(id) end self.player[id].menu_airports=nil - self.player[id].menu_aircraft=nil + --self.player[id].menu_aircraft=nil end --- Create "F10/Pseudo ATC" menu items "Airport Data". @@ -417,7 +428,7 @@ function PSEUDOATC:MenuAirports(id) self:F(id) -- Table for menu entries. - self.player[id].menu_airports={} + self.player[id].menu_airports=missionCommands.addSubMenuForGroup(id, "Airports", self.player[id].menu_main) local i=0 for _,airport in pairs(self.player[id].airports) do @@ -432,15 +443,15 @@ function PSEUDOATC:MenuAirports(id) local pos=AIRBASE:FindByName(name):GetCoordinate() --F10menu_ATC_airports[ID][name] = missionCommands.addSubMenuForGroup(ID, name, F10menu_ATC) - local submenu=missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) - self.player[id].menu_airports[name]=submenu + local submenu=missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_airports) + --self.player[id].menu_airports[name]=submenu -- Create menu reporting commands missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, name) - missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, name) - missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, name) - missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, name) - missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, name) + --missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, name) + --missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, name) + --missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, name) + --missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, name) missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, name) -- Debug message. @@ -455,7 +466,7 @@ function PSEUDOATC:MenuAircraft(id) self:F(id) -- Table for menu entries. - self.player[id].menu_aircraft={} + --self.player[id].menu_aircraft={} local unit=self.player[id].unit --Wrapper.Unit#UNIT local callsign=self.player[id].callsign @@ -465,14 +476,13 @@ function PSEUDOATC:MenuAircraft(id) self:T(PSEUDOATC.id..string.format("Creating menu item %s for ID %d", name,id)) -- F10/PseudoATC/My Aircraft (callsign) - self.player[id].menu_aircraft.main = missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) + --self.player[id].menu_aircraft.main = missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) + - -- F10/PseudoATC/My Aircraft (callsign)/Waypoints if #self.player[id].waypoints>0 then - --F10menu_ATC_waypoints[ID]={} - self.player[id].menu_aircraft_waypoints={} - self.player[id].menu_aircraft_waypoints.main=missionCommands.addSubMenuForGroup(id, "Waypoints", self.player[id].menu_aircraft.main) + -- F10/PseudoATC/Waypoints + self.player[id].menu_waypoints=missionCommands.addSubMenuForGroup(id, "Waypoints", self.player[id].menu_main) local j=0 for i, wp in pairs(self.player[id].waypoints) do @@ -483,27 +493,26 @@ function PSEUDOATC:MenuAircraft(id) break -- max ten menu entries end + -- Position of Waypoint local pos=COORDINATE:New(wp.x,wp.alt,wp.z) - - local fname=string.format("Waypoint %d for %s", i-1, callsign) - local pname=string.format("Waypoint %d", i-1) + local name=string.format("Waypoint %d", i-1) - -- "F10/PseudoATC/My Aircraft (callsign)/Waypoints/Waypoint X" - local submenu=missionCommands.addSubMenuForGroup(id, pname, self.player[id].menu_aircraft_waypoints.main) - self.player[id].menu_aircraft_waypoints.pname=submenu + -- "F10/PseudoATC/Waypoints/Waypoint X" + local submenu=missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_waypoints) -- Menu commands for each waypoint "F10/PseudoATC/My Aircraft (callsign)/Waypoints/Waypoint X/" - missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, pname) - missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, pname) - missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, pname) - missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, pname) - missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, pname) - missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, pname) + missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, name) + --missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, pname) + --missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, pname) + --missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, pname) + --missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, pname) + missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, name) end end - missionCommands.addCommandForGroup(id, "Request current altitude AGL", self.player[id].menu_aircraft.main, self.ReportHeight, self, id) - missionCommands.addCommandForGroup(id, "Report altitude until touchdown", self.player[id].menu_aircraft.main, self.AltidudeStartTimer, self, id) - missionCommands.addCommandForGroup(id, "Quit reporting altitude", self.player[id].menu_aircraft.main, self.AltidudeStopTimer, self, id) + + missionCommands.addCommandForGroup(id, "Request current altitude AGL", self.player[id].menu_main, self.ReportHeight, self, id) + missionCommands.addCommandForGroup(id, "Report altitude until touchdown", self.player[id].menu_main, self.AltidudeStartTimer, self, id) + missionCommands.addCommandForGroup(id, "Quit reporting altitude", self.player[id].menu_main, self.AltidudeStopTimer, self, id) end ----------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index a9ba91251..bf8cbb193 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -211,6 +211,9 @@ -- -- The function @{#RANGE.DebugON}() can be used to send messages on screen. It also smokes all defined strafe and bombing targets, the strafe pit approach boxes and the range zone. -- +-- Note that it can happen that the RANGE radio menu is not shown. Check that the range object is defined as a **global** variable rather than a local one. +-- The could avoid the lua garbage collection to accidentally/falsely deallocate the RANGE objects. +-- -- -- -- @field #RANGE From 441fba0830522e8f1f3cef6133a3437edbf6dd2d Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 24 Apr 2018 21:12:35 +0200 Subject: [PATCH 065/170] PseudoATC Fixed waypoints BR --- Moose Development/Moose/Functional/PseudoATC.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 3d17615a7..d70e9d069 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -68,7 +68,7 @@ -- @field #PSEUDOATC PSEUDOATC={ ClassName = "PSEUDOATC", - Debug=false, + Debug=true, player={}, maxairport=10, mdur=30, @@ -477,8 +477,7 @@ function PSEUDOATC:MenuAircraft(id) -- F10/PseudoATC/My Aircraft (callsign) --self.player[id].menu_aircraft.main = missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) - - + if #self.player[id].waypoints>0 then -- F10/PseudoATC/Waypoints @@ -494,7 +493,7 @@ function PSEUDOATC:MenuAircraft(id) end -- Position of Waypoint - local pos=COORDINATE:New(wp.x,wp.alt,wp.z) + local pos=COORDINATE:New(wp.x, wp.alt, wp.y) local name=string.format("Waypoint %d", i-1) -- "F10/PseudoATC/Waypoints/Waypoint X" @@ -705,7 +704,8 @@ function PSEUDOATC:ReportBR(id, position, location) local coord=unit:GetCoordinate() -- Direction vector from current position (coord) to target (position). - local vec3=coord:GetDirectionVec3(position) + local pos=coord:Translate(30,90) + local vec3=coord:GetDirectionVec3(pos) local angle=coord:GetAngleDegrees(vec3) local range=coord:Get2DDistance(position) From 33271edf78a8bc03c74c18c71984c1f95f11f300 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 24 Apr 2018 23:38:41 +0200 Subject: [PATCH 066/170] Added ARTY class First draft... --- .../Moose/Functional/Artillery.lua | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 Moose Development/Moose/Functional/Artillery.lua diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua new file mode 100644 index 000000000..0695ae427 --- /dev/null +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -0,0 +1,267 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- **Functional** - Control artillery units. +-- +-- ![Banner Image](..\Presentations\ARTILLERY\Artillery_Main.png) +-- +-- ==== +-- +-- Make artillery fire on targets. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) +-- +-- === +-- +-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** +-- +-- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- +-- ==== +-- @module Arty + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- ARTY class +-- @type ARTY +-- @field #string ClassName Name of the class. +-- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players. +-- @field #table targets Targets assigned. +-- @extends Core.Fsm#FSM_CONTROLLABLE +-- + +---# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE} +-- Artillery class.. +-- +-- ## Target aquisition... +-- +-- ![Process](..\Presentations\ART\Arty_Process.png) +-- +-- The arty process can be described as follows. +-- +-- ### Submenu +-- +-- @field #ARTY +ARTY={ + ClassName = "ARTY", + Debug = false, + targets = {}, +} + +--- Enumerator of possible rules of engagement. +-- @field #list ROE +ARTY.ROE={ + Hold="Weapon Hold", + Free="Weapon Free", + Return="Return Fire", +} + +--- Enumerator of possible alarm states. +-- @field #list AlarmState +ARTY.AlarmState={ + Auto="Auto", + Green="Green", + Red="Red", +} + +--- Main F10 menu for suppresion, i.e. F10/Artillery. +-- @field #string MenuF10 +ARTY.MenuF10=nil + +--- Some ID to identify who we are in output of the DCS.log file. +-- @field #string id +ARTY.id="ARTY | " + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO list: +-- TODO: don't know yet... +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Creates a new ARTY object. +-- @param #ARTY self +-- @param Wrapper.Group#GROUP group The GROUP object for which artillery tasks should be assigned. +-- @return #ARTY ARTY object. +-- @return nil If group does not exist or is not a ground group. +function ARTY:New(group) + BASE:F2(group) + + -- Inherits from FSM_CONTROLLABLE + local self=BASE:Inherit(self, FSM_CONTROLLABLE:New()) -- #ARTY + + -- Check that group is present. + if group then + self:T(ARTY.id.."ARTY group "..group:GetName()) + else + self:E(ARTY.id.."ARTY: Requested group does not exist! (Has to be a MOOSE group.)") + return nil + end + + -- Check that we actually have a GROUND group. + if group:IsGround()==false and group:IsShip()==false then + self:E(ARTY.id.."ARTY group "..group:GetName().." has to be a GROUND or SHIP group!") + return nil + end + + -- Set the controllable for the FSM. + self:SetControllable(group) + + -- Get DCS descriptors of group. + local DCSgroup=Group.getByName(group:GetName()) + local DCSunit=DCSgroup:getUnit(1) + self.DCSdesc=DCSunit:getDesc() + + -- Get max speed the group can do and convert to km/h. + --self.SpeedMax=self.DCSdesc.speedMaxOffRoad*3.6 + + -- Set speed to maximum. + --self.Speed=self.SpeedMax + + -- Is this infantry or not. + self.IsInfantry=DCSunit:hasAttribute("Infantry") + + -- Type of group. + self.Type=group:GetTypeName() + + -- Initial group strength. + self.IniGroupStrength=#group:GetUnits() + + -- Set ROE and Alarm State. + --self:SetDefaultROE("Free") + --self:SetDefaultAlarmState("Auto") + + -- Transitions + self:AddTransition("*", "Start", "CombatReady") + self:AddTransition("CombatReady", "OpenFire", "Firing") + self:AddTransition("Firing", "CeaseFire", "CombatReady") + self:AddTransition("*", "Dead", "*") + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- After "Start" event. Initialized ROE and alarm state. Starts the event handler. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterStart(Controllable, From, Event, To) + self:_EventFromTo("onafterStart", Event, From, To) + + local text=string.format("Started ARTY for group %s.", Controllable:GetName()) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + + -- Create main F10 menu if it is not there yet. + if self.MenuON then + if not ARTY.MenuF10 then + ARTY.MenuF10 = MENU_MISSION:New("ARTY") + end + self:_CreateMenuGroup() + end + + -- Set the current ROE and alam state. + --self:_SetAlarmState(self.DefaultAlarmState) + --self:_SetROE(self.DefaultROE) + + local text=string.format("\n******************************************************\n") + text=text..string.format("Arty group = %s\n", Controllable:GetName()) + text=text..string.format("Type = %s\n", self.Type) + text=text..string.format("******************************************************\n") + self:T(ARTY.id..text) + + -- Add event handler. + self:HandleEvent(EVENTS.Shot, self._OnEventShot) + self:HandleEvent(EVENTS.Dead, self._OnEventDead) + +end + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Assign a group of targets +-- @param #ARTY self +-- @param Wrapper.Group#GROUP group Group of targets. +-- @param #number range Range. +function ARTY:AssignTargetGroup(group, range) + self:E({group=group, range=range}) + + local _target={coord=group:GetCoordinate(), range=range} + + table.insert(self.targets, _target) + --table.insert(self.strafeTargets, {name=_name, polygon=_polygon, coordinate= Ccenter, goodPass=goodpass, targets=_targets, foulline=foulline, smokepoints=p, heading=heading}) + + local vec2=group:GetVec2() + --local zone=ZONE:New("target", vec2, range) + local zone=ZONE_RADIUS:New("target", vec2, range) + self:_FireAtZone(zone, 10) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +function ARTY:_OnEventShot(EventData) + self:F(EventData) +end + +function ARTY:_OnEventDead(EventData) + self:F(EventData) +end + +--- Set task for firing at a zone +-- @param #ARTY self +-- @param Wrapper.Zone#ZONE zone Zone to fire upon. +-- @param #number nshells Number of shells to fire. +function ARTY:_FireAtZone(zone, nshells) + self:E({zone=zone, nshells=nshells}) + + local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + + local units=group:GetUnits() + local nunits=#units + + local nshells_tot=nshells*nunits + + -- set ROE to weapon free + group:OptionROEWeaponFree() + + -- assign task + local q=zone:GetVec2() + local r=zone:GetRadius() + local fire=group:TaskFireAtPoint(q, r, nshells_tot) + + -- Execute task + group:SetTask(fire) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Print event-from-to string to DCS log file. +-- @param #ARTY self +-- @param #string BA Before/after info. +-- @param #string Event Event. +-- @param #string From From state. +-- @param #string To To state. +function ARTY:_EventFromTo(BA, Event, From, To) + local text=string.format("\n%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) + self:T(ARTY.id..text) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file From 0ec3192fb7d993e1b30e147f53e1044a8061915c Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 25 Apr 2018 22:49:36 +0200 Subject: [PATCH 067/170] Arty improvements --- .../Moose/Functional/Artillery.lua | 112 ++++++++++++++---- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 0695ae427..ea95af7dc 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -84,6 +84,7 @@ ARTY.id="ARTY | " -- TODO list: -- TODO: don't know yet... + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Creates a new ARTY object. @@ -185,6 +186,25 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) + -- Start scheduler to monitor task queue. + self.TaskQueueSched=SCHEDULER:New(nil, ARTY._CheckTaskQueue, {self}, 5, 10) + +end + +--- Assign a group of targets +-- @param #ARTY self +function ARTY:_CheckTaskQueue() + self:F() + + local _counter=0 + for _,target in pairs(self.targets) do + if target.underfire==false then + env.info(ARTY.id..string.format("Opening fire on target %s", target.name)) + self:OpenFire(target) + break + end + end + end @@ -195,20 +215,29 @@ end --- Assign a group of targets -- @param #ARTY self -- @param Wrapper.Group#GROUP group Group of targets. --- @param #number range Range. -function ARTY:AssignTargetGroup(group, range) - self:E({group=group, range=range}) +-- @param #number radius (Optional) Radius. Default is 100 m. +-- @param #number nshells (Optional) How many shells are fired on target per unit. Default 5. +function ARTY:AssignTargetGroup(group, radius, nshells) + self:E({group=group, radius=radius, nshells=nshells}) - local _target={coord=group:GetCoordinate(), range=range} + nshells=nshells or 5 + radius=radius or 100 + local coord=group:GetCoordinate() + local name=group:GetName() + + -- Prepare target array. + local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false} + + -- Add to table. table.insert(self.targets, _target) - --table.insert(self.strafeTargets, {name=_name, polygon=_polygon, coordinate= Ccenter, goodPass=goodpass, targets=_targets, foulline=foulline, smokepoints=p, heading=heading}) - - local vec2=group:GetVec2() - --local zone=ZONE:New("target", vec2, range) - local zone=ZONE_RADIUS:New("target", vec2, range) - self:_FireAtZone(zone, 10) + -- Debug info. + env.info(ARTY.id.."Targets:") + for _,target in pairs(self.targets) do + env.info(ARTY.id..string.format("Name: %s", target.name)) + end + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -216,6 +245,7 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- function ARTY:_OnEventShot(EventData) + env.info("Event Shot") self:F(EventData) end @@ -223,29 +253,33 @@ function ARTY:_OnEventDead(EventData) self:F(EventData) end ---- Set task for firing at a zone +--- Set task for firing at a coordinate. -- @param #ARTY self --- @param Wrapper.Zone#ZONE zone Zone to fire upon. --- @param #number nshells Number of shells to fire. -function ARTY:_FireAtZone(zone, nshells) - self:E({zone=zone, nshells=nshells}) +-- @param Core.Point#COORDINATE coord Coordinates to fire upon. +-- @param #number radius Radius around coordinate. +-- @param #number nshells Number of shells to fire per unit. +function ARTY:_FireAtCoord(coord, radius, nshells) + self:E({coord=coord, radius=radius, nshells=nshells}) + -- Controllable. local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + -- Number of units. local units=group:GetUnits() local nunits=#units local nshells_tot=nshells*nunits - -- set ROE to weapon free + -- Set ROE to weapon free. group:OptionROEWeaponFree() - -- assign task - local q=zone:GetVec2() - local r=zone:GetRadius() - local fire=group:TaskFireAtPoint(q, r, nshells_tot) + -- Get Vec2 + local vec2=coord:GetVec2() - -- Execute task + -- Get task. + local fire=group:TaskFireAtPoint(vec2, radius, nshells_tot) + + -- Execute task. group:SetTask(fire) end @@ -253,6 +287,42 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Before "OpenFire" event. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table target Array holding the target info. +-- @return boolean +function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) + self:_EventFromTo("onbeforeOpenFire", Event, From, To) + + return true +end + +--- After "OpenFire" event. +-- @param #SUPPRESSION self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table target Array holding the target info. _target={coord=coord, radius=radius, nshells=nshells, engaged=0, underattack=false} +function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) + self:_EventFromTo("onafterOpenFire", Event, From, To) + + local _coord=target.coord --Core.Point#COORDINATE + + --_coord:MarkToAll("Arty Target") + + self:_FireAtCoord(target.coord, target.radius, target.nshells) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + --- Print event-from-to string to DCS log file. -- @param #ARTY self -- @param #string BA Before/after info. From b14a672b0ef438c1fb83619c1869ab6cc039d15b Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 26 Apr 2018 23:08:16 +0200 Subject: [PATCH 068/170] ARTY improvements. --- .../Moose/Functional/Artillery.lua | 360 ++++++++++++++---- 1 file changed, 295 insertions(+), 65 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index ea95af7dc..00c83a08a 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -52,8 +52,10 @@ -- @field #ARTY ARTY={ ClassName = "ARTY", - Debug = false, + Debug = true, targets = {}, + currentTarget = nil, + Nshots=0, } --- Enumerator of possible rules of engagement. @@ -80,6 +82,10 @@ ARTY.MenuF10=nil -- @field #string id ARTY.id="ARTY | " +--- Range script version. +-- @field #number version +ARTY.version="0.1.0" + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list: @@ -100,15 +106,15 @@ function ARTY:New(group) -- Check that group is present. if group then - self:T(ARTY.id.."ARTY group "..group:GetName()) + self:T(ARTY.id..string.format("ARTY script version %s. Added group %s.", ARTY.version, group:GetName())) else - self:E(ARTY.id.."ARTY: Requested group does not exist! (Has to be a MOOSE group.)") + self:E(ARTY.id.."ERROR! Requested ARTY group does not exist! (Has to be a MOOSE group.)") return nil end -- Check that we actually have a GROUND group. if group:IsGround()==false and group:IsShip()==false then - self:E(ARTY.id.."ARTY group "..group:GetName().." has to be a GROUND or SHIP group!") + self:E(ARTY.id..string.format("ERROR! ARTY group %s has to be a GROUND or SHIP group!",group:GetName())) return nil end @@ -142,7 +148,8 @@ function ARTY:New(group) -- Transitions self:AddTransition("*", "Start", "CombatReady") self:AddTransition("CombatReady", "OpenFire", "Firing") - self:AddTransition("Firing", "CeaseFire", "CombatReady") + self:AddTransition("Firing", "CeaseFire", "CombatReady") + self:AddTransition("*", "NoAmmo", "OutOfAmmo") self:AddTransition("*", "Dead", "*") return self @@ -152,6 +159,41 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Assign a group of target(s). +-- @param #ARTY self +-- @param Wrapper.Group#GROUP group Group of targets. +-- @param #number radius (Optional) Radius. Default is 100 m. +-- @param #number nshells (Optional) How many shells are fired on target per unit. Default 5. +-- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. +function ARTY:AssignTargetGroup(group, radius, nshells, prio) + self:E({group=group, radius=radius, nshells=nshells, prio=prio}) + + -- Set default values. + nshells=nshells or 5 + radius=radius or 100 + prio=prio or 50 + prio=math.max( 1, prio) + prio=math.min(100, prio) + + -- Coordinate and name. + local coord=group:GetCoordinate() + local name=group:GetName() + + -- Prepare target array. + local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio} + + -- Add to table. + table.insert(self.targets, _target) + + -- Debug info. + env.info(ARTY.id..string.format("Added target %s, radius=%d, nshells=%d, prio=%d.", name, radius, nshells, prio)) + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -181,7 +223,14 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Type = %s\n", self.Type) text=text..string.format("******************************************************\n") self:T(ARTY.id..text) - + + -- Get Ammo. + self:_GetAmmo(self.Controllable) + + for _, target in pairs(self.targets) do + env.info(ARTY.id..string.format("Target %s, radius=%d, nshells=%d, prio=%d.", target.name, target.radius, target.nshells, target.prio)) + end + -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) @@ -191,64 +240,57 @@ function ARTY:onafterStart(Controllable, From, Event, To) end ---- Assign a group of targets +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Eventhandler for shot event. -- @param #ARTY self -function ARTY:_CheckTaskQueue() - self:F() +-- @param Core.Event#EVENTDATA EventData +function ARTY:_OnEventShot(EventData) + self:F(EventData) - local _counter=0 - for _,target in pairs(self.targets) do - if target.underfire==false then - env.info(ARTY.id..string.format("Opening fire on target %s", target.name)) - self:OpenFire(target) - break - end - end - -end - - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - ---- Assign a group of targets --- @param #ARTY self --- @param Wrapper.Group#GROUP group Group of targets. --- @param #number radius (Optional) Radius. Default is 100 m. --- @param #number nshells (Optional) How many shells are fired on target per unit. Default 5. -function ARTY:AssignTargetGroup(group, radius, nshells) - self:E({group=group, radius=radius, nshells=nshells}) - - nshells=nshells or 5 - radius=radius or 100 - - local coord=group:GetCoordinate() - local name=group:GetName() - - -- Prepare target array. - local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false} - - -- Add to table. - table.insert(self.targets, _target) + -- Weapon data. + local _weapon = EventData.Weapon:getTypeName() -- should be the same as Event.WeaponTypeName + local _weaponStrArray = self:_split(_weapon,"%.") + local _weaponName = _weaponStrArray[#_weaponStrArray] -- Debug info. - env.info(ARTY.id.."Targets:") - for _,target in pairs(self.targets) do - env.info(ARTY.id..string.format("Name: %s", target.name)) + self:T(ARTY.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) + self:T(ARTY.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) + self:T(ARTY.id.."EVENT SHOT: Weapon type = ".._weapon) + self:T(ARTY.id.."EVENT SHOT: Weapon name = ".._weaponName) + + local group = EventData.IniGroup --Wrapper.Group#GROUP + + if group and group:IsAlive() then + + if EventData.IniGroupName == self.Controllable:GetName() then + + if self.currentTarget then + + -- Increase number of shots fired by this group on this target. + self.Nshots=self.Nshots+1 + + -- Debug output. + self:T(ARTY.id..string.format("Group %s fired shot # %d on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.name)) + + -- Check if number of shots reached max. + if self.Nshots >= self.currentTarget.nshells then + self:CeaseFire(self.currentTarget) + self.Nshots=0 + end + + else + self:T(ARTY.id..string.format("No current target?!")) + end + end end - -end - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -function ARTY:_OnEventShot(EventData) - env.info("Event Shot") - self:F(EventData) end +--- Eventhandler for dead event. +-- @param #ARTY self +-- @param Core.Event#EVENTDATA EventData function ARTY:_OnEventDead(EventData) self:F(EventData) end @@ -257,7 +299,7 @@ end -- @param #ARTY self -- @param Core.Point#COORDINATE coord Coordinates to fire upon. -- @param #number radius Radius around coordinate. --- @param #number nshells Number of shells to fire per unit. +-- @param #number nshells Number of shells to fire. function ARTY:_FireAtCoord(coord, radius, nshells) self:E({coord=coord, radius=radius, nshells=nshells}) @@ -288,41 +330,211 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Before "OpenFire" event. --- @param #SUPPRESSION self +-- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #table target Array holding the target info. --- @return boolean +-- @return #boolean If true proceed to onafterOpenfire. function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onbeforeOpenFire", Event, From, To) - + + if self.currentTarget then + self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), target.name)) + return false + end + return true end --- After "OpenFire" event. --- @param #SUPPRESSION self +-- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #table target Array holding the target info. _target={coord=coord, radius=radius, nshells=nshells, engaged=0, underattack=false} -function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) +function ARTY:onafterOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onafterOpenFire", Event, From, To) local _coord=target.coord --Core.Point#COORDINATE --_coord:MarkToAll("Arty Target") - + + -- Get target array index. + local id=self:_GetTargetByName(target.name) + + -- Target is now under fire and has been engaged once more. + if id then + self.targets[id].underfire=true + self.targets[id].engaged=self.targets[id].engaged+1 + self.currentTarget=target + end + + -- Start firing. self:_FireAtCoord(target.coord, target.radius, target.nshells) end +--- Before "CeaseFire" event. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table target Array holding the target info. +-- @return #boolean +function ARTY:onbeforeCeaseFire(Controllable, From, Event, To, target) + self:_EventFromTo("onbeforeCeaseFire", Event, From, To) + + return true +end + +--- After "CeaseFire" event. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table target Array holding the target info. +function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) + self:_EventFromTo("onafterCeaseFire", Event, From, To) + + local name=self.currentTarget.name + + local id=self:_GetTargetByName(name) + + self.targets[id].underfire=false + + self.currentTarget=nil + + --Controllable:ClearTasks() + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Go through queue of assigned tasks. +-- @param #ARTY self +function ARTY:_CheckTaskQueue() + self:F() + + -- Sort targets. + self:_SortTaskQueue() + + for i=1,#self.targets do + + local _target=self.targets[i] + + if _target.underfire==false then + + env.info(ARTY.id..string.format("Opening fire on target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) + + -- Call OpenFire event. + self:OpenFire(_target) + + break + end + end + +end + + +--- Sort targets with respect to priority and number of times it was already engaged. +-- @param #ARTY self +function ARTY:_SortTaskQueue() + self:F() + + -- Sort results table wrt times they have already been engaged. + local function _sort(a, b) + return (a.engaged < b.engaged) or (a.engaged==b.engaged and a.prio < b.prio) + end + table.sort(self.targets, _sort) + + -- Debug output. + env.info(ARTY.id.."Sorted targets:") + for i=1,#self.targets do + env.info(ARTY.id..string.format("Target %s. Prio = %d, engaged = %d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) + end +end + + +--- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE controllable +-- @return Number of shells left +function ARTY:_GetAmmo(controllable) + self:F2(controllable) + + -- Get all units. + local units=controllable:GetUnits() + + -- Init counter. + local ammo=0 + + for _,unit in pairs(units) do + + local ammotable=unit:GetAmmo() + self:T2({ammotable=ammotable}) + + local name=unit:GetName() + + if ammotable ~= nil then + + local weapons=#ammotable + self:T2(ARTY.id..string.format("Number of weapons %d.", weapons)) + + for w=1,weapons do + + local Nammo=ammotable[w]["count"] + local Tammo=ammotable[w]["desc"]["typeName"] + + -- We are specifically looking for shells here. + if string.match(Tammo, "shell") then + + -- Add up all shells + ammo=ammo+Nammo + + local text=string.format("Unit %s has %d rounds ammo of type %s (shells)", name, Nammo, Tammo) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + else + local text=string.format("Unit %s has %d ammo of type %s", name, Nammo, Tammo) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + end + + end + end + end + + return ammo +end + + +--- Get a target by its name. +-- @param #ARTY self +-- @param #string name Name of target. +-- @return #number Arrayindex of target. +function ARTY:_GetTargetByName(name) + self:F2(name) + + for i=1,#self.targets do + local targetname=self.targets[i].name + if targetname==name then + self:E(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) + return i + end + end + + self:E(ARTY.id..string.format("ERROR: Target with name %s could not be found!", name)) + return nil +end + + --- Print event-from-to string to DCS log file. -- @param #ARTY self -- @param #string BA Before/after info. @@ -330,8 +542,26 @@ end -- @param #string From From state. -- @param #string To To state. function ARTY:_EventFromTo(BA, Event, From, To) - local text=string.format("\n%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) + local text=string.format("%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) self:T(ARTY.id..text) end + +--- Split string. Cf http://stackoverflow.com/questions/1426954/split-string-in-lua +-- @param #ARTY self +-- @param #string str Sting to split. +-- @param #string sep Speparator for split. +-- @return #table Split text. +function ARTY:_split(str, sep) + self:F2({str=str, sep=sep}) + + local result = {} + local regex = ("([^%s]+)"):format(sep) + for each in str:gmatch(regex) do + table.insert(result, each) + end + + return result +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file From e5268a29cf48f3dd9eec9810a8a1d53544df872e Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 30 Apr 2018 12:05:51 +0200 Subject: [PATCH 069/170] ARTY v0.3 First working version. But still WIP. --- .../Moose/Functional/Artillery.lua | 914 +++++++++++++++--- .../Moose/Wrapper/Controllable.lua | 9 +- 2 files changed, 789 insertions(+), 134 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 00c83a08a..d18a1b725 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -1,11 +1,12 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- **Functional** - Control artillery units. -- --- ![Banner Image](..\Presentations\ARTILLERY\Artillery_Main.png) +-- ![Banner Image](..\Presentations\ARTY\Artillery_Main.png) -- -- ==== -- --- Make artillery fire on targets. +-- The ARTY class can be used to easily assign targets for artillery units. Multiple targets can be assigned. +-- -- -- ==== -- @@ -35,6 +36,26 @@ -- @field #string ClassName Name of the class. -- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players. -- @field #table targets Targets assigned. +-- @field #table currentTarget Holds the current target, if there is one assigned. +-- @field #number Nammo0 Initial amount total ammunition (shells+rockets+missiles) of the whole group. +-- @field #number Nshells0 Initial amount of shells of the whole group. +-- @field #number Nrockets0 Initial amount of rockets of the whole group. +-- @field #number Nmissiles0 Initial amount of missiles of the whole group. +-- @field Core.Scheduler#SCHEDULER TargetQueueSched Scheduler updating the target queue and calling OpenFire event. +-- @field #number TargetQueueUpdate Interval between updates of the target queue. +-- @field Core.Scheduler#SCHEDULER CheckRearmedSched Scheduler checking whether reaming of the ARTY group is complete. +-- @field #table DCSdesc DCS descriptors of the ARTY group. +-- @field #string Type Type of the ARTY group. +-- @field #number IniGroupStrength Inital number of units in the ARTY group. +-- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". +-- @field #number Speed Max speed of ARTY group. +-- @field Wrapper.Unit#UNIT RearmingUnit Unit designated to rearm the ARTY group. +-- @field #boolean report Arty group sends messages about their current state or target to its coaliton. +-- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells. +-- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. +-- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. +-- @field #number Nshots Number of shots fired on current target. +-- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. -- @extends Core.Fsm#FSM_CONTROLLABLE -- @@ -43,7 +64,7 @@ -- -- ## Target aquisition... -- --- ![Process](..\Presentations\ART\Arty_Process.png) +-- ![Process](..\Presentations\ARTY\Artillery_Process.png) -- -- The arty process can be described as follows. -- @@ -55,41 +76,59 @@ ARTY={ Debug = true, targets = {}, currentTarget = nil, + Nammo0=0, + Nshells0=0, + Nrockets0=0, + Nmissiles0=0, + TargetQueueSched=nil, + TargetQueueUpdate=5, + CheckRearmedSched=nil, + DCSdesc=nil, + Type=nil, + IniGroupStrength=0, + IsArtillery=nil, + RearmingUnit=nil, + report=true, + ammoshells={"weapons.shells"}, + ammorockets={"weapons.nurs"}, + ammomissiles={"weapons.missiles"}, Nshots=0, + WaitForShotTime=300, } ---- Enumerator of possible rules of engagement. --- @field #list ROE -ARTY.ROE={ - Hold="Weapon Hold", - Free="Weapon Free", - Return="Return Fire", +--- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag +-- @list WeaponType +ARTY.WeaponType={ + Auto=1073741822, + UnguidedAny=805339120, + UnguidedCannon=805306368, + UnguidedRockets=30720, + GuidedAny=268402702, + GuidedMissile=268402688, + CruiseMissile=2097152, } ---- Enumerator of possible alarm states. --- @field #list AlarmState -ARTY.AlarmState={ - Auto="Auto", - Green="Green", - Red="Red", -} - ---- Main F10 menu for suppresion, i.e. F10/Artillery. --- @field #string MenuF10 -ARTY.MenuF10=nil - --- Some ID to identify who we are in output of the DCS.log file. -- @field #string id ARTY.id="ARTY | " --- Range script version. -- @field #number version -ARTY.version="0.1.0" +ARTY.version="0.3.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list: --- TODO: don't know yet... +-- DONE: Delete targets from queue user function. +-- TODO: Delete entire target queue user function. +-- TODO: Add weapon types. +-- DONE: Add user defined rearm weapon types. +-- TODO: Check if target is in range. Maybe this requires a data base with the ranges of all arty units. Pfff... +-- TODO: Make ARTY move to reaming position. +-- TODO: Check that right reaming vehicle is specified. Blue M818, Red Ural-375. Are there more? +-- TODO: Check if ARTY group is still alive. +-- TODO: Handle dead events. +-- TODO: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -108,13 +147,13 @@ function ARTY:New(group) if group then self:T(ARTY.id..string.format("ARTY script version %s. Added group %s.", ARTY.version, group:GetName())) else - self:E(ARTY.id.."ERROR! Requested ARTY group does not exist! (Has to be a MOOSE group.)") + self:E(ARTY.id.."ERROR: Requested ARTY group does not exist! (Has to be a MOOSE group.)") return nil end -- Check that we actually have a GROUND group. if group:IsGround()==false and group:IsShip()==false then - self:E(ARTY.id..string.format("ERROR! ARTY group %s has to be a GROUND or SHIP group!",group:GetName())) + self:E(ARTY.id..string.format("ERROR: ARTY group %s has to be a GROUND or SHIP group!", group:GetName())) return nil end @@ -126,31 +165,40 @@ function ARTY:New(group) local DCSunit=DCSgroup:getUnit(1) self.DCSdesc=DCSunit:getDesc() - -- Get max speed the group can do and convert to km/h. - --self.SpeedMax=self.DCSdesc.speedMaxOffRoad*3.6 + -- DCS descriptors. + self:T3(ARTY.id.."DCS descriptors for group "..group:GetName()) + for id,desc in pairs(self.DCSdesc) do + self:T3({id=id, desc=desc}) + end - -- Set speed to maximum. - --self.Speed=self.SpeedMax + -- Set speed to maximum in km/h. + self.Speed=self.DCSdesc.speedMax*3.6 + + -- Displayed name (similar to type name below) + self.DisplayName=self.DCSdesc.displayName -- Is this infantry or not. - self.IsInfantry=DCSunit:hasAttribute("Infantry") + self.IsArtillery=DCSunit:hasAttribute("Artillery") -- Type of group. self.Type=group:GetTypeName() -- Initial group strength. self.IniGroupStrength=#group:GetUnits() - + -- Set ROE and Alarm State. --self:SetDefaultROE("Free") --self:SetDefaultAlarmState("Auto") -- Transitions - self:AddTransition("*", "Start", "CombatReady") - self:AddTransition("CombatReady", "OpenFire", "Firing") - self:AddTransition("Firing", "CeaseFire", "CombatReady") - self:AddTransition("*", "NoAmmo", "OutOfAmmo") - self:AddTransition("*", "Dead", "*") + self:AddTransition("*", "Start", "CombatReady") + self:AddTransition("CombatReady", "OpenFire", "Firing") + self:AddTransition("Firing", "OpenFire", "Firing") -- Other target assigned + self:AddTransition("Firing", "CeaseFire", "CombatReady") + self:AddTransition("*", "Winchester", "OutOfAmmo") + self:AddTransition("OutOfAmmo", "Rearm", "Rearming") + self:AddTransition("Rearming", "Rearmed", "CombatReady") + --self:AddTransition("*", "Dead", "*") return self end @@ -159,35 +207,140 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Assign a group of target(s). +--- Add a group of target(s) for the ARTY group. -- @param #ARTY self -- @param Wrapper.Group#GROUP group Group of targets. --- @param #number radius (Optional) Radius. Default is 100 m. --- @param #number nshells (Optional) How many shells are fired on target per unit. Default 5. -- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. -function ARTY:AssignTargetGroup(group, radius, nshells, prio) - self:E({group=group, radius=radius, nshells=nshells, prio=prio}) +-- @param #number radius (Optional) Radius. Default is 100 m. +-- @param #number nshells (Optional) How many shells (or rockets) are fired on target per engagement. Default 5. +-- @param #number maxengage (Optional) How many times a target is engaged. Default 9999. +-- @param #string time Day time at which the target should be engaged. Passed as a string in format "08:13:45". Current task will be canceled. +-- @param #number weapontype Type of weapon to be used to attack this target. Default ARTY.WeaponType.Auto. +-- @return #string Name of the target. Can be used for further reference, e.g. deleting the target from the list. +-- @usage ARTY:AssignTargetGroup(GROUP:FindByName("Red Target"), 10, 250, 10, 2, "13:25:45") +function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, weapontype) + self:E({group=group, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype}) -- Set default values. nshells=nshells or 5 radius=radius or 100 + maxengage=maxengage or 9999 + prio=prio or 50 + prio=math.max( 1, prio) + prio=math.min(100, prio) + weapontype=weapontype or ARTY.WeaponType.Auto + + -- Coordinate of target. + local coord=group:GetCoordinate() + local name=group:GetName() + + -- Name of target defined my Lat/long in Degree Minute Second format. + --local name=coord:ToStringLLDMS() + + -- Check if the name has already been used for another target. If so, the function returns a new unique name. + name=self:_CheckTargetName(name) + + -- Time in seconds. + local _time=self:_ClockToSeconds(time) + + -- Prepare target array. + local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage, time=_time, weapontype=weapontype} + + -- Add to table. + table.insert(self.targets, _target) + + -- Clock. + local _clock=self:_SecondsToClock(_target.time) + + -- Debug info. + self:T(ARTY.id..string.format("Added target %s, prio=%d, radius=%d, nshells=%d, maxengage=%d, time=%s, weapontype=%d", name, prio, radius, nshells, maxengage, _clock, weapontype)) +end + + +--- Assign coordinates of a target for the ARTY group. +-- @param #ARTY self +-- @param Wrapper.Point#COORDINATE coord Coordinates of the target. +-- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. +-- @param #number radius (Optional) Radius. Default is 100 m. +-- @param #number nshells (Optional) How many shells are fired on target per engagement. Default 5. +-- @param #number maxengage (Optional) How many times a target is engaged. Default 9999. +-- @return #string targetname Name of the target. +function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage) + self:E({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage}) + + -- Set default values. + nshells=nshells or 5 + radius=radius or 100 + maxengage=maxengage or 9999 prio=prio or 50 prio=math.max( 1, prio) prio=math.min(100, prio) -- Coordinate and name. - local coord=group:GetCoordinate() - local name=group:GetName() + local name=coord:ToStringLLDMS() -- Prepare target array. - local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio} + local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage} -- Add to table. table.insert(self.targets, _target) -- Debug info. - env.info(ARTY.id..string.format("Added target %s, radius=%d, nshells=%d, prio=%d.", name, radius, nshells, prio)) + self:T(ARTY.id..string.format("Added target %s, radius=%d, nshells=%d, prio=%d, maxengage=%d.", name, prio, radius, nshells, maxengage)) + return name +end + +--- Assign a unit which is responsible for rearming the ARTY group. If the unit is too far away from the ARTY group it will be guided towards the ARTY group. +-- @param #ARTY self +-- @param Wrapper.Unit#UNIT unit Unit that is supposed to rearm the ARTY group. +function ARTY:SetRearmingUnit(unit) + self:F({unit=unit}) + self.RearmingUnit=unit +end + +--- Delete target from target list. +-- @param #ARTY self +-- @param #string name Name of the target. +function ARTY:RemoveTarget(name) + self:F2(name) + local id=self:_GetTargetByName(name) + if id then + table.remove(self.targets, id) + end +end + +--- Define shell types that are counted to determine the ammo amount the ARTY group has. +-- @param #ARTY self +-- @param #table tableofnames Table of shell type names. +function ARTY:SetShellTypes(tableofnames) + self:F2(tableofnames) + self.ammoshells={} + for _,_type in pairs(tableofnames) do + table.insert(self.ammoshells, _type) + end +end + +--- Define rocket types that are counted to determine the ammo amount the ARTY group has. +-- @param #ARTY self +-- @param #table tableofnames Table of rocket type names. +function ARTY:SetRocketTypes(tableofnames) + self:F2(tableofnames) + self.ammorockets={} + for _,_type in pairs(tableofnames) do + table.insert(self.ammorockets, _type) + end +end + +--- Define missile types that are counted to determine the ammo amount the ARTY group has. +-- @param #ARTY self +-- @param #table tableofnames Table of rocket type names. +function ARTY:SetMissileTypes(tableofnames) + self:F2(tableofnames) + self.ammomissiles={} + for _,_type in pairs(tableofnames) do + table.insert(self.ammomissiles, _type) + end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -206,37 +359,52 @@ function ARTY:onafterStart(Controllable, From, Event, To) local text=string.format("Started ARTY for group %s.", Controllable:GetName()) MESSAGE:New(text, 10):ToAllIf(self.Debug) - -- Create main F10 menu if it is not there yet. - if self.MenuON then - if not ARTY.MenuF10 then - ARTY.MenuF10 = MENU_MISSION:New("ARTY") - end - self:_CreateMenuGroup() - end - -- Set the current ROE and alam state. --self:_SetAlarmState(self.DefaultAlarmState) --self:_SetROE(self.DefaultROE) - local text=string.format("\n******************************************************\n") - text=text..string.format("Arty group = %s\n", Controllable:GetName()) - text=text..string.format("Type = %s\n", self.Type) - text=text..string.format("******************************************************\n") - self:T(ARTY.id..text) - -- Get Ammo. - self:_GetAmmo(self.Controllable) + self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:_GetAmmo(self.Controllable) + local text=string.format("\n******************************************************\n") + text=text..string.format("Arty group = %s\n", Controllable:GetName()) + text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery)) + text=text..string.format("Type = %s\n", self.Type) + text=text..string.format("Number of units = %d\n", self.IniGroupStrength) + text=text..string.format("Max Speed [km/h] = %d\n", self.Speed) + text=text..string.format("Total ammo count = %d\n", self.Nammo0) + text=text..string.format("Number of shells = %d\n", self.Nshells0) + text=text..string.format("Number of rockets = %d\n", self.Nrockets0) + text=text..string.format("Number of missiles = %d\n", self.Nmissiles0) + text=text..string.format("******************************************************\n") + text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do - env.info(ARTY.id..string.format("Target %s, radius=%d, nshells=%d, prio=%d.", target.name, target.radius, target.nshells, target.prio)) + local _clock=self:_SecondsToClock(target.time) + local _weapon=self:_WeaponTypeName(target.weapontype) + text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, maxengage=%3d, time=%s, weapon=%s\n", target.name, target.prio, target.radius, target.nshells, target.maxengage, _clock, _weapon) end + text=text..string.format("******************************************************\n") + text=text..string.format("Shell types:\n") + for _,_type in pairs(self.ammoshells) do + text=text..string.format("- %s\n", _type) + end + text=text..string.format("Rocket types:\n") + for _,_type in pairs(self.ammorockets) do + text=text..string.format("- %s\n", _type) + end + text=text..string.format("Missile types:\n") + for _,_type in pairs(self.ammomissiles) do + text=text..string.format("- %s\n", _type) + end + text=text..string.format("******************************************************") + self:T(ARTY.id..text) -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) -- Start scheduler to monitor task queue. - self.TaskQueueSched=SCHEDULER:New(nil, ARTY._CheckTaskQueue, {self}, 5, 10) + self.TargetQueueSched=SCHEDULER:New(nil, ARTY._TargetQueue, {self}, 5, self.TargetQueueUpdate) end @@ -256,10 +424,10 @@ function ARTY:_OnEventShot(EventData) local _weaponName = _weaponStrArray[#_weaponStrArray] -- Debug info. - self:T(ARTY.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) - self:T(ARTY.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) - self:T(ARTY.id.."EVENT SHOT: Weapon type = ".._weapon) - self:T(ARTY.id.."EVENT SHOT: Weapon name = ".._weaponName) + self:T3(ARTY.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) + self:T3(ARTY.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) + self:T3(ARTY.id.."EVENT SHOT: Weapon type = ".._weapon) + self:T3(ARTY.id.."EVENT SHOT: Weapon name = ".._weaponName) local group = EventData.IniGroup --Wrapper.Group#GROUP @@ -273,16 +441,70 @@ function ARTY:_OnEventShot(EventData) self.Nshots=self.Nshots+1 -- Debug output. - self:T(ARTY.id..string.format("Group %s fired shot # %d on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.name)) - + local text=string.format("Group %s fired shot %d of %d with weapon %s on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name) + self:T(ARTY.id..text) + MESSAGE:New(text, 5):ToAllIf(self.Debug) + + -- Get current ammo. + local _nammo,_nshells,_nrockets,_nmissiles=self:_GetAmmo(self.Controllable) + + if _nammo==0 then + + self:E(ARTY.id.."completely out of ammo") + self.Nshots=0 + self:Winchester() + + -- Current target is deallocated ==> return + return + end + + -- Weapon type name for current target. + local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) + self:E(ARTY.id..string.format("nammo=%d, nshells=%d, nrockets=%d, nmissiles=%d", _nammo, _nshells, _nrockets, _nmissiles)) + self:E(ARTY.id..string.format("Weapontype = %s", _weapontype)) + + -- Special weapon type requested ==> Check if corresponding ammo is empty. + if self.currentTarget.weapontype==ARTY.WeaponType.UnguidedCannon and _nshells==0 then + + self:E(ARTY.id.."cannons requested and shells empty") + self.Nshots=0 + self:CeaseFire(self.currentTarget) + return + + elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedRockets and _nrockets==0 then + + self:E(ARTY.id.."rockets requested and rockets empty") + self.Nshots=0 + self:CeaseFire(self.currentTarget) + return + + elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then + + self:E(ARTY.id.."unguided weapon requested and shells+rockets empty") + self.Nshots=0 + self:CeaseFire(self.currentTarget) + return + + elseif self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then + + self:E(ARTY.id.."cruise missiles requested and missiles empty") + self.Nshots=0 + self:CeaseFire(self.currentTarget) + return + end + -- Check if number of shots reached max. if self.Nshots >= self.currentTarget.nshells then - self:CeaseFire(self.currentTarget) + local text=string.format("Group %s stop firing on target %s.", self.Controllable:GetName(), self.currentTarget.name) + self:T(ARTY.id..text) + MESSAGE:New(text, 5):ToAllIf(self.Debug) + self.Nshots=0 + self:CeaseFire(self.currentTarget) end else - self:T(ARTY.id..string.format("No current target?!")) + self:E(ARTY.id..string.format("ERROR: No current target?!")) end end end @@ -300,29 +522,25 @@ end -- @param Core.Point#COORDINATE coord Coordinates to fire upon. -- @param #number radius Radius around coordinate. -- @param #number nshells Number of shells to fire. -function ARTY:_FireAtCoord(coord, radius, nshells) +-- @param #number weapontype Type of weapon to use. +function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) self:E({coord=coord, radius=radius, nshells=nshells}) -- Controllable. local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE - -- Number of units. - local units=group:GetUnits() - local nunits=#units - - local nshells_tot=nshells*nunits - -- Set ROE to weapon free. - group:OptionROEWeaponFree() + group:OptionROEOpenFire() -- Get Vec2 local vec2=coord:GetVec2() -- Get task. - local fire=group:TaskFireAtPoint(vec2, radius, nshells_tot) + local fire=group:TaskFireAtPoint(vec2, radius, nshells, weapontype) -- Execute task. group:SetTask(fire) + --group:PushTask(fire) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -340,11 +558,34 @@ end function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onbeforeOpenFire", Event, From, To) - if self.currentTarget then - self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), target.name)) - return false + + -- If this target has an attack time and it's prio is higher than the current task, we allow the transition. + if target.time~=nil and self.currentTarget~=nil and self.currentTarget.prio > target.prio then + -- Debug info. + self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, target.name)) + + -- Reset current task. + --self.Controllable:ClearTasks() + + -- Set number of shots counter to zero. + self.Nshots=0 + + -- Stop firing on current target. + self:CeaseFire(self.currentTarget) + + -- Alow transition to onafterOpenfire. + return true end + -- Check that group has no current target already. + if self.currentTarget then + -- Debug info. + self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name)) + + -- Deny transition. + return false + end + return true end @@ -367,16 +608,34 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) -- Target is now under fire and has been engaged once more. if id then + -- Set under fire flag. self.targets[id].underfire=true + -- Increase engaged counter self.targets[id].engaged=self.targets[id].engaged+1 + -- Clear the attack time. + self.targets[id].time=nil + -- Set current target. self.currentTarget=target end + -- Distance to target + local range=Controllable:GetCoordinate():Get2DDistance(target.coord) + + -- Send message. + local text=string.format("%s, opening fire on target %s with %s shells. Distance %.1f km.", Controllable:GetName(), target.name, target.nshells, range/1000) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + -- Start firing. - self:_FireAtCoord(target.coord, target.radius, target.nshells) + self:_FireAtCoord(target.coord, target.radius, target.nshells, target.weapontype) + + -- Check that after a certain time a shot event occured. + --self.CheckShootingSched, self.CheckRearmedSchedID=SCHEDULER:New(nil, self._CheckShootingStarted, {self}, self.WaitForShotTime) end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + --- Before "CeaseFire" event. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -400,42 +659,195 @@ end -- @param #table target Array holding the target info. function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) self:_EventFromTo("onafterCeaseFire", Event, From, To) + + -- Send message. + local text=string.format("%s, ceasing fire on target %s.", Controllable:GetName(), target.name) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) - local name=self.currentTarget.name + -- ARTY group has no current target any more. + self.currentTarget=nil - local id=self:_GetTargetByName(name) + -- Get target array index. + local id=self:_GetTargetByName(target.name) + -- Target is not under fire any more. self.targets[id].underfire=false - self.currentTarget=nil - - --Controllable:ClearTasks() + -- If number of engagements has been reached, the target is removed. + if target.engaged >= target.maxengage then + self:RemoveTarget(target.name) + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- After "Winchester" event. Group is out of ammo. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterWinchester(Controllable, From, Event, To) + self:_EventFromTo("onafterWinchester", Event, From, To) + + local text=string.format("Group %s is winchester (out of ammo)!", Controllable:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + + -- Send message. + local text=string.format("%s, winchester.", Controllable:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + + -- Remove current target. + if self.currentTarget then + local id=self:_GetTargetByName(self.currentTarget.name) + self.targets[id].underfire=false + self.currentTarget=nil + end + + -- Init rearming. + self:Rearm() end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "Rearm" event. Check if a unit to rearm the ARTY group has been defined. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onbeforeRearm(Controllable, From, Event, To) + self:_EventFromTo("onbeforeRearm", Event, From, To) + + if self.RearmingUnit and self.RearmingUnit:IsAlive() then + return true + else + return false + end + +end + + +--- After "Rearm" event. Send message if reporting is on. Route rearming unit to ARTY group. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterRearm(Controllable, From, Event, To) + self:_EventFromTo("onafterRearm", Event, From, To) + + -- Send message. + local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + + -- Random point 20-100 m away from unit. + local coord=self.Controllable:GetCoordinate() + local vec2=coord:GetRandomVec2InRadius(20, 100) + local pops=COORDINATE:NewFromVec2(vec2) + + -- Route unit to ARTY group. + self.RearmingUnit:RouteGroundOnRoad(pops, 50, 5) + + -- Start scheduler to monitor ammo count until rearming is complete. + self.CheckRearmedSched=SCHEDULER:New(nil,self._CheckRearmed, {self}, 5, 10) +end + + +--- Check if ARTY group is reamed. +-- @param #ARTY self +function ARTY:_CheckRearmed() + self:F2() + + -- Get current ammo. + local nammo,nshells,nrockets,nmissiles=self:_GetAmmo(self.Controllable) + + -- Rearming --> Rearmed --> CombatReady + if nammo==self.Nammo0 then + self:Rearmed() + end + +end + +--- After "Rearmed" event. Send message if reporting is on and stop the scheduler. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterRearmed(Controllable, From, Event, To) + self:_EventFromTo("onafterRearmed", Event, From, To) + + -- Send message. + local text=string.format("%s, rearming complete.", Controllable:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + + -- Stop scheduler. + self.CheckRearmedSched:Stop() +end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Go through queue of assigned tasks. -- @param #ARTY self -function ARTY:_CheckTaskQueue() - self:F() +function ARTY:_TargetQueue() + self:F2() + + -- Debug info + self:T(ARTY.id..string.format("Group %s, number of targets = %d", self.Controllable:GetName(), #self.targets)) - -- Sort targets. - self:_SortTaskQueue() + -- We already have a target. +-- if self.currentTarget then +-- self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name)) +-- return +-- end + + -- First check if there is a target with a certain time for attack. + for i=1,#self.targets do + local _target=self.targets[i] + if _target and _target.time then + if timer.getAbsTime() >= _target.time and _target.underfire==false then + + -- Clock time format. + local _clock=self:_SecondsToClock(_target.time) + local _Cnow=self:_SecondsToClock(timer.getAbsTime()) + -- Debug info. + self:T(ARTY.id..string.format("Engaging timed target %s. Prio=%d, engaged=%d, time=%s, tnow=%s",_target.name,_target.prio,_target.engaged,_clock,_Cnow)) + + -- Call OpenFire event. + self:OpenFire(_target) + + end + end + end + + -- Sort targets w.r.t. prio and number times engaged already. + self:_SortTargetQueuePrio() + + -- Loop over all sorted targets. for i=1,#self.targets do local _target=self.targets[i] - if _target.underfire==false then - - env.info(ARTY.id..string.format("Opening fire on target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) + if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged then + -- Debug info. + self:T(ARTY.id..string.format("Engaging target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) + -- Call OpenFire event. self:OpenFire(_target) - + break end end @@ -445,8 +857,8 @@ end --- Sort targets with respect to priority and number of times it was already engaged. -- @param #ARTY self -function ARTY:_SortTaskQueue() - self:F() +function ARTY:_SortTargetQueuePrio() + self:F2() -- Sort results table wrt times they have already been engaged. local function _sort(a, b) @@ -455,17 +867,44 @@ function ARTY:_SortTaskQueue() table.sort(self.targets, _sort) -- Debug output. - env.info(ARTY.id.."Sorted targets:") + self:T2(ARTY.id.."Sorted targets wrt prio and number of engagements:") for i=1,#self.targets do - env.info(ARTY.id..string.format("Target %s. Prio = %d, engaged = %d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) + self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) end end +--- Sort targets with respect to engage time. +-- @param #ARTY self +function ARTY:_SortTargetQueueTime() + self:F2() + + -- Sort targets w.r.t attack time. + local function _sort(a, b) + if a.time == nil and b.time == nil then + return false + end + if a.time == nil then + return false + end + if b.time == nil then + return true + end + return a.time < b.time + end + table.sort(self.targets, _sort) + + -- Debug output. + self:T2(ARTY.id.."Sorted targets wrt time:") + for i=1,#self.targets do + self:T(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) + end + +end --- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE controllable --- @return Number of shells left +-- @return Number of ALL shells left from the whole group. function ARTY:_GetAmmo(controllable) self:F2(controllable) @@ -473,48 +912,136 @@ function ARTY:_GetAmmo(controllable) local units=controllable:GetUnits() -- Init counter. - local ammo=0 + local nammo=0 + local nshells=0 + local nrockets=0 + local nmissiles=0 for _,unit in pairs(units) do - local ammotable=unit:GetAmmo() - self:T2({ammotable=ammotable}) - - local name=unit:GetName() - - if ammotable ~= nil then - - local weapons=#ammotable - self:T2(ARTY.id..string.format("Number of weapons %d.", weapons)) + if unit and unit:IsAlive() then + + local ammotable=unit:GetAmmo() + self:T({ammotable=ammotable}) - for w=1,weapons do + local name=unit:GetName() - local Nammo=ammotable[w]["count"] - local Tammo=ammotable[w]["desc"]["typeName"] + if ammotable ~= nil then + + local weapons=#ammotable - -- We are specifically looking for shells here. - if string.match(Tammo, "shell") then + self:T2(ARTY.id..string.format("Number of weapons %d.", weapons)) + self:T2(ammotable) - -- Add up all shells - ammo=ammo+Nammo + -- Loop over all weapons. + for w=1,weapons do - local text=string.format("Unit %s has %d rounds ammo of type %s (shells)", name, Nammo, Tammo) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug) - else - local text=string.format("Unit %s has %d ammo of type %s", name, Nammo, Tammo) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug) + -- Number of current weapon. + local Nammo=ammotable[w]["count"] + + -- Typename of current weapon + local Tammo=ammotable[w]["desc"]["typeName"] + + -- Check for correct shell type. + local _gotshell=false + for _,_type in pairs(self.ammoshells) do + if string.match(Tammo, _type) then + _gotshell=true + end + end + + -- Check for correct rocket type. + local _gotrocket=false + for _,_type in pairs(self.ammorockets) do + if string.match(Tammo, _type) then + _gotrocket=true + end + end + + -- Check for correct missile type. + local _gotmissile=false + for _,_type in pairs(self.ammomissiles) do + if string.match(Tammo,_type) then + _gotmissile=true + end + end + + + -- We are specifically looking for shells or rockets here. + if _gotshell then + + -- Add up all shells. + nshells=nshells+Nammo + + -- Debug info. + local text=string.format("Unit %s has %d shells of type %s", name, Nammo, Tammo) + self:T2(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + + elseif _gotrocket then + + -- Add up all rockets. + nrockets=nrockets+Nammo + + -- Debug info. + local text=string.format("Unit %s has %d rockets of type %s", name, Nammo, Tammo) + self:T2(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + + elseif _gotmissile then + + -- Add up all rockets. + nmissiles=nmissiles+Nammo + + -- Debug info. + local text=string.format("Unit %s has %d missiles of type %s", name, Nammo, Tammo) + self:T2(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + + else + + -- Debug info. + local text=string.format("Unit %s has %d ammo of type %s", name, Nammo, Tammo) + self:T2(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + + end + end - end end end - return ammo + -- Total amount of ammunition. + nammo=nshells+nrockets+nmissiles + + return nammo, nshells, nrockets, nmissiles end +--- Check whether shooting started within a certain time (~5 min). If not, the current target is considered invalid and removed from the target list. +-- @param #ARTY self +function ARTY:_CheckShootingStarted() + self:F2() + + if self.currentTarget and self.Nshots==0 then + + -- Get name and id of target. + local name=self.currentTarget.name + local id=self:_GetTargetByName(name) + + -- Debug info. + self:T(ARTY.id..string.format("No shot event after %d seconds. Removing current target %s from list.", self.WaitForShotTime, name)) + + -- CeaseFire. + self:CeaseFire(self.currentTarget) + + -- Remove target from list. + self:RemoveTarget(name) + + end +end + --- Get a target by its name. -- @param #ARTY self -- @param #string name Name of target. @@ -525,7 +1052,7 @@ function ARTY:_GetTargetByName(name) for i=1,#self.targets do local targetname=self.targets[i].name if targetname==name then - self:E(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) + self:T2(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) return i end end @@ -535,6 +1062,70 @@ function ARTY:_GetTargetByName(name) end +--- Get the weapon type name, which should be used to attack the target. +-- @param #ARTY self +-- @param #string name Desired target name. +-- @return #string Unique name, which is not already given for another target. +function ARTY:_CheckTargetName(name) + self:F2(name) + + local newname=name + local counter=1 + + repeat + -- We assume the name is unique. + local unique=true + + -- Loop over all targets already defined. + for _,_target in pairs(self.targets) do + + -- Target name. + local _targetname=_target.name + + if _targetname==newname then + -- Define new name = "name #01" + newname=string.format("%s #%02d", name, counter) + + -- Increase counter. + counter=counter+1 + + -- Name is already used for another target ==> try again with new name. + unique=false + end + end + + until (unique) + + -- Debug output and return new name. + self:T(string.format("Original name %s, new name = %s", name, newname)) + return newname +end + +--- Get the weapon type name, which should be used to attack the target. +-- @param #ARTY self +-- @param #number tnumber Number of weapon type ARTY.WeaponType.XXX +-- @return #number tnumber of weapon type. +function ARTY:_WeaponTypeName(tnumber) + local name="unknown" + if tnumber==ARTY.WeaponType.Auto then + name="Auto (Cannon, Rockets, Missiles)" + elseif tnumber==ARTY.WeaponType.CruiseMissile then + name="Cruise Missile" + elseif tnumber==ARTY.WeaponType.GuidedAny then + name="Any Guided Missile" + elseif tnumber==ARTY.WeaponType.GuidedMissile then + name="Guided Missile" + elseif tnumber==ARTY.WeaponType.UnguidedAny then + name="Any Unguided Weapon (Cannon or Rockets)" + elseif tnumber==ARTY.WeaponType.UnguidedCannon then + name="Unguided Cannon" + elseif tnumber==ARTY.WeaponType.UnguidedRockets then + name="Unguided Rockets" + end + + return name +end + --- Print event-from-to string to DCS log file. -- @param #ARTY self -- @param #string BA Before/after info. @@ -543,25 +1134,84 @@ end -- @param #string To To state. function ARTY:_EventFromTo(BA, Event, From, To) local text=string.format("%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) - self:T(ARTY.id..text) + self:T3(ARTY.id..text) end ---- Split string. Cf http://stackoverflow.com/questions/1426954/split-string-in-lua +--- Split string. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua -- @param #ARTY self -- @param #string str Sting to split. -- @param #string sep Speparator for split. -- @return #table Split text. function ARTY:_split(str, sep) - self:F2({str=str, sep=sep}) + self:F3({str=str, sep=sep}) local result = {} local regex = ("([^%s]+)"):format(sep) for each in str:gmatch(regex) do - table.insert(result, each) + table.insert(result, each) end return result end +--- Convert time in seconds to hours, minutes and seconds. +-- @param #ARTY self +-- @param #number seconds Time in seconds. +-- @return #string Time in format Hours:minutes:seconds. +function ARTY:_SecondsToClock(seconds) + self:F3({seconds=seconds}) + + -- Seconds + local seconds = tonumber(seconds) + + if seconds==nil then + return "00:00:00" + end + + if seconds <= 0 then + return "00:00:00" + else + local hours = string.format("%02.f", math.floor(seconds/3600)) + local mins = string.format("%02.f", math.floor(seconds/60 - (hours*60))) + local secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60)) + return hours..":"..mins..":"..secs + --return hours, mins, secs + end +end + +--- Convert clock time from hours, minutes and seconds to seconds. +-- @param #ARTY self +-- @param #string clock String of clock time. E.g., "06:12:35". +function ARTY:_ClockToSeconds(clock) + self:F3({clock=clock}) + + if clock==nil then + return nil + end + + -- Split string by ":" + local tsplit=string.gmatch(clock, '([^:]+)') + + -- Get time in seconds + local seconds=0 + local i=1 + for time in tsplit do + if i==1 then + -- Hours + seconds=seconds+tonumber(time)*60*60 + elseif i==2 then + -- Minutes + seconds=seconds+tonumber(time)*60 + elseif i==3 then + -- Seconds + seconds=seconds+tonumber(time) + end + i=i+1 + end + + self:T3(ARTY.id..string.format("Clock %s = %d seconds", clock, seconds)) + return seconds +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 0b68255c5..92d258b5f 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1048,9 +1048,10 @@ end -- @param Dcs.DCSTypes#Vec2 Vec2 The point to fire at. -- @param Dcs.DCSTypes#Distance Radius The radius of the zone to deploy the fire at. -- @param #number AmmoCount (optional) Quantity of ammunition to expand (omit to fire until ammunition is depleted). +-- @param #number WeaponType (optional) Enum for weapon type ID. This value is only required if you want the group firing to use a specific weapon, for instance using the task on a ship to force it to fire guided missiles at targets within cannon range. See http://wiki.hoggit.us/view/DCS_enum_weapon_flag -- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount ) - self:F2( { self.ControllableName, Vec2, Radius, AmmoCount } ) +function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType ) + self:F2( { self.ControllableName, Vec2, Radius, AmmoCount, WeaponType } ) -- FireAtPoint = { -- id = 'FireAtPoint', @@ -1076,6 +1077,10 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount ) DCSTask.params.expendQty = AmmoCount DCSTask.params.expendQtyEnabled = true end + + if WeaponType then + DCSTask.params.weaponType=WeaponType + end self:T3( { DCSTask } ) return DCSTask From 394b5f5b89994732b04ba16565d120de4a98ecaf Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 30 Apr 2018 22:53:57 +0200 Subject: [PATCH 070/170] ARTY v0.4.0 Improved assigned time for engagement. Next day should be possible now. Added check whether a group started firing within a certain time. --- .../Moose/Functional/Artillery.lua | 169 ++++++++++-------- 1 file changed, 95 insertions(+), 74 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index d18a1b725..01d909b1b 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -55,7 +55,7 @@ -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. -- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. -- @field #number Nshots Number of shots fired on current target. --- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. +-- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. -- @extends Core.Fsm#FSM_CONTROLLABLE -- @@ -114,7 +114,7 @@ ARTY.id="ARTY | " --- Range script version. -- @field #number version -ARTY.version="0.3.0" +ARTY.version="0.4.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -128,7 +128,8 @@ ARTY.version="0.3.0" -- TODO: Check that right reaming vehicle is specified. Blue M818, Red Ural-375. Are there more? -- TODO: Check if ARTY group is still alive. -- TODO: Handle dead events. --- TODO: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. +-- DONE: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. +-- DONE: Improve assigned time for engagement. Next day? ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -185,10 +186,6 @@ function ARTY:New(group) -- Initial group strength. self.IniGroupStrength=#group:GetUnits() - - -- Set ROE and Alarm State. - --self:SetDefaultROE("Free") - --self:SetDefaultAlarmState("Auto") -- Transitions self:AddTransition("*", "Start", "CombatReady") @@ -213,7 +210,7 @@ end -- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. -- @param #number radius (Optional) Radius. Default is 100 m. -- @param #number nshells (Optional) How many shells (or rockets) are fired on target per engagement. Default 5. --- @param #number maxengage (Optional) How many times a target is engaged. Default 9999. +-- @param #number maxengage (Optional) How many times a target is engaged. Default 1. -- @param #string time Day time at which the target should be engaged. Passed as a string in format "08:13:45". Current task will be canceled. -- @param #number weapontype Type of weapon to be used to attack this target. Default ARTY.WeaponType.Auto. -- @return #string Name of the target. Can be used for further reference, e.g. deleting the target from the list. @@ -224,7 +221,7 @@ function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, w -- Set default values. nshells=nshells or 5 radius=radius or 100 - maxengage=maxengage or 9999 + maxengage=maxengage or 1 prio=prio or 50 prio=math.max( 1, prio) prio=math.min(100, prio) @@ -253,7 +250,7 @@ function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, w local _clock=self:_SecondsToClock(_target.time) -- Debug info. - self:T(ARTY.id..string.format("Added target %s, prio=%d, radius=%d, nshells=%d, maxengage=%d, time=%s, weapontype=%d", name, prio, radius, nshells, maxengage, _clock, weapontype)) + self:T(ARTY.id..string.format("Added target %s, prio=%d, radius=%d, nshells=%d, maxengage=%d, time=%s, weapontype=%d", name, prio, radius, nshells, maxengage, tostring(_clock), weapontype)) end @@ -381,7 +378,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) for _, target in pairs(self.targets) do local _clock=self:_SecondsToClock(target.time) local _weapon=self:_WeaponTypeName(target.weapontype) - text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, maxengage=%3d, time=%s, weapon=%s\n", target.name, target.prio, target.radius, target.nshells, target.maxengage, _clock, _weapon) + text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, maxengage=%3d, time=%11s, weapon=%s\n", target.name, target.prio, target.radius, target.nshells, target.maxengage, tostring(_clock), _weapon) end text=text..string.format("******************************************************\n") text=text..string.format("Shell types:\n") @@ -406,6 +403,9 @@ function ARTY:onafterStart(Controllable, From, Event, To) -- Start scheduler to monitor task queue. self.TargetQueueSched=SCHEDULER:New(nil, ARTY._TargetQueue, {self}, 5, self.TargetQueueUpdate) + -- Start scheduler to monitor if ARTY group started firing within a certain time. + self.CheckShootingSched=SCHEDULER:New(nil, ARTY._CheckShootingStarted, {self}, 60, 60) + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -450,8 +450,7 @@ function ARTY:_OnEventShot(EventData) if _nammo==0 then - self:E(ARTY.id.."completely out of ammo") - self.Nshots=0 + self:E(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) self:Winchester() -- Current target is deallocated ==> return @@ -466,29 +465,25 @@ function ARTY:_OnEventShot(EventData) -- Special weapon type requested ==> Check if corresponding ammo is empty. if self.currentTarget.weapontype==ARTY.WeaponType.UnguidedCannon and _nshells==0 then - self:E(ARTY.id.."cannons requested and shells empty") - self.Nshots=0 + self:T(ARTY.id.."Cannons requested and shells empty.") self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedRockets and _nrockets==0 then - self:E(ARTY.id.."rockets requested and rockets empty") - self.Nshots=0 + self:T(ARTY.id.."Rockets requested and rockets empty.") self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - self:E(ARTY.id.."unguided weapon requested and shells+rockets empty") - self.Nshots=0 + self:T(ARTY.id.."Unguided weapon requested and shells+rockets empty.") self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then - self:E(ARTY.id.."cruise missiles requested and missiles empty") - self.Nshots=0 + self:E(ARTY.id.."Cruise missiles requested and missiles empty.") self:CeaseFire(self.currentTarget) return end @@ -499,7 +494,7 @@ function ARTY:_OnEventShot(EventData) self:T(ARTY.id..text) MESSAGE:New(text, 5):ToAllIf(self.Debug) - self.Nshots=0 + -- Cease fire. self:CeaseFire(self.currentTarget) end @@ -616,6 +611,8 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) self.targets[id].time=nil -- Set current target. self.currentTarget=target + -- Set time the target was assigned. + self.currentTarget.Tassigned=timer.getTime() end -- Distance to target @@ -629,9 +626,6 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) -- Start firing. self:_FireAtCoord(target.coord, target.radius, target.nshells, target.weapontype) - -- Check that after a certain time a shot event occured. - --self.CheckShootingSched, self.CheckRearmedSchedID=SCHEDULER:New(nil, self._CheckShootingStarted, {self}, self.WaitForShotTime) - end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -665,9 +659,9 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) - -- ARTY group has no current target any more. - self.currentTarget=nil - + -- Set number of shots to zero. + self.Nshots=0 + -- Get target array index. local id=self:_GetTargetByName(target.name) @@ -678,7 +672,10 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) if target.engaged >= target.maxengage then self:RemoveTarget(target.name) end - + + -- ARTY group has no current target any more. + self.currentTarget=nil + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -692,23 +689,15 @@ end function ARTY:onafterWinchester(Controllable, From, Event, To) self:_EventFromTo("onafterWinchester", Event, From, To) - local text=string.format("Group %s is winchester (out of ammo)!", Controllable:GetName()) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug) - -- Send message. local text=string.format("%s, winchester.", Controllable:GetName()) self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + MESSAGE:New(text, 30):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - -- Remove current target. - if self.currentTarget then - local id=self:_GetTargetByName(self.currentTarget.name) - self.targets[id].underfire=false - self.currentTarget=nil - end - - -- Init rearming. + -- Cease fire first. + self:CeaseFire(self.currentTarget) + + -- Init rearming if possible. self:Rearm() end @@ -745,7 +734,7 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Send message. local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName()) self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) -- Random point 20-100 m away from unit. local coord=self.Controllable:GetCoordinate() @@ -756,7 +745,7 @@ function ARTY:onafterRearm(Controllable, From, Event, To) self.RearmingUnit:RouteGroundOnRoad(pops, 50, 5) -- Start scheduler to monitor ammo count until rearming is complete. - self.CheckRearmedSched=SCHEDULER:New(nil,self._CheckRearmed, {self}, 5, 10) + self.CheckRearmedSched=SCHEDULER:New(nil,self._CheckRearmed, {self}, 20, 20) end @@ -768,6 +757,14 @@ function ARTY:_CheckRearmed() -- Get current ammo. local nammo,nshells,nrockets,nmissiles=self:_GetAmmo(self.Controllable) + -- Rearming status in per cent. + local _rearmpc=nammo/self.Nammo0*100 + + -- Send message. + local text=string.format("%s, rearming %d %% complete.", self.Controllable:GetName(), _rearmpc) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + -- Rearming --> Rearmed --> CombatReady if nammo==self.Nammo0 then self:Rearmed() @@ -806,11 +803,11 @@ function ARTY:_TargetQueue() -- Debug info self:T(ARTY.id..string.format("Group %s, number of targets = %d", self.Controllable:GetName(), #self.targets)) - -- We already have a target. --- if self.currentTarget then --- self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name)) --- return --- end + -- No targets assigned at the moment. + if #self.targets==0 then + self:T(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _TargetQueue.", self.Controllable:GetName())) + return + end -- First check if there is a target with a certain time for attack. for i=1,#self.targets do @@ -851,7 +848,7 @@ function ARTY:_TargetQueue() break end end - + end @@ -896,7 +893,7 @@ function ARTY:_SortTargetQueueTime() -- Debug output. self:T2(ARTY.id.."Sorted targets wrt time:") for i=1,#self.targets do - self:T(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) + self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) end end @@ -1024,21 +1021,30 @@ end function ARTY:_CheckShootingStarted() self:F2() - if self.currentTarget and self.Nshots==0 then + if self.currentTarget then + + -- Current time. + local Tnow=timer.getTime() - -- Get name and id of target. - local name=self.currentTarget.name - local id=self:_GetTargetByName(name) + -- Time that passed after current target has been assigned. + local dt=Tnow-self.currentTarget.Tassigned - -- Debug info. - self:T(ARTY.id..string.format("No shot event after %d seconds. Removing current target %s from list.", self.WaitForShotTime, name)) + + if dt > self.WaitForShotTime and self.Nshots==0 then - -- CeaseFire. - self:CeaseFire(self.currentTarget) + -- Get name and id of target. + local name=self.currentTarget.name + + -- Debug info. + self:T(ARTY.id..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.Controllable:GetName(), self.WaitForShotTime, name)) - -- Remove target from list. - self:RemoveTarget(name) + -- CeaseFire. + self:CeaseFire(self.currentTarget) + + -- Remove target from list. + self:RemoveTarget(name) + end end end @@ -1161,21 +1167,26 @@ end -- @return #string Time in format Hours:minutes:seconds. function ARTY:_SecondsToClock(seconds) self:F3({seconds=seconds}) - + + if seconds==nil then + return nil + --return "00:00:00" + end + -- Seconds local seconds = tonumber(seconds) - if seconds==nil then - return "00:00:00" - end + -- Seconds of this day. + local _seconds=seconds%(60*60*24) if seconds <= 0 then return "00:00:00" else - local hours = string.format("%02.f", math.floor(seconds/3600)) - local mins = string.format("%02.f", math.floor(seconds/60 - (hours*60))) - local secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60)) - return hours..":"..mins..":"..secs + local hours = string.format("%02.f", math.floor(_seconds/3600)) + local mins = string.format("%02.f", math.floor(_seconds/60 - (hours*60))) + local secs = string.format("%02.f", math.floor(_seconds - hours*3600 - mins *60)) + local days = string.format("%d", seconds/(60*60*24)) + return hours..":"..mins..":"..secs.."+"..days --return hours, mins, secs end end @@ -1190,13 +1201,23 @@ function ARTY:_ClockToSeconds(clock) return nil end - -- Split string by ":" - local tsplit=string.gmatch(clock, '([^:]+)') - - -- Get time in seconds + -- Seconds init. local seconds=0 + + -- Split additional days. + local dsplit=self:_split(clock, "+") + + -- Convert days to seconds. + if #dsplit>1 then + seconds=seconds+tonumber(dsplit[2])*60*60*24 + end + + -- Split hours, minutes, seconds + local tsplit=self:_split(dsplit[1], ":") + + -- Get time in seconds local i=1 - for time in tsplit do + for _,time in ipairs(tsplit) do if i==1 then -- Hours seconds=seconds+tonumber(time)*60*60 From 274b44459ee0df7a63b2f56725f89f26a513298f Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 2 May 2018 00:14:05 +0200 Subject: [PATCH 071/170] ARTY v0.5 - Adjusted schedulers. - Improved transitions. - Make rearming unit go back to its original position. - Added user functions. - Using only coodinates for target assignments. - Added dead event handling. --- Moose Development/Moose/Core/Point.lua | 8 +- .../Moose/Functional/Artillery.lua | 498 +++++++++++++----- Moose Development/Moose/Wrapper/Group.lua | 1 + Moose Development/Moose/Wrapper/Unit.lua | 14 +- 4 files changed, 384 insertions(+), 137 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index de1a81cfc..6b46e8e78 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -471,8 +471,8 @@ do -- COORDINATE -- @param height (Optional) parameter specifying the height ASL. -- @return Temperature in Degrees Celsius. function COORDINATE:GetTemperature(height) + self:F2(height) local y=height or self.y - env.info("FF height = "..y) local point={x=self.x, y=height or self.y, z=self.z} -- get temperature [K] and pressure [Pa] at point local T,P=atmosphere.getTemperatureAndPressure(point) @@ -940,13 +940,13 @@ do -- COORDINATE -- @param #COORDINATE ToCoord Coordinate of destination. -- @return #table Table of coordinates on road. function COORDINATE:GetPathOnRoad(ToCoord) - local Path={} + self:F2(ToCoord) local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z) + local Path={} for i, v in ipairs(path) do - --self:E(v) - local coord=COORDINATE:NewFromVec2(v) Path[#Path+1]=COORDINATE:NewFromVec2(v) end + self:F(string.format("Number of points in Path on Road = %d", #Path)) return Path end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 01d909b1b..10c5282eb 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -5,7 +5,7 @@ -- -- ==== -- --- The ARTY class can be used to easily assign targets for artillery units. Multiple targets can be assigned. +-- The ARTY class can be used to easily assign targets for artillery units. Multiple targets can be assigned. -- -- -- ==== @@ -41,21 +41,29 @@ -- @field #number Nshells0 Initial amount of shells of the whole group. -- @field #number Nrockets0 Initial amount of rockets of the whole group. -- @field #number Nmissiles0 Initial amount of missiles of the whole group. --- @field Core.Scheduler#SCHEDULER TargetQueueSched Scheduler updating the target queue and calling OpenFire event. +-- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. +-- @field Core.Scheduler#SCHEDULER scheduler Scheduler object handling various timed functions. +-- @field #number SchedIDTargetQueue Scheduler ID for updating the target queue and calling OpenFire event. -- @field #number TargetQueueUpdate Interval between updates of the target queue. --- @field Core.Scheduler#SCHEDULER CheckRearmedSched Scheduler checking whether reaming of the ARTY group is complete. +-- @field #number SchedIDCheckRearmed Scheduler ID responsible for checking whether reaming of the ARTY group is complete. +-- @field #number SchedIDCheckShooting Scheduler ID for checking whether a group startet firing within a certain time after the fire at point task was assigned. +-- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. +-- @field #number SchedIDStatusReport Scheduler ID for status report messages. The scheduler is only launched in debug mode. -- @field #table DCSdesc DCS descriptors of the ARTY group. -- @field #string Type Type of the ARTY group. +-- @field #string DisplayName Extended type name of the ARTY group. -- @field #number IniGroupStrength Inital number of units in the ARTY group. -- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". -- @field #number Speed Max speed of ARTY group. -- @field Wrapper.Unit#UNIT RearmingUnit Unit designated to rearm the ARTY group. +-- @field Wrapper.Point#COORDINATE RearmingUnitCoord Initial coordinates of the rearming unit. After rearming complete, the unit will return to this position. -- @field #boolean report Arty group sends messages about their current state or target to its coaliton. -- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells. -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. -- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. -- @field #number Nshots Number of shots fired on current target. --- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. +-- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0 km. +-- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. -- @extends Core.Fsm#FSM_CONTROLLABLE -- @@ -80,20 +88,28 @@ ARTY={ Nshells0=0, Nrockets0=0, Nmissiles0=0, - TargetQueueSched=nil, + FullAmmo=0, + scheduler=nil, + SchedIDTargetQueue=nil, TargetQueueUpdate=5, - CheckRearmedSched=nil, + SchedIDCheckRearmed=nil, + SchedIDCheckShooting=nil, + WaitForShotTime=300, + SchedIDStatusReport=nil, DCSdesc=nil, Type=nil, + DisplayName=nil, IniGroupStrength=0, IsArtillery=nil, RearmingUnit=nil, + RearmingUnitCoord=nil, report=true, ammoshells={"weapons.shells"}, ammorockets={"weapons.nurs"}, ammomissiles={"weapons.missiles"}, Nshots=0, - WaitForShotTime=300, + minrange=0, + maxrange=1000000, } --- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag @@ -114,22 +130,24 @@ ARTY.id="ARTY | " --- Range script version. -- @field #number version -ARTY.version="0.4.0" +ARTY.version="0.5.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list: -- DONE: Delete targets from queue user function. --- TODO: Delete entire target queue user function. --- TODO: Add weapon types. +-- DONE: Delete entire target queue user function. +-- TODO: Add weapon types. Done but needs improvements. -- DONE: Add user defined rearm weapon types. -- TODO: Check if target is in range. Maybe this requires a data base with the ranges of all arty units. Pfff... -- TODO: Make ARTY move to reaming position. -- TODO: Check that right reaming vehicle is specified. Blue M818, Red Ural-375. Are there more? -- TODO: Check if ARTY group is still alive. --- TODO: Handle dead events. +-- DONE: Handle dead events. -- DONE: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. -- DONE: Improve assigned time for engagement. Next day? +-- TODO: Improve documentation. +-- TODO: Add pseudo user transitions. OnAfter... ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -137,7 +155,7 @@ ARTY.version="0.4.0" -- @param #ARTY self -- @param Wrapper.Group#GROUP group The GROUP object for which artillery tasks should be assigned. -- @return #ARTY ARTY object. --- @return nil If group does not exist or is not a ground group. +-- @return nil If group does not exist or is not a ground or naval group. function ARTY:New(group) BASE:F2(group) @@ -161,6 +179,9 @@ function ARTY:New(group) -- Set the controllable for the FSM. self:SetControllable(group) + -- Create scheduler object. + self.scheduler=SCHEDULER:New(self) + -- Get DCS descriptors of group. local DCSgroup=Group.getByName(group:GetName()) local DCSunit=DCSgroup:getUnit(1) @@ -193,9 +214,9 @@ function ARTY:New(group) self:AddTransition("Firing", "OpenFire", "Firing") -- Other target assigned self:AddTransition("Firing", "CeaseFire", "CombatReady") self:AddTransition("*", "Winchester", "OutOfAmmo") - self:AddTransition("OutOfAmmo", "Rearm", "Rearming") + self:AddTransition("*", "Rearm", "Rearming") self:AddTransition("Rearming", "Rearmed", "CombatReady") - --self:AddTransition("*", "Dead", "*") + self:AddTransition("*", "Dead", "*") return self end @@ -204,19 +225,22 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Add a group of target(s) for the ARTY group. +--- Assign target coordinates to the ARTY group. Only the first parameter, i.e. the coordinate of the target is mandatory. The remaining parameters are optional and can be used to fine tune the engagement. -- @param #ARTY self --- @param Wrapper.Group#GROUP group Group of targets. +-- @param Wrapper.Point#COORDINATE coord Coordinates of the target. -- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. -- @param #number radius (Optional) Radius. Default is 100 m. -- @param #number nshells (Optional) How many shells (or rockets) are fired on target per engagement. Default 5. -- @param #number maxengage (Optional) How many times a target is engaged. Default 1. --- @param #string time Day time at which the target should be engaged. Passed as a string in format "08:13:45". Current task will be canceled. --- @param #number weapontype Type of weapon to be used to attack this target. Default ARTY.WeaponType.Auto. +-- @param #string time (Optional) Day time at which the target should be engaged. Passed as a string in format "08:13:45". Current task will be canceled. +-- @param #number weapontype (Optional) Type of weapon to be used to attack this target. Default ARTY.WeaponType.Auto, i.e. the DCS logic automatically determins the appropriate weapon. +-- @param #string name (Optional) Name of the target. Default is LL DMS coordinate of the target. If the name was already given, the numbering "#01", "#02",... is appended automatically. -- @return #string Name of the target. Can be used for further reference, e.g. deleting the target from the list. --- @usage ARTY:AssignTargetGroup(GROUP:FindByName("Red Target"), 10, 250, 10, 2, "13:25:45") -function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, weapontype) - self:E({group=group, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype}) +-- @usage paladin=ARTY:New(GROUP:FindByName("Blue Paladin")) +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 10, 300, 10, 1, "08:02:00", ARTY.WeaponType.Auto, "Red Targets 1") +-- paladin:Start() +function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, weapontype, name) + self:T({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype, name=name}) -- Set default values. nshells=nshells or 5 @@ -227,21 +251,17 @@ function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, w prio=math.min(100, prio) weapontype=weapontype or ARTY.WeaponType.Auto - -- Coordinate of target. - local coord=group:GetCoordinate() - local name=group:GetName() - - -- Name of target defined my Lat/long in Degree Minute Second format. - --local name=coord:ToStringLLDMS() - + -- Name of the target. + local _name=name or coord:ToStringLLDMS() + -- Check if the name has already been used for another target. If so, the function returns a new unique name. - name=self:_CheckTargetName(name) + _name=self:_CheckTargetName(_name) -- Time in seconds. local _time=self:_ClockToSeconds(time) -- Prepare target array. - local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage, time=_time, weapontype=weapontype} + local _target={name=_name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage, time=_time, weapontype=weapontype} -- Add to table. table.insert(self.targets, _target) @@ -254,38 +274,28 @@ function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, w end ---- Assign coordinates of a target for the ARTY group. +--- Set minimum firing range. Targets closer than this distance are not engaged. -- @param #ARTY self --- @param Wrapper.Point#COORDINATE coord Coordinates of the target. --- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. --- @param #number radius (Optional) Radius. Default is 100 m. --- @param #number nshells (Optional) How many shells are fired on target per engagement. Default 5. --- @param #number maxengage (Optional) How many times a target is engaged. Default 9999. --- @return #string targetname Name of the target. -function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage) - self:E({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage}) - - -- Set default values. - nshells=nshells or 5 - radius=radius or 100 - maxengage=maxengage or 9999 - prio=prio or 50 - prio=math.max( 1, prio) - prio=math.min(100, prio) - - -- Coordinate and name. - local name=coord:ToStringLLDMS() - - -- Prepare target array. - local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage} - - -- Add to table. - table.insert(self.targets, _target) - - -- Debug info. - self:T(ARTY.id..string.format("Added target %s, radius=%d, nshells=%d, prio=%d, maxengage=%d.", name, prio, radius, nshells, maxengage)) +-- @param #number range Min range in kilometers. Default is 0 km. +function ARTY:SetMinFiringRange(range) + self:F({range=range}) + self.minrange=range or 0 +end - return name +--- Set maximum firing range. Targets further away than this distance are not engaged. +-- @param #ARTY self +-- @param #number range Max range in kilometers. Default is 1000 km. +function ARTY:SetMaxFiringRange(range) + self:F({range=range}) + self.maxrange=range*1000 or 1000*1000 +end + +--- Set time how it is waited a unit the first shot event happens. If no shot is fired after this time, the task to fire is aborted and the target removed. +-- @param #ARTY self +-- @param #number waittime Time in seconds. Default 300 seconds. +function ARTY:SetWaitForShotTime(waittime) + self:F({waittime=waittime}) + self.WaitForShotTime=waittime or 300 end --- Assign a unit which is responsible for rearming the ARTY group. If the unit is too far away from the ARTY group it will be guided towards the ARTY group. @@ -296,6 +306,26 @@ function ARTY:SetRearmingUnit(unit) self.RearmingUnit=unit end +--- Report messages of ARTY group turned on. This is the default. +-- @param #ARTY self +function ARTY:SetReportON() + self.report=true +end + +--- Report messages of ARTY group turned off. Default is on. +-- @param #ARTY self +function ARTY:SetReportOFF() + self.report=false +end + +--- Set target queue update time interval. +-- @param #ARTY self +-- @param #number interval Time interval in seconds. Default is 5 seconds. +function ARTY:SetTargetQueueUpdateInterval(interval) + self:F2({interval=interval}) + self.TargetQueueUpdate=interval or 5 +end + --- Delete target from target list. -- @param #ARTY self -- @param #string name Name of the target. @@ -303,8 +333,19 @@ function ARTY:RemoveTarget(name) self:F2(name) local id=self:_GetTargetByName(name) if id then + self:T(ARTY.id..string.format("Group %s: Removing target %s (id=%d).", self.Controllable:GetName(), name, id)) table.remove(self.targets, id) end + self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) +end + +--- Delete ALL targets from current target list. +-- @param #ARTY self +function ARTY:RemoveAllTargets() + self:F2() + for _,target in pairs(self.targets) do + self:RemoveTarget(target.name) + end end --- Define shell types that are counted to determine the ammo amount the ARTY group has. @@ -353,13 +394,10 @@ end function ARTY:onafterStart(Controllable, From, Event, To) self:_EventFromTo("onafterStart", Event, From, To) + -- Debug output. local text=string.format("Started ARTY for group %s.", Controllable:GetName()) MESSAGE:New(text, 10):ToAllIf(self.Debug) - -- Set the current ROE and alam state. - --self:_SetAlarmState(self.DefaultAlarmState) - --self:_SetROE(self.DefaultROE) - -- Get Ammo. self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:_GetAmmo(self.Controllable) @@ -367,8 +405,11 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Arty group = %s\n", Controllable:GetName()) text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery)) text=text..string.format("Type = %s\n", self.Type) + text=text..string.format("Display Name = %s\n", self.DisplayName) text=text..string.format("Number of units = %d\n", self.IniGroupStrength) text=text..string.format("Max Speed [km/h] = %d\n", self.Speed) + text=text..string.format("Min range [km] = %d\n", self.minrange/1000) + text=text..string.format("Max range [km] = %d\n", self.maxrange/1000) text=text..string.format("Total ammo count = %d\n", self.Nammo0) text=text..string.format("Number of shells = %d\n", self.Nshells0) text=text..string.format("Number of rockets = %d\n", self.Nrockets0) @@ -401,13 +442,50 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:HandleEvent(EVENTS.Dead, self._OnEventDead) -- Start scheduler to monitor task queue. - self.TargetQueueSched=SCHEDULER:New(nil, ARTY._TargetQueue, {self}, 5, self.TargetQueueUpdate) + self.SchedIDTargetQueue=self.scheduler:Schedule(self, ARTY._TargetQueue, {self}, 5, self.TargetQueueUpdate) -- Start scheduler to monitor if ARTY group started firing within a certain time. - self.CheckShootingSched=SCHEDULER:New(nil, ARTY._CheckShootingStarted, {self}, 60, 60) + self.SchedIDCheckShooting=self.scheduler:Schedule(self, ARTY._CheckShootingStarted, {self}, 60, 60) + + -- Start cheduler for status reports. + if self.Debug then + self.SchedIDStatusReport=self.scheduler:Schedule(self, ARTY._StatusReport, {self}, 30, 30) + end end +--- After "Start" event. Initialized ROE and alarm state. Starts the event handler. +-- @param #ARTY self +function ARTY:_StatusReport() + + -- Get Ammo. + local Nammo, Nshells, Nrockets, Nmissiles=self:_GetAmmo(self.Controllable) + + local text=string.format("\n******************************************************\n") + text=text..string.format("Status of ARTY = %s\n", self.Controllable:GetName()) + text=text..string.format("FSM state = %s\n", self:GetState()) + text=text..string.format("Total ammo count = %d\n", Nammo) + text=text..string.format("Number of shells = %d\n", Nshells) + text=text..string.format("Number of rockets = %d\n", Nrockets) + text=text..string.format("Number of missiles = %d\n", Nmissiles) + if self.currentTarget then + text=text..string.format("Current Target = %s\n", tostring(self.currentTarget.name)) + else + text=text..string.format("Current Target = %s\n", "none") + end + text=text..string.format("Nshots curr. Target = %d\n", self.Nshots) + text=text..string.format("Targets:\n") + for _, target in pairs(self.targets) do + local _clock=self:_SecondsToClock(target.time) + local _weapon=self:_WeaponTypeName(target.weapontype) + text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, engaged=%3d, maxengage=%3d, weapon=%s, time=%s\n", + target.name, target.prio, target.radius, target.nshells, target.engaged, target.maxengage, _weapon, tostring(_clock)) + end + text=text..string.format("******************************************************") + env.info(ARTY.id..text) + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -465,19 +543,19 @@ function ARTY:_OnEventShot(EventData) -- Special weapon type requested ==> Check if corresponding ammo is empty. if self.currentTarget.weapontype==ARTY.WeaponType.UnguidedCannon and _nshells==0 then - self:T(ARTY.id.."Cannons requested and shells empty.") + self:T(ARTY.id.."Cannons requested but shells empty.") self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedRockets and _nrockets==0 then - self:T(ARTY.id.."Rockets requested and rockets empty.") + self:T(ARTY.id.."Rockets requested but rockets empty.") self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - self:T(ARTY.id.."Unguided weapon requested and shells+rockets empty.") + self:T(ARTY.id.."Unguided weapon requested but shells and rockets empty.") self:CeaseFire(self.currentTarget) return @@ -505,37 +583,27 @@ function ARTY:_OnEventShot(EventData) end end ---- Eventhandler for dead event. +--- Event handler for event Dead. -- @param #ARTY self -- @param Core.Event#EVENTDATA EventData function ARTY:_OnEventDead(EventData) self:F(EventData) -end - ---- Set task for firing at a coordinate. --- @param #ARTY self --- @param Core.Point#COORDINATE coord Coordinates to fire upon. --- @param #number radius Radius around coordinate. --- @param #number nshells Number of shells to fire. --- @param #number weapontype Type of weapon to use. -function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) - self:E({coord=coord, radius=radius, nshells=nshells}) - - -- Controllable. - local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE - - -- Set ROE to weapon free. - group:OptionROEOpenFire() - -- Get Vec2 - local vec2=coord:GetVec2() + env.info("FF event dead") - -- Get task. - local fire=group:TaskFireAtPoint(vec2, radius, nshells, weapontype) - - -- Execute task. - group:SetTask(fire) - --group:PushTask(fire) + -- Name of controllable. + local _name=self.Controllable:GetName() + + -- Check for correct group. + if EventData.IniGroupName==_name then + + -- Dead Unit. + self:T2(string.format("%s: Captured dead event for unit %s.", _name, EventData.IniUnitName)) + + -- FSM Dead event. We give one second for update of data base. + self:__Dead(1) + end + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -558,13 +626,7 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) if target.time~=nil and self.currentTarget~=nil and self.currentTarget.prio > target.prio then -- Debug info. self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, target.name)) - - -- Reset current task. - --self.Controllable:ClearTasks() - - -- Set number of shots counter to zero. - self.Nshots=0 - + -- Stop firing on current target. self:CeaseFire(self.currentTarget) @@ -580,7 +642,30 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) -- Deny transition. return false end + +-- Distance to target + local range=Controllable:GetCoordinate():Get2DDistance(target.coord) + + -- Check that distance to target is within range. + if rangeself.maxrange then + + -- Debug output. + local text + if rangeself.maxrange then + text=string.format("%s, target is out of range. Distance of %d km is greater than max range of %d km.", Controllable:GetName(), range/1000, self.maxrange/1000) + end + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + -- Remove target. + self:RemoveTarget(target.name) + + -- Deny transition. + return false + end + return true end @@ -605,10 +690,6 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) if id then -- Set under fire flag. self.targets[id].underfire=true - -- Increase engaged counter - self.targets[id].engaged=self.targets[id].engaged+1 - -- Clear the attack time. - self.targets[id].time=nil -- Set current target. self.currentTarget=target -- Set time the target was assigned. @@ -630,7 +711,7 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Before "CeaseFire" event. +--- Before "CeaseFire" event. Nothing to do at the moment. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -658,16 +739,28 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) local text=string.format("%s, ceasing fire on target %s.", Controllable:GetName(), target.name) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) - - -- Set number of shots to zero. - self.Nshots=0 - + -- Get target array index. local id=self:_GetTargetByName(target.name) - -- Target is not under fire any more. - self.targets[id].underfire=false + -- Increase engaged counter + if id then + -- Target was actually engaged. (Could happen that engagement was aborted while group was still aiming.) + if self.Nshots>0 then + self.targets[id].engaged=self.targets[id].engaged+1 + -- Clear the attack time. + self.targets[id].time=nil + end + -- Target is not under fire any more. + self.targets[id].underfire=false + end + -- Clear tasks. + self.Controllable:ClearTasks() + + -- Set number of shots to zero. + self.Nshots=0 + -- If number of engagements has been reached, the target is removed. if target.engaged >= target.maxengage then self:RemoveTarget(target.name) @@ -679,6 +772,21 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Before "Winchester" event. Cease fire on current target. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onbeforeWinchester(Controllable, From, Event, To) + + -- Cease fire first. + if self.currentTarget then + self:CeaseFire(self.currentTarget) + end + + return true +end --- After "Winchester" event. Group is out of ammo. -- @param #ARTY self @@ -693,10 +801,7 @@ function ARTY:onafterWinchester(Controllable, From, Event, To) local text=string.format("%s, winchester.", Controllable:GetName()) self:T(ARTY.id..text) MESSAGE:New(text, 30):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - - -- Cease fire first. - self:CeaseFire(self.currentTarget) - + -- Init rearming if possible. self:Rearm() @@ -741,11 +846,14 @@ function ARTY:onafterRearm(Controllable, From, Event, To) local vec2=coord:GetRandomVec2InRadius(20, 100) local pops=COORDINATE:NewFromVec2(vec2) + -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. + self.RearmingUnitCoord=self.RearmingUnit:GetCoordinate() + -- Route unit to ARTY group. self.RearmingUnit:RouteGroundOnRoad(pops, 50, 5) -- Start scheduler to monitor ammo count until rearming is complete. - self.CheckRearmedSched=SCHEDULER:New(nil,self._CheckRearmed, {self}, 20, 20) + self.SchedIDCheckRearmed=self.scheduler:Schedule(self, ARTY._CheckRearmed, {self}, 20, 20) end @@ -757,8 +865,18 @@ function ARTY:_CheckRearmed() -- Get current ammo. local nammo,nshells,nrockets,nmissiles=self:_GetAmmo(self.Controllable) + -- Number of units still alive. + local units=self.Controllable:GetUnits() + local nunits=0 + if units then + nunits=#units + end + + -- Full Ammo count. + self.FullAmmo=self.Nammo0 * nunits / self.IniGroupStrength + -- Rearming status in per cent. - local _rearmpc=nammo/self.Nammo0*100 + local _rearmpc=nammo/self.FullAmmo*100 -- Send message. local text=string.format("%s, rearming %d %% complete.", self.Controllable:GetName(), _rearmpc) @@ -766,7 +884,7 @@ function ARTY:_CheckRearmed() MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) -- Rearming --> Rearmed --> CombatReady - if nammo==self.Nammo0 then + if nammo==self.FullAmmo then self:Rearmed() end @@ -784,17 +902,127 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) -- Send message. local text=string.format("%s, rearming complete.", Controllable:GetName()) self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) -- Stop scheduler. - self.CheckRearmedSched:Stop() + --self.SchedCheckRearmed:Stop() + if self.SchedIDCheckRearmed then + self.scheduler:Stop(self.SchedIDCheckRearmed) + end + + -- Route unit back to where it came from. + self.RearmingUnit:RouteGroundOnRoad(self.RearmingUnitCoord, 50, 5) end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- After "Dead" event, when a unit has died. When all units of a group are dead, FSM is stopped and eventhandler removed. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterDead(Controllable, From, Event, To) + self:_EventFromTo("onafterDead", Event, From, To) + + -- Number of units left in the group. + local units=self.Controllable:GetUnits() + local nunits=0 + if units~=nil then + nunits=#units + end + + -- Adjust full ammo count + self.FullAmmo=self.Nammo0*nunits/self.IniGroupStrength + + -- Message. + local text=string.format("%s, one of our units just died! %d units left.", self.Controllable:GetName(), nunits) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + self:T(ARTY.id..text) + + -- Go to stop state. + if nunits==0 then + self:Stop() + end + +end + +--- Before "Stop" event. Cease fire on current target. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onbeforeStop(Controllable, From, Event, To) + self:_EventFromTo("onbeforeStop", Event, From, To) + + -- Cease Fire on current target. + if self.currentTarget then + self:CeaseFire(self.currentTarget) + end + + return true +end + +--- After "Stop" event. Remove all target, stop schedulers, unhandle events and stop the FSM. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterStop(Controllable, From, Event, To) + self:_EventFromTo("onafterStop", Event, From, To) + + -- Debug info. + self:T(ARTY.id..string.format("Stopping ARTY FSM for group %s.", Controllable:GetName())) + -- Remove all targets. + --self:RemoveAllTargets() + -- Stop schedulers. + if self.SchedIDTargetQueue then + self.scheduler:Stop(self.SchedIDTargetQueue) + end + if self.SchedIDCheckShooting then + self.scheduler:Stop(self.SchedIDCheckShooting) + end + if self.SchedIDCheckRearmed then + self.scheduler:Stop(self.SchedIDCheckRearmed) + end + -- Unhandle event. + self:UnHandleEvent(EVENTS.Shot) + self:UnHandleEvent(EVENTS.Dead) +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Set task for firing at a coordinate. +-- @param #ARTY self +-- @param Core.Point#COORDINATE coord Coordinates to fire upon. +-- @param #number radius Radius around coordinate. +-- @param #number nshells Number of shells to fire. +-- @param #number weapontype Type of weapon to use. +function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) + self:E({coord=coord, radius=radius, nshells=nshells}) + + -- Controllable. + local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + + -- Set ROE to weapon free. + group:OptionROEOpenFire() + + -- Get Vec2 + local vec2=coord:GetVec2() + + -- Get task. + local fire=group:TaskFireAtPoint(vec2, radius, nshells, weapontype) + + -- Execute task. + group:SetTask(fire) + --group:PushTask(fire) +end + + --- Go through queue of assigned tasks. -- @param #ARTY self function ARTY:_TargetQueue() @@ -805,7 +1033,7 @@ function ARTY:_TargetQueue() -- No targets assigned at the moment. if #self.targets==0 then - self:T(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _TargetQueue.", self.Controllable:GetName())) + self:T3(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _TargetQueue.", self.Controllable:GetName())) return end @@ -904,15 +1132,18 @@ end -- @return Number of ALL shells left from the whole group. function ARTY:_GetAmmo(controllable) self:F2(controllable) - - -- Get all units. - local units=controllable:GetUnits() - + -- Init counter. local nammo=0 local nshells=0 local nrockets=0 local nmissiles=0 + + -- Get all units. + local units=controllable:GetUnits() + if units==nil then + return nammo, nshells, nrockets, nmissiles + end for _,unit in pairs(units) do @@ -1024,17 +1255,22 @@ function ARTY:_CheckShootingStarted() if self.currentTarget then -- Current time. - local Tnow=timer.getTime() + local Tnow=timer.getTime() + -- Get name and id of target. + local name=self.currentTarget.name + -- Time that passed after current target has been assigned. local dt=Tnow-self.currentTarget.Tassigned - + -- Debug info + if self.Nshots==0 then + self:T(ARTY.id..string.format("%s, waiting for %d seconds for first shot on target %s.", self.Controllable:GetName(), dt, name)) + end + + -- Check if we waited long enough and no shot was fired. if dt > self.WaitForShotTime and self.Nshots==0 then - -- Get name and id of target. - local name=self.currentTarget.name - -- Debug info. self:T(ARTY.id..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.Controllable:GetName(), self.WaitForShotTime, name)) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index c595a5dbb..db2092e9e 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -264,6 +264,7 @@ function GROUP:Destroy( GenerateEvent ) if self:IsAir() then self:CreateEventCrash( timer.getTime(), UnitData ) else + env.info("FF create event dead") self:CreateEventDead( timer.getTime(), UnitData ) end end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 2734279bd..1c4236dc3 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -161,18 +161,28 @@ end --- Destroys the UNIT. -- @param #UNIT self +-- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:Destroy() +function UNIT:Destroy( GenerateEvent ) self:F2( self.ObjectName ) local DCSObject = self:GetDCSObject() if DCSObject then + local UnitGroup = self:GetGroup() local UnitGroupName = UnitGroup:GetName() self:F( { UnitGroupName = UnitGroupName } ) + + if GenerateEvent and GenerateEvent == true then + if self:IsAir() then + self:CreateEventCrash( timer.getTime(), DCSObject ) + else + self:CreateEventDead( timer.getTime(), DCSObject ) + end + end + USERFLAG:New( UnitGroupName ):Set( 100 ) - --BASE:CreateEventCrash( timer.getTime(), DCSObject ) DCSObject:destroy() end From 810d900d7eed50de5e6d3e7ace0d324f6eda25c7 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 2 May 2018 22:18:07 +0200 Subject: [PATCH 072/170] Working with Transporting mode on or off. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 369 ++++++++++++------ Moose Development/Moose/Cargo/Cargo.lua | 45 ++- Moose Development/Moose/Cargo/CargoGroup.lua | 249 ++++++++---- Moose Development/Moose/Cargo/CargoUnit.lua | 27 +- Moose Development/Moose/Core/Point.lua | 2 + .../Moose/Wrapper/Controllable.lua | 39 +- .../Moose/Wrapper/Positionable.lua | 9 + 7 files changed, 545 insertions(+), 195 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 68ffc7046..d5022f135 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -1,4 +1,4 @@ ---- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo). +--- **AI** -- (R2.3) - Models the intelligent transportation of infantry and other cargo. -- -- === -- @@ -12,14 +12,69 @@ -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE} +--- # AI\_CARGO\_APC class, extends @{Core.Base#BASE} -- -- === -- +-- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups. +-- +-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- +-- ## Cargo loading. +-- +-- The module will load automatically cargo when the APCs are within boarding or loading range. +-- The boarding or loading range is specified when the cargo is created in the simulation, and therefore, this range depends on the type of cargo +-- and the specified boarding range. +-- +-- ## Enemies nearby. +-- +-- When the APCs are approaching enemy units, something special is happening. +-- The APCs will stop moving, and the loaded infantry will unboard and follow the APCs and will help to defend the group. +-- The carrier will hold the route once the unboarded infantry is further than 50 meters from the APCs, +-- to ensure that the APCs are not too far away from the following running infantry. +-- Once all enemies are cleared, the infantry will board again automatically into the APCs. Once boarded, the APCs will follow its pre-defined route. +-- +-- A combat range needs to be specified in meters at the @{#AI_CARGO_APC.New}() method. +-- This combat range will trigger the unboarding of troops when enemies are within the combat range around the APCs. +-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit range (effectiveness) versus +-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered. +-- A combat range of 350 meters to 500 meters has been proven to be the most effective and efficient. +-- +-- ## Infantry health. +-- +-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield. +-- As a result, the unboarding infantry is very _healthy_ every time it unboards. +-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter. +-- However, infantry that was destroyed when unboarded and following the APCs, won't be respawned again. Destroyed is destroyed. +-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has +-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every +-- time is not so much of an issue ... +-- +-- ## Control the APCs on the map. +-- +-- It is possible also as a human ground commander to influence the path of the APCs, by pointing a new path using the DCS user interface on the map. +-- In this case, the APCs will change the direction towards its new indicated route. However, there is a catch! +-- Once the APCs are near the enemy, and infantry is unboarded, the APCs won't be able to hold the route until the infantry could catch up. +-- The APCs will simply drive on and won't stop! This is a limitation in ED that prevents user actions being controlled by the scripting engine. +-- No workaround is possible on this. +-- +-- ## Cargo deployment. +-- +-- Using the @{#AI_CARGO_APC.Deploy}() method, you are able to direct the APCs towards a point on the battlefield to unboard/unload the cargo at the specific coordinate. +-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment. +-- +-- ## Cargo pickup. +-- +-- Using the @{#AI_CARGO_APC.Pickup}() method, you are able to direct the APCs towards a point on the battlefield to board/load the cargo at the specific coordinate. +-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment. +-- +-- +-- -- @field #AI_CARGO_APC AI_CARGO_APC = { ClassName = "AI_CARGO_APC", - Coordinate = nil -- Core.Point#COORDINATE, + Coordinate = nil, -- Core.Point#COORDINATE, + APC_Cargo = {}, } --- Creates a new AI_CARGO_APC object. @@ -45,7 +100,7 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) - self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) + self:AddTransition( { "Unboarding", "Unloaded" }, "Unloaded", "Unloaded" ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) @@ -131,6 +186,7 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:__Monitor( 1 ) self:SetCarrier( CargoCarrier ) + self.Transporting = false return self end @@ -184,6 +240,11 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier ) end +function AI_CARGO_APC:IsTransporting() + + return self.Transporting == true +end + --- Find a free Carrier within a range. -- @param #AI_CARGO_APC self -- @param Core.Point#COORDINATE Coordinate @@ -214,18 +275,20 @@ end --- Follow Infantry to the Carrier. -- @param #AI_CARGO_APC self -- @param #AI_CARGO_APC Me --- @param Wrapper.Group#GROUP CargoCarrier --- @param Wrapper.Group#GROUP InfantryGroup +-- @param Wrapper.Unit#UNIT APCUnit +-- @param Cargo.CargoGroup#CARGO_GROUP Cargo -- @return #AI_CARGO_APC -function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) +function AI_CARGO_APC:FollowToCarrier( Me, APCUnit, CargoGroup ) + + local InfantryGroup = CargoGroup:GetGroup() self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } ) --if self:Is( "Following" ) then - if CargoCarrier:IsAlive() then + if APCUnit:IsAlive() then -- We check if the Cargo is near to the CargoCarrier. - if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then + if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", APCUnit, 25 ) ) then -- The Cargo does not need to follow the Carrier. Me:Guard() @@ -246,12 +309,12 @@ function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) self:F({FromGround=FromGround}) table.insert( Waypoints, FromGround ) - local ToCoord = CargoCarrier:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 ) + local ToCoord = APCUnit:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 ) local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) self:F({ToGround=ToGround}) table.insert( Waypoints, ToGround ) - local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) + local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, APCUnit, CargoGroup ) self:F({Waypoints = Waypoints}) local Waypoint = Waypoints[#Waypoints] @@ -265,40 +328,43 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterMonitor( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then + if APC and APC:IsAlive() then if self.CarrierCoordinate then - local Coordinate = CargoCarrier:GetCoordinate() - self.Zone:Scan( { Object.Category.UNIT } ) - if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - if self:Is( "Unloaded" ) or self:Is( "Following" ) then - -- There are no enemies within combat range. Load the CargoCarrier. - self:Load() - end - else - if self:Is( "Loaded" ) then - -- There are enemies within combat range. Unload the CargoCarrier. - self:__Unload( 1 ) + if self:IsTransporting() then + local Coordinate = APC:GetCoordinate() + self.Zone:Scan( { Object.Category.UNIT } ) + if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then + if self:Is( "Unloaded" ) or self:Is( "Following" ) then + -- There are no enemies within combat range. Load the CargoCarrier. + self:Load() + end else - if self:Is( "Unloaded" ) then - if not self.Cargo:IsNear( CargoCarrier, 5 ) then + if self:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + self:__Unload( 1 ) + else + if self:Is( "Unloaded" ) then self:Follow() end - end - if self:Is( "Following" ) then - local Distance = Coordinate:Get2DDistance( self.Cargo:GetCoordinate() ) - self:F( { Distance = Distance } ) - if Distance > 40 then - CargoCarrier:RouteStop() - self.CarrierStopped = true - else - if self.CarrierStopped then - if self.Cargo:IsNear( CargoCarrier, 10 ) then - CargoCarrier:RouteResume() - self.CarrierStopped = nil + if self:Is( "Following" ) then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsAlive() then + if not Cargo:IsNear( APCUnit, 40 ) then + APCUnit:RouteStop() + self.CarrierStopped = true + else + if self.CarrierStopped then + if Cargo:IsNear( APCUnit, 25 ) then + APCUnit:RouteResume() + self.CarrierStopped = nil + end + end + end end end end @@ -307,7 +373,7 @@ function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) end end - self.CarrierCoordinate = CargoCarrier:GetCoordinate() + self.CarrierCoordinate = APC:GetCoordinate() end self:__Monitor( -5 ) @@ -316,25 +382,40 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC:onbeforeLoad( Carrier, From, Event, To ) - self:F( { Carrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if Carrier and Carrier:IsAlive() then - for _, Cargo in pairs( self.CargoSet:GetSet() ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( Cargo ) - if Cargo:IsInLoadRadius( Carrier:GetCoordinate() ) then - self:F( "In radius" ) - Carrier:RouteStop() - self:__Board( 1, Cargo ) - Cargo:Board( Carrier:GetUnit(1), 25 ) - return true + local Boarding = false + self.BoardingCount = 0 + + if APC and APC:IsAlive() then + self.APC_Cargo = {} + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) + if Cargo:IsUnLoaded() then + if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then + self:F( { "In radius", APCUnit:GetName() } ) + APC:RouteStop() + --Cargo:Ungroup() + Cargo:Board( APCUnit, 25 ) + self:__Board( 1, Cargo ) + Boarding = true + + -- So now this APCUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.APC_Cargo[APCUnit] = Cargo + break + end + end end end end - - return false + + return Boarding end @@ -348,147 +429,203 @@ function AI_CARGO_APC:onafterBoard( Carrier, From, Event, To, Cargo ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else - self:__Loaded( 1, Cargo ) + self:__Loaded( 1 ) end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To, Cargo ) - self:F( { CargoCarrier, From, Event, To, Cargo } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteResume() - self.Cargo = Cargo + local Loaded = true + + if APC and APC:IsAlive() then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) + if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then + Loaded = false + end + end + end + if Loaded == true then + APC:RouteResume() + end + + return Loaded + end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterUnload( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterUnload( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteStop() - self.Cargo:UnBoard() - self:__Unboard( 10 ) + if APC and APC:IsAlive() then + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + APC:RouteStop() + for _, Cargo in pairs( APCUnit:GetCargo() ) do + Cargo:UnBoard() + self:__Unboard( 10, Cargo ) + end + end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo:GetName() } ) - if CargoCarrier and CargoCarrier:IsAlive() then - if not self.Cargo:IsUnLoaded() then - self:__Unboard( 10 ) + if APC and APC:IsAlive() then + if not Cargo:IsUnLoaded() then + self:__Unboard( 10, Cargo ) else - self:__Unloaded( 1 ) + self:__Unloaded( 1, Cargo ) end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterUnloaded( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo:GetName() } ) - if CargoCarrier and CargoCarrier:IsAlive() then - self:Guard() - self.CargoCarrier = CargoCarrier - CargoCarrier:RouteResume() + local AllUnloaded = true + + --Cargo:Regroup() + + if APC and APC:IsAlive() then + for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do + local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO + self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) + if CargoCheck:IsUnLoaded() == false then + AllUnloaded = false + break + end + end + + if AllUnloaded == true then + self:Guard() + self.CargoCarrier = APC + self.APC_Cargo = {} + end end + self:F( { AllUnloaded = AllUnloaded } ) + return AllUnloaded + end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterFollow( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) self:F( "Follow" ) - if CargoCarrier and CargoCarrier:IsAlive() then - self.Cargo.CargoSet:ForEach( - --- @param Core.Cargo#CARGO Cargo - function( Cargo ) - self:F( { "Follow", Cargo.CargoObject:GetName() } ) - if Cargo.CargoObject:IsAlive() == true then - self:F( { "Follow", Cargo.CargoObject:GetID() } ) - self:FollowToCarrier( self, CargoCarrier, Cargo.CargoObject:GetGroup() ) - end + if APC and APC:IsAlive() then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsUnLoaded() then + self:FollowToCarrier( self, APCUnit, Cargo ) + APCUnit:RouteResume() end - ) + end end end --- @param #AI_CARGO_APC --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC._Pickup( Carrier ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC._Pickup( APC, self ) - Carrier:F( { "AI_CARGO_APC._Pickup:", Carrier:GetName() } ) + APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } ) - if Carrier:IsAlive() then - Carrier:__Load( 1 ) + if APC:IsAlive() then + self:Load() + self.Transporting = true end end --- @param #AI_CARGO_APC --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC._Deploy( Carrier ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC._Deploy( APC, self ) - Carrier:F( { "AI_CARGO_APC._Deploy:", Carrier:GetName() } ) + APC:F( { "AI_CARGO_APC._Deploy:", APC } ) - if Carrier:IsAlive() then - Carrier:__Unload( 1 ) + if APC:IsAlive() then + self:Unload() + self.Transporting = false end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier +-- @param Wrapper.Group#GROUP APC -- @param From -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterPickup( Carrier, From, Event, To, Coordinate, Speed ) +function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed ) - if Carrier and Carrier:IsAlive() then + if APC and APC:IsAlive() then - self.RoutePickup = true + if Coordinate then + self.RoutePickup = true + + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + + local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. - Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. + else + AI_CARGO_APC._Pickup( APC, self ) + end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier +-- @param Wrapper.Group#GROUP APC -- @param From -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterDeploy( Carrier, From, Event, To, Coordinate, Speed ) +function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed ) - if Carrier and Carrier:IsAlive() then + if APC and APC:IsAlive() then self.RouteDeploy = true - Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + + local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. + + APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. end end diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 6c2bbe033..215b1cba7 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -293,7 +293,41 @@ do -- CARGO local CargoFound = _DATABASE:FindCargo( CargoName ) return CargoFound - end + end + + --- Get the x position of the cargo. + -- @param #CARGO self + -- @return #number + function CARGO:GetX() + if self:IsLoaded() then + return self.CargoCarrier:GetCoordinate().x + else + return self.CargoObject:GetCoordinate().x + end + end + + --- Get the y position of the cargo. + -- @param #CARGO self + -- @return #number + function CARGO:GetY() + if self:IsLoaded() then + return self.CargoCarrier:GetCoordinate().z + else + return self.CargoObject:GetCoordinate().z + end + end + + --- Get the heading of the cargo. + -- @param #CARGO self + -- @return #number + function CARGO:GetHeading() + if self:IsLoaded() then + return self.CargoCarrier:GetHeading() + else + return self.CargoObject:GetHeading() + end + end + --- Check if the cargo can be Slingloaded. -- @param #CARGO self @@ -431,7 +465,16 @@ do -- CARGO function CARGO:IsBoarding() return self:Is( "Boarding" ) end + + --- Check if cargo is unboarding. + -- @param #CARGO self + -- @return #boolean true if unboarding + function CARGO:IsUnboarding() + return self:Is( "UnBoarding" ) + end + + --- Check if cargo is alive. -- @param #CARGO self -- @return #boolean true if unloaded diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index d71c81a16..c4712c10e 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -53,47 +53,47 @@ do -- CARGO_GROUP self:F( { Type, Name, LoadRadius } ) self.CargoSet = SET_CARGO:New() + self.CargoGroup = CargoGroup + self.Grouped = true + self.CargoUnitTemplate = {} self:SetDeployed( false ) local WeightGroup = 0 + self.CargoGroup:Destroy() + local GroupName = CargoGroup:GetName() - local CargoName = GroupName:match("(.*)~CARGO") or GroupName + self.CargoName = GroupName:match("(.*)~CARGO") or GroupName self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) ) + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + GroupTemplate.name = self.CargoName .. "#CARGO" + GroupTemplate.groupId = nil - CargoGroup:Destroy() + GroupTemplate.units = {} - -- We iterate through the group template and for each unit in the template, we create a new group with one unit. for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do - - local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - --local GroupName = env.getValueDictByKey( GroupTemplate.name ) - - -- We create a new group object with one unit... - -- First we prepare the template... - GroupTemplate.name = CargoName .. "#CARGO#" .. UnitID - GroupTemplate.groupId = nil - GroupTemplate.units = {} - GroupTemplate.units[1] = UnitTemplate - local UnitName = UnitTemplate.name .. "#CARGO" - GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" - - - -- Then we register the new group in the database - local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) - - -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) + UnitTemplate.name = UnitTemplate.name .. "#CARGO" + local CargoUnitName = UnitTemplate.name + self.CargoUnitTemplate[CargoUnitName] = UnitTemplate + + GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName] + GroupTemplate.units[#GroupTemplate.units].unitId = nil -- And we register the spawned unit as part of the CargoSet. - local Unit = UNIT:FindByName( UnitName ) + local Unit = UNIT:Register( CargoUnitName ) --local WeightUnit = Unit:GetDesc().massEmpty --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) - self.CargoSet:Add( UnitName, CargoUnit ) + local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10 ) + self.CargoSet:Add( CargoUnitName, CargoUnit ) end - + + -- Then we register the new group in the database + self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) self:SetWeight( WeightGroup ) self.CargoLimit = 10 @@ -112,13 +112,108 @@ do -- CARGO_GROUP return self end + + --- Ungroup the cargo group into individual groups with one unit. + -- This is required because by default a group will move in formation and this is really an issue for group control. + -- Therefore this method is made to be able to ungroup a group. + -- This works for ground only groups. + -- @param #CARGO_GROUP self + function CARGO_GROUP:Ungroup() + + if self.Grouped == true then + + self.Grouped = false + + self.CargoGroup:Destroy() + + for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do + local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT + + if CargoUnit:IsUnLoaded() then + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + --local GroupName = env.getValueDictByKey( GroupTemplate.name ) + + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = self.CargoName .. "#CARGO#" .. CargoUnitName + GroupTemplate.groupId = nil + + if CargoUnit:IsUnLoaded() then + GroupTemplate.units = {} + GroupTemplate.units[1] = self.CargoUnitTemplate[CargoUnitName] + GroupTemplate.units[#GroupTemplate.units].unitId = nil + GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX() + GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY() + GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading() + end + + + -- Then we register the new group in the database + local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + end + end + end + + end + + --- Regroup the cargo group into one group with multiple unit. + -- This is required because by default a group will move in formation and this is really an issue for group control. + -- Therefore this method is made to be able to regroup a group. + -- This works for ground only groups. + -- @param #CARGO_GROUP self + function CARGO_GROUP:Regroup() + + self:F("Regroup") + + if self.Grouped == false then + + self.Grouped = true + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + GroupTemplate.name = self.CargoName .. "#CARGO" + GroupTemplate.groupId = nil + GroupTemplate.units = {} + + for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do + local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT + + self:F( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } ) + + if CargoUnit:IsUnLoaded() then + + CargoUnit.CargoObject:Destroy() + + GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName] + GroupTemplate.units[#GroupTemplate.units].unitId = nil + GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX() + GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY() + GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading() + end + end + + -- Then we register the new group in the database + self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + self:F( { "Regroup", GroupTemplate } ) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + end + + end + + --- @param #CARGO_GROUP self -- @param Core.Event#EVENTDATA EventData function CARGO_GROUP:OnEventCargoDead( EventData ) + self:I( EventData ) - local Destroyed = false + local Destroyed = false - if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then + if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() or self:IsUnboarding() then Destroyed = true for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do local Cargo = CargoData -- #CARGO @@ -171,10 +266,10 @@ do -- CARGO_GROUP --- Enter Loaded State. -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier -- @param #string Event -- @param #string From -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) --self:F( { From, Event, To, CargoCarrier, ...} ) @@ -187,6 +282,7 @@ do -- CARGO_GROUP --self.CargoObject:Destroy() self.CargoCarrier = CargoCarrier + self.CargoCarrier:AddCargo( self ) end @@ -244,14 +340,6 @@ do -- CARGO_GROUP end end - - --- Get the amount of cargo units in the group. - -- @param #CARGO_GROUP self - -- @return #CARGO_GROUP - function CARGO_GROUP:GetCount() - return self.CargoSet:Count() - end - --- Enter UnBoarding State. -- @param #CARGO_GROUP self @@ -274,10 +362,12 @@ do -- CARGO_GROUP -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 self.CargoSet:ForEach( + --- @param Cargo.Cargo#CARGO Cargo function( Cargo, NearRadius ) - - Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 3 + if not Cargo:IsDestroyed() then + Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) + Timer = Timer + 3 + end end, { NearRadius } ) @@ -307,7 +397,7 @@ do -- CARGO_GROUP -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) + self:T( { Cargo:GetName(), Cargo.current } ) if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then UnBoarded = false end @@ -362,6 +452,9 @@ do -- CARGO_GROUP end + self.CargoCarrier:RemoveCargo( self ) + self.CargoCarrier = nil + end @@ -371,8 +464,8 @@ do -- CARGO_GROUP -- @return #nil There is no valid Cargo in the CargoGroup. function CARGO_GROUP:GetCoordinate() self:F() - - local Cargo = self.CargoSet:GetFirst() + + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then return Cargo.CargoObject:GetCoordinate() @@ -387,26 +480,46 @@ do -- CARGO_GROUP -- @return #boolean false if the CargoGroup is dead. function CARGO_GROUP:IsAlive() - local Alive = true - - -- For each Cargo within the CargoSet, check if the Cargo is Alive. - -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. - -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. - self.CargoSet:ForEach( - function( Cargo ) - if self:IsLoaded() then - Alive = Alive == true and Cargo.CargoCarrier:IsAlive() - else - Alive = Alive == true and Cargo.CargoObject:IsAlive() - end - end - ) - - return Alive + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO + return Cargo ~= nil end + --- Get the first alive Cargo Unit of the Cargo Group. + -- @param #CARGO_GROUP self + -- @return #CARGO_GROUP + function CARGO_GROUP:GetFirstAlive() + + local CargoFirstAlive = nil + + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + if not Cargo:IsDestroyed() then + CargoFirstAlive = Cargo + break + end + end + return CargoFirstAlive + end + + + --- Get the amount of cargo units in the group. + -- @param #CARGO_GROUP self + -- @return #CARGO_GROUP + function CARGO_GROUP:GetCount() + return self.CargoSet:Count() + end + + + --- Get the amount of cargo units in the group. + -- @param #CARGO_GROUP self + -- @return #CARGO_GROUP + function CARGO_GROUP:GetGroup( Cargo ) + local Cargo = Cargo or self:GetFirstAlive() -- Cargo.Cargo#CARGO + return Cargo.CargoObject:GetGroup() + end + + --- Route Cargo to Coordinate and randomize locations. -- @param #CARGO_GROUP self -- @param Core.Point#COORDINATE Coordinate @@ -430,12 +543,16 @@ do -- CARGO_GROUP -- @return #boolean The Cargo is near to the Carrier. -- @return #nil The Cargo is not near to the Carrier. function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) - --self:F( {NearRadius = NearRadius } ) + self:F( {NearRadius = NearRadius } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO - - if Cargo then - return Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsAlive() then + if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then + self:F( "Near" ) + return true + end + end end return nil @@ -448,7 +565,7 @@ do -- CARGO_GROUP function CARGO_GROUP:IsInLoadRadius( Coordinate ) --self:F( { Coordinate } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then local Distance = 0 @@ -478,7 +595,7 @@ do -- CARGO_GROUP function CARGO_GROUP:IsInReportRadius( Coordinate ) --self:F( { Coordinate } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then self:F( { Cargo } ) diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index d28d113a7..85b6ea6cc 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -146,13 +146,13 @@ do -- CARGO_UNIT local Distance = 5 if From == "UnBoarding" then - if self:IsNear( ToPointVec2, NearRadius ) then + --if self:IsNear( ToPointVec2, NearRadius ) then return true - else + --else - self:__UnBoarding( 1, ToPointVec2, NearRadius ) - end - return false + --self:__UnBoarding( 1, ToPointVec2, NearRadius ) + --end + --return false end end @@ -258,14 +258,17 @@ do -- CARGO_UNIT local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - + + -- Set the CargoObject to state Green to ensure it is boarding! + self.CargoObject:OptionAlarmStateGreen() + local Points = {} local PointStartVec2 = self.CargoObject:GetPointVec2() Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - + local TaskRoute = self.CargoObject:TaskRoute( Points ) self.CargoObject:SetTask( TaskRoute, 2 ) self:__Boarding( -1, CargoCarrier, NearRadius ) @@ -295,7 +298,7 @@ do -- CARGO_UNIT else self:__Boarding( -1, CargoCarrier, NearRadius, ... ) self.RunCount = self.RunCount + 1 - if self.RunCount >= 60 then + if self.RunCount >= 40 then self.RunCount = 0 local Speed = 90 local Angle = 180 @@ -308,12 +311,15 @@ do -- CARGO_UNIT local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + -- Set the CargoObject to state Green to ensure it is boarding! + self.CargoObject:OptionAlarmStateGreen() + local Points = {} local PointStartVec2 = self.CargoObject:GetPointVec2() - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) + Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" ) + Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" ) local TaskRoute = self.CargoObject:TaskRoute( Points ) self.CargoObject:SetTask( TaskRoute, 0.2 ) @@ -367,6 +373,7 @@ do -- CARGO_UNIT if self.CargoObject then self:T("Destroying") self.CargoObject:Destroy() + --self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 ) end end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 15d9cf436..c49f02994 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -893,11 +893,13 @@ do -- COORDINATE function COORDINATE:WaypointGround( Speed, Formation ) self:F2( { Formation, Speed } ) + local RoutePoint = {} RoutePoint.x = self.x RoutePoint.y = self.z RoutePoint.action = Formation or "" + --RoutePoint.formation_template = Formation and "" or nil RoutePoint.speed = ( Speed or 20 ) / 3.6 diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index c63a94af8..6f55ff3d6 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -359,7 +359,7 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) local Controller = self:_GetController() Controller:setTask( DCSTask ) else - BASE:E( DCSControllableName .. " is not alive anymore. Cannot set DCSTask " .. DCSTask ) + BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } ) end end @@ -1964,11 +1964,46 @@ do -- Route methods end -- Route controllable to destination. - self:Route(route, DelaySeconds) + self:Route( route, DelaySeconds ) return self end + + --- Make a task for a GROUND Controllable to drive towards a specific point using (only) roads. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @return Task + function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed ) + + -- Current coordinate. + local FromCoordinate = self:GetCoordinate() + + -- Formation is set to on road. + local Formation="On Road" + + -- Path on road from current position to destination coordinate. + local path=FromCoordinate:GetPathOnRoad( ToCoordinate ) + + -- Route, ground waypoints along roads. + local Route = {} + table.insert( Route, FromCoordinate:WaypointGround( Speed, Formation ) ) + + -- Convert coordinates to ground waypoints and insert into table. + for _, coord in ipairs(path) do + table.insert( Route, coord:WaypointGround( Speed, Formation ) ) + end + + -- Add the final coordinate because the final coordinate in path is last point on road. + local dist=ToCoordinate:Get2DDistance(path[#path]) + if dist>10 then + table.insert( Route, ToCoordinate:WaypointGround( Speed, "Vee" ) ) + end + + return Route + end + --- Make the AIR Controllable fly towards a specific point. -- @param #CONTROLLABLE self diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 2a6605bb9..d9308e8bb 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -808,6 +808,15 @@ function POSITIONABLE:AddCargo( Cargo ) return self end +--- Get all contained cargo. +-- @param #POSITIONABLE self +-- @return #POSITIONABLE +function POSITIONABLE:GetCargo() + return self.__.Cargo +end + + + --- Remove cargo. -- @param #POSITIONABLE self -- @param Core.Cargo#CARGO Cargo From 531c1d7e9018ef5d9b968d2f16e69f1aeb94fd29 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 3 May 2018 00:24:23 +0200 Subject: [PATCH 073/170] ARTY v0.6 (WIP) Added documentation Added user FSM functions. Adjusted FSM (untested) Added task route function. --- .../Moose/Functional/Artillery.lua | 714 +++++++++++++++--- 1 file changed, 604 insertions(+), 110 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 10c5282eb..d54830eb0 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -1,12 +1,20 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- **Functional** - Control artillery units. +--- **Functional** - (R2.4) Control artillery units. +-- +-- === -- -- ![Banner Image](..\Presentations\ARTY\Artillery_Main.png) -- -- ==== -- --- The ARTY class can be used to easily assign targets for artillery units. Multiple targets can be assigned. +-- The ARTY class can be used to easily assign targets for artillery units. -- +-- ## Features: +-- +-- * Multiple targets can be assigned. No restriction on number of targets. +-- * Targets can be given a priority. Engagement of targets is executed a according to their priority. +-- * Engagements can be scheduled, i.e. will be executed at a certain time of the day. +-- * Special weapon types can be selected. -- -- ==== -- @@ -24,13 +32,12 @@ -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- ### Contributions: **[FlightControl](https://forums.eagle.ru/member.php?u=89536)** -- -- ==== -- @module Arty ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - --- ARTY class -- @type ARTY -- @field #string ClassName Name of the class. @@ -45,7 +52,7 @@ -- @field Core.Scheduler#SCHEDULER scheduler Scheduler object handling various timed functions. -- @field #number SchedIDTargetQueue Scheduler ID for updating the target queue and calling OpenFire event. -- @field #number TargetQueueUpdate Interval between updates of the target queue. --- @field #number SchedIDCheckRearmed Scheduler ID responsible for checking whether reaming of the ARTY group is complete. +-- @field #number SchedIDCheckRearmed Scheduler ID responsible for checking whether rearming of the ARTY group is complete. -- @field #number SchedIDCheckShooting Scheduler ID for checking whether a group startet firing within a certain time after the fire at point task was assigned. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. -- @field #number SchedIDStatusReport Scheduler ID for status report messages. The scheduler is only launched in debug mode. @@ -57,6 +64,8 @@ -- @field #number Speed Max speed of ARTY group. -- @field Wrapper.Unit#UNIT RearmingUnit Unit designated to rearm the ARTY group. -- @field Wrapper.Point#COORDINATE RearmingUnitCoord Initial coordinates of the rearming unit. After rearming complete, the unit will return to this position. +-- @field Wrapper.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there. +-- @field Wrapper.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group. -- @field #boolean report Arty group sends messages about their current state or target to its coaliton. -- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells. -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. @@ -65,18 +74,152 @@ -- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0 km. -- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. -- @extends Core.Fsm#FSM_CONTROLLABLE --- ---# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- Artillery class.. +-- +-- The ARTY class enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can +-- interact with the process at certain events or states. -- --- ## Target aquisition... +-- A new ARTY object can be created with the @{#ARTY.New}(*group*) contructor. +-- The parameter *group* has to be a MOOSE Group object and defines ARTY group. +-- +-- The ARTY FSM process can be started by the @{#ARTY.Start}() command. +-- +-- ## The ARTY Process -- -- ![Process](..\Presentations\ARTY\Artillery_Process.png) -- --- The arty process can be described as follows. +-- After the FMS process is started the ARTY group will be in the state **CombatReady**. Once a target is assigned the **OpenFire** event will be triggered and the group starts +-- firing. At this point the group in in the state **Firing**. -- --- ### Submenu +-- When the defined number of shots has been fired on the current target the event **CeaseFire** is triggered. The group will stop firing and go back to the state **CombatReady**. +-- If another target is defined (or multiple engagements of the same target), the cycle starts anew. +-- +-- When the ARTY group runs out of ammunition, the event **Winchester** is triggered and the group enters the state **OutOfAmmo**. +-- In this state, the group is unable to engage further targets. +-- +-- With the @{#ARTY.SetRearmingUnit}(*unit*) command, a special unit can be defined to rearm the ARTY group. If this unit has been assigned and the group has entered the state +-- **OutOfAmmo** the event **Rearm** is triggered followed by a transition to the state **Rearming**. +-- If the rearming unit is less than 100 meters away from the ARTY group, the rearming process starts. If the rearming unit is more than 100 meters away from the ARTY unit, the +-- rearming unit is routed to a point 20 to 100 m from the ARTY group. +-- +-- Once the rearming is complete, the **Rearmed** event is triggered and the group enters the state **CombatReady**. At this point targeted can be engaged again. +-- +-- ## Assigning Targets +-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultanioulsly and are put into a queue. +-- Of course, targets can be added at any time during the mission. For example, once they are detected by a reconnaissance unit. +-- +-- In order to add a target, the function @{#ARTY.AssignTargetCoord}(*coord*, *prio*, *radius*, *nshells*, *maxengage*, *time*, *weapontype*, *name*) has to be used. +-- Only the first parameter *coord* is mandatory while all remaining parameters are all optional. +-- +-- ### Parameters: +-- +-- * *coord*: Coordinates of the target, given as @{Point#COORDINATE} object. +-- * *prio*: Priority of the target. This a number between 1 (high prio) and 100 (low prio). Targets with higher priority are engaged before targets with lower priority. +-- * *radius*: Radius in meters which defines the area the ARTY group will attempt to be hitting. Default is 100 meters. +-- * *nshells*: Number of shots (shells, rockets, missiles) fired by the group at each engagement of a target. Default is 5. +-- * *maxengage*: Number of times a target is engaged. +-- * *time*: Time of day the engagement is schedule in the format "hh:mm:ss" for hh=hours, mm=minutes, ss=seconds. +-- For example "10:15:35". In the case the attack will be executed at a quarter past ten in the morning at the day the mission started. +-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denots the following day. +-- This is useful for longer running missions or if the mission starts at 23:00 hours and the attack should be scheduled at 01:00 hours on the following day. +-- Of course, later days are also possible by appending "+2", "+3", etc. +-- **Note** that the time has to be given as a string. So the enclosing quotation marks "" are important. +-- * *weapontype*: Specified the weapon type that should be used for this attack if the ARTY group has multiple weapons to engage the target. +-- For example, this is useful for naval units which carry a bigger arsenal (cannons and missiles). Default is Auto, i.e. DCS logic selects the appropriate weapon type. +-- *name*: A special name can be defined for this target. Default name are the coordinates of the target in LL DMS format. If a name is already given for another target +-- or the same target should be attacked two or more times with different parameters a suffix "#01", "#02", "#03" is automatically appended to the specified name. +-- +-- ## Target Queue +-- In case, multiple targets have been defined, it is important to understand how the target queue works. +-- +-- Here, the important parameters are the priority *prio*, the number of engagements *maxengage* and the scheduled *time* as described above. +-- +-- For example, we have assigned two targets one with *prio*=10 and the other with *prio*=50 and both targets should be engaged three times (*maxengage*=3). +-- Let's first consider the case that none of the targets is scheduled to be executed at a certain time (*time*=nil). +-- The ARTY group will first engage the target with higher priority (*prio*=10). After the engagement is finished, the target with lower priority is attacked. +-- This is because the target with lower prio has been attacked one time less. After the attack on the lower priority task is finished and both targets +-- have been engaged equally often, the target with the higher priority is engaged again. This coninues until a target has engaged three times. +-- Once the maximum number of engagements is reached, the target is deleted from the queue. +-- +-- In other works, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with +-- respect to their priority. +-- +-- ### Timed Engagements +-- +-- As mentioned above, targets can be engaged at a specific time of the day via the *time* parameter. +-- +-- If the *time* parameter is specified for a target, the first engagement of that target will happen at that time of the day and not before. +-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specifed time. +-- When that timed attack is finished, the *time* parameter is deleted and the remaining engagements are carried out in the same manner as for untimed targets (described above). +-- +-- Of course, it can happen that a scheduled task should be executed at a time, when another target is already under attack. +-- If the priority of the target is higher than the priority of the current target, then the current attack is cancelled and the engagement of the target with the higher +-- priority is started. +-- +-- By contrast, if the current target has a higher priority than the target scheduled at that time, the current attack is finished before the scheduled attack is started. +-- +-- ## Determining the Amount of Ammo +-- +-- In order to determin when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted. +-- For most artillery unit types, this is simple because they only have one type of weapon and hence ammunition. +-- +-- However, there are more complex scenarios. For example, naval units carry a big arsenal of different ammunition types ranging from various cannon shell types +-- over surface-to-air missiles to cruise missiles. Obviously, not all of these ammo types can be employed for artillery tasks. +-- +-- Unfortunately, there is no easy way to count only those ammo types useable as artillery. Therefore, to keep the implementation general the user +-- can specify the names of the ammo types by the following functions: +-- +-- * @{#ARTY.SetShellTypes}(*tableofnames*): Defines the ammo types for unguided cannons. Default is *tableofnames*={"weapons.shells"}, i.e. **all** types of shells are counted. +-- * @{#ARTY.SetRocketTypes}(*tableofnames*): Defines the ammo types of unguided rockets. Default is *tableofnames*={"weapons.nurs"}, i.e. **all** types of rockets are counted. +-- * @{#ARTY.SetMissileTypes}(*tableofnames*): Defines the ammo types of guided missiles. Default is *tableofnames*={"weapons.missiles"}, i.e. **all** types of missiles are counted. +-- +-- **Note** that the default parameters "weapons.shells", "weapons.nurs", "weapons.missiles" **should in priciple** capture all the corresponding ammo types. +-- However, the logic searches for the string "weapon.missies" in the ammo type. Especially for missiles, this string is often not contained in the ammo type descriptor. +-- +-- One way to determin which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}(). +-- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file. +-- +-- ## Empoying Selected Weapons +-- +-- If an ARTY group carries multiple weapons, which can be used for artillery task, a certain weapon type can be selected to attack the target. +-- This is done via the *weapontype* parameter of the @{#ARTY.AssignTargetCoord}(..., *weapontype*, ...) function. +-- +-- The enumerator @{#ARTY.WeaponType} has been defined to select a certain weapon type. Supported values are: +-- +-- * @{#ARTY.WeaponType}.Auto: Automatic weapon selection by the DCS logic. This is the default setting. +-- * @{#ARTY.WeaponType}.Cannon: Only cannons are used during the attack. Corresponding ammo type are shells and can be defined by @{#ARTY.SetShellTypes}. +-- * @{#ARTY.WeaponType}.Rockets: Only unguided are used during the attack. Corresponding ammo type are rockets/nurs and can be defined by @{#ARTY.SetRocketTypes}. +-- * @{#ARTY.WeaponType}.UnguidedAny: Any unguided weapon (cannons or rockes) will be used. +-- * @{#ARTY.WeaponType}.GuidedMissile: Any guided missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. +-- * @{#ARTY.WeaponType}.CruiseMissile: Only cruise missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. +-- +-- ## Fine Tuning +-- +-- The mission designer has a few options to tailor the ARTY object according to his needs. +-- +-- * @{#ARTY.RemoveAllTargets}() removes all targets from the target queue. +-- * @{#ARTY.RemoveTarget}(*name*) deletes the target with *name* from the target queue. +-- * @{#ARTY.SetMaxFiringRange}(*range*) defines the maximum firing range. Targets further away than this distance are not engaged. +-- * @{#ARTY.SetMinFiringRange}(*range*) defines the minimum firing range. Targets closer than this distance are not engaged. +-- * @{#ARTY.SetRearmingUnit}(*unit*) sets the unit resposible for rearming of the ARTY group once it is out of ammo. +-- * @{#ARTY.SetReportON}() and @{#ARTY.SetReportOFF}() can be used to enable/disable status reports of the ARTY group send to all coalition members. +-- * @{#ARTY.SetTargetQueueUpdateInterval}(*interval*) sets the interval (in seconds) at which the target queue is updated. Default is every 5 seconds. +-- * @{#ARTY.SetWaitForShotTime}(*waittime*) sets the time after which a target is deleted from the queue if no shooting event occured after the target engagement started. +-- Default is 300 seconds. Note that this can for example happen, when the assigned target is out of range. +-- * @{#ARTY.SetDebugON}() and @{#ARTY.SetDebugOFF}() can be used to enable/disable the debug mode. +-- +-- ## Examples +-- +-- ### Assigning Multiple Targets +-- This basic example illustrates how to assign multiple targets. +-- +-- ### Scheduled Engagements +-- This example shows how to execute an engagement at a certain time. +-- +-- ### Specific Weapons +-- This example demonstrates how to use specific weapons during an engagement. +-- -- -- @field #ARTY ARTY={ @@ -103,6 +246,8 @@ ARTY={ IsArtillery=nil, RearmingUnit=nil, RearmingUnitCoord=nil, + RearmingPlaceCoord=nil, + InitialCoord=nil, report=true, ammoshells={"weapons.shells"}, ammorockets={"weapons.nurs"}, @@ -116,10 +261,9 @@ ARTY={ -- @list WeaponType ARTY.WeaponType={ Auto=1073741822, + Cannon=805306368, + Rockets=30720, UnguidedAny=805339120, - UnguidedCannon=805306368, - UnguidedRockets=30720, - GuidedAny=268402702, GuidedMissile=268402688, CruiseMissile=2097152, } @@ -128,26 +272,26 @@ ARTY.WeaponType={ -- @field #string id ARTY.id="ARTY | " ---- Range script version. +--- Arty script version. -- @field #number version -ARTY.version="0.5.0" +ARTY.version="0.6.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list: -- DONE: Delete targets from queue user function. -- DONE: Delete entire target queue user function. --- TODO: Add weapon types. Done but needs improvements. +-- DONE: Add weapon types. Done but needs improvements. -- DONE: Add user defined rearm weapon types. --- TODO: Check if target is in range. Maybe this requires a data base with the ranges of all arty units. Pfff... --- TODO: Make ARTY move to reaming position. --- TODO: Check that right reaming vehicle is specified. Blue M818, Red Ural-375. Are there more? --- TODO: Check if ARTY group is still alive. +-- DONE: Check if target is in range. Maybe this requires a data base with the ranges of all arty units. +-- DONE: Make ARTY move to rearming position. +-- DONE: Check that right rearming vehicle is specified. Blue M818, Red Ural-375. Are there more? +-- DONE: Check if ARTY group is still alive. -- DONE: Handle dead events. -- DONE: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. -- DONE: Improve assigned time for engagement. Next day? --- TODO: Improve documentation. --- TODO: Add pseudo user transitions. OnAfter... +-- DONE: Improve documentation. +-- DONE: Add pseudo user transitions. OnAfter... ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -179,6 +323,9 @@ function ARTY:New(group) -- Set the controllable for the FSM. self:SetControllable(group) + -- Set the initial coordinates of the ARTY group. + self.InitialCoord=group:GetCoordinate() + -- Create scheduler object. self.scheduler=SCHEDULER:New(self) @@ -211,13 +358,177 @@ function ARTY:New(group) -- Transitions self:AddTransition("*", "Start", "CombatReady") self:AddTransition("CombatReady", "OpenFire", "Firing") - self:AddTransition("Firing", "OpenFire", "Firing") -- Other target assigned + self:AddTransition("CombatReady", "Winchester", "OutOfAmmo") + self:AddTransition("Firing", "OpenFire", "Firing") self:AddTransition("Firing", "CeaseFire", "CombatReady") - self:AddTransition("*", "Winchester", "OutOfAmmo") - self:AddTransition("*", "Rearm", "Rearming") + self:AddTransition("OutOfAmmo", "Rearm", "Rearming") self:AddTransition("Rearming", "Rearmed", "CombatReady") + self:AddTransition("CombatReady", "Move", "Moving") + self:AddTransition("Moving", "Arrived", "CombatReady") self:AddTransition("*", "Dead", "*") + --- User function for OnBefore "OpenFire" event. + -- @function [parent=#ARTY] OnBeforeOpenFire + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + -- @return #boolean If true, allow transition to OnAfterOpenFire. + + --- User function for OnAfter "OpenFire" event. + -- @function [parent=#ARTY] OnAfterOpenFire + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + + + --- User function for OnBefore "CeaseFire" event. + -- @function [parent=#ARTY] OnBeforeCeaseFire + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + -- @return #boolean If true, allow transition to OnAfterCeaseFire. + + --- User function for OnAfter "CeaseFire" event. + -- @function [parent=#ARTY] OnAfterCeaseFire + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + + + --- User function for OnBefore "Winchester" event. + -- @function [parent=#ARTY] OnBeforeWinchester + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean If true, allow transition to OnAfterWinchester. + + --- User function for OnAfter "Winchester" event. + -- @function [parent=#ARTY] OnAfterWinchester + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "Rearm" event. + -- @function [parent=#ARTY] OnBeforeRearm + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean If true, allow transition to OnAfterRearm. + + --- User function for OnAfter "Rearm" event. + -- @function [parent=#ARTY] OnAfterRearm + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "Rearmed" event. + -- @function [parent=#ARTY] OnBeforeRearmed + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean If true, allow transition to OnAfterRearmed. + + --- User function for OnAfter "Rearmed" event. + -- @function [parent=#ARTY] OnAfterRearmed + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "Start" event. + -- @function [parent=#ARTY] OnBeforeStart + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean If true, allow transition to OnAfterStart. + + --- User function for OnAfter "Start" event. + -- @function [parent=#ARTY] OnAfterStart + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnBefore "Dead" event. + -- @function [parent=#ARTY] OnBeforeDead + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @return #boolean If true, allow transition to OnAfterDead. + + --- User function for OnAfter "Dead" event. + -- @function [parent=#ARTY] OnAfterDead + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnEnter "CombatReady" state. + -- @function [parent=#ARTY] OnEnterCombatReady + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "Firing" state. + -- @function [parent=#ARTY] OnEnterFiring + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "OutOfAmmo" state. + -- @function [parent=#ARTY] OnEnterOutOfAmmo + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "Rearming" state. + -- @function [parent=#ARTY] OnEnterRearming + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + return self end @@ -306,6 +617,14 @@ function ARTY:SetRearmingUnit(unit) self.RearmingUnit=unit end +--- Defines the rearming place of the ARTY group. If the place is too far away from the ARTY group it will be routed to the place. +-- @param #ARTY self +-- @param Wrapper.Point#COORDINATE coord Coordinates of the rearming place. +function ARTY:SetRearmingPlace(coord) + self:F({coord=coord}) + self.RearmingPlaceCoord=coord +end + --- Report messages of ARTY group turned on. This is the default. -- @param #ARTY self function ARTY:SetReportON() @@ -318,6 +637,18 @@ function ARTY:SetReportOFF() self.report=false end +--- Turn debug mode on. Information is printed to screen. +-- @param #ARTY self +function ARTY:SetDebugON() + self.Debug=true +end + +--- Turn debug mode off. This is the default setting. +-- @param #ARTY self +function ARTY:SetDebugOFF() + self.Debug=false +end + --- Set target queue update time interval. -- @param #ARTY self -- @param #number interval Time interval in seconds. Default is 5 seconds. @@ -407,13 +738,20 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Type = %s\n", self.Type) text=text..string.format("Display Name = %s\n", self.DisplayName) text=text..string.format("Number of units = %d\n", self.IniGroupStrength) - text=text..string.format("Max Speed [km/h] = %d\n", self.Speed) - text=text..string.format("Min range [km] = %d\n", self.minrange/1000) - text=text..string.format("Max range [km] = %d\n", self.maxrange/1000) + text=text..string.format("Max Speed = %d km/h\n", self.Speed) + text=text..string.format("Min range = %d km\n", self.minrange/1000) + text=text..string.format("Max range = %d km\n", self.maxrange/1000) text=text..string.format("Total ammo count = %d\n", self.Nammo0) text=text..string.format("Number of shells = %d\n", self.Nshells0) text=text..string.format("Number of rockets = %d\n", self.Nrockets0) text=text..string.format("Number of missiles = %d\n", self.Nmissiles0) + if self.RearmingUnit then + text=text..string.format("Reaming unit = %s\n", self.RearmingUnit:GetName()) + end + if self.RearmingPlaceCoord then + local dist=self.InitialCoord:Get2DDistance(self.RearmingPlaceCoord) + text=text..string.format("Reaming coord dist. = %d m\n", dist) + end text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do @@ -460,6 +798,7 @@ function ARTY:_StatusReport() -- Get Ammo. local Nammo, Nshells, Nrockets, Nmissiles=self:_GetAmmo(self.Controllable) + local Tnow=timer.getTime() local text=string.format("\n******************************************************\n") text=text..string.format("Status of ARTY = %s\n", self.Controllable:GetName()) @@ -469,7 +808,8 @@ function ARTY:_StatusReport() text=text..string.format("Number of rockets = %d\n", Nrockets) text=text..string.format("Number of missiles = %d\n", Nmissiles) if self.currentTarget then - text=text..string.format("Current Target = %s\n", tostring(self.currentTarget.name)) + text=text..string.format("Current Target = %s\n", tostring(self.currentTarget.name)) + text=text..string.format("Curr. Tgt assigned = %d\n", Tnow-self.currentTarget.Tassigned) else text=text..string.format("Current Target = %s\n", "none") end @@ -528,7 +868,9 @@ function ARTY:_OnEventShot(EventData) if _nammo==0 then - self:E(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) + -- Cease fire first. + self:CeaseFire(self.currentTarget) self:Winchester() -- Current target is deallocated ==> return @@ -537,17 +879,17 @@ function ARTY:_OnEventShot(EventData) -- Weapon type name for current target. local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) - self:E(ARTY.id..string.format("nammo=%d, nshells=%d, nrockets=%d, nmissiles=%d", _nammo, _nshells, _nrockets, _nmissiles)) - self:E(ARTY.id..string.format("Weapontype = %s", _weapontype)) + self:T(ARTY.id..string.format("nammo=%d, nshells=%d, nrockets=%d, nmissiles=%d", _nammo, _nshells, _nrockets, _nmissiles)) + self:T(ARTY.id..string.format("Weapontype = %s", _weapontype)) -- Special weapon type requested ==> Check if corresponding ammo is empty. - if self.currentTarget.weapontype==ARTY.WeaponType.UnguidedCannon and _nshells==0 then + if self.currentTarget.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then self:T(ARTY.id.."Cannons requested but shells empty.") self:CeaseFire(self.currentTarget) return - elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedRockets and _nrockets==0 then + elseif self.currentTarget.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then self:T(ARTY.id.."Rockets requested but rockets empty.") self:CeaseFire(self.currentTarget) @@ -559,9 +901,9 @@ function ARTY:_OnEventShot(EventData) self:CeaseFire(self.currentTarget) return - elseif self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then + elseif (self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile) and _nmissiles==0 then - self:E(ARTY.id.."Cruise missiles requested and missiles empty.") + self:T(ARTY.id.."Guided or Cruise missiles requested but all missiles empty.") self:CeaseFire(self.currentTarget) return end @@ -588,9 +930,7 @@ end -- @param Core.Event#EVENTDATA EventData function ARTY:_OnEventDead(EventData) self:F(EventData) - - env.info("FF event dead") - + -- Name of controllable. local _name=self.Controllable:GetName() @@ -610,18 +950,17 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Before "OpenFire" event. +--- Before "OpenFire" event. Checks if group already has a target. Checks for valid min/max range and removes the target if necessary. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param #table target Array holding the target info. --- @return #boolean If true proceed to onafterOpenfire. +-- @return #boolean If true, proceed to onafterOpenfire. function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onbeforeOpenFire", Event, From, To) - - + -- If this target has an attack time and it's prio is higher than the current task, we allow the transition. if target.time~=nil and self.currentTarget~=nil and self.currentTarget.prio > target.prio then -- Debug info. @@ -637,7 +976,7 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) -- Check that group has no current target already. if self.currentTarget then -- Debug info. - self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name)) + self:T2(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name)) -- Deny transition. return false @@ -669,18 +1008,17 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) return true end ---- After "OpenFire" event. +--- After "OpenFire" event. Sets the current target and starts the fire at point task. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param #table target Array holding the target info. _target={coord=coord, radius=radius, nshells=nshells, engaged=0, underattack=false} +-- @param #table target Array holding the target info. function ARTY:onafterOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onafterOpenFire", Event, From, To) - local _coord=target.coord --Core.Point#COORDINATE - + --local _coord=target.coord --Core.Point#COORDINATE --_coord:MarkToAll("Arty Target") -- Get target array index. @@ -711,21 +1049,7 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Before "CeaseFire" event. Nothing to do at the moment. --- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. --- @param #table target Array holding the target info. --- @return #boolean -function ARTY:onbeforeCeaseFire(Controllable, From, Event, To, target) - self:_EventFromTo("onbeforeCeaseFire", Event, From, To) - - return true -end - ---- After "CeaseFire" event. +--- After "CeaseFire" event. Clears task of the group and removes the target if max engagement was reached. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -778,17 +1102,15 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. +-- @return #boolean If true, proceed to onafterWinchester. function ARTY:onbeforeWinchester(Controllable, From, Event, To) - -- Cease fire first. - if self.currentTarget then - self:CeaseFire(self.currentTarget) - end + return true end ---- After "Winchester" event. Group is out of ammo. +--- After "Winchester" event. Group is out of ammo. Trigger "Rearm" event. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -815,18 +1137,20 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. +-- @return #boolean If true, proceed to onafterRearm. function ARTY:onbeforeRearm(Controllable, From, Event, To) self:_EventFromTo("onbeforeRearm", Event, From, To) if self.RearmingUnit and self.RearmingUnit:IsAlive() then return true + elseif self.RearmingPlaceCoord then + return true else return false end end - --- After "Rearm" event. Send message if reporting is on. Route rearming unit to ARTY group. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -836,28 +1160,95 @@ end function ARTY:onafterRearm(Controllable, From, Event, To) self:_EventFromTo("onafterRearm", Event, From, To) - -- Send message. - local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName()) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + -- Coordinate of ARTY unit. + local coordARTY=self.Controllable:GetCoordinate() + local coordRARM + if self.RearmingUnit then + -- Coordinate of the rearming unit. + coordRARM=self.RearmingUnit:GetCoordinate() + -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. + self.RearmingUnitCoord=coordRARM + end - -- Random point 20-100 m away from unit. - local coord=self.Controllable:GetCoordinate() - local vec2=coord:GetRandomVec2InRadius(20, 100) - local pops=COORDINATE:NewFromVec2(vec2) + if self.RearmingUnit and self.RearmingPlaceCoord and self.Speed>0 then - -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. - self.RearmingUnitCoord=self.RearmingUnit:GetCoordinate() + -- Rearming unit and ARTY group meet at rearming place. + local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) + local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) + + -- Route ARTY group to rearming place. + if dA>100 then + self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) + end + + -- Route Rearming unit to rearming place + if dR>100 then + self.RearmingUnit:RouteGroundOnRoad(self.RearmingPlaceCoord, 50, 1) + end - -- Route unit to ARTY group. - self.RearmingUnit:RouteGroundOnRoad(pops, 50, 5) + elseif self.RearmingUnit then + + -- Send message. + local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + + -- Distance between ARTY group and rearming unit. + local distance=coordARTY:Get2DDistance(coordRARM) + + -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. + if distance > 100 then + -- Random point 20-100 m away from unit. + local vec2=coord:GetRandomVec2InRadius(20, 100) + local pops=COORDINATE:NewFromVec2(vec2) + + -- Route unit to ARTY group. + self.RearmingUnit:RouteGroundOnRoad(pops, 50, 1) + end + end -- Start scheduler to monitor ammo count until rearming is complete. self.SchedIDCheckRearmed=self.scheduler:Schedule(self, ARTY._CheckRearmed, {self}, 20, 20) end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Check if ARTY group is reamed. +--- After "Rearmed" event. Send message if reporting is on and stop the scheduler. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterRearmed(Controllable, From, Event, To) + self:_EventFromTo("onafterRearmed", Event, From, To) + + -- Send message. + local text=string.format("%s, rearming complete.", Controllable:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + + -- Stop scheduler. + if self.SchedIDCheckRearmed then + self.scheduler:Stop(self.SchedIDCheckRearmed) + end + + -- Route ARTY group backto where it came from (if distance is > 100 m). + local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) + if d1>100 then + self.Controllable:RouteGroundOnRoad(self.InitialCoord, self.Speed, 5) + end + + -- Route unit back to where it came from (if distance is > 100 m). + if self.RearmingUnit and self.RearmingUnit:IsAlive() then + local d=self.RearmingUnit:GetCoordinate():Get2DDistance(self.RearmingUnitCoord) + if d>100 then + self.RearmingUnit:RouteGroundOnRoad(self.RearmingUnitCoord, 50, 1) + end + end + +end + +--- Check if ARTY group is rearmed. -- @param #ARTY self function ARTY:_CheckRearmed() self:F2() @@ -890,33 +1281,61 @@ function ARTY:_CheckRearmed() end ---- After "Rearmed" event. Send message if reporting is on and stop the scheduler. + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Before "Move" event. Check if a unit to rearm the ARTY group has been defined. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function ARTY:onafterRearmed(Controllable, From, Event, To) - self:_EventFromTo("onafterRearmed", Event, From, To) +-- @param Wrapper.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. +-- @param #boolean OnRoad If true group should move on road mainly. +-- @return #boolean If true, proceed to onafterMove. +function ARTY:onbeforeMove(Controllable, From, Event, To, ToCoord, OnRoad) + self:_EventFromTo("onbeforeMove", Event, From, To) - -- Send message. - local text=string.format("%s, rearming complete.", Controllable:GetName()) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - - -- Stop scheduler. - --self.SchedCheckRearmed:Stop() - if self.SchedIDCheckRearmed then - self.scheduler:Stop(self.SchedIDCheckRearmed) + -- Check if group can actually move... + if self.Speed==0 then + return false + end + + -- Cease fire first. + if self.currentTarget then + self:CeaseFire(self.currentTarget) + end + + return true +end + +--- After "Move" event. Route group to given coordinate. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. +-- @param #boolean OnRoad If true group should move on road mainly. +function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, OnRoad) + self:_EventFromTo("onafterMove", Event, From, To) + + -- Set alarm state to green and ROE to weapon hold. + self.Controllable:OptionAlarmStateGreen() + self.Controllable:OptionROEHoldFire() + + -- Route group to coodinate. + if OnRoad then + self.Controllable:RouteGroundOnRoad(ToCoord, self.Speed, 1) + else + self.Controllable:RouteGroundTo(ToCoord, self.Speed, "Vee", 1) end - -- Route unit back to where it came from. - self.RearmingUnit:RouteGroundOnRoad(self.RearmingUnitCoord, 50, 5) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- After "Dead" event, when a unit has died. When all units of a group are dead, FSM is stopped and eventhandler removed. +--- After "Dead" event, when a unit has died. When all units of a group are dead trigger "Stop" event. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -953,6 +1372,7 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. +-- @return #boolean If true, proceed to onafterStop. function ARTY:onbeforeStop(Controllable, From, Event, To) self:_EventFromTo("onbeforeStop", Event, From, To) @@ -964,7 +1384,7 @@ function ARTY:onbeforeStop(Controllable, From, Event, To) return true end ---- After "Stop" event. Remove all target, stop schedulers, unhandle events and stop the FSM. +--- After "Stop" event. Stop schedulers and unhandle events. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -1351,20 +1771,17 @@ function ARTY:_WeaponTypeName(tnumber) local name="unknown" if tnumber==ARTY.WeaponType.Auto then name="Auto (Cannon, Rockets, Missiles)" - elseif tnumber==ARTY.WeaponType.CruiseMissile then - name="Cruise Missile" - elseif tnumber==ARTY.WeaponType.GuidedAny then - name="Any Guided Missile" - elseif tnumber==ARTY.WeaponType.GuidedMissile then - name="Guided Missile" + elseif tnumber==ARTY.WeaponType.Cannon then + name="Cannon" + elseif tnumber==ARTY.WeaponType.Rockets then + name="Rockets" elseif tnumber==ARTY.WeaponType.UnguidedAny then name="Any Unguided Weapon (Cannon or Rockets)" - elseif tnumber==ARTY.WeaponType.UnguidedCannon then - name="Unguided Cannon" - elseif tnumber==ARTY.WeaponType.UnguidedRockets then - name="Unguided Rockets" + elseif tnumber==ARTY.WeaponType.CruiseMissile then + name="Cruise Missile" + elseif tnumber==ARTY.WeaponType.GuidedMissile then + name="Guided Missile" end - return name end @@ -1471,4 +1888,81 @@ function ARTY:_ClockToSeconds(clock) return seconds end -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Route group to a certain point. +-- @param #ARTY self +-- @param Wrapper.Group#GROUP group Group to route. +-- @param Core.Point#COORDINATE ToCoord Coordinate where we want to go. +-- @param #number Speed Speed in km/h. +-- @param #boolean OnRoad If true, use (mainly) roads. +function ARTY:_Move(group, ToCoord, Speed, OnRoad) + + -- Clear all tasks. + group:ClearTasks() + group:OptionAlarmStateGreen() + group:OptionROEHoldFire() + + -- Set formation. + local formation = "Off road" + + -- Current coordinates of group. + local cpini=group:GetCoordinate() + cpini:SmokeWhite() + + -- Distance between current and final point. + local dist=cpini:Get2DDistance(ToCoord) + + -- Waypoint and task arrays. + local path={} + local task={} + + -- First waypoint is the current position of the group. + path[#path+1]=cpini:WaypointGround(Speed, formation) + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, 0, false) + + path[#path+1]=ToCoord:WaypointGround(Speed, formation) + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, 1, true) + + -- Init waypoints of the group. + local Waypoints={} + + -- New points are added to the default route. + for i,p in ipairs(path) do + table.insert(Waypoints, i, path[i]) + end + + -- Set task for all waypoints. + for i,wp in ipairs(Waypoints) do + group:SetTaskWaypoint(Waypoints[i], task[i]) + end + + -- Submit task and route group along waypoints. + group:Route(Waypoints) + +end + +--- Function called when group is passing a waypoint. +-- @param Wrapper.Group#GROUP group Group for which waypoint passing should be monitored. +-- @param #ARTY arty ARTY object. +-- @param #number i Waypoint number that has been reached. +-- @param #boolean final True if it is the final waypoint. +function ARTY._PassingWaypoint(group, arty, i, final) + + -- Debug message. + local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final)) + + local pos=group:GetCoordinate() + local MarkerID=pos:MarkToAll(string.format("Reached Waypoint %d of group %s", i, group:GetName())) + pos:SmokeRed() + + MESSAGE:New(text,10):ToAll() + env.info(ARTY.id..text) + + -- Move --> Moving --> Arrived --> CombatReady. + if final then + arty:Arrived() + end + +end + \ No newline at end of file From 4fccfa38d425967ab60347bccc36635e1a5ee8f2 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 3 May 2018 23:42:03 +0200 Subject: [PATCH 074/170] ARTY v0.7 Added "NewTarget" event. Improved task function for waypoints Removed TargetQueue scheduler. --- Moose Development/Moose/Core/Fsm.lua | 8 +- .../Moose/Functional/Artillery.lua | 221 +++++++++++++----- 2 files changed, 166 insertions(+), 63 deletions(-) diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 4e959004f..62b80aee2 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -682,15 +682,15 @@ do -- FSM end if execute then + self:_call_handler("onafter", EventName, Params, EventName ) + self:_call_handler("OnAfter", EventName, Params, EventName ) + -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! --if from ~= to then self:_call_handler("onenter", To, Params, EventName ) self:_call_handler("OnEnter", To, Params, EventName ) --end - - self:_call_handler("onafter", EventName, Params, EventName ) - self:_call_handler("OnAfter", EventName, Params, EventName ) - + self:_call_handler("onstate", "change", Params, EventName ) end else diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index d54830eb0..41e6e1f29 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -3,7 +3,7 @@ -- -- === -- --- ![Banner Image](..\Presentations\ARTY\Artillery_Main.png) +-- ![Banner Image](..\Presentations\ARTY\ARTY_Main.png) -- -- ==== -- @@ -50,8 +50,6 @@ -- @field #number Nmissiles0 Initial amount of missiles of the whole group. -- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. -- @field Core.Scheduler#SCHEDULER scheduler Scheduler object handling various timed functions. --- @field #number SchedIDTargetQueue Scheduler ID for updating the target queue and calling OpenFire event. --- @field #number TargetQueueUpdate Interval between updates of the target queue. -- @field #number SchedIDCheckRearmed Scheduler ID responsible for checking whether rearming of the ARTY group is complete. -- @field #number SchedIDCheckShooting Scheduler ID for checking whether a group startet firing within a certain time after the fire at point task was assigned. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. @@ -87,7 +85,7 @@ -- -- ## The ARTY Process -- --- ![Process](..\Presentations\ARTY\Artillery_Process.png) +-- ![Process](..\Presentations\ARTY\ARTY_Process.png) -- -- After the FMS process is started the ARTY group will be in the state **CombatReady**. Once a target is assigned the **OpenFire** event will be triggered and the group starts -- firing. At this point the group in in the state **Firing**. @@ -204,7 +202,6 @@ -- * @{#ARTY.SetMinFiringRange}(*range*) defines the minimum firing range. Targets closer than this distance are not engaged. -- * @{#ARTY.SetRearmingUnit}(*unit*) sets the unit resposible for rearming of the ARTY group once it is out of ammo. -- * @{#ARTY.SetReportON}() and @{#ARTY.SetReportOFF}() can be used to enable/disable status reports of the ARTY group send to all coalition members. --- * @{#ARTY.SetTargetQueueUpdateInterval}(*interval*) sets the interval (in seconds) at which the target queue is updated. Default is every 5 seconds. -- * @{#ARTY.SetWaitForShotTime}(*waittime*) sets the time after which a target is deleted from the queue if no shooting event occured after the target engagement started. -- Default is 300 seconds. Note that this can for example happen, when the assigned target is out of range. -- * @{#ARTY.SetDebugON}() and @{#ARTY.SetDebugOFF}() can be used to enable/disable the debug mode. @@ -233,8 +230,6 @@ ARTY={ Nmissiles0=0, FullAmmo=0, scheduler=nil, - SchedIDTargetQueue=nil, - TargetQueueUpdate=5, SchedIDCheckRearmed=nil, SchedIDCheckShooting=nil, WaitForShotTime=300, @@ -274,7 +269,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.6.0" +ARTY.version="0.7.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -340,8 +335,8 @@ function ARTY:New(group) self:T3({id=id, desc=desc}) end - -- Set speed to maximum in km/h. - self.Speed=self.DCSdesc.speedMax*3.6 + -- Set speed to 1/2 of maximum in km/h. + self.Speed=self.DCSdesc.speedMax*3.6 * 0.5 -- Displayed name (similar to type name below) self.DisplayName=self.DCSdesc.displayName @@ -365,6 +360,7 @@ function ARTY:New(group) self:AddTransition("Rearming", "Rearmed", "CombatReady") self:AddTransition("CombatReady", "Move", "Moving") self:AddTransition("Moving", "Arrived", "CombatReady") + self:AddTransition("*", "NewTarget", "*") self:AddTransition("*", "Dead", "*") --- User function for OnBefore "OpenFire" event. @@ -582,6 +578,9 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w -- Debug info. self:T(ARTY.id..string.format("Added target %s, prio=%d, radius=%d, nshells=%d, maxengage=%d, time=%s, weapontype=%d", name, prio, radius, nshells, maxengage, tostring(_clock), weapontype)) + + -- Trigger new target event. + self:NewTarget(_target) end @@ -649,14 +648,6 @@ function ARTY:SetDebugOFF() self.Debug=false end ---- Set target queue update time interval. --- @param #ARTY self --- @param #number interval Time interval in seconds. Default is 5 seconds. -function ARTY:SetTargetQueueUpdateInterval(interval) - self:F2({interval=interval}) - self.TargetQueueUpdate=interval or 5 -end - --- Delete target from target list. -- @param #ARTY self -- @param #string name Name of the target. @@ -715,6 +706,17 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Before "Start" event. Initialized ROE and alarm state. Starts the event handler. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onbeforeStart(Controllable, From, Event, To) + self:_EventFromTo("onbeforeStart", Event, From, To) + + env.info("FF: onbeforeStart") +end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self @@ -779,9 +781,6 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) - -- Start scheduler to monitor task queue. - self.SchedIDTargetQueue=self.scheduler:Schedule(self, ARTY._TargetQueue, {self}, 5, self.TargetQueueUpdate) - -- Start scheduler to monitor if ARTY group started firing within a certain time. self.SchedIDCheckShooting=self.scheduler:Schedule(self, ARTY._CheckShootingStarted, {self}, 60, 60) @@ -950,6 +949,23 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- After "NewTarget" event. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table target Array holding the target info. +-- @return #boolean If true, proceed to onafterOpenfire. +function ARTY:onafterNewTarget(Controllable, From, Event, To, target) + self:_EventFromTo("onafterNewTarget", Event, From, To) + + -- Debug message. + local text=string.format("Adding new target %s.", target.name) + MESSAGE:New(text, 30):ToAllIf(self.Debug) + self:T(ARTY.id..text) +end + --- Before "OpenFire" event. Checks if group already has a target. Checks for valid min/max range and removes the target if necessary. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -973,6 +989,7 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) return true end + -- Check that group has no current target already. if self.currentTarget then -- Debug info. @@ -1095,6 +1112,36 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) end +--- Enter "CombatReady" state. Route the group back if necessary. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onenterCombatReady(Controllable, From, Event, To) + + env.info(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) + + if From=="Rearming" and Event=="Rearmed" then + env.info("FF: Comabatready after Rearmed") + + -- Distance to initial position. + local dist=Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) + + if dist>100 then + -- Route group back to its original position, when rearming was at another place. + self:T(ARTY.id..string.format("%s is routed back to its initial position. Distance = %d m.", Controllable:GetName(), dist)) + self:__Move(30, self.InitialCoord, true) + end + + else + -- Update target queue and open fire. + env.info("FF: Comabatready ==> _openfireontarget.") + self:_openfireontarget() + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Before "Winchester" event. Cease fire on current target. -- @param #ARTY self @@ -1105,8 +1152,6 @@ end -- @return #boolean If true, proceed to onafterWinchester. function ARTY:onbeforeWinchester(Controllable, From, Event, To) - - return true end @@ -1141,6 +1186,7 @@ end function ARTY:onbeforeRearm(Controllable, From, Event, To) self:_EventFromTo("onbeforeRearm", Event, From, To) + -- Check if a reaming unit or rearming place was specified. if self.RearmingUnit and self.RearmingUnit:IsAlive() then return true elseif self.RearmingPlaceCoord then @@ -1162,7 +1208,9 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Coordinate of ARTY unit. local coordARTY=self.Controllable:GetCoordinate() - local coordRARM + + -- Coordinate of rearming unit. + local coordRARM=nil if self.RearmingUnit then -- Coordinate of the rearming unit. coordRARM=self.RearmingUnit:GetCoordinate() @@ -1172,22 +1220,28 @@ function ARTY:onafterRearm(Controllable, From, Event, To) if self.RearmingUnit and self.RearmingPlaceCoord and self.Speed>0 then - -- Rearming unit and ARTY group meet at rearming place. + -- CASE 1: Rearming unit and ARTY group meet at rearming place. + + -- Distances. local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) -- Route ARTY group to rearming place. if dA>100 then - self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) + --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) + self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) end -- Route Rearming unit to rearming place if dR>100 then self.RearmingUnit:RouteGroundOnRoad(self.RearmingPlaceCoord, 50, 1) + --self:_Move(self.RearmingUnit, self.RearmingPlaceCoord, 50, true) end elseif self.RearmingUnit then + -- CASE 2: Rearming unit drives to ARTY group. + -- Send message. local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName()) self:T(ARTY.id..text) @@ -1199,12 +1253,26 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. if distance > 100 then -- Random point 20-100 m away from unit. - local vec2=coord:GetRandomVec2InRadius(20, 100) + local vec2=coordARTY:GetRandomVec2InRadius(20, 100) local pops=COORDINATE:NewFromVec2(vec2) -- Route unit to ARTY group. self.RearmingUnit:RouteGroundOnRoad(pops, 50, 1) end + + elseif self.RearmingPlaceCoord then + + -- CASE 3: ARTY drives to rearming place. + + -- Distance. + local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) + + -- Route ARTY group to rearming place. + if dA>100 then + --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) + self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) + end + end -- Start scheduler to monitor ammo count until rearming is complete. @@ -1325,14 +1393,30 @@ function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, OnRoad) self.Controllable:OptionROEHoldFire() -- Route group to coodinate. - if OnRoad then - self.Controllable:RouteGroundOnRoad(ToCoord, self.Speed, 1) - else - self.Controllable:RouteGroundTo(ToCoord, self.Speed, "Vee", 1) - end + self:_Move(self.Controllable, ToCoord, self.Speed, OnRoad) end +--- After "Arrived" event. Group has reached its destination. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterArrived(Controllable, From, Event, To) + self:_EventFromTo("onafterArrived", Event, From, To) + + -- Set alarm state to auto. + self.Controllable:OptionAlarmStateAuto() + + -- Send message + local text=string.format("%s, arrived at destination.", Controllable:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + +end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "Dead" event, when a unit has died. When all units of a group are dead trigger "Stop" event. @@ -1398,9 +1482,6 @@ function ARTY:onafterStop(Controllable, From, Event, To) -- Remove all targets. --self:RemoveAllTargets() -- Stop schedulers. - if self.SchedIDTargetQueue then - self.scheduler:Stop(self.SchedIDTargetQueue) - end if self.SchedIDCheckShooting then self.scheduler:Stop(self.SchedIDCheckShooting) end @@ -1443,9 +1524,9 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) end ---- Go through queue of assigned tasks. +--- Go through queue of assigned tasks and trigger OpenFire event. -- @param #ARTY self -function ARTY:_TargetQueue() +function ARTY:_openfireontarget() self:F2() -- Debug info @@ -1453,7 +1534,7 @@ function ARTY:_TargetQueue() -- No targets assigned at the moment. if #self.targets==0 then - self:T3(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _TargetQueue.", self.Controllable:GetName())) + self:T3(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _OpenFire.", self.Controllable:GetName())) return end @@ -1471,7 +1552,7 @@ function ARTY:_TargetQueue() self:T(ARTY.id..string.format("Engaging timed target %s. Prio=%d, engaged=%d, time=%s, tnow=%s",_target.name,_target.prio,_target.engaged,_clock,_Cnow)) -- Call OpenFire event. - self:OpenFire(_target) + self:__OpenFire(1, _target) end end @@ -1491,9 +1572,8 @@ function ARTY:_TargetQueue() self:T(ARTY.id..string.format("Engaging target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) -- Call OpenFire event. - self:OpenFire(_target) - - break + self:__OpenFire(1, _target) + end end @@ -1548,8 +1628,11 @@ end --- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. -- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE controllable --- @return Number of ALL shells left from the whole group. +-- @param Wrapper.Controllable#CONTROLLABLE controllable Controllable for which the ammo is counted. +-- @return #number Total amount of ammo the whole group has left. +-- @return #number Number of shells the group has left. +-- @return #number Number of rockets the group has left. +-- @return #number Number of missiles the group has left. function ARTY:_GetAmmo(controllable) self:F2(controllable) @@ -1570,7 +1653,7 @@ function ARTY:_GetAmmo(controllable) if unit and unit:IsAlive() then local ammotable=unit:GetAmmo() - self:T({ammotable=ammotable}) + self:T2({ammotable=ammotable}) local name=unit:GetName() @@ -1768,6 +1851,7 @@ end -- @param #number tnumber Number of weapon type ARTY.WeaponType.XXX -- @return #number tnumber of weapon type. function ARTY:_WeaponTypeName(tnumber) + self:F2(tnumber) local name="unknown" if tnumber==ARTY.WeaponType.Auto then name="Auto (Cannon, Rockets, Missiles)" @@ -1823,7 +1907,6 @@ function ARTY:_SecondsToClock(seconds) if seconds==nil then return nil - --return "00:00:00" end -- Seconds @@ -1833,14 +1916,13 @@ function ARTY:_SecondsToClock(seconds) local _seconds=seconds%(60*60*24) if seconds <= 0 then - return "00:00:00" + return nil else local hours = string.format("%02.f", math.floor(_seconds/3600)) local mins = string.format("%02.f", math.floor(_seconds/60 - (hours*60))) local secs = string.format("%02.f", math.floor(_seconds - hours*3600 - mins *60)) - local days = string.format("%d", seconds/(60*60*24)) + local days = string.format("%d", seconds/(60*60*24)) return hours..":"..mins..":"..secs.."+"..days - --return hours, mins, secs end end @@ -1908,7 +1990,6 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Current coordinates of group. local cpini=group:GetCoordinate() - cpini:SmokeWhite() -- Distance between current and final point. local dist=cpini:Get2DDistance(ToCoord) @@ -1916,24 +1997,46 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Waypoint and task arrays. local path={} local task={} - + -- First waypoint is the current position of the group. path[#path+1]=cpini:WaypointGround(Speed, formation) - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, 0, false) + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + -- Route group on road if requested. + if OnRoad then + + --path[#path+1]=cpini:GetClosestPointToRoad():WaypointGround(Speed, "On road") + --task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + local _first=cpini:GetClosestPointToRoad() + local _last=ToCoord:GetClosestPointToRoad() + local _onroad=_first:GetPathOnRoad(_last) + + -- Points on road. + for i=1,#_onroad do + path[#path+1]=_onroad[i]:WaypointGround(Speed, "On road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + end + + --path[#path+1]=ToCoord:GetClosestPointToRoad():WaypointGround(Speed, "On road") + --task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + end + + -- Last waypoint at ToCoord. path[#path+1]=ToCoord:WaypointGround(Speed, formation) - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, 1, true) + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, true) + -- Init waypoints of the group. local Waypoints={} -- New points are added to the default route. - for i,p in ipairs(path) do + for i=1,#path do table.insert(Waypoints, i, path[i]) end -- Set task for all waypoints. - for i,wp in ipairs(Waypoints) do + for i=1,#Waypoints do group:SetTaskWaypoint(Waypoints[i], task[i]) end @@ -1952,15 +2055,15 @@ function ARTY._PassingWaypoint(group, arty, i, final) -- Debug message. local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final)) - local pos=group:GetCoordinate() - local MarkerID=pos:MarkToAll(string.format("Reached Waypoint %d of group %s", i, group:GetName())) - pos:SmokeRed() + --local pos=group:GetCoordinate() + --local MarkerID=pos:MarkToAll(string.format("Reached Waypoint %d of group %s", i, group:GetName())) + --pos:SmokeRed() MESSAGE:New(text,10):ToAll() env.info(ARTY.id..text) -- Move --> Moving --> Arrived --> CombatReady. - if final then + if final and arty.Controllable:GetName()==group:GetName() then arty:Arrived() end From 0cf4b8845e83d7ebc16ff8b68bda01bd447fb561 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 5 May 2018 08:44:16 +0200 Subject: [PATCH 075/170] ARTY v0.8.0 WIP version. Not functional. --- .../Moose/Functional/Artillery.lua | 698 +++++++++++------- 1 file changed, 411 insertions(+), 287 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 41e6e1f29..aaf1a77b9 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -60,10 +60,10 @@ -- @field #number IniGroupStrength Inital number of units in the ARTY group. -- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". -- @field #number Speed Max speed of ARTY group. --- @field Wrapper.Unit#UNIT RearmingUnit Unit designated to rearm the ARTY group. --- @field Wrapper.Point#COORDINATE RearmingUnitCoord Initial coordinates of the rearming unit. After rearming complete, the unit will return to this position. --- @field Wrapper.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there. --- @field Wrapper.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group. +-- @field Wrapper.Group#GROUP RearmingGroup Unit designated to rearm the ARTY group. +-- @field Core.Point#COORDINATE RearmingGroupCoord Initial coordinates of the rearming unit. After rearming complete, the unit will return to this position. +-- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there. +-- @field Core.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group. -- @field #boolean report Arty group sends messages about their current state or target to its coaliton. -- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells. -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. @@ -96,10 +96,10 @@ -- When the ARTY group runs out of ammunition, the event **Winchester** is triggered and the group enters the state **OutOfAmmo**. -- In this state, the group is unable to engage further targets. -- --- With the @{#ARTY.SetRearmingUnit}(*unit*) command, a special unit can be defined to rearm the ARTY group. If this unit has been assigned and the group has entered the state +-- With the @{#ARTY.SetRearmingGroup}(*group*) command, a special group can be defined to rearm the ARTY group. If this unit has been assigned and the group has entered the state -- **OutOfAmmo** the event **Rearm** is triggered followed by a transition to the state **Rearming**. --- If the rearming unit is less than 100 meters away from the ARTY group, the rearming process starts. If the rearming unit is more than 100 meters away from the ARTY unit, the --- rearming unit is routed to a point 20 to 100 m from the ARTY group. +-- If the rearming group is less than 100 meters away from the ARTY group, the rearming process starts. If the rearming group is more than 100 meters away from the ARTY unit, the +-- rearming group is routed to a point 20 to 100 m from the ARTY group. -- -- Once the rearming is complete, the **Rearmed** event is triggered and the group enters the state **CombatReady**. At this point targeted can be engaged again. -- @@ -200,7 +200,7 @@ -- * @{#ARTY.RemoveTarget}(*name*) deletes the target with *name* from the target queue. -- * @{#ARTY.SetMaxFiringRange}(*range*) defines the maximum firing range. Targets further away than this distance are not engaged. -- * @{#ARTY.SetMinFiringRange}(*range*) defines the minimum firing range. Targets closer than this distance are not engaged. --- * @{#ARTY.SetRearmingUnit}(*unit*) sets the unit resposible for rearming of the ARTY group once it is out of ammo. +-- * @{#ARTY.SetRearmingGroup}(*group*) sets the group resposible for rearming of the ARTY group once it is out of ammo. -- * @{#ARTY.SetReportON}() and @{#ARTY.SetReportOFF}() can be used to enable/disable status reports of the ARTY group send to all coalition members. -- * @{#ARTY.SetWaitForShotTime}(*waittime*) sets the time after which a target is deleted from the queue if no shooting event occured after the target engagement started. -- Default is 300 seconds. Note that this can for example happen, when the assigned target is out of range. @@ -239,8 +239,8 @@ ARTY={ DisplayName=nil, IniGroupStrength=0, IsArtillery=nil, - RearmingUnit=nil, - RearmingUnitCoord=nil, + RearmingGroup=nil, + RearmingGroupCoord=nil, RearmingPlaceCoord=nil, InitialCoord=nil, report=true, @@ -269,7 +269,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.7.0" +ARTY.version="0.8.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -287,6 +287,10 @@ ARTY.version="0.7.0" -- DONE: Improve assigned time for engagement. Next day? -- DONE: Improve documentation. -- DONE: Add pseudo user transitions. OnAfter... +-- TODO: Make reaming unit a group. +-- TODO: Adjust documenation again. +-- TODO: Add command move to make arty group move. +-- TODO: remove schedulers for status event. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -350,18 +354,35 @@ function ARTY:New(group) -- Initial group strength. self.IniGroupStrength=#group:GetUnits() - -- Transitions - self:AddTransition("*", "Start", "CombatReady") - self:AddTransition("CombatReady", "OpenFire", "Firing") - self:AddTransition("CombatReady", "Winchester", "OutOfAmmo") - self:AddTransition("Firing", "OpenFire", "Firing") - self:AddTransition("Firing", "CeaseFire", "CombatReady") - self:AddTransition("OutOfAmmo", "Rearm", "Rearming") - self:AddTransition("Rearming", "Rearmed", "CombatReady") - self:AddTransition("CombatReady", "Move", "Moving") - self:AddTransition("Moving", "Arrived", "CombatReady") - self:AddTransition("*", "NewTarget", "*") - self:AddTransition("*", "Dead", "*") + -- Transitions: + -- Entry + self:AddTransition("*", "Start", "CombatReady") + + -- Blue branch. + self:AddTransition("CombatReady", "OpenFire", "Firing") + self:AddTransition("Firing", "OpenFire", "Firing") + self:AddTransition("Firing", "CeaseFire", "CombatReady") + --self:AddTransition("CombatReady", "CeaseFire", "CombatReady") -- not in diagram yet. + + -- Violett branch. + self:AddTransition("Firing", "Winchester", "OutOfAmmo") + + -- Red branch. + self:AddTransition("OutOfAmmo", "Rearm", "Rearming") + self:AddTransition("Rearming", "Rearmed", "Rearmed") + + -- Green branch. + self:AddTransition("*", "Move", "Moving") + self:AddTransition("Moving", "Arrived", "Arrived") + + self:AddTransition("*", "CombatReady", "CombatReady") + + -- Yellow branch. + self:AddTransition("*", "NewTarget", "*") + -- Not in diagram. + self:AddTransition("*", "Status", "*") + self:AddTransition("*", "Dead", "*") + --- User function for OnBefore "OpenFire" event. -- @function [parent=#ARTY] OnBeforeOpenFire @@ -608,12 +629,12 @@ function ARTY:SetWaitForShotTime(waittime) self.WaitForShotTime=waittime or 300 end ---- Assign a unit which is responsible for rearming the ARTY group. If the unit is too far away from the ARTY group it will be guided towards the ARTY group. +--- Assign a group, which is responsible for rearming the ARTY group. If the group is too far away from the ARTY group it will be guided towards the ARTY group. -- @param #ARTY self --- @param Wrapper.Unit#UNIT unit Unit that is supposed to rearm the ARTY group. -function ARTY:SetRearmingUnit(unit) - self:F({unit=unit}) - self.RearmingUnit=unit +-- @param Wrapper.Group#GROUP unit Unit that is supposed to rearm the ARTY group. +function ARTY:SetRearmingGroup(group) + self:F({group=group}) + self.RearmingGroup=group end --- Defines the rearming place of the ARTY group. If the place is too far away from the ARTY group it will be routed to the place. @@ -747,8 +768,8 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Number of shells = %d\n", self.Nshells0) text=text..string.format("Number of rockets = %d\n", self.Nrockets0) text=text..string.format("Number of missiles = %d\n", self.Nmissiles0) - if self.RearmingUnit then - text=text..string.format("Reaming unit = %s\n", self.RearmingUnit:GetName()) + if self.RearmingGroup then + text=text..string.format("Reaming group = %s\n", self.RearmingGroup:GetName()) end if self.RearmingPlaceCoord then local dist=self.InitialCoord:Get2DDistance(self.RearmingPlaceCoord) @@ -780,14 +801,16 @@ function ARTY:onafterStart(Controllable, From, Event, To) -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) + + self:__Status(5) -- Start scheduler to monitor if ARTY group started firing within a certain time. self.SchedIDCheckShooting=self.scheduler:Schedule(self, ARTY._CheckShootingStarted, {self}, 60, 60) -- Start cheduler for status reports. - if self.Debug then - self.SchedIDStatusReport=self.scheduler:Schedule(self, ARTY._StatusReport, {self}, 30, 30) - end +-- if self.Debug then +-- self.SchedIDStatusReport=self.scheduler:Schedule(self, ARTY._StatusReport, {self}, 30, 30) +-- end end @@ -868,8 +891,6 @@ function ARTY:_OnEventShot(EventData) if _nammo==0 then self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) - -- Cease fire first. - self:CeaseFire(self.currentTarget) self:Winchester() -- Current target is deallocated ==> return @@ -966,6 +987,242 @@ function ARTY:onafterNewTarget(Controllable, From, Event, To, target) self:T(ARTY.id..text) end +--- After "Status" event. Report status of group. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onafterStatus(Controllable, From, Event, To) + self:_EventFromTo("onafterStatus", Event, From, To) + + if self.Debug then + self:_StatusReport() + end + + local _engage=true + + if self:is("OutOfAmmo") then + + -- Coordinate of ARTY unit. + local coordARTY=self.Controllable:GetCoordinate() + + -- Coordinate of rearming group. + local coordRARM=nil + if self.RearmingGroup then + -- Coordinate of the rearming unit. + coordRARM=self.RearmingGroup:GetCoordinate() + -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. + self.RearmingGroupCoord=coordRARM + end + + if self.RearmingGroup and self.RearmingPlaceCoord and self.Speed>0 then + + -- CASE 1: Rearming unit and ARTY group meet at rearming place. + + -- Distances. + local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) + local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) + + -- Route ARTY group to rearming place. + if dA>100 then + --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) + --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) + self:Move(self.RearmingPlaceCoord, false) + end + + -- Route Rearming unit to rearming place + if dR>100 then + self.RearmingGroup:RouteGroundOnRoad(self.RearmingPlaceCoord, 50, 1) + --self:_Move(self.RearmingGroup, self.RearmingPlaceCoord, 50, true) + end + + elseif self.RearmingGroup then + + -- CASE 2: Rearming unit drives to ARTY group. + + -- Send message. + local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingGroup:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + + -- Distance between ARTY group and rearming unit. + local distance=coordARTY:Get2DDistance(coordRARM) + + -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. + if distance > 100 then + -- Random point 20-100 m away from unit. + local vec2=coordARTY:GetRandomVec2InRadius(20, 100) + local pops=COORDINATE:NewFromVec2(vec2) + + -- Route unit to ARTY group. + self.RearmingGroup:RouteGroundOnRoad(pops, 50, 1) + end + + elseif self.RearmingPlaceCoord then + + -- CASE 3: ARTY drives to rearming place. + + -- Distance. + local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) + + -- Route ARTY group to rearming place. + if dA>100 then + --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) + --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) + self:Move(self.RearmingPlaceCoord, false) + end + + end + + _engage=false + + end + + if self:is("Moving") then + _engage=false + end + + if self:is("Rearming") then + _engage=false + end + + if self:is("Rearmed") then + local distance=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) + if distance > 100 then + self:Move(self.InitialCoord, false) + _engage=false + else + self:CombatReady() + end + end + + + if self:is("Arrived") then + + end + + -- Engage targets. + if _engage then + + -- Get a timed target if it is due to be attacked. + local _timedTarget=self:_CheckTimedTargets() + local _normalTarget=self:_CheckNormalTargets() + + -- Engage target. + if _timedTarget then + if self.currentTarget then + self:CeaseFire() + end + self:OpenFire(_timedTarget) + elseif _normalTarget then + self:OpenFire(_normalTarget) + end + + end + + -- Call status again in 5 sec. + self:__Status(5) +end + +--- Check all timed targets and return the target which should be attacked next. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now. +function ARTY:_CheckTimedTargets() + + -- Current time. + local Tnow=timer.getAbsTime() + + -- Sort Targets wrt time. + self:_SortTargetQueueTime() + + for i=1,#self.targets do + local _target=self.targets[i] + + -- Check if target has an attack time which has already passed. + -- Also check that target is not under fire already and that it is in range. + if _target.time and _target.time>=Tnow and _target.underfire==false and self:_TargetInRange(_target) then + + -- Check if group currently has a target and whether its priorty is lower than the timed target. + if self.currentTarget then + if self.currentTarget.prio > _target.prio then + -- Current target under attack but has lower priority than this target. + self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, target.name)) + return _target + end + else + -- No current target. + return _target + end + end + end + + return nil +end + +--- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now or nil if no target could be found. +function ARTY:_CheckNormalTargets() + + -- Sort targets w.r.t. prio and number times engaged already. + self:_SortTargetQueuePrio() + + -- Loop over all sorted targets. + for i=1,#self.targets do + local _target=self.targets[i] + + -- Check that target no time, is not under fire currently and in range. + if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then + + -- Debug info. + self:T(ARTY.id..string.format("Engaging target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) + + return _target + end + end + + return nil +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Enter "CombatReady" state. Route the group back if necessary. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARTY:onenterCombatReady(Controllable, From, Event, To) + + env.info(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) + +--[[ + if From=="Rearming" and Event=="Rearmed" then + env.info("FF: Comabatready after Rearmed") + + -- Distance to initial position. + local dist=Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) + + if dist>100 then + -- Route group back to its original position, when rearming was at another place. + self:T(ARTY.id..string.format("%s is routed back to its initial position. Distance = %d m.", Controllable:GetName(), dist)) + self:__Move(30, self.InitialCoord, true) + end + + else + + -- Update target queue and open fire. + env.info("FF: Comabatready ==> _openfireontarget.") + self:_openfireontarget() + + end +]] + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + --- Before "OpenFire" event. Checks if group already has a target. Checks for valid min/max range and removes the target if necessary. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -976,20 +1233,7 @@ end -- @return #boolean If true, proceed to onafterOpenfire. function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onbeforeOpenFire", Event, From, To) - - -- If this target has an attack time and it's prio is higher than the current task, we allow the transition. - if target.time~=nil and self.currentTarget~=nil and self.currentTarget.prio > target.prio then - -- Debug info. - self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, target.name)) - - -- Stop firing on current target. - self:CeaseFire(self.currentTarget) - - -- Alow transition to onafterOpenfire. - return true - end - - + -- Check that group has no current target already. if self.currentTarget then -- Debug info. @@ -999,25 +1243,9 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) return false end --- Distance to target - local range=Controllable:GetCoordinate():Get2DDistance(target.coord) - - -- Check that distance to target is within range. - if rangeself.maxrange then - - -- Debug output. - local text - if rangeself.maxrange then - text=string.format("%s, target is out of range. Distance of %d km is greater than max range of %d km.", Controllable:GetName(), range/1000, self.maxrange/1000) - end - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - - -- Remove target. - self:RemoveTarget(target.name) - + -- Check if target is in range. + local _inrange=self:_TargetInRange(target) + if not _inrange then -- Deny transition. return false end @@ -1064,6 +1292,36 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) end +--- Go through queue of assigned tasks and trigger OpenFire event. +-- @param #ARTY self +function ARTY:_openfireontarget() + self:F2() + + -- Debug info + self:T2(ARTY.id..string.format("Group %s, number of targets = %d", self.Controllable:GetName(), #self.targets)) + + -- No targets assigned at the moment. + if #self.targets==0 then + self:T3(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _OpenFire.", self.Controllable:GetName())) + return + end + + -- Check timed targets first. + local _target=self:_CheckTimedTargets() + if _target then + self:__OpenFire(1, _target) + return + end + + -- Check normal targets + local _target=self:_CheckNormalTargets() + if _target then + self:__OpenFire(1, _target) + return + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "CeaseFire" event. Clears task of the group and removes the target if max engagement was reached. @@ -1075,85 +1333,48 @@ end -- @param #table target Array holding the target info. function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) self:_EventFromTo("onafterCeaseFire", Event, From, To) - - -- Send message. - local text=string.format("%s, ceasing fire on target %s.", Controllable:GetName(), target.name) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) - - -- Get target array index. - local id=self:_GetTargetByName(target.name) - -- Increase engaged counter - if id then - -- Target was actually engaged. (Could happen that engagement was aborted while group was still aiming.) - if self.Nshots>0 then - self.targets[id].engaged=self.targets[id].engaged+1 - -- Clear the attack time. - self.targets[id].time=nil + if target then + + -- Send message. + local text=string.format("%s, ceasing fire on target %s.", Controllable:GetName(), target.name) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + + -- Get target array index. + local id=self:_GetTargetByName(target.name) + + -- Increase engaged counter + if id then + -- Target was actually engaged. (Could happen that engagement was aborted while group was still aiming.) + if self.Nshots>0 then + self.targets[id].engaged=self.targets[id].engaged+1 + -- Clear the attack time. + self.targets[id].time=nil + end + -- Target is not under fire any more. + self.targets[id].underfire=false end - -- Target is not under fire any more. - self.targets[id].underfire=false - end - - -- Clear tasks. - self.Controllable:ClearTasks() + -- If number of engagements has been reached, the target is removed. + if target.engaged >= target.maxengage then + self:RemoveTarget(target.name) + end + + -- Clear tasks. + self.Controllable:ClearTasks() + + end + -- Set number of shots to zero. self.Nshots=0 - - -- If number of engagements has been reached, the target is removed. - if target.engaged >= target.maxengage then - self:RemoveTarget(target.name) - end -- ARTY group has no current target any more. self.currentTarget=nil end ---- Enter "CombatReady" state. Route the group back if necessary. --- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. -function ARTY:onenterCombatReady(Controllable, From, Event, To) - - env.info(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) - - if From=="Rearming" and Event=="Rearmed" then - env.info("FF: Comabatready after Rearmed") - - -- Distance to initial position. - local dist=Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) - - if dist>100 then - -- Route group back to its original position, when rearming was at another place. - self:T(ARTY.id..string.format("%s is routed back to its initial position. Distance = %d m.", Controllable:GetName(), dist)) - self:__Move(30, self.InitialCoord, true) - end - - else - -- Update target queue and open fire. - env.info("FF: Comabatready ==> _openfireontarget.") - self:_openfireontarget() - end - -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Before "Winchester" event. Cease fire on current target. --- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. --- @return #boolean If true, proceed to onafterWinchester. -function ARTY:onbeforeWinchester(Controllable, From, Event, To) - - return true -end --- After "Winchester" event. Group is out of ammo. Trigger "Rearm" event. -- @param #ARTY self @@ -1170,7 +1391,7 @@ function ARTY:onafterWinchester(Controllable, From, Event, To) MESSAGE:New(text, 30):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) -- Init rearming if possible. - self:Rearm() + --self:Rearm() end @@ -1187,7 +1408,7 @@ function ARTY:onbeforeRearm(Controllable, From, Event, To) self:_EventFromTo("onbeforeRearm", Event, From, To) -- Check if a reaming unit or rearming place was specified. - if self.RearmingUnit and self.RearmingUnit:IsAlive() then + if self.RearmingGroup and self.RearmingGroup:IsAlive() then return true elseif self.RearmingPlaceCoord then return true @@ -1206,75 +1427,6 @@ end function ARTY:onafterRearm(Controllable, From, Event, To) self:_EventFromTo("onafterRearm", Event, From, To) - -- Coordinate of ARTY unit. - local coordARTY=self.Controllable:GetCoordinate() - - -- Coordinate of rearming unit. - local coordRARM=nil - if self.RearmingUnit then - -- Coordinate of the rearming unit. - coordRARM=self.RearmingUnit:GetCoordinate() - -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. - self.RearmingUnitCoord=coordRARM - end - - if self.RearmingUnit and self.RearmingPlaceCoord and self.Speed>0 then - - -- CASE 1: Rearming unit and ARTY group meet at rearming place. - - -- Distances. - local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) - local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) - - -- Route ARTY group to rearming place. - if dA>100 then - --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) - self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) - end - - -- Route Rearming unit to rearming place - if dR>100 then - self.RearmingUnit:RouteGroundOnRoad(self.RearmingPlaceCoord, 50, 1) - --self:_Move(self.RearmingUnit, self.RearmingPlaceCoord, 50, true) - end - - elseif self.RearmingUnit then - - -- CASE 2: Rearming unit drives to ARTY group. - - -- Send message. - local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName()) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - - -- Distance between ARTY group and rearming unit. - local distance=coordARTY:Get2DDistance(coordRARM) - - -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. - if distance > 100 then - -- Random point 20-100 m away from unit. - local vec2=coordARTY:GetRandomVec2InRadius(20, 100) - local pops=COORDINATE:NewFromVec2(vec2) - - -- Route unit to ARTY group. - self.RearmingUnit:RouteGroundOnRoad(pops, 50, 1) - end - - elseif self.RearmingPlaceCoord then - - -- CASE 3: ARTY drives to rearming place. - - -- Distance. - local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) - - -- Route ARTY group to rearming place. - if dA>100 then - --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) - self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) - end - - end - -- Start scheduler to monitor ammo count until rearming is complete. self.SchedIDCheckRearmed=self.scheduler:Schedule(self, ARTY._CheckRearmed, {self}, 20, 20) end @@ -1307,10 +1459,10 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) end -- Route unit back to where it came from (if distance is > 100 m). - if self.RearmingUnit and self.RearmingUnit:IsAlive() then - local d=self.RearmingUnit:GetCoordinate():Get2DDistance(self.RearmingUnitCoord) + if self.RearmingGroup and self.RearmingGroup:IsAlive() then + local d=self.RearmingGroup:GetCoordinate():Get2DDistance(self.RearmingGroupCoord) if d>100 then - self.RearmingUnit:RouteGroundOnRoad(self.RearmingUnitCoord, 50, 1) + self.RearmingGroup:RouteGroundOnRoad(self.RearmingGroupCoord, 50, 1) end end @@ -1349,7 +1501,6 @@ function ARTY:_CheckRearmed() end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Before "Move" event. Check if a unit to rearm the ARTY group has been defined. @@ -1416,7 +1567,6 @@ function ARTY:onafterArrived(Controllable, From, Event, To) end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "Dead" event, when a unit has died. When all units of a group are dead trigger "Stop" event. @@ -1450,24 +1600,6 @@ function ARTY:onafterDead(Controllable, From, Event, To) end ---- Before "Stop" event. Cease fire on current target. --- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. --- @return #boolean If true, proceed to onafterStop. -function ARTY:onbeforeStop(Controllable, From, Event, To) - self:_EventFromTo("onbeforeStop", Event, From, To) - - -- Cease Fire on current target. - if self.currentTarget then - self:CeaseFire(self.currentTarget) - end - - return true -end - --- After "Stop" event. Stop schedulers and unhandle events. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -1479,8 +1611,15 @@ function ARTY:onafterStop(Controllable, From, Event, To) -- Debug info. self:T(ARTY.id..string.format("Stopping ARTY FSM for group %s.", Controllable:GetName())) + + -- Cease Fire on current target. + if self.currentTarget then + self:CeaseFire(self.currentTarget) + end + -- Remove all targets. --self:RemoveAllTargets() + -- Stop schedulers. if self.SchedIDCheckShooting then self.scheduler:Stop(self.SchedIDCheckShooting) @@ -1488,6 +1627,7 @@ function ARTY:onafterStop(Controllable, From, Event, To) if self.SchedIDCheckRearmed then self.scheduler:Stop(self.SchedIDCheckRearmed) end + -- Unhandle event. self:UnHandleEvent(EVENTS.Shot) self:UnHandleEvent(EVENTS.Dead) @@ -1524,61 +1664,6 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) end ---- Go through queue of assigned tasks and trigger OpenFire event. --- @param #ARTY self -function ARTY:_openfireontarget() - self:F2() - - -- Debug info - self:T(ARTY.id..string.format("Group %s, number of targets = %d", self.Controllable:GetName(), #self.targets)) - - -- No targets assigned at the moment. - if #self.targets==0 then - self:T3(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _OpenFire.", self.Controllable:GetName())) - return - end - - -- First check if there is a target with a certain time for attack. - for i=1,#self.targets do - local _target=self.targets[i] - if _target and _target.time then - if timer.getAbsTime() >= _target.time and _target.underfire==false then - - -- Clock time format. - local _clock=self:_SecondsToClock(_target.time) - local _Cnow=self:_SecondsToClock(timer.getAbsTime()) - - -- Debug info. - self:T(ARTY.id..string.format("Engaging timed target %s. Prio=%d, engaged=%d, time=%s, tnow=%s",_target.name,_target.prio,_target.engaged,_clock,_Cnow)) - - -- Call OpenFire event. - self:__OpenFire(1, _target) - - end - end - end - - -- Sort targets w.r.t. prio and number times engaged already. - self:_SortTargetQueuePrio() - - -- Loop over all sorted targets. - for i=1,#self.targets do - - local _target=self.targets[i] - - if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged then - - -- Debug info. - self:T(ARTY.id..string.format("Engaging target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) - - -- Call OpenFire event. - self:__OpenFire(1, _target) - - end - end - -end - --- Sort targets with respect to priority and number of times it was already engaged. -- @param #ARTY self @@ -1594,7 +1679,9 @@ function ARTY:_SortTargetQueuePrio() -- Debug output. self:T2(ARTY.id.."Sorted targets wrt prio and number of engagements:") for i=1,#self.targets do - self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) + local _target=self.targets[i] + local _clock=self:_SecondsToClock(_target.time) + self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d, time=%s", _target.name, _target.prio, _target.engaged, tostring(_clock))) end end @@ -1621,7 +1708,9 @@ function ARTY:_SortTargetQueueTime() -- Debug output. self:T2(ARTY.id.."Sorted targets wrt time:") for i=1,#self.targets do - self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged)) + local _target=self.targets[i] + local _clock=self:_SecondsToClock(_target.time) + self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d, time=%s", _target.name, _target.prio, _target.engaged, tostring(_clock))) end end @@ -1846,6 +1935,42 @@ function ARTY:_CheckTargetName(name) return newname end +--- Check if target is in range. +-- @param #ARTY self +-- @param #table target Target table. +-- @return #boolean True if target is in range, false otherwise. +function ARTY:_TargetInRange(target) + self:F3(target) + + -- Distance between ARTY group and target. + local _dist=self.Controllable:GetCoordinate():Get2DDistance(target.coord) + + -- Assume we are in range. + local _inrange=true + local text="" + + if _dist < self.minrange then + _inrange=false + text=string.format("%s, target is out of range. Distance of %d km is below min range of %d km.", self.Controllable:GetName(), _dist/1000, self.minrange/1000) + elseif _dist > self.maxrange then + _inrange=false + text=string.format("%s, target is out of range. Distance of %d km is greater than max range of %d km.", self.Controllable:GetName(), _dist/1000, self.maxrange/1000) + end + + -- Debug output. + if not _inrange then + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + end + + -- Remove target if ARTY group cannot move. No change to be ever in range. + if self.Speed==0 then + self:RemoveTarget(target.name) + end + + return _inrange +end + --- Get the weapon type name, which should be used to attack the target. -- @param #ARTY self -- @param #number tnumber Number of weapon type ARTY.WeaponType.XXX @@ -1880,7 +2005,6 @@ function ARTY:_EventFromTo(BA, Event, From, To) self:T3(ARTY.id..text) end - --- Split string. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua -- @param #ARTY self -- @param #string str Sting to split. From 57c5ab1ecd50e5035abecd192291f27480322452 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 5 May 2018 21:45:07 +0200 Subject: [PATCH 076/170] ARTY v0.8.1 Improvements in FSM states. Still not quite functional. --- .../Moose/Functional/Artillery.lua | 508 ++++++------------ 1 file changed, 156 insertions(+), 352 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index aaf1a77b9..3ea6059c6 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -269,7 +269,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.0" +ARTY.version="0.8.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -339,8 +339,8 @@ function ARTY:New(group) self:T3({id=id, desc=desc}) end - -- Set speed to 1/2 of maximum in km/h. - self.Speed=self.DCSdesc.speedMax*3.6 * 0.5 + -- Set speed to 0.7 of maximum in km/h. + self.Speed=self.DCSdesc.speedMax*3.6 * 0.7 -- Displayed name (similar to type name below) self.DisplayName=self.DCSdesc.displayName @@ -353,199 +353,38 @@ function ARTY:New(group) -- Initial group strength. self.IniGroupStrength=#group:GetUnits() - - -- Transitions: - -- Entry + + --------------- + -- Transitions: + --------------- + + -- Entry. self:AddTransition("*", "Start", "CombatReady") -- Blue branch. self:AddTransition("CombatReady", "OpenFire", "Firing") - self:AddTransition("Firing", "OpenFire", "Firing") self:AddTransition("Firing", "CeaseFire", "CombatReady") - --self:AddTransition("CombatReady", "CeaseFire", "CombatReady") -- not in diagram yet. -- Violett branch. - self:AddTransition("Firing", "Winchester", "OutOfAmmo") + self:AddTransition("CombatReady", "Winchester", "OutOfAmmo") -- Red branch. - self:AddTransition("OutOfAmmo", "Rearm", "Rearming") - self:AddTransition("Rearming", "Rearmed", "Rearmed") + self:AddTransition({"CombatReady", "OutOfAmmo"}, "Rearm", "Rearming") + self:AddTransition("Rearming", "Move", "Rearming") + self:AddTransition("Rearming", "Rearmed", "Rearmed") -- Green branch. self:AddTransition("*", "Move", "Moving") self:AddTransition("Moving", "Arrived", "Arrived") - self:AddTransition("*", "CombatReady", "CombatReady") - -- Yellow branch. self:AddTransition("*", "NewTarget", "*") + -- Not in diagram. + self:AddTransition("*", "CombatReady", "CombatReady") self:AddTransition("*", "Status", "*") self:AddTransition("*", "Dead", "*") - - --- User function for OnBefore "OpenFire" event. - -- @function [parent=#ARTY] OnBeforeOpenFire - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param #table target Array holding the target info. - -- @return #boolean If true, allow transition to OnAfterOpenFire. - - --- User function for OnAfter "OpenFire" event. - -- @function [parent=#ARTY] OnAfterOpenFire - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param #table target Array holding the target info. - - - --- User function for OnBefore "CeaseFire" event. - -- @function [parent=#ARTY] OnBeforeCeaseFire - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param #table target Array holding the target info. - -- @return #boolean If true, allow transition to OnAfterCeaseFire. - - --- User function for OnAfter "CeaseFire" event. - -- @function [parent=#ARTY] OnAfterCeaseFire - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param #table target Array holding the target info. - - - --- User function for OnBefore "Winchester" event. - -- @function [parent=#ARTY] OnBeforeWinchester - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @return #boolean If true, allow transition to OnAfterWinchester. - - --- User function for OnAfter "Winchester" event. - -- @function [parent=#ARTY] OnAfterWinchester - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - - --- User function for OnBefore "Rearm" event. - -- @function [parent=#ARTY] OnBeforeRearm - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @return #boolean If true, allow transition to OnAfterRearm. - - --- User function for OnAfter "Rearm" event. - -- @function [parent=#ARTY] OnAfterRearm - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - - --- User function for OnBefore "Rearmed" event. - -- @function [parent=#ARTY] OnBeforeRearmed - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @return #boolean If true, allow transition to OnAfterRearmed. - - --- User function for OnAfter "Rearmed" event. - -- @function [parent=#ARTY] OnAfterRearmed - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - - --- User function for OnBefore "Start" event. - -- @function [parent=#ARTY] OnBeforeStart - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @return #boolean If true, allow transition to OnAfterStart. - - --- User function for OnAfter "Start" event. - -- @function [parent=#ARTY] OnAfterStart - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - - --- User function for OnBefore "Dead" event. - -- @function [parent=#ARTY] OnBeforeDead - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @return #boolean If true, allow transition to OnAfterDead. - - --- User function for OnAfter "Dead" event. - -- @function [parent=#ARTY] OnAfterDead - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - - --- User function for OnEnter "CombatReady" state. - -- @function [parent=#ARTY] OnEnterCombatReady - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - --- User function for OnEnter "Firing" state. - -- @function [parent=#ARTY] OnEnterFiring - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - --- User function for OnEnter "OutOfAmmo" state. - -- @function [parent=#ARTY] OnEnterOutOfAmmo - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - - --- User function for OnEnter "Rearming" state. - -- @function [parent=#ARTY] OnEnterRearming - -- @param #ARTY self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - return self end @@ -598,13 +437,12 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w local _clock=self:_SecondsToClock(_target.time) -- Debug info. - self:T(ARTY.id..string.format("Added target %s, prio=%d, radius=%d, nshells=%d, maxengage=%d, time=%s, weapontype=%d", name, prio, radius, nshells, maxengage, tostring(_clock), weapontype)) + self:T(ARTY.id..string.format("Added target %s", self:_TargetInfo(_target))) -- Trigger new target event. self:NewTarget(_target) end - --- Set minimum firing range. Targets closer than this distance are not engaged. -- @param #ARTY self -- @param #number range Min range in kilometers. Default is 0 km. @@ -891,6 +729,7 @@ function ARTY:_OnEventShot(EventData) if _nammo==0 then self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) + self:CeaseFire(self.currentTarget) self:Winchester() -- Current target is deallocated ==> return @@ -970,23 +809,6 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- After "NewTarget" event. --- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. --- @param #table target Array holding the target info. --- @return #boolean If true, proceed to onafterOpenfire. -function ARTY:onafterNewTarget(Controllable, From, Event, To, target) - self:_EventFromTo("onafterNewTarget", Event, From, To) - - -- Debug message. - local text=string.format("Adding new target %s.", target.name) - MESSAGE:New(text, 30):ToAllIf(self.Debug) - self:T(ARTY.id..text) -end - --- After "Status" event. Report status of group. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -1000,98 +822,27 @@ function ARTY:onafterStatus(Controllable, From, Event, To) self:_StatusReport() end - local _engage=true - if self:is("OutOfAmmo") then - - -- Coordinate of ARTY unit. - local coordARTY=self.Controllable:GetCoordinate() - - -- Coordinate of rearming group. - local coordRARM=nil - if self.RearmingGroup then - -- Coordinate of the rearming unit. - coordRARM=self.RearmingGroup:GetCoordinate() - -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. - self.RearmingGroupCoord=coordRARM - end - - if self.RearmingGroup and self.RearmingPlaceCoord and self.Speed>0 then - - -- CASE 1: Rearming unit and ARTY group meet at rearming place. - - -- Distances. - local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) - local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) - - -- Route ARTY group to rearming place. - if dA>100 then - --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) - --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) - self:Move(self.RearmingPlaceCoord, false) - end - - -- Route Rearming unit to rearming place - if dR>100 then - self.RearmingGroup:RouteGroundOnRoad(self.RearmingPlaceCoord, 50, 1) - --self:_Move(self.RearmingGroup, self.RearmingPlaceCoord, 50, true) - end - - elseif self.RearmingGroup then - - -- CASE 2: Rearming unit drives to ARTY group. - - -- Send message. - local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingGroup:GetName()) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - - -- Distance between ARTY group and rearming unit. - local distance=coordARTY:Get2DDistance(coordRARM) - - -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. - if distance > 100 then - -- Random point 20-100 m away from unit. - local vec2=coordARTY:GetRandomVec2InRadius(20, 100) - local pops=COORDINATE:NewFromVec2(vec2) - - -- Route unit to ARTY group. - self.RearmingGroup:RouteGroundOnRoad(pops, 50, 1) - end - - elseif self.RearmingPlaceCoord then - - -- CASE 3: ARTY drives to rearming place. - - -- Distance. - local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) - - -- Route ARTY group to rearming place. - if dA>100 then - --self.Controllable:RouteGroundOnRoad(self.RearmingPlaceCoord, self.Speed, 1) - --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) - self:Move(self.RearmingPlaceCoord, false) - end - - end - - _engage=false - + self:Rearm() end if self:is("Moving") then - _engage=false + --self.Controllable:GetVelocityKMH() end if self:is("Rearming") then - _engage=false + local _rearmed=self:_CheckRearmed() + env.info("FF: Rearming. _rearmed = ", tostring(_rearmed)) + if _rearmed then + self:Rearmed() + end end if self:is("Rearmed") then local distance=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) + env.info("FF: Rearmed. Distance ARTY to InitalCoord = ", distance) if distance > 100 then - self:Move(self.InitialCoord, false) - _engage=false + --self:Move(self.InitialCoord, false) else self:CombatReady() end @@ -1099,11 +850,11 @@ function ARTY:onafterStatus(Controllable, From, Event, To) if self:is("Arrived") then - + self:CombatReady() end -- Engage targets. - if _engage then + if self:is("CombatReady") then -- Get a timed target if it is due to be attacked. local _timedTarget=self:_CheckTimedTargets() @@ -1112,7 +863,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Engage target. if _timedTarget then if self.currentTarget then - self:CeaseFire() + self:CeaseFire(self.currentTarget) end self:OpenFire(_timedTarget) elseif _normalTarget then @@ -1147,7 +898,7 @@ function ARTY:_CheckTimedTargets() if self.currentTarget then if self.currentTarget.prio > _target.prio then -- Current target under attack but has lower priority than this target. - self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, target.name)) + self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, _target.name)) return _target end else @@ -1197,28 +948,6 @@ function ARTY:onenterCombatReady(Controllable, From, Event, To) env.info(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) ---[[ - if From=="Rearming" and Event=="Rearmed" then - env.info("FF: Comabatready after Rearmed") - - -- Distance to initial position. - local dist=Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) - - if dist>100 then - -- Route group back to its original position, when rearming was at another place. - self:T(ARTY.id..string.format("%s is routed back to its initial position. Distance = %d m.", Controllable:GetName(), dist)) - self:__Move(30, self.InitialCoord, true) - end - - else - - -- Update target queue and open fire. - env.info("FF: Comabatready ==> _openfireontarget.") - self:_openfireontarget() - - end -]] - end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1236,16 +965,16 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) -- Check that group has no current target already. if self.currentTarget then - -- Debug info. - self:T2(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name)) - + -- This should not happen. Some earlier check failed. + self:E(ARTY.id..string.format("ERROR: Group %s already has a target %s!", self.Controllable:GetName(), self.currentTarget.name)) -- Deny transition. return false end -- Check if target is in range. - local _inrange=self:_TargetInRange(target) - if not _inrange then + if not self:_TargetInRange(target) then + -- This should not happen. Some earlier check failed. + self:E(ARTY.id..string.format("ERROR: Group %s, target %s is out of range!", self.Controllable:GetName(), self.currentTarget.name)) -- Deny transition. return false end @@ -1292,36 +1021,6 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) end ---- Go through queue of assigned tasks and trigger OpenFire event. --- @param #ARTY self -function ARTY:_openfireontarget() - self:F2() - - -- Debug info - self:T2(ARTY.id..string.format("Group %s, number of targets = %d", self.Controllable:GetName(), #self.targets)) - - -- No targets assigned at the moment. - if #self.targets==0 then - self:T3(ARTY.id..string.format("Group %s, no targets assigned at the moment. No need for _OpenFire.", self.Controllable:GetName())) - return - end - - -- Check timed targets first. - local _target=self:_CheckTimedTargets() - if _target then - self:__OpenFire(1, _target) - return - end - - -- Check normal targets - local _target=self:_CheckNormalTargets() - if _target then - self:__OpenFire(1, _target) - return - end - -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "CeaseFire" event. Clears task of the group and removes the target if max engagement was reached. @@ -1427,10 +1126,74 @@ end function ARTY:onafterRearm(Controllable, From, Event, To) self:_EventFromTo("onafterRearm", Event, From, To) - -- Start scheduler to monitor ammo count until rearming is complete. - self.SchedIDCheckRearmed=self.scheduler:Schedule(self, ARTY._CheckRearmed, {self}, 20, 20) + -- Coordinate of ARTY unit. + local coordARTY=self.Controllable:GetCoordinate() + + -- Coordinate of rearming group. + local coordRARM=nil + if self.RearmingGroup then + -- Coordinate of the rearming unit. + coordRARM=self.RearmingGroup:GetCoordinate() + -- Remember the coordinates of the rearming unit. After rearming it will go back to this position. + self.RearmingGroupCoord=coordRARM + end + + if self.RearmingGroup and self.RearmingPlaceCoord and self.Speed>0 then + + -- CASE 1: Rearming unit and ARTY group meet at rearming place. + + -- Distances. + local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) + local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) + + -- Route ARTY group to rearming place. + if dA>100 then + --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) + self:Move(self:_VicinityCoord(self.RearmingPlaceCoord, 20, 50), false) + end + + -- Route Rearming unit to rearming place + if dR>100 then + self:_Move(self.RearmingGroup, self:_VicinityCoord(self.RearmingPlaceCoord, 20, 50), 50, false) + end + + elseif self.RearmingGroup then + + -- CASE 2: Rearming unit drives to ARTY group. + + -- Send message. + local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingGroup:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + + -- Distance between ARTY group and rearming unit. + local distance=coordARTY:Get2DDistance(coordRARM) + + -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. + if distance > 100 then + + -- Route unit to ARTY group. + self:_Move(self.RearmingGroup, self:_VicinityCoord(coordARTY), 50, false) + end + + elseif self.RearmingPlaceCoord then + + -- CASE 3: ARTY drives to rearming place. + + -- Distance. + local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) + + -- Route ARTY group to rearming place. + if dA>100 then + --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) + self:Move(self:_VicinityCoord(self.RearmingPlaceCoord), false) + end + + end + end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "Rearmed" event. Send message if reporting is on and stop the scheduler. @@ -1447,29 +1210,25 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - -- Stop scheduler. - if self.SchedIDCheckRearmed then - self.scheduler:Stop(self.SchedIDCheckRearmed) - end - -- Route ARTY group backto where it came from (if distance is > 100 m). local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) if d1>100 then - self.Controllable:RouteGroundOnRoad(self.InitialCoord, self.Speed, 5) + self:Move(self.InitialCoord, false) end -- Route unit back to where it came from (if distance is > 100 m). if self.RearmingGroup and self.RearmingGroup:IsAlive() then local d=self.RearmingGroup:GetCoordinate():Get2DDistance(self.RearmingGroupCoord) if d>100 then - self.RearmingGroup:RouteGroundOnRoad(self.RearmingGroupCoord, 50, 1) + self:_Move(self.RearmingGroup, self.RearmingGroupCoord, 50, false) end end end ---- Check if ARTY group is rearmed. +--- Check if ARTY group is rearmed, i.e. has its full amount of ammo. -- @param #ARTY self +-- @return #boolean True if rearming is complete, false otherwise. function ARTY:_CheckRearmed() self:F2() @@ -1490,13 +1249,17 @@ function ARTY:_CheckRearmed() local _rearmpc=nammo/self.FullAmmo*100 -- Send message. - local text=string.format("%s, rearming %d %% complete.", self.Controllable:GetName(), _rearmpc) - self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) - + if _rearmpc>1 then + local text=string.format("%s, rearming %d %% complete.", self.Controllable:GetName(), _rearmpc) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + end + -- Rearming --> Rearmed --> CombatReady if nammo==self.FullAmmo then - self:Rearmed() + return true + else + return false end end @@ -1569,6 +1332,23 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- After "NewTarget" event. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table target Array holding the target info. +-- @return #boolean If true, proceed to onafterOpenfire. +function ARTY:onafterNewTarget(Controllable, From, Event, To, target) + self:_EventFromTo("onafterNewTarget", Event, From, To) + + -- Debug message. + local text=string.format("Adding new target %s.", target.name) + MESSAGE:New(text, 30):ToAllIf(self.Debug) + self:T(ARTY.id..text) +end + --- After "Dead" event, when a unit has died. When all units of a group are dead trigger "Stop" event. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -1625,7 +1405,7 @@ function ARTY:onafterStop(Controllable, From, Event, To) self.scheduler:Stop(self.SchedIDCheckShooting) end if self.SchedIDCheckRearmed then - self.scheduler:Stop(self.SchedIDCheckRearmed) + --self.scheduler:Stop(self.SchedIDCheckRearmed) end -- Unhandle event. @@ -1994,6 +1774,22 @@ function ARTY:_WeaponTypeName(tnumber) return name end +--- After "Rearmed" event. Send message if reporting is on and stop the scheduler. +-- @param #ARTY self +-- @param Core.Point#COORDINATE coord Center coordinate. +-- @param #number rmin (Optional) Minimum distance in meters from center coordinate. Default 20 m. +-- @param #number rmax (Optional) Maximum distance in meters from center coordinate. Default 100 m. +-- @return Core.Point#COORDINATE Random coordinate in a certain distance from center coordinate. +function ARTY:_VicinityCoord(coord, rmin, rmax) + self:F2({coord=coord, rmin=rmin, rmax=rmax}) + rmin=rmin or 20 + rmax=rmax or 100 + -- Random point. + local vec2=coord:GetRandomVec2InRadius(rmin, rmax) + local pops=COORDINATE:NewFromVec2(vec2) + return pops +end + --- Print event-from-to string to DCS log file. -- @param #ARTY self -- @param #string BA Before/after info. @@ -2022,6 +1818,14 @@ function ARTY:_split(str, sep) return result end +--- Returns the target info as formatted string. +-- @param #ARTY self +-- @return #string name, prio, radius, nshells, engaged, maxengage, time, weapontype +function ARTY:_TargetInfo(target) + local clock=tostring(self:_SecondsToClock(target.time)) + return string.format("%s, prio=%d, radius=%d, nshells=%d, engaged=%d maxengage=%d, weapontype=%d, time=%s", target.name, target.prio, target.radius, target.nshells, target.engaged, target.maxengage, target.weapontype, clock) +end + --- Convert time in seconds to hours, minutes and seconds. -- @param #ARTY self -- @param #number seconds Time in seconds. From f33856cddd82bd8282c8010aed9f44b38e347419 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 5 May 2018 22:51:43 +0200 Subject: [PATCH 077/170] ARTY v0.8.2 Fixes. Stil WIP --- .../Moose/Functional/Artillery.lua | 56 +++++++++---------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 3ea6059c6..94c24cff8 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -269,7 +269,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.1" +ARTY.version="0.8.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -618,7 +618,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) for _, target in pairs(self.targets) do local _clock=self:_SecondsToClock(target.time) local _weapon=self:_WeaponTypeName(target.weapontype) - text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, maxengage=%3d, time=%11s, weapon=%s\n", target.name, target.prio, target.radius, target.nshells, target.maxengage, tostring(_clock), _weapon) + text=text..string.format("- %s\n", self:_TargetInfo(target)) end text=text..string.format("******************************************************\n") text=text..string.format("Shell types:\n") @@ -676,10 +676,7 @@ function ARTY:_StatusReport() text=text..string.format("Nshots curr. Target = %d\n", self.Nshots) text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do - local _clock=self:_SecondsToClock(target.time) - local _weapon=self:_WeaponTypeName(target.weapontype) - text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, engaged=%3d, maxengage=%3d, weapon=%s, time=%s\n", - target.name, target.prio, target.radius, target.nshells, target.engaged, target.maxengage, _weapon, tostring(_clock)) + text=text..string.format("- %s\n", self:_TargetInfo(target)) end text=text..string.format("******************************************************") env.info(ARTY.id..text) @@ -890,19 +887,19 @@ function ARTY:_CheckTimedTargets() for i=1,#self.targets do local _target=self.targets[i] - -- Check if target has an attack time which has already passed. - -- Also check that target is not under fire already and that it is in range. - if _target.time and _target.time>=Tnow and _target.underfire==false and self:_TargetInRange(_target) then + -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. + if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then -- Check if group currently has a target and whether its priorty is lower than the timed target. if self.currentTarget then if self.currentTarget.prio > _target.prio then -- Current target under attack but has lower priority than this target. - self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, _target.name)) + self:T(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInRange(_target))) return _target end else -- No current target. + self:T(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) return _target end end @@ -927,7 +924,7 @@ function ARTY:_CheckNormalTargets() if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then -- Debug info. - self:T(ARTY.id..string.format("Engaging target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged)) + self:T(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) return _target end @@ -945,7 +942,9 @@ end -- @param #string Event Event. -- @param #string To To state. function ARTY:onenterCombatReady(Controllable, From, Event, To) - + self:_EventFromTo("onenterCombatReady", Event, From, To) + + -- Debug info env.info(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) end @@ -1088,9 +1087,6 @@ function ARTY:onafterWinchester(Controllable, From, Event, To) local text=string.format("%s, winchester.", Controllable:GetName()) self:T(ARTY.id..text) MESSAGE:New(text, 30):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - - -- Init rearming if possible. - --self:Rearm() end @@ -1823,7 +1819,10 @@ end -- @return #string name, prio, radius, nshells, engaged, maxengage, time, weapontype function ARTY:_TargetInfo(target) local clock=tostring(self:_SecondsToClock(target.time)) - return string.format("%s, prio=%d, radius=%d, nshells=%d, engaged=%d maxengage=%d, weapontype=%d, time=%s", target.name, target.prio, target.radius, target.nshells, target.engaged, target.maxengage, target.weapontype, clock) + local weapon=self:_WeaponTypeName(target.weapontype) + local _underfire=tostring(target.underfire) + return string.format("%s, prio=%d, radius=%d, nshells=%d, engaged=%d/%d, weapontype=%s, time=%s, underfire=%s", + target.name, target.prio, target.radius, target.nshells, target.engaged, target.maxengage, weapon, clock,_underfire) end --- Convert time in seconds to hours, minutes and seconds. @@ -1932,10 +1931,7 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Route group on road if requested. if OnRoad then - - --path[#path+1]=cpini:GetClosestPointToRoad():WaypointGround(Speed, "On road") - --task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - + local _first=cpini:GetClosestPointToRoad() local _last=ToCoord:GetClosestPointToRoad() local _onroad=_first:GetPathOnRoad(_last) @@ -1946,8 +1942,6 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) end - --path[#path+1]=ToCoord:GetClosestPointToRoad():WaypointGround(Speed, "On road") - --task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) end -- Last waypoint at ToCoord. @@ -1981,16 +1975,18 @@ end function ARTY._PassingWaypoint(group, arty, i, final) -- Debug message. - local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final)) - - --local pos=group:GetCoordinate() - --local MarkerID=pos:MarkToAll(string.format("Reached Waypoint %d of group %s", i, group:GetName())) - --pos:SmokeRed() - - MESSAGE:New(text,10):ToAll() + local text=string.format("%s, passing waypoint %d.", group:GetName(), i) + if final then + text=string.format("%s, arrived at destination.", group:GetName()) + end env.info(ARTY.id..text) + if final then + MESSAGE:New(text, 10):ToCoalitionIf(group:GetCoalition(), arty.Debug or arty.report) + else + MESSAGE:New(text, 10):ToAllIf(arty.Debug) + end - -- Move --> Moving --> Arrived --> CombatReady. + -- Arrived event. if final and arty.Controllable:GetName()==group:GetName() then arty:Arrived() end From ba944444daa44b0bdffa1466be97704f597d1812 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 5 May 2018 23:59:02 +0200 Subject: [PATCH 078/170] ARTY v0.8.3 Various improvements. Still WIP. --- .../Moose/Functional/Artillery.lua | 211 +++++++++--------- 1 file changed, 105 insertions(+), 106 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 94c24cff8..6a8b5d1d5 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -269,7 +269,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.2" +ARTY.version="0.8.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -287,7 +287,7 @@ ARTY.version="0.8.2" -- DONE: Improve assigned time for engagement. Next day? -- DONE: Improve documentation. -- DONE: Add pseudo user transitions. OnAfter... --- TODO: Make reaming unit a group. +-- DONE: Make reaming unit a group. -- TODO: Adjust documenation again. -- TODO: Add command move to make arty group move. -- TODO: remove schedulers for status event. @@ -384,12 +384,15 @@ function ARTY:New(group) self:AddTransition("*", "CombatReady", "CombatReady") self:AddTransition("*", "Status", "*") self:AddTransition("*", "Dead", "*") + + -- Unknown transitons. To be checked if adding these causes problems. + self:AddTransition("Rearming", "Arrived", "Rearming") return self end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- User Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Assign target coordinates to the ARTY group. Only the first parameter, i.e. the coordinate of the target is mandatory. The remaining parameters are optional and can be used to fine tune the engagement. @@ -563,19 +566,8 @@ function ARTY:SetMissileTypes(tableofnames) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- FSM Start Event ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Before "Start" event. Initialized ROE and alarm state. Starts the event handler. --- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. -function ARTY:onbeforeStart(Controllable, From, Event, To) - self:_EventFromTo("onbeforeStart", Event, From, To) - - env.info("FF: onbeforeStart") -end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self @@ -643,12 +635,8 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:__Status(5) -- Start scheduler to monitor if ARTY group started firing within a certain time. + --TODO: move this to status checks self.SchedIDCheckShooting=self.scheduler:Schedule(self, ARTY._CheckShootingStarted, {self}, 60, 60) - - -- Start cheduler for status reports. --- if self.Debug then --- self.SchedIDStatusReport=self.scheduler:Schedule(self, ARTY._StatusReport, {self}, 30, 30) --- end end @@ -684,7 +672,7 @@ function ARTY:_StatusReport() end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Event Handling ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Eventhandler for shot event. @@ -803,7 +791,7 @@ function ARTY:_OnEventDead(EventData) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- FSM Events and States ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "Status" event. Report status of group. @@ -815,29 +803,36 @@ end function ARTY:onafterStatus(Controllable, From, Event, To) self:_EventFromTo("onafterStatus", Event, From, To) + -- Debug current status info. if self.Debug then self:_StatusReport() end + -- Group is out of ammo. if self:is("OutOfAmmo") then + env.info(string.format("FF: OutOfAmmo. ==> Rearm")) self:Rearm() end + -- Group is out of moving. if self:is("Moving") then - --self.Controllable:GetVelocityKMH() + local _speed=self.Controllable:GetVelocityKMH() + env.info(string.format("FF: Moving. Velocity = %d km/h", _speed)) end + -- Group is rearming. if self:is("Rearming") then local _rearmed=self:_CheckRearmed() - env.info("FF: Rearming. _rearmed = ", tostring(_rearmed)) + env.info(string.format("FF: Rearming. _rearmed = %s", tostring(_rearmed))) if _rearmed then self:Rearmed() end end + -- Group finished rearming. if self:is("Rearmed") then local distance=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) - env.info("FF: Rearmed. Distance ARTY to InitalCoord = ", distance) + env.info(string.format("FF: Rearmed. Distance ARTY to InitalCoord = %d", distance)) if distance > 100 then --self:Move(self.InitialCoord, false) else @@ -845,25 +840,31 @@ function ARTY:onafterStatus(Controllable, From, Event, To) end end - + -- Group arrived at destination. if self:is("Arrived") then + env.info(string.format("FF: Arrived. ==> CombatReady")) self:CombatReady() end - -- Engage targets. + -- Group is combat ready. if self:is("CombatReady") then + env.info(string.format("FF: Combatready. Looking for targets.")) - -- Get a timed target if it is due to be attacked. + -- Get a valid timed target if it is due to be attacked. local _timedTarget=self:_CheckTimedTargets() + -- Get a valid normal target (one that is not timed). local _normalTarget=self:_CheckNormalTargets() -- Engage target. if _timedTarget then + -- Cease fire on current target first. if self.currentTarget then self:CeaseFire(self.currentTarget) end + -- Open fire on timed target. self:OpenFire(_timedTarget) elseif _normalTarget then + -- Open fire on normal target. self:OpenFire(_normalTarget) end @@ -873,66 +874,6 @@ function ARTY:onafterStatus(Controllable, From, Event, To) self:__Status(5) end ---- Check all timed targets and return the target which should be attacked next. --- @param #ARTY self --- @return #table Target which is due to be attacked now. -function ARTY:_CheckTimedTargets() - - -- Current time. - local Tnow=timer.getAbsTime() - - -- Sort Targets wrt time. - self:_SortTargetQueueTime() - - for i=1,#self.targets do - local _target=self.targets[i] - - -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. - if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then - - -- Check if group currently has a target and whether its priorty is lower than the timed target. - if self.currentTarget then - if self.currentTarget.prio > _target.prio then - -- Current target under attack but has lower priority than this target. - self:T(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInRange(_target))) - return _target - end - else - -- No current target. - self:T(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) - return _target - end - end - end - - return nil -end - ---- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. --- @param #ARTY self --- @return #table Target which is due to be attacked now or nil if no target could be found. -function ARTY:_CheckNormalTargets() - - -- Sort targets w.r.t. prio and number times engaged already. - self:_SortTargetQueuePrio() - - -- Loop over all sorted targets. - for i=1,#self.targets do - local _target=self.targets[i] - - -- Check that target no time, is not under fire currently and in range. - if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then - - -- Debug info. - self:T(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) - - return _target - end - end - - return nil -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Enter "CombatReady" state. Route the group back if necessary. @@ -943,10 +884,8 @@ end -- @param #string To To state. function ARTY:onenterCombatReady(Controllable, From, Event, To) self:_EventFromTo("onenterCombatReady", Event, From, To) - -- Debug info - env.info(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) - + self:T(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1189,7 +1128,6 @@ function ARTY:onafterRearm(Controllable, From, Event, To) end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- After "Rearmed" event. Send message if reporting is on and stop the scheduler. @@ -1206,7 +1144,7 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) - -- Route ARTY group backto where it came from (if distance is > 100 m). + -- Route ARTY group back to where it came from (if distance is > 100 m). local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) if d1>100 then self:Move(self.InitialCoord, false) @@ -1420,7 +1358,7 @@ end -- @param #number nshells Number of shells to fire. -- @param #number weapontype Type of weapon to use. function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) - self:E({coord=coord, radius=radius, nshells=nshells}) + self:F({coord=coord, radius=radius, nshells=nshells}) -- Controllable. local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE @@ -1436,7 +1374,6 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) -- Execute task. group:SetTask(fire) - --group:PushTask(fire) end @@ -1491,6 +1428,66 @@ function ARTY:_SortTargetQueueTime() end +--- Check all timed targets and return the target which should be attacked next. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now. +function ARTY:_CheckTimedTargets() + + -- Current time. + local Tnow=timer.getAbsTime() + + -- Sort Targets wrt time. + self:_SortTargetQueueTime() + + for i=1,#self.targets do + local _target=self.targets[i] + + -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. + if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then + + -- Check if group currently has a target and whether its priorty is lower than the timed target. + if self.currentTarget then + if self.currentTarget.prio > _target.prio then + -- Current target under attack but has lower priority than this target. + self:T(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInRange(_target))) + return _target + end + else + -- No current target. + self:T(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) + return _target + end + end + end + + return nil +end + +--- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now or nil if no target could be found. +function ARTY:_CheckNormalTargets() + + -- Sort targets w.r.t. prio and number times engaged already. + self:_SortTargetQueuePrio() + + -- Loop over all sorted targets. + for i=1,#self.targets do + local _target=self.targets[i] + + -- Check that target no time, is not under fire currently and in range. + if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then + + -- Debug info. + self:T(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) + + return _target + end + end + + return nil +end + --- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE controllable Controllable for which the ammo is counted. @@ -1561,8 +1558,7 @@ function ARTY:_GetAmmo(controllable) _gotmissile=true end end - - + -- We are specifically looking for shells or rockets here. if _gotshell then @@ -1755,17 +1751,17 @@ function ARTY:_WeaponTypeName(tnumber) self:F2(tnumber) local name="unknown" if tnumber==ARTY.WeaponType.Auto then - name="Auto (Cannon, Rockets, Missiles)" + name="Auto" -- (Cannon, Rockets, Missiles) elseif tnumber==ARTY.WeaponType.Cannon then - name="Cannon" + name="Cannons" elseif tnumber==ARTY.WeaponType.Rockets then name="Rockets" elseif tnumber==ARTY.WeaponType.UnguidedAny then - name="Any Unguided Weapon (Cannon or Rockets)" + name="Unguided Weapons" -- (Cannon or Rockets) elseif tnumber==ARTY.WeaponType.CruiseMissile then - name="Cruise Missile" + name="Cruise Missiles" elseif tnumber==ARTY.WeaponType.GuidedMissile then - name="Guided Missile" + name="Guided Missiles" end return name end @@ -1774,15 +1770,18 @@ end -- @param #ARTY self -- @param Core.Point#COORDINATE coord Center coordinate. -- @param #number rmin (Optional) Minimum distance in meters from center coordinate. Default 20 m. --- @param #number rmax (Optional) Maximum distance in meters from center coordinate. Default 100 m. +-- @param #number rmax (Optional) Maximum distance in meters from center coordinate. Default 80 m. -- @return Core.Point#COORDINATE Random coordinate in a certain distance from center coordinate. function ARTY:_VicinityCoord(coord, rmin, rmax) self:F2({coord=coord, rmin=rmin, rmax=rmax}) + -- Set default if necessary. rmin=rmin or 20 - rmax=rmax or 100 - -- Random point. - local vec2=coord:GetRandomVec2InRadius(rmin, rmax) + rmax=rmax or 80 + -- Random point withing range. + local vec2=coord:GetRandomVec2InRadius(rmax, rmin) local pops=COORDINATE:NewFromVec2(vec2) + -- Debug info. + self:T(ARTY.id..string.format("Vicinity distance = %d (rmin=%d, rmax=%d)", pops:Get2DDistance(coord), rmin, rmax)) return pops end From 19b3dcec2194345a92d40fafbcc04f0897e8d542 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 6 May 2018 07:36:58 +0200 Subject: [PATCH 079/170] # Conflicts: # Moose Development/Moose/AI/AI_Cargo_APC.lua # Moose Development/Moose/Wrapper/Controllable.lua --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 29 ++++--- .../Moose/AI/AI_Cargo_Helicopter.lua | 83 ++++++++++++++++--- .../Moose/Wrapper/Controllable.lua | 5 +- 3 files changed, 90 insertions(+), 27 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index d5022f135..be3b2b77e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -395,7 +395,7 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) local APCUnit = APCUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( self.CargoSet:GetSet() ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) + self:F( { IsUnLoaded = Cargo:IsUnLoaded(), Cargo:GetName(), APC:GetName() } ) if Cargo:IsUnLoaded() then if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then self:F( { "In radius", APCUnit:GetName() } ) @@ -420,12 +420,12 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC:onafterBoard( Carrier, From, Event, To, Cargo ) - self:F( { Carrier, From, Event, To, Cargo } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterBoard( APC, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo } ) - if Carrier and Carrier:IsAlive() then - self:F({ IsLoaded = Cargo:IsLoaded() } ) + if APC and APC:IsAlive() then + self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), APC:GetName() } ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else @@ -445,7 +445,7 @@ function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) if APC and APC:IsAlive() then for APCUnit, Cargo in pairs( self.APC_Cargo ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), APC:GetName() } ) if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then Loaded = false end @@ -505,8 +505,9 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) --Cargo:Regroup() if APC and APC:IsAlive() then - for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do - local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + local CargoCheck = self.APC_Cargo[APCUnit] self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) if CargoCheck:IsUnLoaded() == false then AllUnloaded = false @@ -580,14 +581,15 @@ end -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed ) +-- @param #string EndPointFormation The formation at the end point of the action. +function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, EndPointFormation ) if APC and APC:IsAlive() then if Coordinate then self.RoutePickup = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) @@ -611,13 +613,14 @@ end -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed ) +-- @param #string EndPointFormation The formation at the end point of the action. +function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, EndPointFormation ) if APC and APC:IsAlive() then self.RouteDeploy = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index ad502c322..c993755ee 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -333,19 +333,41 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinate ) +function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To, Coordinate ) + + local Boarding = false if Helicopter and Helicopter:IsAlive() then - for _, Cargo in pairs( self.CargoSet:GetSet() ) do - if Cargo:IsInLoadRadius( Coordinate ) then - self:__Board( 5 ) - Cargo:Board( Helicopter:GetUnit(1), 25 ) - self.Cargo = Cargo - break + self.BoardingCount = 0 + + if Helicopter and Helicopter:IsAlive() then + self.Helicopter_Cargo = {} + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) + if Cargo:IsUnLoaded() then + if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then + self:F( { "In radius", HelicopterUnit:GetName() } ) + --Cargo:Ungroup() + Cargo:Board( HelicopterUnit, 25 ) + self:__Board( 1, Cargo ) + Boarding = true + + -- So now this APCUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.Helicopter_Cargo[HelicopterUnit] = Cargo + break + end + end + end end end end + + return Boarding end @@ -366,11 +388,23 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To ) + + local Loaded = true if Helicopter and Helicopter:IsAlive() then + for HelicopterUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) + if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then + Loaded = false + end + end + end + return Loaded + end @@ -379,9 +413,15 @@ end function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then - self.Cargo:UnBoard() - self:__Unboard( 10 ) + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do + Cargo:UnBoard() + self:__Unboard( 10, Cargo ) + end + end end + end @@ -401,12 +441,31 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To ) + + local AllUnloaded = true + + --Cargo:Regroup() if Helicopter and Helicopter:IsAlive() then - self.Helicopter = Helicopter + for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do + local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO + self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) + if CargoCheck:IsUnLoaded() == false then + AllUnloaded = false + break + end + end + + if AllUnloaded == true then + self.Helicopter = Helicopter + self.Helicopter_Cargo = {} + end end + self:F( { AllUnloaded = AllUnloaded } ) + return AllUnloaded + end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 6f55ff3d6..11809e47a 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1974,8 +1974,9 @@ do -- Route methods -- @param #CONTROLLABLE self -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #string EndPointFormation The formation to achieve at the end point. -- @return Task - function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed ) + function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, EndPointFormation ) -- Current coordinate. local FromCoordinate = self:GetCoordinate() @@ -1998,7 +1999,7 @@ do -- Route methods -- Add the final coordinate because the final coordinate in path is last point on road. local dist=ToCoordinate:Get2DDistance(path[#path]) if dist>10 then - table.insert( Route, ToCoordinate:WaypointGround( Speed, "Vee" ) ) + table.insert( Route, ToCoordinate:WaypointGround( Speed, EndPointFormation ) ) end return Route From c36579f88a1e96a33a2c65110d9c8828755171eb Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 6 May 2018 12:05:23 +0200 Subject: [PATCH 080/170] ARTY v0.8.4 Several improvments and fixes. --- .../Moose/Functional/Artillery.lua | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 6a8b5d1d5..410b083c1 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -269,7 +269,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.3" +ARTY.version="0.8.4" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -407,10 +407,10 @@ end -- @param #string name (Optional) Name of the target. Default is LL DMS coordinate of the target. If the name was already given, the numbering "#01", "#02",... is appended automatically. -- @return #string Name of the target. Can be used for further reference, e.g. deleting the target from the list. -- @usage paladin=ARTY:New(GROUP:FindByName("Blue Paladin")) --- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 10, 300, 10, 1, "08:02:00", ARTY.WeaponType.Auto, "Red Targets 1") +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 10, 300, 10, 1, "08:02:00", ARTY.WeaponType.Auto, "Target 1") -- paladin:Start() function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, weapontype, name) - self:T({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype, name=name}) + self:F({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype, name=name}) -- Set default values. nshells=nshells or 5 @@ -436,12 +436,6 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w -- Add to table. table.insert(self.targets, _target) - -- Clock. - local _clock=self:_SecondsToClock(_target.time) - - -- Debug info. - self:T(ARTY.id..string.format("Added target %s", self:_TargetInfo(_target))) - -- Trigger new target event. self:NewTarget(_target) end @@ -632,12 +626,8 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) + -- Start checking status. self:__Status(5) - - -- Start scheduler to monitor if ARTY group started firing within a certain time. - --TODO: move this to status checks - self.SchedIDCheckShooting=self.scheduler:Schedule(self, ARTY._CheckShootingStarted, {self}, 60, 60) - end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. @@ -648,8 +638,8 @@ function ARTY:_StatusReport() local Nammo, Nshells, Nrockets, Nmissiles=self:_GetAmmo(self.Controllable) local Tnow=timer.getTime() - local text=string.format("\n******************************************************\n") - text=text..string.format("Status of ARTY = %s\n", self.Controllable:GetName()) + local text=string.format("\n******************* STATUS ***************************\n") + text=text..string.format("ARTY group = %s\n", self.Controllable:GetName()) text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("Total ammo count = %d\n", Nammo) text=text..string.format("Number of shells = %d\n", Nshells) @@ -846,28 +836,41 @@ function ARTY:onafterStatus(Controllable, From, Event, To) self:CombatReady() end - -- Group is combat ready. - if self:is("CombatReady") then - env.info(string.format("FF: Combatready. Looking for targets.")) - - -- Get a valid timed target if it is due to be attacked. - local _timedTarget=self:_CheckTimedTargets() - -- Get a valid normal target (one that is not timed). - local _normalTarget=self:_CheckNormalTargets() + -- Group is firing on target. + if self:is("Firing") then + -- Check that firing started after ~5 min. If not, target is removed. + self:_CheckShootingStarted() + end + + + -- Get a valid timed target if it is due to be attacked. + local _timedTarget=self:_CheckTimedTargets() + + -- Get a valid normal target (one that is not timed). + local _normalTarget=self:_CheckNormalTargets() + + + -- Group is combat ready or firing but we have a high prio timed target. + if self:is("CombatReady") or (self:is("Firing") and _timedTarget) then + env.info(string.format("FF: Combatready or firing and high prio timed target.")) -- Engage target. if _timedTarget then + -- Cease fire on current target first. if self.currentTarget then self:CeaseFire(self.currentTarget) end + -- Open fire on timed target. self:OpenFire(_timedTarget) + elseif _normalTarget then + -- Open fire on normal target. self:OpenFire(_normalTarget) + end - end -- Call status again in 5 sec. @@ -1023,7 +1026,7 @@ function ARTY:onafterWinchester(Controllable, From, Event, To) self:_EventFromTo("onafterWinchester", Event, From, To) -- Send message. - local text=string.format("%s, winchester.", Controllable:GetName()) + local text=string.format("%s, winchester!", Controllable:GetName()) self:T(ARTY.id..text) MESSAGE:New(text, 30):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) @@ -1130,7 +1133,7 @@ end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- After "Rearmed" event. Send message if reporting is on and stop the scheduler. +--- After "Rearmed" event. Send ARTY and rearming group back to their inital positions. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -1189,7 +1192,7 @@ function ARTY:_CheckRearmed() MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) end - -- Rearming --> Rearmed --> CombatReady + -- Return if ammo is full. if nammo==self.FullAmmo then return true else @@ -1314,7 +1317,7 @@ function ARTY:onafterDead(Controllable, From, Event, To) end ---- After "Stop" event. Stop schedulers and unhandle events. +--- After "Stop" event. Unhandle events and cease fire on current target. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. -- @param #string From From state. @@ -1334,14 +1337,6 @@ function ARTY:onafterStop(Controllable, From, Event, To) -- Remove all targets. --self:RemoveAllTargets() - -- Stop schedulers. - if self.SchedIDCheckShooting then - self.scheduler:Stop(self.SchedIDCheckShooting) - end - if self.SchedIDCheckRearmed then - --self.scheduler:Stop(self.SchedIDCheckRearmed) - end - -- Unhandle event. self:UnHandleEvent(EVENTS.Shot) self:UnHandleEvent(EVENTS.Dead) @@ -1361,7 +1356,7 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) self:F({coord=coord, radius=radius, nshells=nshells}) -- Controllable. - local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE + local group=self.Controllable --Wrapper.Group#GROUP -- Set ROE to weapon free. group:OptionROEOpenFire() @@ -1393,14 +1388,14 @@ function ARTY:_SortTargetQueuePrio() self:T2(ARTY.id.."Sorted targets wrt prio and number of engagements:") for i=1,#self.targets do local _target=self.targets[i] - local _clock=self:_SecondsToClock(_target.time) - self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d, time=%s", _target.name, _target.prio, _target.engaged, tostring(_clock))) + self:T2(ARTY.id..string.format("Target %s", self:_TargetInfo(_target))) end end ---- Sort targets with respect to engage time. +--- Sort array with respect to time. Array elements must have a .time entry. -- @param #ARTY self -function ARTY:_SortTargetQueueTime() +-- @param #table queue Array to sort. Should have elemnt .time. +function ARTY:_SortQueueTime(queue) self:F2() -- Sort targets w.r.t attack time. @@ -1416,14 +1411,15 @@ function ARTY:_SortTargetQueueTime() end return a.time < b.time end - table.sort(self.targets, _sort) + table.sort(queue, _sort) -- Debug output. - self:T2(ARTY.id.."Sorted targets wrt time:") - for i=1,#self.targets do - local _target=self.targets[i] - local _clock=self:_SecondsToClock(_target.time) - self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d, time=%s", _target.name, _target.prio, _target.engaged, tostring(_clock))) + self:T(ARTY.id.."Sorted queue wrt time:") + for i=1,#queue do + local _queue=queue[i] + local _time=tostring(_queue.time) + local _clock=tostring(self:_SecondsToClock(_queue.time)) + self:T(ARTY.id..string.format("%s: time=%s, clock=%s", _queue.name, _time, _clock)) end end @@ -1437,11 +1433,14 @@ function ARTY:_CheckTimedTargets() local Tnow=timer.getAbsTime() -- Sort Targets wrt time. - self:_SortTargetQueueTime() + self:_SortQueueTime(self.targets) for i=1,#self.targets do local _target=self.targets[i] + -- Debug info. + self:T3(ARTY.id..string.format("Check TIMED target %d: %s", i, self:_TargetInfo(_target))) + -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then @@ -1449,7 +1448,7 @@ function ARTY:_CheckTimedTargets() if self.currentTarget then if self.currentTarget.prio > _target.prio then -- Current target under attack but has lower priority than this target. - self:T(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInRange(_target))) + self:T(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInfo(_target))) return _target end else @@ -1474,6 +1473,9 @@ function ARTY:_CheckNormalTargets() -- Loop over all sorted targets. for i=1,#self.targets do local _target=self.targets[i] + + -- Debug info. + self:T3(ARTY.id..string.format("Check NORMAL target %d: %s", i, self:_TargetInfo(_target))) -- Check that target no time, is not under fire currently and in range. if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then @@ -1802,14 +1804,12 @@ end -- @param #string sep Speparator for split. -- @return #table Split text. function ARTY:_split(str, sep) - self:F3({str=str, sep=sep}) - + self:F3({str=str, sep=sep}) local result = {} local regex = ("([^%s]+)"):format(sep) for each in str:gmatch(regex) do table.insert(result, each) end - return result end From a2c12dc05eec4304ef00d5fe608487e0b0dd73bc Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 6 May 2018 12:51:51 +0200 Subject: [PATCH 081/170] ARTY v0.8.5 Improved GetAmmo function. Display of ammo table. Removed all schedulers. --- .../Moose/Functional/Artillery.lua | 90 +++++++++---------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 410b083c1..19b401e65 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -14,7 +14,9 @@ -- * Multiple targets can be assigned. No restriction on number of targets. -- * Targets can be given a priority. Engagement of targets is executed a according to their priority. -- * Engagements can be scheduled, i.e. will be executed at a certain time of the day. --- * Special weapon types can be selected. +-- * Special weapon types can be selected for each attack, e.g. cruise missiles for Naval units. +-- * Automatic rearming once the artillery is out of ammo. +-- * Finite state machine implementation. User can interact when certain events occur. -- -- ==== -- @@ -49,11 +51,7 @@ -- @field #number Nrockets0 Initial amount of rockets of the whole group. -- @field #number Nmissiles0 Initial amount of missiles of the whole group. -- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. --- @field Core.Scheduler#SCHEDULER scheduler Scheduler object handling various timed functions. --- @field #number SchedIDCheckRearmed Scheduler ID responsible for checking whether rearming of the ARTY group is complete. --- @field #number SchedIDCheckShooting Scheduler ID for checking whether a group startet firing within a certain time after the fire at point task was assigned. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. --- @field #number SchedIDStatusReport Scheduler ID for status report messages. The scheduler is only launched in debug mode. -- @field #table DCSdesc DCS descriptors of the ARTY group. -- @field #string Type Type of the ARTY group. -- @field #string DisplayName Extended type name of the ARTY group. @@ -229,9 +227,6 @@ ARTY={ Nrockets0=0, Nmissiles0=0, FullAmmo=0, - scheduler=nil, - SchedIDCheckRearmed=nil, - SchedIDCheckShooting=nil, WaitForShotTime=300, SchedIDStatusReport=nil, DCSdesc=nil, @@ -269,7 +264,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.4" +ARTY.version="0.8.5" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -290,7 +285,7 @@ ARTY.version="0.8.4" -- DONE: Make reaming unit a group. -- TODO: Adjust documenation again. -- TODO: Add command move to make arty group move. --- TODO: remove schedulers for status event. +-- DONE: remove schedulers for status event. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -325,9 +320,6 @@ function ARTY:New(group) -- Set the initial coordinates of the ARTY group. self.InitialCoord=group:GetCoordinate() - -- Create scheduler object. - self.scheduler=SCHEDULER:New(self) - -- Get DCS descriptors of group. local DCSgroup=Group.getByName(group:GetName()) local DCSunit=DCSgroup:getUnit(1) @@ -577,7 +569,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) MESSAGE:New(text, 10):ToAllIf(self.Debug) -- Get Ammo. - self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:_GetAmmo(self.Controllable) + self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:GetAmmo(self.Controllable, self.Debug) local text=string.format("\n******************************************************\n") text=text..string.format("Arty group = %s\n", Controllable:GetName()) @@ -635,7 +627,7 @@ end function ARTY:_StatusReport() -- Get Ammo. - local Nammo, Nshells, Nrockets, Nmissiles=self:_GetAmmo(self.Controllable) + local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo(self.Controllable) local Tnow=timer.getTime() local text=string.format("\n******************* STATUS ***************************\n") @@ -699,7 +691,7 @@ function ARTY:_OnEventShot(EventData) MESSAGE:New(text, 5):ToAllIf(self.Debug) -- Get current ammo. - local _nammo,_nshells,_nrockets,_nmissiles=self:_GetAmmo(self.Controllable) + local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo(self.Controllable) if _nammo==0 then @@ -1170,7 +1162,7 @@ function ARTY:_CheckRearmed() self:F2() -- Get current ammo. - local nammo,nshells,nrockets,nmissiles=self:_GetAmmo(self.Controllable) + local nammo,nshells,nrockets,nmissiles=self:GetAmmo(self.Controllable) -- Number of units still alive. local units=self.Controllable:GetUnits() @@ -1385,10 +1377,10 @@ function ARTY:_SortTargetQueuePrio() table.sort(self.targets, _sort) -- Debug output. - self:T2(ARTY.id.."Sorted targets wrt prio and number of engagements:") + self:T3(ARTY.id.."Sorted targets wrt prio and number of engagements:") for i=1,#self.targets do local _target=self.targets[i] - self:T2(ARTY.id..string.format("Target %s", self:_TargetInfo(_target))) + self:T3(ARTY.id..string.format("Target %s", self:_TargetInfo(_target))) end end @@ -1396,7 +1388,7 @@ end -- @param #ARTY self -- @param #table queue Array to sort. Should have elemnt .time. function ARTY:_SortQueueTime(queue) - self:F2() + self:F3({queue=queue}) -- Sort targets w.r.t attack time. local function _sort(a, b) @@ -1414,12 +1406,12 @@ function ARTY:_SortQueueTime(queue) table.sort(queue, _sort) -- Debug output. - self:T(ARTY.id.."Sorted queue wrt time:") + self:T3(ARTY.id.."Sorted queue wrt time:") for i=1,#queue do local _queue=queue[i] local _time=tostring(_queue.time) local _clock=tostring(self:_SecondsToClock(_queue.time)) - self:T(ARTY.id..string.format("%s: time=%s, clock=%s", _queue.name, _time, _clock)) + self:T3(ARTY.id..string.format("%s: time=%s, clock=%s", _queue.name, _time, _clock)) end end @@ -1428,7 +1420,8 @@ end -- @param #ARTY self -- @return #table Target which is due to be attacked now. function ARTY:_CheckTimedTargets() - + self:F3() + -- Current time. local Tnow=timer.getAbsTime() @@ -1448,12 +1441,12 @@ function ARTY:_CheckTimedTargets() if self.currentTarget then if self.currentTarget.prio > _target.prio then -- Current target under attack but has lower priority than this target. - self:T(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInfo(_target))) + self:T2(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInfo(_target))) return _target end else -- No current target. - self:T(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) + self:T2(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) return _target end end @@ -1481,7 +1474,7 @@ function ARTY:_CheckNormalTargets() if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then -- Debug info. - self:T(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) + self:T2(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) return _target end @@ -1493,12 +1486,17 @@ end --- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE controllable Controllable for which the ammo is counted. +-- @param #boolean display Display ammo table as message to all. Default false. -- @return #number Total amount of ammo the whole group has left. -- @return #number Number of shells the group has left. -- @return #number Number of rockets the group has left. -- @return #number Number of missiles the group has left. -function ARTY:_GetAmmo(controllable) - self:F2(controllable) +function ARTY:GetAmmo(controllable, display) + self:F3({controllable=controllable, display=display}) + + if display==nil then + display=false + end -- Init counter. local nammo=0 @@ -1515,18 +1513,19 @@ function ARTY:_GetAmmo(controllable) for _,unit in pairs(units) do if unit and unit:IsAlive() then + + -- Output. + local text=string.format("ARTY group %s - unit %s:\n", self.Controllable:GetName(), unit:GetName()) + -- Get ammo table. local ammotable=unit:GetAmmo() - self:T2({ammotable=ammotable}) - - local name=unit:GetName() - + if ammotable ~= nil then local weapons=#ammotable self:T2(ARTY.id..string.format("Number of weapons %d.", weapons)) - self:T2(ammotable) + self:T2({ammotable=ammotable}) -- Loop over all weapons. for w=1,weapons do @@ -1568,9 +1567,7 @@ function ARTY:_GetAmmo(controllable) nshells=nshells+Nammo -- Debug info. - local text=string.format("Unit %s has %d shells of type %s", name, Nammo, Tammo) - self:T2(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + text=text..string.format("- %d shells of type %s\n", Nammo, Tammo) elseif _gotrocket then @@ -1578,9 +1575,7 @@ function ARTY:_GetAmmo(controllable) nrockets=nrockets+Nammo -- Debug info. - local text=string.format("Unit %s has %d rockets of type %s", name, Nammo, Tammo) - self:T2(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + text=text..string.format("- %d rockets of type %s\n", Nammo, Tammo) elseif _gotmissile then @@ -1588,21 +1583,22 @@ function ARTY:_GetAmmo(controllable) nmissiles=nmissiles+Nammo -- Debug info. - local text=string.format("Unit %s has %d missiles of type %s", name, Nammo, Tammo) - self:T2(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) - + text=text..string.format("- %d missiles of type %s\n", name, Nammo, Tammo) + else -- Debug info. - local text=string.format("Unit %s has %d ammo of type %s", name, Nammo, Tammo) - self:T2(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report) + text=text..string.format("- %d unknown ammo of type %s\n", Nammo, Tammo) end end end + + self:T2(ARTY.id..text) + MESSAGE:New(text, 10):ToAllIf(display) + + end end @@ -1768,7 +1764,7 @@ function ARTY:_WeaponTypeName(tnumber) return name end ---- After "Rearmed" event. Send message if reporting is on and stop the scheduler. +--- Find a random coordinate in the vicinity of another coordinate. -- @param #ARTY self -- @param Core.Point#COORDINATE coord Center coordinate. -- @param #number rmin (Optional) Minimum distance in meters from center coordinate. Default 20 m. From 16d4a65569724ffec23fdc5b38ed47aee0b390d6 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 6 May 2018 15:13:36 +0200 Subject: [PATCH 082/170] ARTY v0.8.6 Added user function for rearming properties. Minor bug fixes. --- .../Moose/Functional/Artillery.lua | 136 +++++++++++++----- 1 file changed, 97 insertions(+), 39 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 19b401e65..1b2d15fdf 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -44,30 +44,36 @@ -- @type ARTY -- @field #string ClassName Name of the class. -- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players. --- @field #table targets Targets assigned. +-- @field #table targets All targets assigned. +-- @field #table moves All moves assigned. -- @field #table currentTarget Holds the current target, if there is one assigned. -- @field #number Nammo0 Initial amount total ammunition (shells+rockets+missiles) of the whole group. -- @field #number Nshells0 Initial amount of shells of the whole group. -- @field #number Nrockets0 Initial amount of rockets of the whole group. -- @field #number Nmissiles0 Initial amount of missiles of the whole group. -- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. +-- @field #number StatusInterval Update interval in seconds between status updates. Default 10 seconds. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. -- @field #table DCSdesc DCS descriptors of the ARTY group. -- @field #string Type Type of the ARTY group. -- @field #string DisplayName Extended type name of the ARTY group. -- @field #number IniGroupStrength Inital number of units in the ARTY group. -- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". --- @field #number Speed Max speed of ARTY group. +-- @field #number Speed Maximum speed of ARTY group in km/h. +-- @field #number RearmingDistance Safe distance in meters between ARTY group and rearming group or place at which rearming is possible. Default 100 m. -- @field Wrapper.Group#GROUP RearmingGroup Unit designated to rearm the ARTY group. +-- @field #number RearmingGroupSpeed Speed in km/h the rearming unit moves at. Default 50 km/h. +-- @field #boolean RearmingGroupOnRoad If true, rearming group will move to ARTY group or rearming place using mainly roads. Default false. -- @field Core.Point#COORDINATE RearmingGroupCoord Initial coordinates of the rearming unit. After rearming complete, the unit will return to this position. -- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there. +-- @field #boolean RearmingArtyOnRoad If true, ARTY group will move to rearming place using mainly roads. Default false. -- @field Core.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group. -- @field #boolean report Arty group sends messages about their current state or target to its coaliton. -- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells. -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. -- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. -- @field #number Nshots Number of shots fired on current target. --- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0 km. +-- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0.5 km. -- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. -- @extends Core.Fsm#FSM_CONTROLLABLE @@ -221,29 +227,34 @@ ARTY={ ClassName = "ARTY", Debug = true, targets = {}, + moves = {}, currentTarget = nil, Nammo0=0, Nshells0=0, Nrockets0=0, Nmissiles0=0, FullAmmo=0, + StatusInterval=10, WaitForShotTime=300, - SchedIDStatusReport=nil, DCSdesc=nil, Type=nil, DisplayName=nil, IniGroupStrength=0, IsArtillery=nil, + RearmingDistance=100, RearmingGroup=nil, + RearmingGroupSpeed=50, + RearmingGroupOnRoad=false, RearmingGroupCoord=nil, RearmingPlaceCoord=nil, + RearmingArtyOnRoad=false, InitialCoord=nil, report=true, ammoshells={"weapons.shells"}, ammorockets={"weapons.nurs"}, ammomissiles={"weapons.missiles"}, Nshots=0, - minrange=0, + minrange=500, maxrange=1000000, } @@ -264,7 +275,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.5" +ARTY.version="0.8.6" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -434,10 +445,10 @@ end --- Set minimum firing range. Targets closer than this distance are not engaged. -- @param #ARTY self --- @param #number range Min range in kilometers. Default is 0 km. +-- @param #number range Min range in kilometers. Default is 0.5 km. function ARTY:SetMinFiringRange(range) self:F({range=range}) - self.minrange=range or 0 + self.minrange=range*1000 or 500 end --- Set maximum firing range. Targets further away than this distance are not engaged. @@ -448,6 +459,14 @@ function ARTY:SetMaxFiringRange(range) self.maxrange=range*1000 or 1000*1000 end +--- Set time interval between status updates. During the status check, new events are triggered. +-- @param #ARTY self +-- @param #number interval Time interval in seconds. Default 10 seconds. +function ARTY:SetStatusInterval(interval) + self:F({interval=interval}) + self.StatusInterval=interval or 10 +end + --- Set time how it is waited a unit the first shot event happens. If no shot is fired after this time, the task to fire is aborted and the target removed. -- @param #ARTY self -- @param #number waittime Time in seconds. Default 300 seconds. @@ -456,14 +475,52 @@ function ARTY:SetWaitForShotTime(waittime) self.WaitForShotTime=waittime or 300 end +--- Define the safe distance between ARTY group and rearming unit or rearming place at which rearming process is possible. +-- @param #ARTY self +-- @param #number distance Safe distance in meters. Default is 100 m. +function ARTY:SetRearmingDistance(distance) + self:F({distance=distance}) + self.RearmingDistance=distance or 100 +end + --- Assign a group, which is responsible for rearming the ARTY group. If the group is too far away from the ARTY group it will be guided towards the ARTY group. -- @param #ARTY self --- @param Wrapper.Group#GROUP unit Unit that is supposed to rearm the ARTY group. +-- @param Wrapper.Group#GROUP group Group that is supposed to rearm the ARTY group. function ARTY:SetRearmingGroup(group) self:F({group=group}) self.RearmingGroup=group end +--- Set the speed the rearming group moves at towards the ARTY group or the rearming place. +-- @param #ARTY self +-- @param #number speed Speed in km/h. Default 50 km/h. +function ARTY:SetRearmingGroupSpeed(speed) + self:F({speed=speed}) + self.RearmingGroupSpeed=speed or 50 +end + +--- Define if rearming group uses mainly roads to drive to the ARTY group or rearming place. +-- @param #ARTY self +-- @param #boolean onroad If true, rearming group uses mainly roads. If false, it drives directly to the ARTY group or rearming place. +function ARTY:SetRearmingGroupOnRoad(onroad) + self:F({onroad=onroad}) + if onroad==nil then + onroad=true + end + self.RearmingGroupOnRoad=onroad +end + +--- Define if ARTY group uses mainly roads to drive to the rearming place. +-- @param #ARTY self +-- @param #boolean onroad If true, ARTY group uses mainly roads. If false, it drives directly to the rearming place. +function ARTY:SetRearmingArtyOnRoad(onroad) + self:F({onroad=onroad}) + if onroad==nil then + onroad=true + end + self.RearmingArtyOnRoad=onroad +end + --- Defines the rearming place of the ARTY group. If the place is too far away from the ARTY group it will be routed to the place. -- @param #ARTY self -- @param Wrapper.Point#COORDINATE coord Coordinates of the rearming place. @@ -584,18 +641,22 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Number of shells = %d\n", self.Nshells0) text=text..string.format("Number of rockets = %d\n", self.Nrockets0) text=text..string.format("Number of missiles = %d\n", self.Nmissiles0) + if self.RearmingGroup or self.RearmingPlaceCoord then + text=text..string.format("Rearming safe dist. = %d m\n", self.RearmingDistance) + end if self.RearmingGroup then - text=text..string.format("Reaming group = %s\n", self.RearmingGroup:GetName()) + text=text..string.format("Rearming group = %s\n", self.RearmingGroup:GetName()) + text=text..string.format("Rearming group speed= %d km/h\n", self.RearmingGroupSpeed) + text=text..string.format("Rearming group roads= %s\n", tostring(self.RearmingGroupOnRoad)) end if self.RearmingPlaceCoord then - local dist=self.InitialCoord:Get2DDistance(self.RearmingPlaceCoord) - text=text..string.format("Reaming coord dist. = %d m\n", dist) + local dist=self.InitialCoord:Get2DDistance(self.RearmingPlaceCoord) + text=text..string.format("Rearming coord dist = %d m\n", dist) + text=text..string.format("Rearming ARTY roads = %s\n", tostring(self.RearmingArtyOnRoad)) end text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do - local _clock=self:_SecondsToClock(target.time) - local _weapon=self:_WeaponTypeName(target.weapontype) text=text..string.format("- %s\n", self:_TargetInfo(target)) end text=text..string.format("******************************************************\n") @@ -619,7 +680,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:HandleEvent(EVENTS.Dead, self._OnEventDead) -- Start checking status. - self:__Status(5) + self:__Status(self.StatusInterval) end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. @@ -798,8 +859,9 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Group is out of moving. if self:is("Moving") then - local _speed=self.Controllable:GetVelocityKMH() - env.info(string.format("FF: Moving. Velocity = %d km/h", _speed)) + --local _speed=self.Controllable:GetVelocityKMH() + --env.info(string.format("FF: Moving. Velocity = %d km/h", _speed)) + env.info(string.format("FF: Moving")) end -- Group is rearming. @@ -815,9 +877,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To) if self:is("Rearmed") then local distance=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) env.info(string.format("FF: Rearmed. Distance ARTY to InitalCoord = %d", distance)) - if distance > 100 then - --self:Move(self.InitialCoord, false) - else + if distance <= self.RearmingDistance then self:CombatReady() end end @@ -841,7 +901,6 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Get a valid normal target (one that is not timed). local _normalTarget=self:_CheckNormalTargets() - -- Group is combat ready or firing but we have a high prio timed target. if self:is("CombatReady") or (self:is("Firing") and _timedTarget) then env.info(string.format("FF: Combatready or firing and high prio timed target.")) @@ -865,8 +924,8 @@ function ARTY:onafterStatus(Controllable, From, Event, To) end end - -- Call status again in 5 sec. - self:__Status(5) + -- Call status again in ~10 sec. + self:__Status(self.StatusInterval) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1077,14 +1136,13 @@ function ARTY:onafterRearm(Controllable, From, Event, To) local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) -- Route ARTY group to rearming place. - if dA>100 then - --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) - self:Move(self:_VicinityCoord(self.RearmingPlaceCoord, 20, 50), false) + if dA > self.RearmingDistance then + self:Move(self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2), self.RearmingArtyOnRoad) end - -- Route Rearming unit to rearming place - if dR>100 then - self:_Move(self.RearmingGroup, self:_VicinityCoord(self.RearmingPlaceCoord, 20, 50), 50, false) + -- Route Rearming group to rearming place. + if dR > self.RearmingDistance then + self:_Move(self.RearmingGroup, self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2), self.RearmingGroupSpeed, self.RearmingGroupOnRoad) end elseif self.RearmingGroup then @@ -1099,11 +1157,11 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Distance between ARTY group and rearming unit. local distance=coordARTY:Get2DDistance(coordRARM) - -- If distance is larger than 100 m, the Rearming unit is routed to the ARTY group. - if distance > 100 then + -- If distance is larger than ~100 m, the Rearming unit is routed to the ARTY group. + if distance > self.RearmingDistance then - -- Route unit to ARTY group. - self:_Move(self.RearmingGroup, self:_VicinityCoord(coordARTY), 50, false) + -- Route rearming group to ARTY group. + self:_Move(self.RearmingGroup, self:_VicinityCoord(coordARTY), self.RearmingGroupSpeed, self.RearmingGroupOnRoad) end elseif self.RearmingPlaceCoord then @@ -1114,7 +1172,7 @@ function ARTY:onafterRearm(Controllable, From, Event, To) local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) -- Route ARTY group to rearming place. - if dA>100 then + if dA > self.RearmingDistance then --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) self:Move(self:_VicinityCoord(self.RearmingPlaceCoord), false) end @@ -1141,15 +1199,15 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) -- Route ARTY group back to where it came from (if distance is > 100 m). local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) - if d1>100 then + if d1 > self.RearmingDistance then self:Move(self.InitialCoord, false) end -- Route unit back to where it came from (if distance is > 100 m). if self.RearmingGroup and self.RearmingGroup:IsAlive() then local d=self.RearmingGroup:GetCoordinate():Get2DDistance(self.RearmingGroupCoord) - if d>100 then - self:_Move(self.RearmingGroup, self.RearmingGroupCoord, 50, false) + if d > self.RearmingDistance then + self:_Move(self.RearmingGroup, self.RearmingGroupCoord, self.RearmingGroupSpeed, self.RearmingGroupOnRoad) end end @@ -1721,10 +1779,10 @@ function ARTY:_TargetInRange(target) if _dist < self.minrange then _inrange=false - text=string.format("%s, target is out of range. Distance of %d km is below min range of %d km.", self.Controllable:GetName(), _dist/1000, self.minrange/1000) + text=string.format("%s, target is out of range. Distance of %.1f km is below min range of %.1f km.", self.Controllable:GetName(), _dist/1000, self.minrange/1000) elseif _dist > self.maxrange then _inrange=false - text=string.format("%s, target is out of range. Distance of %d km is greater than max range of %d km.", self.Controllable:GetName(), _dist/1000, self.maxrange/1000) + text=string.format("%s, target is out of range. Distance of %.1f km is greater than max range of %.1f km.", self.Controllable:GetName(), _dist/1000, self.maxrange/1000) end -- Debug output. From d9222c23cb9ab419b9a716e6891d18f104fb3e6f Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 6 May 2018 17:03:31 +0200 Subject: [PATCH 083/170] ARTY v0.8.7 Added first version of move implementation. Moves are not executed yet. --- .../Moose/Functional/Artillery.lua | 139 +++++++++++++++--- 1 file changed, 117 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 1b2d15fdf..36a847036 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -59,7 +59,8 @@ -- @field #string DisplayName Extended type name of the ARTY group. -- @field #number IniGroupStrength Inital number of units in the ARTY group. -- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". --- @field #number Speed Maximum speed of ARTY group in km/h. +-- @field #number SpeedMax Maximum speed of ARTY group in km/h. This is determined from the DCS descriptor table. +-- @field #number Speed Default speed in km/h the ARTY group moves at. Maximum speed possible is 80% of maximum speed the group can do. -- @field #number RearmingDistance Safe distance in meters between ARTY group and rearming group or place at which rearming is possible. Default 100 m. -- @field Wrapper.Group#GROUP RearmingGroup Unit designated to rearm the ARTY group. -- @field #number RearmingGroupSpeed Speed in km/h the rearming unit moves at. Default 50 km/h. @@ -275,7 +276,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.6" +ARTY.version="0.8.7" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -297,6 +298,7 @@ ARTY.version="0.8.6" -- TODO: Adjust documenation again. -- TODO: Add command move to make arty group move. -- DONE: remove schedulers for status event. +-- TODO: Improve handling of special weapons. When winchester? ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -342,8 +344,11 @@ function ARTY:New(group) self:T3({id=id, desc=desc}) end - -- Set speed to 0.7 of maximum in km/h. - self.Speed=self.DCSdesc.speedMax*3.6 * 0.7 + -- Maximum speed in km/h. + self.SpeedMax=self.DCSdesc.speedMax*3.6 + + -- Set speed to 0.7 of maximum. + self.Speed=self.SpeedMax * 0.7 -- Displayed name (similar to type name below) self.DisplayName=self.DCSdesc.displayName @@ -386,6 +391,7 @@ function ARTY:New(group) -- Not in diagram. self:AddTransition("*", "CombatReady", "CombatReady") self:AddTransition("*", "Status", "*") + self:AddTransition("*", "NewMove", "*") self:AddTransition("*", "Dead", "*") -- Unknown transitons. To be checked if adding these causes problems. @@ -428,7 +434,7 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w local _name=name or coord:ToStringLLDMS() -- Check if the name has already been used for another target. If so, the function returns a new unique name. - _name=self:_CheckTargetName(_name) + _name=self:_CheckName(self.targets, _name) -- Time in seconds. local _time=self:_ClockToSeconds(time) @@ -441,6 +447,53 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w -- Trigger new target event. self:NewTarget(_target) + + return _name +end + +--- Assign coordinate to where the ARTY group should move. +-- @param #ARTY self +-- @param Wrapper.Point#COORDINATE coord Coordinates of the target. +-- @param #string time (Optional) Day time at which the group should start moving. Passed as a string in format "08:13:45". +-- @param #number speed (Optinal) Speed in km/h the group should move at. Default 50 km/h. +-- @param #boolean onroad (Optional) If true, group will mainly use roads. Default off, i.e. go directly towards the specified coordinate. +-- @param #boolean cancel (Optional) If true, cancel any running attack when move should begin. Default is false. +-- @param #string name (Optional) Name of the coordinate. Default is LL DMS string of the coordinate. If the name was already given, the numbering "#01", "#02",... is appended automatically. +-- @return #string Name of the move. Can be used for further reference, e.g. deleting the move from the list. +function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name) + self:F({coord=coord, time=time, speed=speed, onroad=onroad, cancel=cancel, name=name}) + + -- Name of the target. + local _name=name or coord:ToStringLLDMS() + + -- Check if the name has already been used for another target. If so, the function returns a new unique name. + _name=self:_CheckName(self.moves, _name) + + -- Default is current time if no time was specified. + time=time or self:_SecondsToClock(timer.getAbsTime()) + + -- Default speed is 50 km/h. + speed=speed or 50 + + -- Default is off road. + if onroad==nil then + onroad=false + end + + -- Default is not to cancel a running attack. + if cancel==nil then + cancel=false + end + + -- Time in seconds. + local _time=self:_ClockToSeconds(time) + + -- Prepare move array. + local _move={name=_name, coord=coord, time=_time, speed=speed, onroad=onroad, cancel=cancel} + + -- Add to table. + table.insert(self.moves, _move) + end --- Set minimum firing range. Targets closer than this distance are not engaged. @@ -634,7 +687,8 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Type = %s\n", self.Type) text=text..string.format("Display Name = %s\n", self.DisplayName) text=text..string.format("Number of units = %d\n", self.IniGroupStrength) - text=text..string.format("Max Speed = %d km/h\n", self.Speed) + text=text..string.format("Speed max = %d km/h\n", self.SpeedMax) + text=text..string.format("Speed default = %d km/h\n", self.Speed) text=text..string.format("Min range = %d km\n", self.minrange/1000) text=text..string.format("Max range = %d km\n", self.maxrange/1000) text=text..string.format("Total ammo count = %d\n", self.Nammo0) @@ -659,6 +713,12 @@ function ARTY:onafterStart(Controllable, From, Event, To) for _, target in pairs(self.targets) do text=text..string.format("- %s\n", self:_TargetInfo(target)) end + text=text..string.format("Moves:\n") + for i=1,#self.moves do + local _move=self.moves[i] + local _clock=tostring(self:_SecondsToClock(_move.time)) + text=text..string.format("- %s: time=%s, speed=%d, onroad=%s, cancel=%s\n", _move.name, _clock, _move.speed, tostring(_move.onroad), tostring(_move.cancel)) + end text=text..string.format("******************************************************\n") text=text..string.format("Shell types:\n") for _,_type in pairs(self.ammoshells) do @@ -1127,17 +1187,22 @@ function ARTY:onafterRearm(Controllable, From, Event, To) self.RearmingGroupCoord=coordRARM end - if self.RearmingGroup and self.RearmingPlaceCoord and self.Speed>0 then + if self.RearmingGroup and self.RearmingPlaceCoord and self.SpeedMax>0 then -- CASE 1: Rearming unit and ARTY group meet at rearming place. + -- Send message. + local text=string.format("%s, %s, request rearming at rearming place.", Controllable:GetName(), self.RearmingGroup:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + -- Distances. local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) local dR=coordRARM:Get2DDistance(self.RearmingPlaceCoord) -- Route ARTY group to rearming place. if dA > self.RearmingDistance then - self:Move(self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2), self.RearmingArtyOnRoad) + self:Move(self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2), self.Speed, self.RearmingArtyOnRoad) end -- Route Rearming group to rearming place. @@ -1167,14 +1232,18 @@ function ARTY:onafterRearm(Controllable, From, Event, To) elseif self.RearmingPlaceCoord then -- CASE 3: ARTY drives to rearming place. + + -- Send message. + local text=string.format("%s, moving to rearming place.", Controllable:GetName()) + self:T(ARTY.id..text) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) -- Distance. local dA=coordARTY:Get2DDistance(self.RearmingPlaceCoord) -- Route ARTY group to rearming place. if dA > self.RearmingDistance then - --self:_Move(self.Controllable, self.RearmingPlaceCoord, self.Speed, true) - self:Move(self:_VicinityCoord(self.RearmingPlaceCoord), false) + self:Move(self:_VicinityCoord(self.RearmingPlaceCoord), self.Speed, self.RearmingArtyOnRoad) end end @@ -1200,7 +1269,7 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) -- Route ARTY group back to where it came from (if distance is > 100 m). local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) if d1 > self.RearmingDistance then - self:Move(self.InitialCoord, false) + self:Move(self.InitialCoord, self.Speed, self.RearmingArtyOnRoad) end -- Route unit back to where it came from (if distance is > 100 m). @@ -1266,7 +1335,7 @@ function ARTY:onbeforeMove(Controllable, From, Event, To, ToCoord, OnRoad) self:_EventFromTo("onbeforeMove", Event, From, To) -- Check if group can actually move... - if self.Speed==0 then + if self.SpeedMax==0 then return false end @@ -1285,16 +1354,20 @@ end -- @param #string Event Event. -- @param #string To To state. -- @param Wrapper.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. +-- @param #number Speed Speed in km/h at which the grou p should move. -- @param #boolean OnRoad If true group should move on road mainly. -function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, OnRoad) +function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, Speed, OnRoad) self:_EventFromTo("onafterMove", Event, From, To) -- Set alarm state to green and ROE to weapon hold. self.Controllable:OptionAlarmStateGreen() self.Controllable:OptionROEHoldFire() + + -- Take care of max speed. + local _Speed=math.min(Speed, self.SpeedMax) -- Route group to coodinate. - self:_Move(self.Controllable, ToCoord, self.Speed, OnRoad) + self:_Move(self.Controllable, ToCoord, _Speed, OnRoad) end @@ -1325,7 +1398,7 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param #table target Array holding the target info. +-- @param #table target Array holding the target parameters. -- @return #boolean If true, proceed to onafterOpenfire. function ARTY:onafterNewTarget(Controllable, From, Event, To, target) self:_EventFromTo("onafterNewTarget", Event, From, To) @@ -1336,6 +1409,24 @@ function ARTY:onafterNewTarget(Controllable, From, Event, To, target) self:T(ARTY.id..text) end +--- After "NewMove" event. +-- @param #ARTY self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #table move Array holding the move parameters. +-- @return #boolean If true, proceed to onafterOpenfire. +function ARTY:onafterNewMove(Controllable, From, Event, To, move) + self:_EventFromTo("onafterNewTarget", Event, From, To) + + -- Debug message. + local text=string.format("Adding new move %s.", move.name) + MESSAGE:New(text, 30):ToAllIf(self.Debug) + self:T(ARTY.id..text) +end + + --- After "Dead" event, when a unit has died. When all units of a group are dead trigger "Stop" event. -- @param #ARTY self -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. @@ -1724,12 +1815,13 @@ function ARTY:_GetTargetByName(name) end ---- Get the weapon type name, which should be used to attack the target. +--- Check if a name is unique. If not, a new unique name is created by adding a running index #01, #02, ... -- @param #ARTY self --- @param #string name Desired target name. +-- @param #table givennames Table with entries of already given names. Must contain a .name item. +-- @param #string name Desired name. -- @return #string Unique name, which is not already given for another target. -function ARTY:_CheckTargetName(name) - self:F2(name) +function ARTY:_CheckName(givennames, name) + self:F2({givennames=givennames, name=name}) local newname=name local counter=1 @@ -1739,12 +1831,12 @@ function ARTY:_CheckTargetName(name) local unique=true -- Loop over all targets already defined. - for _,_target in pairs(self.targets) do + for _,_target in pairs(givennames) do -- Target name. - local _targetname=_target.name + local _givenname=givennames.name - if _targetname==newname then + if _givenname==newname then -- Define new name = "name #01" newname=string.format("%s #%02d", name, counter) @@ -1968,6 +2060,9 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Set formation. local formation = "Off road" + -- Default speed is 30 km/h. + Speed=Speed or 30 + -- Current coordinates of group. local cpini=group:GetCoordinate() From 3157a63b7e817d23c684167d7a00b667985d5ffc Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 6 May 2018 20:40:14 +0200 Subject: [PATCH 084/170] ARTY v0.8.8 Added working implementation for moves. Other minor adjustments. --- .../Moose/Functional/Artillery.lua | 190 +++++++++++++++--- 1 file changed, 157 insertions(+), 33 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 36a847036..ee6ab8178 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -47,6 +47,7 @@ -- @field #table targets All targets assigned. -- @field #table moves All moves assigned. -- @field #table currentTarget Holds the current target, if there is one assigned. +-- @field #table currentMove Holds the current commanded move, if there is one assigned. -- @field #number Nammo0 Initial amount total ammunition (shells+rockets+missiles) of the whole group. -- @field #number Nshells0 Initial amount of shells of the whole group. -- @field #number Nrockets0 Initial amount of rockets of the whole group. @@ -225,11 +226,12 @@ -- -- @field #ARTY ARTY={ - ClassName = "ARTY", - Debug = true, - targets = {}, - moves = {}, - currentTarget = nil, + ClassName="ARTY", + Debug=true, + targets={}, + moves={}, + currentTarget=nil, + currentMove=nil, Nammo0=0, Nshells0=0, Nrockets0=0, @@ -276,7 +278,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.7" +ARTY.version="0.8.8" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -296,7 +298,7 @@ ARTY.version="0.8.7" -- DONE: Add pseudo user transitions. OnAfter... -- DONE: Make reaming unit a group. -- TODO: Adjust documenation again. --- TODO: Add command move to make arty group move. +-- DONE: Add command move to make arty group move. -- DONE: remove schedulers for status event. -- TODO: Improve handling of special weapons. When winchester? @@ -606,12 +608,12 @@ function ARTY:SetDebugOFF() self.Debug=false end ---- Delete target from target list. +--- Delete a target from target list. -- @param #ARTY self -- @param #string name Name of the target. function ARTY:RemoveTarget(name) self:F2(name) - local id=self:_GetTargetByName(name) + local id=self:_GetTargetIndexByName(name) if id then self:T(ARTY.id..string.format("Group %s: Removing target %s (id=%d).", self.Controllable:GetName(), name, id)) table.remove(self.targets, id) @@ -619,6 +621,19 @@ function ARTY:RemoveTarget(name) self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) end +--- Delete a move from move list. +-- @param #ARTY self +-- @param #string name Name of the target. +function ARTY:RemoveMove(name) + self:F2(name) + local id=self:_GetMoveIndexByName(name) + if id then + self:T(ARTY.id..string.format("Group %s: Removing move %s (id=%d).", self.Controllable:GetName(), name, id)) + table.remove(self.moves, id) + end + self:T(ARTY.id..string.format("Group %s: Number of moves = %d.", self.Controllable:GetName(), #self.moves)) +end + --- Delete ALL targets from current target list. -- @param #ARTY self function ARTY:RemoveAllTargets() @@ -679,7 +694,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) MESSAGE:New(text, 10):ToAllIf(self.Debug) -- Get Ammo. - self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:GetAmmo(self.Controllable, self.Debug) + self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:GetAmmo(self.Debug) local text=string.format("\n******************************************************\n") text=text..string.format("Arty group = %s\n", Controllable:GetName()) @@ -715,9 +730,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) end text=text..string.format("Moves:\n") for i=1,#self.moves do - local _move=self.moves[i] - local _clock=tostring(self:_SecondsToClock(_move.time)) - text=text..string.format("- %s: time=%s, speed=%d, onroad=%s, cancel=%s\n", _move.name, _clock, _move.speed, tostring(_move.onroad), tostring(_move.cancel)) + text=text..string.format("- %s\n", self:_MoveInfo(self.moves[i])) end text=text..string.format("******************************************************\n") text=text..string.format("Shell types:\n") @@ -748,7 +761,7 @@ end function ARTY:_StatusReport() -- Get Ammo. - local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo(self.Controllable) + local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() local Tnow=timer.getTime() local text=string.format("\n******************* STATUS ***************************\n") @@ -766,8 +779,12 @@ function ARTY:_StatusReport() end text=text..string.format("Nshots curr. Target = %d\n", self.Nshots) text=text..string.format("Targets:\n") - for _, target in pairs(self.targets) do - text=text..string.format("- %s\n", self:_TargetInfo(target)) + for i=1,#self.targets do + text=text..string.format("- %s\n", self:_TargetInfo(self.targets[i])) + end + text=text..string.format("Moves:\n") + for i=1,#self.moves do + text=text..string.format("- %s\n", self:_MoveInfo(self.moves[i])) end text=text..string.format("******************************************************") env.info(ARTY.id..text) @@ -812,7 +829,7 @@ function ARTY:_OnEventShot(EventData) MESSAGE:New(text, 5):ToAllIf(self.Debug) -- Get current ammo. - local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo(self.Controllable) + local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() if _nammo==0 then @@ -960,9 +977,18 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Get a valid normal target (one that is not timed). local _normalTarget=self:_CheckNormalTargets() + + -- Get a commaned move to another location. + local _move=self:_CheckMoves() -- Group is combat ready or firing but we have a high prio timed target. - if self:is("CombatReady") or (self:is("Firing") and _timedTarget) then + if (self:is("CombatReady") or self:is("Firing")) and _move then + + -- Command to move. + self.currentMove=_move + self:Move(_move.coord, _move.speed, _move.onroad) + + elseif self:is("CombatReady") or (self:is("Firing") and _timedTarget) then env.info(string.format("FF: Combatready or firing and high prio timed target.")) -- Engage target. @@ -1048,7 +1074,7 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) --_coord:MarkToAll("Arty Target") -- Get target array index. - local id=self:_GetTargetByName(target.name) + local id=self:_GetTargetIndexByName(target.name) -- Target is now under fire and has been engaged once more. if id then @@ -1062,9 +1088,36 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) -- Distance to target local range=Controllable:GetCoordinate():Get2DDistance(target.coord) + + -- Get ammo. + local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() + local nfire=Nammo + local _type="shots" + if self.WeaponType==ARTY.WeaponType.Auto then + nfire=Nammo + _type="shots" + elseif self.WeaponType==ARTY.WeaponType.Cannon then + nfire=Nshells + _type="shells" + elseif self.WeaponType==ARTY.WeaponType.Rockets then + nfire=Nrockets + _type="rockets" + elseif self.WeaponType==ARTY.WeaponType.UnguidedAny then + nfire=Nshells+Nrockets + _type="shells or rockets" + elseif self.WeaponType==ARTY.WeaponType.GuidedMissile then + nfire=Nmissiles + _type="missiles" + elseif self.WeaponType==ARTY.WeaponType.CruiseMissile then + nfire=Nmissiles + _type="cruise missiles" + end + + -- Adjust if less than requested ammo is left. + local _n=math.min(target.nshells, nfire) -- Send message. - local text=string.format("%s, opening fire on target %s with %s shells. Distance %.1f km.", Controllable:GetName(), target.name, target.nshells, range/1000) + local text=string.format("%s, opening fire on target %s with %d %s. Distance %.1f km.", Controllable:GetName(), target.name, _n, _type, range/1000) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) @@ -1093,7 +1146,7 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) -- Get target array index. - local id=self:_GetTargetByName(target.name) + local id=self:_GetTargetIndexByName(target.name) -- Increase engaged counter if id then @@ -1289,7 +1342,7 @@ function ARTY:_CheckRearmed() self:F2() -- Get current ammo. - local nammo,nshells,nrockets,nmissiles=self:GetAmmo(self.Controllable) + local nammo,nshells,nrockets,nmissiles=self:GetAmmo() -- Number of units still alive. local units=self.Controllable:GetUnits() @@ -1353,7 +1406,7 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param Wrapper.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. +-- @param Core.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. -- @param #number Speed Speed in km/h at which the grou p should move. -- @param #boolean OnRoad If true group should move on road mainly. function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, Speed, OnRoad) @@ -1365,6 +1418,11 @@ function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, Speed, OnRoad) -- Take care of max speed. local _Speed=math.min(Speed, self.SpeedMax) + + -- Smoke coordinate + if self.Debug then + ToCoord:SmokeRed() + end -- Route group to coodinate. self:_Move(self.Controllable, ToCoord, _Speed, OnRoad) @@ -1388,6 +1446,12 @@ function ARTY:onafterArrived(Controllable, From, Event, To) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + -- Remove executed move from queue. + if self.currentMove then + self:RemoveMove(self.currentMove.name) + self.currentMove=nil + end + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1604,6 +1668,36 @@ function ARTY:_CheckTimedTargets() return nil end +--- Check all moves and return the one which should be executed next. +-- @param #ARTY self +-- @return #table Move which is due. +function ARTY:_CheckMoves() + self:F3() + + -- Current time. + local Tnow=timer.getAbsTime() + + -- Sort Targets wrt time. + self:_SortQueueTime(self.moves) + + -- Check if we are currently firing. + local firing=false + if self.currentTarget then + firing=true + end + + for i=1,#self.moves do + local _move=self.moves[i] + + -- Check if time for move is reached. + if Tnow >= _move.time and (firing==false or _move.cancel) then + return _move + end + end + + return nil +end + --- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. -- @param #ARTY self -- @return #table Target which is due to be attacked now or nil if no target could be found. @@ -1634,15 +1728,15 @@ end --- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. -- @param #ARTY self --- @param Wrapper.Controllable#CONTROLLABLE controllable Controllable for which the ammo is counted. -- @param #boolean display Display ammo table as message to all. Default false. -- @return #number Total amount of ammo the whole group has left. -- @return #number Number of shells the group has left. -- @return #number Number of rockets the group has left. -- @return #number Number of missiles the group has left. -function ARTY:GetAmmo(controllable, display) - self:F3({controllable=controllable, display=display}) +function ARTY:GetAmmo(display) + self:F3({display=display}) + -- Default is display false. if display==nil then display=false end @@ -1654,7 +1748,7 @@ function ARTY:GetAmmo(controllable, display) local nmissiles=0 -- Get all units. - local units=controllable:GetUnits() + local units=self.Controllable:GetUnits() if units==nil then return nammo, nshells, nrockets, nmissiles end @@ -1744,10 +1838,10 @@ function ARTY:GetAmmo(controllable, display) end end + -- Debug text and send message. self:T2(ARTY.id..text) MESSAGE:New(text, 10):ToAllIf(display) - - + end end @@ -1795,11 +1889,11 @@ function ARTY:_CheckShootingStarted() end end ---- Get a target by its name. +--- Get the index of a target by its name. -- @param #ARTY self -- @param #string name Name of target. -- @return #number Arrayindex of target. -function ARTY:_GetTargetByName(name) +function ARTY:_GetTargetIndexByName(name) self:F2(name) for i=1,#self.targets do @@ -1814,6 +1908,26 @@ function ARTY:_GetTargetByName(name) return nil end +--- Get the index of a move by its name. +-- @param #ARTY self +-- @param #string name Name of move. +-- @return #number Arrayindex of move. +function ARTY:_GetMoveIndexByName(name) + self:F2(name) + + for i=1,#self.moves do + local movename=self.moves[i].name + if movename==name then + self:T2(ARTY.id..string.format("Found move with name %s. Index = %d", name, i)) + return i + end + end + + self:E(ARTY.id..string.format("ERROR: Move with name %s could not be found!", name)) + return nil +end + + --- Check if a name is unique. If not, a new unique name is created by adding a running index #01, #02, ... -- @param #ARTY self @@ -1959,17 +2073,27 @@ function ARTY:_split(str, sep) return result end ---- Returns the target info as formatted string. +--- Returns the target parameters as formatted string. -- @param #ARTY self -- @return #string name, prio, radius, nshells, engaged, maxengage, time, weapontype function ARTY:_TargetInfo(target) local clock=tostring(self:_SecondsToClock(target.time)) local weapon=self:_WeaponTypeName(target.weapontype) local _underfire=tostring(target.underfire) - return string.format("%s, prio=%d, radius=%d, nshells=%d, engaged=%d/%d, weapontype=%s, time=%s, underfire=%s", + return string.format("%s: prio=%d, radius=%d, nshells=%d, engaged=%d/%d, weapontype=%s, time=%s, underfire=%s", target.name, target.prio, target.radius, target.nshells, target.engaged, target.maxengage, weapon, clock,_underfire) end +--- Returns a formatted string with information about all move parameters. +-- @param #ARTY self +-- @param #table move Move table item. +-- @return #string Info string. +function ARTY:_MoveInfo(move) + self:F3(move) + local _clock=self:_SecondsToClock(move.time) + return string.format("%s: time=%s, speed=%d, onroad=%s, cancel=%s", move.name, _clock, move.speed, tostring(move.onroad), tostring(move.cancel)) +end + --- Convert time in seconds to hours, minutes and seconds. -- @param #ARTY self -- @param #number seconds Time in seconds. From 6554fa55d16dfc85352b4bf1f39f90d26346aab4 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 7 May 2018 00:20:19 +0200 Subject: [PATCH 085/170] ARTY v0.8.8 Minor Changes. --- Moose Development/Moose/Functional/Artillery.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index ee6ab8178..227f67413 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -763,9 +763,11 @@ function ARTY:_StatusReport() -- Get Ammo. local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() local Tnow=timer.getTime() + local Clock=self:_SecondsToClock(timer.getAbsTime()) local text=string.format("\n******************* STATUS ***************************\n") text=text..string.format("ARTY group = %s\n", self.Controllable:GetName()) + text=text..string.format("Clock = %s\n", Clock) text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("Total ammo count = %d\n", Nammo) text=text..string.format("Number of shells = %d\n", Nshells) @@ -1469,7 +1471,7 @@ function ARTY:onafterNewTarget(Controllable, From, Event, To, target) -- Debug message. local text=string.format("Adding new target %s.", target.name) - MESSAGE:New(text, 30):ToAllIf(self.Debug) + --MESSAGE:New(text, 30):ToAllIf(self.Debug) self:T(ARTY.id..text) end From dd636939bb075863a978af615462013fa208819a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 7 May 2018 06:11:58 +0200 Subject: [PATCH 086/170] Documentation and performance fix. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 3 + Moose Development/Moose/Cargo/Cargo.lua | 70 ++++++------------- Moose Development/Moose/Core/Point.lua | 14 ++-- .../Moose/Wrapper/Controllable.lua | 4 +- 4 files changed, 38 insertions(+), 53 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index be3b2b77e..424f81d9c 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -19,6 +19,9 @@ -- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups. -- -- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\APC module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\APC object recognize the cargo. +-- Please consult the @{Cargo} module for more information. -- -- ## Cargo loading. -- diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 215b1cba7..8869a14cc 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -6,31 +6,11 @@ -- -- === -- --- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): --- --- * CARGO_UNIT, represented by a @{Unit} in a singleton @{Group}: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable... --- * CARGO_GROUP, represented by a @{Group}. A CARGO_GROUP is reportable... -- -- This module is still under construction, but is described above works already, and will keep working ... -- -- === -- --- # Demo Missions --- --- ### [CARGO Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CGO%20-%20Cargo) --- --- ### [CARGO Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CGO%20-%20Cargo) --- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) --- --- === --- --- # YouTube Channel --- --- ### [CARGO YouTube Channel](https://www.youtube.com/watch?v=tM00lTlkpYs&list=PL7ZUrU4zZUl2zUTuKrLW5RsO9zLMqUtbf) --- --- === --- -- ### Author: **FlightControl** -- ### Contributions: -- @@ -172,11 +152,31 @@ do -- CARGO -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - --- # (R2.1) CARGO class, extends @{Fsm#FSM_PROCESS} + --- # (R2.4) CARGO class, extends @{Fsm#FSM_PROCESS} -- -- The CARGO class defines the core functions that defines a cargo object within MOOSE. - -- A cargo is a logical object defined that is available for transport, and has a life status within a simulation. + -- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation. + -- + -- CARGO is not meant to be used directly by mission designers, but provides a base class for **concrete cargo implementation classes** to handle: + -- + -- * Cargo **group objects**, implemented by the @{Cargo.CargoGroup#CARGO_GROUP} class. + -- * Cargo **Unit objects**, implemented by the @{Cargo.CargoUnit#CARGO_UNIT} class. + -- * Cargo **Crate objects**, implemented by the @{Cargo.CargoCrate#CARGO_CRATE} class. + -- * Cargo **Sling Load objects**, implemented by the @{Cargo.CargoSlingload#CARGO_SLINGLOAD} class. -- + -- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo: + -- + -- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC#AI_CARGO_APC} class. + -- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter#AI_CARGO_HELICOPTER} class. + -- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Plane#AI_CARGO_PLANE} class. + -- * AI Ships is planned. + -- + -- The above cargo classes are also used by the TASK\_CARGO\_ classes to allow human players to transport cargo as part of a tasking: + -- + -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players. + -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players. + -- + -- -- The CARGO is a state machine: it manages the different events and states of the cargo. -- All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. -- @@ -186,32 +186,8 @@ do -- CARGO -- * @{#CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. -- * @{#CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. -- * @{#CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. - -- * @{#CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. + -- * @{#CARGO.Destroyed}( Controllable ): The cargo is dead. The cargo process will be ended. -- - -- ## CARGO States: - -- - -- * **UnLoaded**: The cargo is unloaded from a carrier. - -- * **Boarding**: The cargo is currently boarding (= running) into a carrier. - -- * **Loaded**: The cargo is loaded into a carrier. - -- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. - -- * **Dead**: The cargo is dead ... - -- * **End**: The process has come to an end. - -- - -- ## CARGO state transition methods: - -- - -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. - -- There are 2 moments when state transition methods will be called by the state machine: - -- - -- * **Leaving** the state. - -- The state transition method needs to start with the name **OnLeave + the name of the state**. - -- If the state transition method returns false, then the processing of the state transition will not be done! - -- If you want to change the behaviour of the AIControllable at this event, return false, - -- but then you'll need to specify your own logic using the AIControllable! - -- - -- * **Entering** the state. - -- The state transition method needs to start with the name **OnEnter + the name of the state**. - -- These state transition methods need to provide a return value, which is specified at the function description. - -- -- @field #CARGO CARGO = { ClassName = "CARGO", diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index c49f02994..79bacd0f6 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -942,11 +942,15 @@ do -- COORDINATE function COORDINATE:GetPathOnRoad(ToCoord) local Path={} local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z) - for i, v in ipairs(path) do - --self:E(v) - local coord=COORDINATE:NewFromVec2(v) - Path[#Path+1]=COORDINATE:NewFromVec2(v) - end + Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) + Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) + -- I've removed this stuff because it severely slows down DCS in case of paths with a lot of segments. + -- Just the beginning and the end point is sufficient. +-- for i, v in ipairs(path) do +-- self:I(v) +-- local coord=COORDINATE:NewFromVec2(v) +-- Path[#Path+1]=COORDINATE:NewFromVec2(v) +-- end return Path end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 11809e47a..9667bd6fc 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -357,7 +357,9 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) local function SetTask( Controller, DCSTask ) if self and self:IsAlive() then local Controller = self:_GetController() + self:I( "Before SetTask" ) Controller:setTask( DCSTask ) + self:I( "After SetTask" ) else BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } ) end @@ -496,7 +498,7 @@ function CONTROLLABLE:SetTaskWaypoint( Waypoint, Task ) Waypoint.task = self:TaskCombo( { Task } ) - self:T3( { Waypoint.task } ) + self:F( { Waypoint.task } ) return Waypoint.task end From 92c3b530cce1792c3e0ceadbcfda81079c2db2b2 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 7 May 2018 17:33:48 +0200 Subject: [PATCH 087/170] ARTY v0.8.9 Improved documentation. --- .../Moose/Functional/Artillery.lua | 123 ++++++++++++++++-- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 227f67413..2edf7dd89 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -7,7 +7,7 @@ -- -- ==== -- --- The ARTY class can be used to easily assign targets for artillery units. +-- The ARTY class can be used to easily assign and manage targets for artillery units. -- -- ## Features: -- @@ -16,7 +16,8 @@ -- * Engagements can be scheduled, i.e. will be executed at a certain time of the day. -- * Special weapon types can be selected for each attack, e.g. cruise missiles for Naval units. -- * Automatic rearming once the artillery is out of ammo. --- * Finite state machine implementation. User can interact when certain events occur. +-- * New targets can be added during the mission, e.g. when they are detected by recon units. +-- * Finite state machine implementation. Mission designer can interact when certain events occur. -- -- ==== -- @@ -93,15 +94,17 @@ -- -- ![Process](..\Presentations\ARTY\ARTY_Process.png) -- +-- ### Blue Branch -- After the FMS process is started the ARTY group will be in the state **CombatReady**. Once a target is assigned the **OpenFire** event will be triggered and the group starts -- firing. At this point the group in in the state **Firing**. --- -- When the defined number of shots has been fired on the current target the event **CeaseFire** is triggered. The group will stop firing and go back to the state **CombatReady**. -- If another target is defined (or multiple engagements of the same target), the cycle starts anew. -- +-- ### Violet Branch -- When the ARTY group runs out of ammunition, the event **Winchester** is triggered and the group enters the state **OutOfAmmo**. -- In this state, the group is unable to engage further targets. -- +-- ### Red Branch -- With the @{#ARTY.SetRearmingGroup}(*group*) command, a special group can be defined to rearm the ARTY group. If this unit has been assigned and the group has entered the state -- **OutOfAmmo** the event **Rearm** is triggered followed by a transition to the state **Rearming**. -- If the rearming group is less than 100 meters away from the ARTY group, the rearming process starts. If the rearming group is more than 100 meters away from the ARTY unit, the @@ -109,6 +112,16 @@ -- -- Once the rearming is complete, the **Rearmed** event is triggered and the group enters the state **CombatReady**. At this point targeted can be engaged again. -- +-- ### Green Branch +-- The ARTY group can be ordered to change its position via the @{#ARTY.AssignMoveCoord}() function as described below. When the group receives the command to move +-- the event **Move** is triggered and the state changes to **Moving**. When the unit arrives to its destination the event **Arrived** is triggered and the group +-- becomes **CombatReady** again. +-- +-- Note, that the ARTY group will not open fire while it is in state **Moving**. This property differentiates artillery from tanks. +-- +-- ### Yellow Branch +-- When a new target is assigned via the @{#ARTY.AssignTargetCoord}() function (see below), the **NewTarget** event is triggered. +-- -- ## Assigning Targets -- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultanioulsly and are put into a queue. -- Of course, targets can be added at any time during the mission. For example, once they are detected by a reconnaissance unit. @@ -135,9 +148,9 @@ -- or the same target should be attacked two or more times with different parameters a suffix "#01", "#02", "#03" is automatically appended to the specified name. -- -- ## Target Queue --- In case, multiple targets have been defined, it is important to understand how the target queue works. +-- In case multiple targets have been defined, it is important to understand how the target queue works. -- --- Here, the important parameters are the priority *prio*, the number of engagements *maxengage* and the scheduled *time* as described above. +-- Here, the essential parameters are the priority *prio*, the number of engagements *maxengage* and the scheduled *time* as described above. -- -- For example, we have assigned two targets one with *prio*=10 and the other with *prio*=50 and both targets should be engaged three times (*maxengage*=3). -- Let's first consider the case that none of the targets is scheduled to be executed at a certain time (*time*=nil). @@ -146,7 +159,7 @@ -- have been engaged equally often, the target with the higher priority is engaged again. This coninues until a target has engaged three times. -- Once the maximum number of engagements is reached, the target is deleted from the queue. -- --- In other works, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with +-- In other words, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with -- respect to their priority. -- -- ### Timed Engagements @@ -198,6 +211,43 @@ -- * @{#ARTY.WeaponType}.GuidedMissile: Any guided missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. -- * @{#ARTY.WeaponType}.CruiseMissile: Only cruise missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. -- +-- ## Assigning Moves +-- The ARTY group can be commanded to move. This is done by the @{#ARTY.AssignMoveCoord}(*coord*,*time*,*speed*,*onroad*,*cancel*,*name*) function. +-- With this multiple timed moves of the group can be scheduled easily. By default, these moves will only be executed if the group is state **CombatReady**. +-- +-- ### Parameters +-- +-- * *coord*: Coordinates where the group should move to given as @{Point#COORDINATE} object. +-- * *time*: The time when the move should be executed. This has to be given as a string in the format "hh:mm:ss" (hh=hours, mm=minutes, ss=seconds). +-- * *speed*: Speed of the group in km/h. +-- * *onroad*: If this parameter is set to true, the group uses mainly roads to get to the commanded coordinates. +-- * *cancel*: If set to true, any current engagement of targets is cancelled at the time the move should be executed. +-- * *name*: Can be used to set a user defined name of the move. By default the name is created from the LL DMS coordinates. +-- +-- ## Automatic Rearming +-- +-- If an ARTY group runs out of ammunition, it can be rearmed automatically. +-- +-- ### Rearming Group +-- The first way to activate the automatic rearming is to define a rearming group with the function @{#ARTY.SetRearmingGroup}(*group*). For the blue side, this +-- could be a M181 transport truck and for the red side an Ural-375 truck. +-- +-- Once the ARTY group is out of ammo and the **Rearm** event is triggered, the defined rearming truck will drive to the ARTY group. +-- So the rearming truck does not have to be placed nearby the artillery group. When the rearming is complete, the rearming truck will drive back to its original position. +-- +-- ### Rearming Place +-- The second alternative is to define a rearming place, e.g. a FRAP, airport or any other warehouse. This is done with the function @{#ARTY.SetRearmingPlace}(*coord*). +-- The parameter *coord* specifies the coordinate of the rearming place which should not be further away then 100 meters from the warehouse. +-- +-- When the **Rearm** event is triggered, the ARTY group will move to the rearming place. Of course, the group must be mobil. So for a mortar this rearming procedure would not work. +-- +-- After the rearming is complete, the ARTY group will move back to its original position and resume normal operations. +-- +-- ### Rearming Group **and** Rearming Place +-- If both a rearming group *and* a rearming place are specified like described above, both the ARTY group and the rearming truck will move to the rearming place and meet there. +-- +-- After the rearming is complete, both groups will move back to their original positions. +-- -- ## Fine Tuning -- -- The mission designer has a few options to tailor the ARTY object according to his needs. @@ -215,13 +265,66 @@ -- ## Examples -- -- ### Assigning Multiple Targets --- This basic example illustrates how to assign multiple targets. +-- This basic example illustrates how to assign multiple targets and defining a rearming group. +-- -- Creat a new ARTY object from a Paladin group. +-- paladin=ARTY:New(GROUP:FindByName("Blue Paladin")) +-- +-- -- Define a rearming group. This is a Transport M818 truck. +-- paladin:SetRearmingGroup(GROUP:FindByName("Blue Ammo Truck")) +-- +-- -- Set the max firing range. A Paladin unit has a range of 20 km. +-- paladin:SetMaxFiringRange(20) +-- +-- -- Low priorty (90) target, will be engage last. Target is engaged two times. At each engagement five shots are fired. +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 3"):GetCoordinate(), 90, nil, 5, 2) +-- -- Medium priorty (nil=50) target, will be engage second. Target is engaged two times. At each engagement ten shots are fired. +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), nil, nil, 10, 2) +-- -- High priorty (10) target, will be engage first. Target is engaged three times. At each engagement twenty shots are fired. +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 2"):GetCoordinate(), 10, nil, 20, 3) +-- +-- -- Start ARTY process. +-- paladin:Start() +-- **Note** +-- +-- * If a parameter should be set to its default value, it has to be set to *nil* if other non-default parameters follow. Parameters at the end can simply be skiped. +-- * In this example, the target coordinates are taken from groups placed in the mission edit using the COORDINATE:GetCoordinate() function. -- -- ### Scheduled Engagements --- This example shows how to execute an engagement at a certain time. +-- -- Mission starts at 8 o'clock. +-- -- Assign two scheduled targets. +-- +-- -- Create ARTY object from Paladin group. +-- paladin=ARTY:New(GROUP:FindByName("Blue Paladin")) +-- +-- -- Assign target coordinates. Priority=50 (medium), radius=100 m, use 5 shells per engagement, engage 1 time at two past 8 o'clock. +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 50, 100, 5, 1, "08:02:00", ARTY.WeaponType.Auto, "Target 1") +-- +-- -- Assign target coordinates. Priority=10 (high), radius=300 m, use 10 shells per engagement, engage 1 time at seven past 8 o'clock. +-- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 2"):GetCoordinate(), 10, 300, 10, 1, "08:07:00", ARTY.WeaponType.Auto, "Target 2") +-- +-- -- Start ARTY process. +-- paladin:Start() -- -- ### Specific Weapons -- This example demonstrates how to use specific weapons during an engagement. +-- -- Define the Normandy as ARTY object. +-- normandy=ARTY:New(GROUP:FindByName("Normandy")) +-- +-- -- Add target: prio=50, radius=300 m, number of missiles=20, number of engagements=1, start time=08:05 hours, only use cruise missiles for this attack. +-- normandy:AssignTargetCoord(GROUP:FindByName("Red Targets 1"), 20, 300, 50, 1, "08:01:00", ARTY.WeaponType.CruiseMissile) +-- +-- -- Add target: prio=50, radius=300 m, number of shells=100, number of engagements=1, start time=08:15 hours, only use cannons during this attack. +-- normandy:AssignTargetCoord(GROUP:FindByName("Red Targets 1"), 50, 300, 100, 1, "08:15:00", ARTY.WeaponType.Cannon) +-- +-- -- Define shells that are counted to check whether the ship is out of ammo. +-- -- Note that this is necessary because the Normandy has a lot of other shell type weapons which cannot be used to engage ground targets in an artillery style manner. +-- normandy:SetShellTypes({"MK45_127"}) +-- +-- -- Define missile types that are counted. +-- normandy:SetMissileTypes({"BGM"}) +-- +-- -- Start ARTY process. +-- normandy:Start() -- -- -- @field #ARTY @@ -278,7 +381,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.8" +ARTY.version="0.8.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -301,6 +404,8 @@ ARTY.version="0.8.8" -- DONE: Add command move to make arty group move. -- DONE: remove schedulers for status event. -- TODO: Improve handling of special weapons. When winchester? +-- TODO: Handle rearming for ships. +-- TODO: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 9429ec66cabe53f2af998eb6797a430b15cabc07 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 7 May 2018 17:44:53 +0200 Subject: [PATCH 088/170] RAT fixed typo --- Moose Development/Moose/Functional/RAT.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index c6c422798..8196a67f5 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -4265,10 +4265,10 @@ end function RAT:_CommandImmortal(group, switch) -- Command structure for setting groups to invisible. - local SetInvisible = {id = 'SetImmortal', params = {value = switch}} + local SetImmortal = {id = 'SetImmortal', params = {value = switch}} -- Execute command. - group:SetCommand(SetInvisible) + group:SetCommand(SetImmortal) end --- Adds a parking spot at an airport when it has been used by a spawned RAT aircraft to the RAT parking data base. From 95d7b8250d1a4f2c2437c9d8f3f897ba76df6cd9 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 7 May 2018 23:32:57 +0200 Subject: [PATCH 089/170] Minor Changes. --- Moose Development/Moose/Functional/Artillery.lua | 6 +++--- Moose Development/Moose/Wrapper/Group.lua | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 2edf7dd89..973b6ccbf 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -398,12 +398,12 @@ ARTY.version="0.8.9" -- DONE: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. -- DONE: Improve assigned time for engagement. Next day? -- DONE: Improve documentation. --- DONE: Add pseudo user transitions. OnAfter... +-- TODO: Add pseudo user transitions. OnAfter... -- DONE: Make reaming unit a group. --- TODO: Adjust documenation again. +-- DONE: Write documenation. -- DONE: Add command move to make arty group move. -- DONE: remove schedulers for status event. --- TODO: Improve handling of special weapons. When winchester? +-- TODO: Improve handling of special weapons. When winchester if using selected weapons? -- TODO: Handle rearming for ships. -- TODO: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index db2092e9e..c595a5dbb 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -264,7 +264,6 @@ function GROUP:Destroy( GenerateEvent ) if self:IsAir() then self:CreateEventCrash( timer.getTime(), UnitData ) else - env.info("FF create event dead") self:CreateEventDead( timer.getTime(), UnitData ) end end From 0600c962825b42733d6a0b55f08f701dc19e25a9 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 8 May 2018 06:43:15 +0200 Subject: [PATCH 090/170] Finish Cargo/AI_Cargo_APC --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 424f81d9c..69bc431ee 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -511,10 +511,12 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) for _, APCUnit in pairs( APC:GetUnits() ) do local APCUnit = APCUnit -- Wrapper.Unit#UNIT local CargoCheck = self.APC_Cargo[APCUnit] - self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) - if CargoCheck:IsUnLoaded() == false then - AllUnloaded = false - break + if CargoCheck then + self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) + if CargoCheck:IsUnLoaded() == false then + AllUnloaded = false + break + end end end From a1eb0ff4d96da15ff27f5e0a2d975b26e0f7955e Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 8 May 2018 20:26:46 +0200 Subject: [PATCH 091/170] Fixes --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 69bc431ee..f867256b9 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -523,7 +523,6 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) if AllUnloaded == true then self:Guard() self.CargoCarrier = APC - self.APC_Cargo = {} end end @@ -574,6 +573,7 @@ function AI_CARGO_APC._Deploy( APC, self ) if APC:IsAlive() then self:Unload() self.Transporting = false + self.APC_Cargo = {} end end From 191fcb25beb680abb574c622ea09481cf4388c1b Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 9 May 2018 00:11:53 +0200 Subject: [PATCH 092/170] PseudoATC v0.7.0 Pseudo ATC improvements. Minor changes in RAT and Suppression. --- .../Moose/Functional/PseudoATC.lua | 407 ++++++++++++------ Moose Development/Moose/Functional/RAT.lua | 6 +- .../Moose/Functional/Suppression.lua | 46 +- 3 files changed, 320 insertions(+), 139 deletions(-) diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index d70e9d069..10b28166e 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -7,7 +7,7 @@ -- -- The pseudo ATC enhances the standard DCS ATC functions. -- --- In particular, a menu entry "Pseudo ATC" is created in the special F10 menu. +-- In particular, a menu entry "Pseudo ATC" is created in the "F10 Other..." radiomenu. -- -- ## Features -- @@ -17,18 +17,17 @@ -- * Report absolute bearing and range to nearest airports. -- * Report current altitude AGL of own aircraft. -- * Upon request, ATC reports altitude until touchdown. --- * Pressure temperature, wind data and BR for mission waypoints. +-- * Report weather (pressure temperature, wind) and BR at players mission waypoints. -- * Works with static and dynamic weather. --- * All maps supported (Caucasus, NTTR, Normandy, and all future maps). --- * Multiplayer ready (?) (I suppose yes, but I don't have a server to test or debug. Jumping from client to client works.) +-- * Player can select the unit system (metric or imperial) in which data is reported. +-- * All maps supported (Caucasus, NTTR, Normandy, Persion Gulf and all future maps). -- --- Pressure units: hPa (european aircraft), mmHg (russian aircraft), inHg (american aircraft). --- -- ==== -- -- # Demo Missions -- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- ### [ALL Demo Missions of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master) +-- ### [ALL Demo Missions of the latest deveopment branch](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop) -- -- ==== -- @@ -40,7 +39,7 @@ -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)** -- -- ==== -- @module PseudoATC @@ -49,9 +48,10 @@ --- PSEUDOATC class -- @type PSEUDOATC -- @field #string ClassName Name of the Class. +-- @field #table player Table comprising each player info. -- @field #boolean Debug If true, print debug info to dcs.log file. --- @field #table player Table comprising the player info. -- @field #number mdur Duration in seconds how low messages to the player are displayed. +-- @field #number mrefresh Interval in seconds after which the F10 menu is refreshed. E.g. by the closest airports. -- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. -- @extends Core.Base#BASE @@ -60,19 +60,19 @@ -- -- ## Scripting: -- --- Scripting is almost trivial. Just add the following line to your script: +-- Scripting is almost trivial. Just add the following two lines to your script: -- --- PSEUDOATC:Start() +-- pseudoATC=PSEUDOATC:New() +-- pseudoATC:Start() -- -- -- @field #PSEUDOATC PSEUDOATC={ ClassName = "PSEUDOATC", - Debug=true, player={}, - maxairport=10, + Debug=false, mdur=30, - mrefresh=120, + mrefresh=60, eventsmoose=true, } @@ -92,38 +92,93 @@ PSEUDOATC.unit={ PSEUDOATC.id="PseudoATC | " --- PSEUDOATC version. --- @field #list -PSEUDOATC.version={ - version = "0.6.0", - print = true, -} +-- @field #number version +PSEUDOATC.version="0.7.0" +----------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO list +-- TODO: Add takeoff event. +-- TODO: Add user functions. + +----------------------------------------------------------------------------------------------------------------------------------------- --- PSEUDOATC contructor. Starts the PseudoATC. -- @param #PSEUDOATC self -- @return #PSEUDOATC Returns a PSEUDOATC object. -function PSEUDOATC:Start() +function PSEUDOATC:New() -- Inherit BASE. local self=BASE:Inherit(self, BASE:New()) -- #PSEUDOATC -- Debug info - self:E(PSEUDOATC.id..string.format("Creating PseudoATC object. PseudoATC version %s", PSEUDOATC.version.version)) + self:E(PSEUDOATC.id..string.format("PseudoATC version %s", PSEUDOATC.version)) + + -- Return object. + return self +end + +--- PSEUDOATC contructor. Starts the PseudoATC. +-- @param #PSEUDOATC self +-- @return #PSEUDOATC Returns a PSEUDOATC object. +function PSEUDOATC:Start() + self:F() + + -- Debug info + self:E(PSEUDOATC.id.."Starting PseudoATC") -- Handle events. if self.eventsmoose then - self:HandleEvent(EVENTS.Birth, self._OnBirth) + self:T(PSEUDOATC.id.."Events are handled by MOOSE.") + self:HandleEvent(EVENTS.Birth, self._OnBirth) + self:HandleEvent(EVENTS.Land, self._PlayerLanded) + self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff) self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft) - --self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft) - self:HandleEvent(EVENTS.Land, self._PlayerLanded) - --self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeoff) + self:HandleEvent(EVENTS.Crash, self._PlayerLeft) + self:HandleEvent(EVENTS.Ejection, self._PlayerLeft) + --self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft) else + self:T(PSEUDOATC.id.."Events are handled by DCS.") -- Events are handled directly by DCS. world.addEventHandler(self) end - -- Return object. - return self +end + +----------------------------------------------------------------------------------------------------------------------------------------- +-- User Functions + +--- Debug mode on. Send messages to everone. +-- @param #PSEUDOATC self +function PSEUDOATC:DebugOn() + self.Debug=true +end + +--- Debug mode off. This is the default setting. +-- @param #PSEUDOATC self +function PSEUDOATC:DebugOff() + self.Debug=false +end + +--- Set message duration how long messages are displayed. +-- @param #PSEUDOATC self +-- @param #number duration Time in seconds. Default is 30 sec. +function PSEUDOATC:SetMessageDuration(duration) + self.mdur=duration or 30 +end + +--- Set time interval after which the F10 radio menu is refreshed. +-- @param #PSEUDOATC self +-- @param #number interval Interval in seconds. Default is every 60 sec. +function PSEUDOATC:SetMessageDuration(interval) + self.mrefresh=interval or 60 +end + +--- Enable/disable event handling by MOOSE or DCS. +-- @param #PSEUDOATC self +-- @param #boolean switch If true, events are handled by MOOSE (default). If fase, events are handled directly by DCS. +function PSEUDOATC:SetMessageDuration(switch) + self.eventsmoose=switch end ----------------------------------------------------------------------------------------------------------------------------------------- @@ -163,20 +218,23 @@ function PSEUDOATC:onEvent(Event) end -- Event info. - if self.Debug then - env.info(PSEUDOATC.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id))) - env.info(PSEUDOATC.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName))) - env.info(PSEUDOATC.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName))) - env.info(PSEUDOATC.id..string.format("EVENT: Ini player = %s" , tostring(_playername))) - env.info(PSEUDOATC.id..string.format("EVENT: Place = %s" , tostring(EventData.PlaceName))) - env.info(PSEUDOATC.id..string.format("EVENT: SubPlace = %s" , tostring(EventData.SubPlaceName))) - end + self:T3(PSEUDOATC.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id))) + self:T3(PSEUDOATC.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName))) + self:T3(PSEUDOATC.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName))) + self:T3(PSEUDOATC.id..string.format("EVENT: Ini player = %s" , tostring(_playername))) + self:T3(PSEUDOATC.id..string.format("EVENT: Place = %s" , tostring(EventData.PlaceName))) + self:T3(PSEUDOATC.id..string.format("EVENT: SubPlace = %s" , tostring(EventData.SubPlaceName))) -- Event birth. if Event.id == world.event.S_EVENT_BIRTH and _playername then self:_OnBirth(EventData) end + -- Event takeoff. + if Event.id == world.event.S_EVENT_TAKEOFF and _playername then + self:_PlayerTakeOff(EventData) + end + -- Event land. if Event.id == world.event.S_EVENT_LAND and _playername and EventData.Place then self:_PlayerLanded(EventData) @@ -186,6 +244,26 @@ function PSEUDOATC:onEvent(Event) if Event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and _playername then self:_PlayerLeft(EventData) end + + -- Event crash ==> player left unit + if Event.id == world.event.S_EVENT_CRASH and _playername then + self:_PlayerLeft(EventData) + end + + -- Event eject ==> player left unit + if Event.id == world.event.S_EVENT_EJECTION and _playername then + self:_PlayerLeft(EventData) + end + + -- Event pilot dead ==> player left unit + if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then + self:_PlayerLeft(EventData) + end + + -- Event pilot dead ==> player left unit + if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then + self:_PlayerLeft(EventData) + end end @@ -248,6 +326,28 @@ function PSEUDOATC:_PlayerLanded(EventData) end end +--- Function called by MOOSE/DCS event handler when a player took off. +-- @param #PSEUDOATC self +-- @param Core.Event#EVENTDATA EventData +function PSEUDOATC:_PlayerTakeOff(EventData) + self:F({EventData=EventData}) + + -- Get unit, player and place. + local _unitName=EventData.IniUnitName + local _unit,_playername=self:_GetPlayerUnitAndName(_unitName) + local _base=nil + local _baseName=nil + if EventData.place then + _base=EventData.place + _baseName=EventData.place:getName() + end + + -- Call take-off function. + if _unit and _playername and _base then + self:PlayerTakeOff(_unit, _baseName) + end +end + ----------------------------------------------------------------------------------------------------------------------------------------- -- Event Functions @@ -283,15 +383,15 @@ function PSEUDOATC:PlayerEntered(unit) -- Create main F10 menu, i.e. "F10/Pseudo ATC" self.player[GID].menu_main=missionCommands.addSubMenuForGroup(GID, "Pseudo ATC") - -- Create list of nearby airports. + -- Create/update list of nearby airports. self:LocalAirports(GID) - -- Create submenu My Positon. - self:MenuAircraft(GID) - - -- Create submenu airports. + -- Create submenu of local airports. self:MenuAirports(GID) + -- Create submenu Waypoints. + self:MenuWaypoints(GID) + -- Start scheduler to refresh the F10 menues. self.player[GID].scheduler, self.player[GID].schedulerid=SCHEDULER:New(nil, self.MenuRefresh, {self, GID}, self.mrefresh, self.mrefresh) @@ -319,7 +419,7 @@ function PSEUDOATC:PlayerLanded(unit, place) MESSAGE:New(text, 30):ToAllIf(self.Debug) -- Stop altitude reporting timer if its activated. - self:AltidudeStopTimer(id) + self:AltitudeTimerStop(id) -- Welcome message. if place then @@ -329,11 +429,40 @@ function PSEUDOATC:PlayerLanded(unit, place) end +--- Function called when a player took off. +-- @param #PSEUDOATC self +-- @param Wrapper.Unit#UNIT unit Unit of player which has landed. +-- @param #string place Name of the place the player landed at. +function PSEUDOATC:PlayerTakeOff(unit, place) + self:F2({unit=unit, place=place}) + + -- Gather some information. + local group=unit:GetGroup() + local id=group:GetID() + local PlayerName=self.player[id].playername + local Callsign=self.player[id].callsign + local UnitName=self.player[id].unitname + local GroupName=self.player[id].groupname + local CallSign=self.player[id].callsign + + -- Debug message. + local text=string.format("Player %s (%s) from group %s (ID %d) took off at %s", PlayerName, UnitName, GroupName, id, place) + self:T(PSEUDOATC.id..text) + MESSAGE:New(text, 30):ToAllIf(self.Debug) + + -- Bye-Bye message. + if place then + local text=string.format("%s, %s, your are airborn. Have a save trip!", place, CallSign) + MESSAGE:New(text, self.mdur):ToGroup(group) + end + +end + --- Function called when a player leaves a unit or dies. -- @param #PSEUDOATC self -- @param Wrapper.Unit#UNIT unit Player unit which was left. function PSEUDOATC:PlayerLeft(unit) - self:F2({unit=unit}) + self:F({unit=unit}) -- Get id. local group=unit:GetGroup() @@ -348,10 +477,15 @@ function PSEUDOATC:PlayerLeft(unit) if self.player[id].schedulerid then self.player[id].scheduler:Stop(self.player[id].schedulerid) end - - -- Remove main menu. - missionCommands.removeItem(self.player[id].menu_main) + -- Stop scheduler for reporting alt if it runs. + self:AltitudeTimerStop(id) + + -- Remove main menu. + if self.player[id].menu_main then + missionCommands.removeItem(self.player[id].menu_main) + end + -- Remove player array. self.player[id]=nil end @@ -375,12 +509,13 @@ function PSEUDOATC:MenuRefresh(id) -- Create list of nearby airports. self:LocalAirports(id) - - -- Create submenu My Positon. - --self:MenuAircraft(id) - - -- Create submenu airports. + + -- Create submenu Local Airports. self:MenuAirports(id) + + -- Create submenu Waypoints etc. + self:MenuWaypoints(id) + end @@ -395,47 +530,49 @@ function PSEUDOATC:MenuClear(id) self:T(PSEUDOATC.id..text) MESSAGE:New(text,30):ToAllIf(self.Debug) - + -- Delete Airports menu. if self.player[id].menu_airports then missionCommands.removeItemForGroup(id, self.player[id].menu_airports) - --[[ - for name,item in pairs(self.player[id].menu_airports) do - - -- Debug message. - self:E(PSEUDOATC.id..string.format("Deleting menu item %s for ID %d", name, id)) - - -- Remove menu item. - missionCommands.removeItemForGroup(id, self.player[id].menu_airports[name]) - end - ]] + self.player[id].menu_airports=nil else self:T2(PSEUDOATC.id.."No airports to clear menus.") end - -- Remove - if self.player[id].menu_aircraft then - missionCommands.removeItemForGroup(id, self.player[id].menu_aircraft.main) + -- Delete waypoints menu. + if self.player[id].menu_waypoints then + missionCommands.removeItemForGroup(id, self.player[id].menu_waypoints) + self.player[id].menu_waypoints=nil end - self.player[id].menu_airports=nil - --self.player[id].menu_aircraft=nil + -- Delete report alt until touchdown menu command. + if self.player[id].menu_reportalt then + missionCommands.removeItemForGroup(id, self.player[id].menu_reportalt) + self.player[id].menu_reportalt=nil + end + + -- Delete request current alt menu command. + if self.player[id].menu_requesttalt then + missionCommands.removeItemForGroup(id, self.player[id].menu_requestalt) + self.player[id].menu_requestalt=nil + end + end ---- Create "F10/Pseudo ATC" menu items "Airport Data". +--- Create "F10/Pseudo ATC/Local Airports" menu item. -- @param #PSEUDOATC self -- @param #number id Group id of player unit for which menues are created. function PSEUDOATC:MenuAirports(id) self:F(id) -- Table for menu entries. - self.player[id].menu_airports=missionCommands.addSubMenuForGroup(id, "Airports", self.player[id].menu_main) + self.player[id].menu_airports=missionCommands.addSubMenuForGroup(id, "Local Airports", self.player[id].menu_main) local i=0 for _,airport in pairs(self.player[id].airports) do i=i+1 - if i>self.maxairport then - break -- Max X<10 airports due to 10 menu items restriction. + if i > 10 then + break -- Max 10 airports due to 10 menu items restriction. end local name=airport.name @@ -444,14 +581,9 @@ function PSEUDOATC:MenuAirports(id) --F10menu_ATC_airports[ID][name] = missionCommands.addSubMenuForGroup(ID, name, F10menu_ATC) local submenu=missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_airports) - --self.player[id].menu_airports[name]=submenu -- Create menu reporting commands missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, name) - --missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, name) - --missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, name) - --missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, name) - --missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, name) missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, name) -- Debug message. @@ -459,32 +591,28 @@ function PSEUDOATC:MenuAirports(id) end end ---- Create F10/Pseudo ATC menu item "My Plane". +--- Create F10/Pseudo ATC/Waypoints menu items and misc items. -- @param #PSEUDOATC self -- @param #number id Group id of player unit for which menues are created. -function PSEUDOATC:MenuAircraft(id) +function PSEUDOATC:MenuWaypoints(id) self:F(id) - -- Table for menu entries. - --self.player[id].menu_aircraft={} - + -- Player unit and callsign. local unit=self.player[id].unit --Wrapper.Unit#UNIT local callsign=self.player[id].callsign local name=string.format("My Aircraft (%s)", callsign) -- Debug info. - self:T(PSEUDOATC.id..string.format("Creating menu item %s for ID %d", name,id)) - - -- F10/PseudoATC/My Aircraft (callsign) - --self.player[id].menu_aircraft.main = missionCommands.addSubMenuForGroup(id, name, self.player[id].menu_main) - + self:T(PSEUDOATC.id..string.format("Creating waypoint menu for %s (ID %d).", name, id)) + if #self.player[id].waypoints>0 then - -- F10/PseudoATC/Waypoints + -- F10/PseudoATC/Waypoints self.player[id].menu_waypoints=missionCommands.addSubMenuForGroup(id, "Waypoints", self.player[id].menu_main) local j=0 for i, wp in pairs(self.player[id].waypoints) do + -- Increase counter j=j+1 @@ -501,23 +629,18 @@ function PSEUDOATC:MenuAircraft(id) -- Menu commands for each waypoint "F10/PseudoATC/My Aircraft (callsign)/Waypoints/Waypoint X/" missionCommands.addCommandForGroup(id, "Weather Report", submenu, self.ReportWeather, self, id, pos, name) - --missionCommands.addCommandForGroup(id, "Request QFE", submenu, self.ReportPressure, self, id, "QFE", pos, pname) - --missionCommands.addCommandForGroup(id, "Request QNH", submenu, self.ReportPressure, self, id, "QNH", pos, pname) - --missionCommands.addCommandForGroup(id, "Request Wind", submenu, self.ReportWind, self, id, pos, pname) - --missionCommands.addCommandForGroup(id, "Request Temperature", submenu, self.ReportTemperature, self, id, pos, pname) missionCommands.addCommandForGroup(id, "Request BR", submenu, self.ReportBR, self, id, pos, name) end end - missionCommands.addCommandForGroup(id, "Request current altitude AGL", self.player[id].menu_main, self.ReportHeight, self, id) - missionCommands.addCommandForGroup(id, "Report altitude until touchdown", self.player[id].menu_main, self.AltidudeStartTimer, self, id) - missionCommands.addCommandForGroup(id, "Quit reporting altitude", self.player[id].menu_main, self.AltidudeStopTimer, self, id) + self.player[id].menu_reportalt = missionCommands.addCommandForGroup(id, "Report alt until touchdown", self.player[id].menu_main, self.AltidudeTimerToggle, self, id) + self.player[id].menu_requestalt = missionCommands.addCommandForGroup(id, "Request altitude AGL", self.player[id].menu_main, self.ReportHeight, self, id) end ----------------------------------------------------------------------------------------------------------------------------------------- -- Reporting Functions ---- Weather Report. Report pressure QFE/QNH, temperature, wind at certain location +--- Weather Report. Report pressure QFE/QNH, temperature, wind at certain location. -- @param #PSEUDOATC self -- @param #number id Group id to which the report is delivered. -- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. @@ -533,7 +656,7 @@ function PSEUDOATC:ReportWeather(id, position, location) -- Get pressure in hPa. local Pqnh=position:GetPressure(0) -- Get pressure at sea level. local Pqfe=position:GetPressure() -- Get pressure at (land) height of position. - + -- Unit conversion. local _Pqnh=string.format("%.2f inHg", Pqnh * PSEUDOATC.unit.hPa2inHg) local _Pqfe=string.format("%.2f inHg", Pqfe * PSEUDOATC.unit.hPa2inHg) @@ -675,7 +798,7 @@ function PSEUDOATC:ReportWind(id, position, location) -- Formatted wind direction. local Ds = string.format('%03d°', Dir) - -- Settings. + -- Player settings. local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS -- Velocity in player units. @@ -732,7 +855,7 @@ end -- @param #number id Group id to the report is delivered. -- @param #number dt (Optional) Duration the message is displayed. -- @param #boolean _clear (Optional) Clear previouse messages. --- @return #number Altuitude above ground. +-- @return #number Altitude above ground. function PSEUDOATC:ReportHeight(id, dt, _clear) self:F({id=id, dt=dt}) @@ -743,43 +866,67 @@ function PSEUDOATC:ReportHeight(id, dt, _clear) -- Return height [m] above ground level. local function get_AGL(p) - local vec2={x=p.x,y=p.z} - local ground=land.getHeight(vec2) - local agl=p.y-ground + local agl=0 + if p then + local vec2={x=p.x,y=p.z} + local ground=land.getHeight(vec2) + local agl=p.y-ground + end return agl end -- Get height AGL. local unit=self.player[id].unit --Wrapper.Unit#UNIT - local position=unit:GetCoordinate() - local height=get_AGL(position) - local callsign=unit:GetCallsign() - -- Settings. - local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + if unit and unit:IsAlive() then - local Hs=string.format("%d m", height) - if settings:IsMetric() then - Hs=string.format("%d ft", height*PSEUDOATC.unit.meter2feet) + local position=unit:GetCoordinate() + local height=get_AGL(position) + local callsign=unit:GetCallsign() + + -- Settings. + local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS + + local Hs=string.format("%d m", height) + if settings:IsMetric() then + Hs=string.format("%d ft", height*PSEUDOATC.unit.meter2feet) + end + + -- Message text. + local _text=string.format("%s: Your altitude is %s AGL.", callsign, Hs) + + -- Send message to player group. + --MESSAGE:New(text, dt):ToGroup(self.player[id].group) + self:_DisplayMessageToGroup(self.player[id].unit,_text, dt,_clear) + + -- Return height + return height end - -- Message text. - local _text=string.format("%s: Your altitude is %s AGL.", callsign, Hs) - - -- Send message to player group. - --MESSAGE:New(text, dt):ToGroup(self.player[id].group) - self:_DisplayMessageToGroup(self.player[id].unit,_text, dt,_clear) - - -- Return height - return height + return 0 end ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Toggle report altitude reporting on/of. +-- @param #PSEUDOATC self. +-- @param #number id Group id of player unit. +function PSEUDOATC:AltidudeTimerToggle(id) + self:F(id) + + if self.player[id].altimerid then + -- If the timer is on, we turn it off. + self:AltitudeTimerStop(id) + else + -- If the timer is off, we turn it on. + self:AltitudeTimeStart(id) + end +end + --- Start altitude reporting scheduler. -- @param #PSEUDOATC self. -- @param #number id Group id of player unit. -function PSEUDOATC:AltidudeStartTimer(id) +function PSEUDOATC:AltitudeTimeStart(id) self:F(id) -- Debug info. @@ -787,13 +934,13 @@ function PSEUDOATC:AltidudeStartTimer(id) -- Start timer. --self.player[id].altimer=timer.scheduleFunction(self.ReportAltTouchdown, self, id, Tnow+2) - self.player[id].altimer, self.player[id].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, id, 0.1, true}, 1, 5) + self.player[id].altimer, self.player[id].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, id, 0.1, true}, 1, 3) end --- Stop/destroy DCS scheduler function for reporting altitude. -- @param #PSEUDOATC self. -- @param #number id Group id of player unit. -function PSEUDOATC:AltidudeStopTimer(id) +function PSEUDOATC:AltitudeTimerStop(id) -- Debug info. self:T(PSEUDOATC.id..string.format("Stopping altitude report timer for player ID %d.", id)) @@ -863,14 +1010,24 @@ function PSEUDOATC:_GetPlayerUnitAndName(_unitName) self:F(_unitName) if _unitName ~= nil then + + -- Get DCS unit from its name. local DCSunit=Unit.getByName(_unitName) - local playername=DCSunit:getPlayerName() + if DCSunit then - - if DCSunit and playername then + -- Get the player name to make sure a player entered. + local playername=DCSunit:getPlayerName() local unit=UNIT:Find(DCSunit) - return unit, playername - end + + -- Debug output. + self:T2({DCSunit=DCSunit, unit=unit, playername=playername}) + + if unit and playername then + -- Return MOOSE unit and player name + return unit, playername + end + + end end return nil,nil diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 8196a67f5..d5e78cdce 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -1280,7 +1280,7 @@ end --- Check if aircraft have accidentally been spawned on the runway. If so they will be removed immediatly. -- @param #RAT self --- @param #booblen switch If true, check is performed. If false, this check is omitted. +-- @param #boolean switch If true, check is performed. If false, this check is omitted. function RAT:CheckOnRunway(switch) self:F2(switch) if switch==nil then @@ -1291,7 +1291,7 @@ end --- Check if aircraft have accidentally been spawned on top of each other. If yes, they will be removed immediately. -- @param #RAT self --- @param #booblen switch If true, check is performed. If false, this check is omitted. +-- @param #boolean switch If true, check is performed. If false, this check is omitted. function RAT:CheckOnTop(switch) self:F2(switch) if switch==nil then @@ -1302,7 +1302,7 @@ end --- Put parking spot coordinates in a data base for future use of aircraft. -- @param #RAT self --- @param #booblen switch If true, parking spots are memorized. This is also the default setting. +-- @param #boolean switch If true, parking spots are memorized. This is also the default setting. function RAT:ParkingSpotDB(switch) self:F2(switch) if switch==nil then diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index f3a4c4954..e9f42c626 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -28,7 +28,7 @@ -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- ### Contributions: **[FlightControl](https://forums.eagle.ru/member.php?u=89536)** -- -- ==== -- @module Suppression @@ -45,7 +45,7 @@ -- @field #string Type Type of the group. -- @field #number SpeedMax Maximum speed of group in km/h. -- @field #boolean IsInfantry True if group has attribute Infantry. --- @field Core.Controllable#CONTROLLABLE Controllable Controllable of the FSM. Must be a ground group. +-- @field Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the FSM. Must be a ground group. -- @field #number Tsuppress_ave Average time in seconds a group gets suppressed. Actual value is sampled randomly from a Gaussian distribution. -- @field #number Tsuppress_min Minimum time in seconds the group gets suppressed. -- @field #number Tsuppress_max Maximum time in seconds the group gets suppressed. @@ -283,11 +283,16 @@ SUPPRESSION.MenuF10=nil -- @field #string id SUPPRESSION.id="SFX | " +--- PSEUDOATC version. +-- @field #number version +SUPPRESSION.version="0.7.0" + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---TODO: Figure out who was shooting and move away from him. ---TODO: Move behind a scenery building if there is one nearby. ---TODO: Retreat to a given zone or point. +--TODO list +--DONE: Figure out who was shooting and move away from him. +--DONE: Move behind a scenery building if there is one nearby. +--DONE: Retreat to a given zone or point. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -304,7 +309,7 @@ function SUPPRESSION:New(group) -- Check that group is present. if group then - self:T(SUPPRESSION.id.."Suppressive fire for group "..group:GetName()) + self:T(SUPPRESSION.id..string.format("SUPPRESSION version %s. Activating suppressive fire for group %s", SUPPRESSION.version, group:GetName())) else self:E(SUPPRESSION.id.."Suppressive fire: Requested group does not exist! (Has to be a MOOSE group.)") return nil @@ -312,7 +317,7 @@ function SUPPRESSION:New(group) -- Check that we actually have a GROUND group. if group:IsGround()==false then - self:E(SUPPRESSION.id.."SUPPRESSION fire group "..group:GetName().." has to be a GROUND group!") + self:E(SUPPRESSION.id..string.format("SUPPRESSION fire group %s has to be a GROUND group!", group:GetName())) return nil end @@ -326,7 +331,6 @@ function SUPPRESSION:New(group) -- Get max speed the group can do and convert to km/h. self.SpeedMax=self.DCSdesc.speedMaxOffRoad*3.6 - --self.SpeedMaxOffRoad=DCSdesc.speedMaxOffRoad -- Set speed to maximum. self.Speed=self.SpeedMax @@ -503,6 +507,7 @@ end -- @param #number Tmin (Optional) Minimum time [seconds] a group will be suppressed. Default is 5 seconds. -- @param #number Tmax (Optional) Maximum time a group will be suppressed. Default is 25 seconds. function SUPPRESSION:SetSuppressionTime(Tave, Tmin, Tmax) + self:F({Tave=Tave, Tmin=Tmin, Tmax=Tmax}) -- Minimum suppression time is input or default but at least 1 second. self.Tsuppress_min=Tmin or self.Tsuppress_min @@ -526,24 +531,28 @@ end -- @param #SUPPRESSION self -- @param Core.Zone#ZONE zone MOOSE zone object. function SUPPRESSION:SetRetreatZone(zone) + self:F({zone=zone}) self.RetreatZone=zone end --- Turn Debug mode on. Enables messages and more output to DCS log file. -- @param #SUPPRESSION self function SUPPRESSION:DebugOn() + self:F() self.Debug=true end --- Flare units when they are hit, die or recover from suppression. -- @param #SUPPRESSION self function SUPPRESSION:FlareOn() + self:F() self.flare=true end --- Smoke positions where units fall back to, hide or retreat. -- @param #SUPPRESSION self function SUPPRESSION:SmokeOn() + self:F() self.smoke=true end @@ -551,6 +560,7 @@ end -- @param #SUPPRESSION self -- @param #string formation Formation of the group. Default "Vee". function SUPPRESSION:SetFormation(formation) + self:F(formation) self.Formation=formation or "Vee" end @@ -558,6 +568,7 @@ end -- @param #SUPPRESSION self -- @param #number speed Speed in km/h of group. Default max speed the group can do. function SUPPRESSION:SetSpeed(speed) + self:F(speed) self.Speed=speed or self.SpeedMax self.Speed=math.min(self.Speed, self.SpeedMax) end @@ -566,6 +577,7 @@ end -- @param #SUPPRESSION self -- @param #boolean switch Enable=true or disable=false fall back of group. function SUPPRESSION:Fallback(switch) + self:F(switch) if switch==nil then switch=true end @@ -576,6 +588,7 @@ end -- @param #SUPPRESSION self -- @param #number distance Distance in meters. function SUPPRESSION:SetFallbackDistance(distance) + self:F(distance) self.FallbackDist=distance end @@ -583,6 +596,7 @@ end -- @param #SUPPRESSION self -- @param #number time Time in seconds. function SUPPRESSION:SetFallbackWait(time) + self:F(time) self.FallbackWait=time end @@ -590,6 +604,7 @@ end -- @param #SUPPRESSION self -- @param #boolean switch Enable=true or disable=false fall back of group. function SUPPRESSION:Takecover(switch) + self:F(switch) if switch==nil then switch=true end @@ -600,6 +615,7 @@ end -- @param #SUPPRESSION self -- @param #number time Time in seconds. function SUPPRESSION:SetTakecoverWait(time) + self:F(time) self.TakecoverWait=time end @@ -607,6 +623,7 @@ end -- @param #SUPPRESSION self -- @param #number range Search range in meters. function SUPPRESSION:SetTakecoverRange(range) + self:F(range) self.TakecoverRange=range end @@ -621,6 +638,7 @@ end -- @param #SUPPRESSION self -- @param #number probability Probability in percent. function SUPPRESSION:SetMinimumFleeProbability(probability) + self:F(probability) self.PminFlee=probability or 10 end @@ -628,6 +646,7 @@ end -- @param #SUPPRESSION self -- @param #number probability Probability in percent. function SUPPRESSION:SetMaximumFleeProbability(probability) + self:F(probability) self.PmaxFlee=probability or 90 end @@ -637,6 +656,7 @@ end -- @param #SUPPRESSION self -- @param #number damage Damage in percent. If group gets damaged above this value, the group will retreat. Default 50 %. function SUPPRESSION:SetRetreatDamage(damage) + self:F(damage) self.RetreatDamage=damage or 50 end @@ -644,6 +664,7 @@ end -- @param #SUPPRESSION self -- @param #number time Time in seconds. Default 7200 seconds = 2 hours. function SUPPRESSION:SetRetreatWait(time) + self:F(time) self.RetreatWait=time or 7200 end @@ -651,6 +672,7 @@ end -- @param #SUPPRESSION self -- @param #string alarmstate Alarm state. Possible "Auto", "Green", "Red". Default is "Auto". function SUPPRESSION:SetDefaultAlarmState(alarmstate) + self:F(alarmstate) if alarmstate:lower()=="auto" then self.DefaultAlarmState=SUPPRESSION.AlarmState.Auto elseif alarmstate:lower()=="green" then @@ -666,6 +688,7 @@ end -- @param #SUPPRESSION self -- @param #string roe ROE after suppression. Possible "Free", "Hold" or "Return". Default "Free". function SUPPRESSION:SetDefaultROE(roe) + self:F(roe) if roe:lower()=="free" then self.DefaultROE=SUPPRESSION.ROE.Free elseif roe:lower()=="hold" then @@ -681,6 +704,7 @@ end -- @param #SUPPRESSION self -- @param #boolean switch Enable=true or disable=false menu group. Default is true. function SUPPRESSION:MenuOn(switch) + self:F(switch) if switch==nil then switch=true end @@ -1298,7 +1322,7 @@ function SUPPRESSION:onEvent(Event) self:_OnEventHit(EventData) end - -- Event HIT + -- Event DEAD if Event.id == world.event.S_EVENT_DEAD then self:_OnEventDead(EventData) end @@ -1441,12 +1465,12 @@ end --- Make group run/drive to a certain point. We put in several intermediate waypoints because sometimes the group stops before it arrived at the desired point. --@param #SUPPRESSION self --@param Core.Point#COORDINATE fin Coordinate where we want to go. ---@param #number speed Speed of group. Default is 999. +--@param #number speed Speed of group. Default is 20. --@param #string formation Formation of group. Default is "Vee". --@param #number wait Time the group will wait/hold at final waypoint. Default is 30 seconds. function SUPPRESSION:_Run(fin, speed, formation, wait) - speed=speed or 999 + speed=speed or 20 formation=formation or "Vee" wait=wait or 30 From f9d7eea72115cf27cfa82109a9d1ce3e4105206e Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 9 May 2018 23:56:55 +0200 Subject: [PATCH 093/170] ARTY, PseudoATC, RANGE, RAT, SUPPRESSION ARTY v0.9.0: Added anti-ship missiles. Various fixes. PSEUDOATC v0.9.0: Added docu. Cleaned up code. Bug fixes. RANGE v1.1.1: Changed menu. RAT v2.2.2: Changed default setting to menu = off. Added user function to enable/disable menus. SUPPRESSION v0.9.0: Improvements. --- .../Moose/Functional/Artillery.lua | 98 +++-- .../Moose/Functional/PseudoATC.lua | 355 ++++++++---------- Moose Development/Moose/Functional/RAT.lua | 30 +- Moose Development/Moose/Functional/Range.lua | 5 +- .../Moose/Functional/Suppression.lua | 19 +- 5 files changed, 250 insertions(+), 257 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 973b6ccbf..418bb359a 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -23,19 +23,19 @@ -- -- # Demo Missions -- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- ### [MOOSE - ALL Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS) -- -- ==== -- -- # YouTube Channel -- --- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) +-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) -- -- === -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: **[FlightControl](https://forums.eagle.ru/member.php?u=89536)** +-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- ==== -- @module Arty @@ -311,10 +311,10 @@ -- normandy=ARTY:New(GROUP:FindByName("Normandy")) -- -- -- Add target: prio=50, radius=300 m, number of missiles=20, number of engagements=1, start time=08:05 hours, only use cruise missiles for this attack. --- normandy:AssignTargetCoord(GROUP:FindByName("Red Targets 1"), 20, 300, 50, 1, "08:01:00", ARTY.WeaponType.CruiseMissile) +-- normandy:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 20, 300, 50, 1, "08:01:00", ARTY.WeaponType.CruiseMissile) -- -- -- Add target: prio=50, radius=300 m, number of shells=100, number of engagements=1, start time=08:15 hours, only use cannons during this attack. --- normandy:AssignTargetCoord(GROUP:FindByName("Red Targets 1"), 50, 300, 100, 1, "08:15:00", ARTY.WeaponType.Cannon) +-- normandy:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 50, 300, 100, 1, "08:15:00", ARTY.WeaponType.Cannon) -- -- -- Define shells that are counted to check whether the ship is out of ammo. -- -- Note that this is necessary because the Normandy has a lot of other shell type weapons which cannot be used to engage ground targets in an artillery style manner. @@ -356,9 +356,12 @@ ARTY={ RearmingArtyOnRoad=false, InitialCoord=nil, report=true, - ammoshells={"weapons.shells"}, - ammorockets={"weapons.nurs"}, - ammomissiles={"weapons.missiles"}, + --ammoshells={"weapons.shells"}, + ammoshells={}, + --ammorockets={"weapons.nurs"}, + ammorockets={}, + --ammomissiles={"weapons.missiles"}, + ammomissiles={}, Nshots=0, minrange=500, maxrange=1000000, @@ -373,6 +376,7 @@ ARTY.WeaponType={ UnguidedAny=805339120, GuidedMissile=268402688, CruiseMissile=2097152, + AntiShipMissile=65536, } --- Some ID to identify who we are in output of the DCS.log file. @@ -381,7 +385,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #number version -ARTY.version="0.8.9" +ARTY.version="0.9.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -485,7 +489,6 @@ function ARTY:New(group) -- Red branch. self:AddTransition({"CombatReady", "OutOfAmmo"}, "Rearm", "Rearming") - self:AddTransition("Rearming", "Move", "Rearming") self:AddTransition("Rearming", "Rearmed", "Rearmed") -- Green branch. @@ -503,7 +506,8 @@ function ARTY:New(group) -- Unknown transitons. To be checked if adding these causes problems. self:AddTransition("Rearming", "Arrived", "Rearming") - + self:AddTransition("Rearming", "Move", "Rearming") + return self end @@ -968,15 +972,16 @@ function ARTY:_OnEventShot(EventData) elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - self:T(ARTY.id.."Unguided weapon requested but shells and rockets empty.") + self:T(ARTY.id.."Unguided weapon requested but shells AND rockets empty.") self:CeaseFire(self.currentTarget) return - elseif (self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile) and _nmissiles==0 then + elseif (self.currentTarget.weapontype==ARTY.WeaponType.GuidedMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then - self:T(ARTY.id.."Guided or Cruise missiles requested but all missiles empty.") + self:T(ARTY.id.."Guided, anti-ship or cruise missiles requested but all missiles empty.") self:CeaseFire(self.currentTarget) return + end -- Check if number of shots reached max. @@ -1214,11 +1219,14 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) _type="shells or rockets" elseif self.WeaponType==ARTY.WeaponType.GuidedMissile then nfire=Nmissiles - _type="missiles" + _type="guided missiles" elseif self.WeaponType==ARTY.WeaponType.CruiseMissile then nfire=Nmissiles _type="cruise missiles" - end + elseif self.WeaponType==ARTY.WeaponType.AntiShipMissile then + nfire=Nmissiles + _type="anti-ship missiles" + end -- Adjust if less than requested ammo is left. local _n=math.min(target.nshells, nfire) @@ -1877,6 +1885,11 @@ function ARTY:GetAmmo(display) self:T2(ARTY.id..string.format("Number of weapons %d.", weapons)) self:T2({ammotable=ammotable}) + self:T(ARTY.id.."Ammotable:") + for id,bla in pairs(ammotable) do + self:T({id=id, ammo=bla}) + end + -- Loop over all weapons. for w=1,weapons do @@ -1886,28 +1899,55 @@ function ARTY:GetAmmo(display) -- Typename of current weapon local Tammo=ammotable[w]["desc"]["typeName"] + -- Get the weapon category: shell=0, missile=1, rocket=2, bomb=3 + local Category=ammotable[w].desc.category + + local MissileCategory=nil + if Category==Weapon.Category.MISSILE then + MissileCategory=ammotable[w].desc.missileCategory + end + -- Check for correct shell type. local _gotshell=false - for _,_type in pairs(self.ammoshells) do - if string.match(Tammo, _type) then + if #self.ammoshells>0 then + -- User explicitly specified the valid type(s) of shells. + for _,_type in pairs(self.ammoshells) do + if string.match(Tammo, _type) then + _gotshell=true + end + end + else + if Category==Weapon.Category.SHELL then _gotshell=true end end -- Check for correct rocket type. local _gotrocket=false - for _,_type in pairs(self.ammorockets) do - if string.match(Tammo, _type) then - _gotrocket=true + if #self.ammorockets>0 then + for _,_type in pairs(self.ammorockets) do + if string.match(Tammo, _type) then + _gotrocket=true + end end + else + if Category==Weapon.Category.ROCKET then + _gotrocket=true + end end -- Check for correct missile type. local _gotmissile=false - for _,_type in pairs(self.ammomissiles) do - if string.match(Tammo,_type) then - _gotmissile=true + if #self.ammomissiles>0 then + for _,_type in pairs(self.ammomissiles) do + if string.match(Tammo,_type) then + _gotmissile=true + end end + else + if Category==Weapon.Category.ROCKET then + _gotmissile=true + end end -- We are specifically looking for shells or rockets here. @@ -1917,7 +1957,7 @@ function ARTY:GetAmmo(display) nshells=nshells+Nammo -- Debug info. - text=text..string.format("- %d shells of type %s\n", Nammo, Tammo) + text=text..string.format("- %d shells of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) elseif _gotrocket then @@ -1925,7 +1965,7 @@ function ARTY:GetAmmo(display) nrockets=nrockets+Nammo -- Debug info. - text=text..string.format("- %d rockets of type %s\n", Nammo, Tammo) + text=text..string.format("- %d rockets of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) elseif _gotmissile then @@ -1933,12 +1973,12 @@ function ARTY:GetAmmo(display) nmissiles=nmissiles+Nammo -- Debug info. - text=text..string.format("- %d missiles of type %s\n", name, Nammo, Tammo) + text=text..string.format("- %d missiles of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) else -- Debug info. - text=text..string.format("- %d unknown ammo of type %s\n", Nammo, Tammo) + text=text..string.format("- %d unknown ammo of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) end @@ -1946,7 +1986,7 @@ function ARTY:GetAmmo(display) end -- Debug text and send message. - self:T2(ARTY.id..text) + self:T(ARTY.id..text) MESSAGE:New(text, 10):ToAllIf(display) end diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 10b28166e..9726f1666 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- **Functional** - Pseudo ATC. +--- **Functional** - (R2.4) Rudimentary ATC. -- -- ![Banner Image](..\Presentations\PSEUDOATC\PSEUDOATC_Main.jpg) -- @@ -11,35 +11,31 @@ -- -- ## Features -- --- * Report QFE or QNH pressures at nearby airbases. --- * Report wind direction and strength at airbases. --- * Report temperature at airbases. --- * Report absolute bearing and range to nearest airports. +-- * Weather report at nearby airbases and mission waypoints. +-- * Report absolute bearing and range to nearest airports and mission waypoints. -- * Report current altitude AGL of own aircraft. -- * Upon request, ATC reports altitude until touchdown. --- * Report weather (pressure temperature, wind) and BR at players mission waypoints. -- * Works with static and dynamic weather. --- * Player can select the unit system (metric or imperial) in which data is reported. --- * All maps supported (Caucasus, NTTR, Normandy, Persion Gulf and all future maps). +-- * Player can select the unit system (metric or imperial) in which information is reported. +-- * All maps supported (Caucasus, NTTR, Normandy, Persian Gulf and all future maps). -- -- ==== -- -- # Demo Missions -- --- ### [ALL Demo Missions of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master) --- ### [ALL Demo Missions of the latest deveopment branch](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop) +-- ### [MOOSE - ALL Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS) -- -- ==== -- -- # YouTube Channel -- --- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) +-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) -- -- === -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)** +-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- ==== -- @module PseudoATC @@ -51,14 +47,37 @@ -- @field #table player Table comprising each player info. -- @field #boolean Debug If true, print debug info to dcs.log file. -- @field #number mdur Duration in seconds how low messages to the player are displayed. --- @field #number mrefresh Interval in seconds after which the F10 menu is refreshed. E.g. by the closest airports. +-- @field #number mrefresh Interval in seconds after which the F10 menu is refreshed. E.g. by the closest airports. Default is 120 sec. +-- @field #number talt Interval in seconds between reporting altitude until touchdown. Default 3 sec. +-- @field #boolean chatty Display some messages on events like take-off and touchdown. -- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. -- @extends Core.Base#BASE ---# PSEUDOATC class, extends @{Base#BASE} -- The PSEUDOATC class adds some rudimentary ATC functionality via the radio menu. -- --- ## Scripting: +-- Local weather reports can be requested for nearby airports and player's mission waypoints. +-- The weather report includes +-- +-- * QFE and QNH pressures, +-- * Temperature, +-- * Wind direction and strength. +-- +-- The list of airports is updated every 60 seconds. This interval can be adjusted by the function @{#PSEUDOATC.SetMenuRefresh}(*interval*). +-- +-- Likewise, absolute bearing and range to the close by airports and mission waypoints can be requested. +-- +-- The player can switch the unit system in which all information is displayed during the mission with the MOOSE settings radio menu. +-- The unit system can be set to either imperial or metric. Altitudes are reported in feet or meter, distances in kilometers or nautical miles, +-- temperatures in degrees Fahrenheit or Celsius and QFE/QNH pressues in inHg or mmHg. +-- Note that the pressures are also reported in hPa independent of the unit system setting. +-- +-- In bad weather conditions, the ATC can "talk you down", i.e. will continuously report your altitude on the final approach. +-- Default reporting time interval is 3 seconds. This can be adjusted via the @{#PSEUDOATC.SetReportAltInterval}(*interval*) function. +-- The reporting stops automatically when the player lands or can be stopped manually by clicking on the radio menu item again. +-- So the radio menu item acts as a toggle to switch the reporting on and off. +-- +-- ## Scripting -- -- Scripting is almost trivial. Just add the following two lines to your script: -- @@ -72,38 +91,31 @@ PSEUDOATC={ player={}, Debug=false, mdur=30, - mrefresh=60, + mrefresh=120, + talt=3, + chatty=true, eventsmoose=true, } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- PSEUDOATC unit conversions. --- @list unit -PSEUDOATC.unit={ - hPa2inHg=0.0295299830714, - hPa2mmHg=0.7500615613030, - meter2feet=3.28084, - km2nm=0.539957, -} - --- Some ID to identify who we are in output of the DCS.log file. -- @field #string id PSEUDOATC.id="PseudoATC | " --- PSEUDOATC version. -- @field #number version -PSEUDOATC.version="0.7.0" +PSEUDOATC.version="0.9.0" ----------------------------------------------------------------------------------------------------------------------------------------- -- TODO list --- TODO: Add takeoff event. --- TODO: Add user functions. +-- DONE: Add takeoff event. +-- DONE: Add user functions. ----------------------------------------------------------------------------------------------------------------------------------------- ---- PSEUDOATC contructor. Starts the PseudoATC. +--- PSEUDOATC contructor. -- @param #PSEUDOATC self -- @return #PSEUDOATC Returns a PSEUDOATC object. function PSEUDOATC:New() @@ -118,9 +130,8 @@ function PSEUDOATC:New() return self end ---- PSEUDOATC contructor. Starts the PseudoATC. +--- Starts the PseudoATC event handlers. -- @param #PSEUDOATC self --- @return #PSEUDOATC Returns a PSEUDOATC object. function PSEUDOATC:Start() self:F() @@ -160,7 +171,19 @@ function PSEUDOATC:DebugOff() self.Debug=false end ---- Set message duration how long messages are displayed. +--- Chatty mode on. Display some messages on take-off and touchdown. +-- @param #PSEUDOATC self +function PSEUDOATC:ChattyOn() + self.chatty=true +end + +--- Chatty mode off. Don't display some messages on take-off and touchdown. +-- @param #PSEUDOATC self +function PSEUDOATC:ChattyOff() + self.chatty=false +end + +--- Set duration how long messages are displayed. -- @param #PSEUDOATC self -- @param #number duration Time in seconds. Default is 30 sec. function PSEUDOATC:SetMessageDuration(duration) @@ -169,18 +192,25 @@ end --- Set time interval after which the F10 radio menu is refreshed. -- @param #PSEUDOATC self --- @param #number interval Interval in seconds. Default is every 60 sec. -function PSEUDOATC:SetMessageDuration(interval) - self.mrefresh=interval or 60 +-- @param #number interval Interval in seconds. Default is every 120 sec. +function PSEUDOATC:SetMenuRefresh(interval) + self.mrefresh=interval or 120 end --- Enable/disable event handling by MOOSE or DCS. -- @param #PSEUDOATC self --- @param #boolean switch If true, events are handled by MOOSE (default). If fase, events are handled directly by DCS. -function PSEUDOATC:SetMessageDuration(switch) +-- @param #boolean switch If true, events are handled by MOOSE (default). If false, events are handled directly by DCS. +function PSEUDOATC:SetEventsMoose(switch) self.eventsmoose=switch end +--- Set time interval for reporting altitude until touchdown. +-- @param #PSEUDOATC self +-- @param #number interval Interval in seconds. Default is every 3 sec. +function PSEUDOATC:SetReportAltInterval(interval) + self.talt=interval or 3 +end + ----------------------------------------------------------------------------------------------------------------------------------------- -- Event Handling @@ -231,7 +261,7 @@ function PSEUDOATC:onEvent(Event) end -- Event takeoff. - if Event.id == world.event.S_EVENT_TAKEOFF and _playername then + if Event.id == world.event.S_EVENT_TAKEOFF and _playername and EventData.Place then self:_PlayerTakeOff(EventData) end @@ -259,12 +289,7 @@ function PSEUDOATC:onEvent(Event) if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then self:_PlayerLeft(EventData) end - - -- Event pilot dead ==> player left unit - if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then - self:_PlayerLeft(EventData) - end - + end --- Function called my MOOSE event handler when a player enters a unit. @@ -376,7 +401,7 @@ function PSEUDOATC:PlayerEntered(unit) self.player[GID].waypoints=group:GetTaskRoute() -- Info message. - local text=string.format("Player %s entered unit %s of group %s. ID = %d", PlayerName, UnitName, GroupName, GID) + local text=string.format("Player %s entered unit %s of group %s (id=%d).", PlayerName, UnitName, GroupName, GID) self:T(PSEUDOATC.id..text) MESSAGE:New(text, 30):ToAllIf(self.Debug) @@ -414,7 +439,7 @@ function PSEUDOATC:PlayerLanded(unit, place) local CallSign=self.player[id].callsign -- Debug message. - local text=string.format("Player %s (%s) from group %s (ID %d) landed at %s", PlayerName, UnitName, GroupName, id, place) + local text=string.format("Player %s in unit %s of group %s (id=%d) landed at %s.", PlayerName, UnitName, GroupName, id, place) self:T(PSEUDOATC.id..text) MESSAGE:New(text, 30):ToAllIf(self.Debug) @@ -422,7 +447,7 @@ function PSEUDOATC:PlayerLanded(unit, place) self:AltitudeTimerStop(id) -- Welcome message. - if place then + if place and self.chatty then local text=string.format("Touchdown! Welcome to %s. Have a nice day!", place) MESSAGE:New(text, self.mdur):ToGroup(group) end @@ -446,13 +471,13 @@ function PSEUDOATC:PlayerTakeOff(unit, place) local CallSign=self.player[id].callsign -- Debug message. - local text=string.format("Player %s (%s) from group %s (ID %d) took off at %s", PlayerName, UnitName, GroupName, id, place) + local text=string.format("Player %s in unit %s of group %s (id=%d) took off at %s.", PlayerName, UnitName, GroupName, id, place) self:T(PSEUDOATC.id..text) MESSAGE:New(text, 30):ToAllIf(self.Debug) -- Bye-Bye message. - if place then - local text=string.format("%s, %s, your are airborn. Have a save trip!", place, CallSign) + if place and self.chatty then + local text=string.format("%s, %s, you are airborn. Have a save trip!", place, CallSign) MESSAGE:New(text, self.mdur):ToGroup(group) end @@ -468,26 +493,30 @@ function PSEUDOATC:PlayerLeft(unit) local group=unit:GetGroup() local id=group:GetID() - -- Debug message. - local text=string.format("Player %s (%s) callsign %s of group %s just left.", self.player[id].playername, self.player[id].unitname, self.player[id].callsign, self.player[id].groupname) - self:T(PSEUDOATC.id..text) - MESSAGE:New(text, 30):ToAllIf(self.Debug) + if self.player[id] then - -- Stop scheduler for menu updates - if self.player[id].schedulerid then - self.player[id].scheduler:Stop(self.player[id].schedulerid) + -- Debug message. + local text=string.format("Player %s (callsign %s) of group %s just left unit %s.", self.player[id].playername, self.player[id].callsign, self.player[id].groupname, self.player[id].unitname) + self:T(PSEUDOATC.id..text) + MESSAGE:New(text, 30):ToAllIf(self.Debug) + + -- Stop scheduler for menu updates + if self.player[id].schedulerid then + self.player[id].scheduler:Stop(self.player[id].schedulerid) + end + + -- Stop scheduler for reporting alt if it runs. + self:AltitudeTimerStop(id) + + -- Remove main menu. + if self.player[id].menu_main then + missionCommands.removeItem(self.player[id].menu_main) + end + + -- Remove player array. + self.player[id]=nil + end - - -- Stop scheduler for reporting alt if it runs. - self:AltitudeTimerStop(id) - - -- Remove main menu. - if self.player[id].menu_main then - missionCommands.removeItem(self.player[id].menu_main) - end - - -- Remove player array. - self.player[id]=nil end ----------------------------------------------------------------------------------------------------------------------------------------- @@ -551,14 +580,14 @@ function PSEUDOATC:MenuClear(id) end -- Delete request current alt menu command. - if self.player[id].menu_requesttalt then + if self.player[id].menu_requestalt then missionCommands.removeItemForGroup(id, self.player[id].menu_requestalt) self.player[id].menu_requestalt=nil end end ---- Create "F10/Pseudo ATC/Local Airports" menu item. +--- Create "F10/Pseudo ATC/Local Airports/Airport Name/" menu items each containing weather report and BR request. -- @param #PSEUDOATC self -- @param #number id Group id of player unit for which menues are created. function PSEUDOATC:MenuAirports(id) @@ -591,7 +620,7 @@ function PSEUDOATC:MenuAirports(id) end end ---- Create F10/Pseudo ATC/Waypoints menu items and misc items. +--- Create "F10/Pseudo ATC/Waypoints/ menu items. -- @param #PSEUDOATC self -- @param #number id Group id of player unit for which menues are created. function PSEUDOATC:MenuWaypoints(id) @@ -600,10 +629,9 @@ function PSEUDOATC:MenuWaypoints(id) -- Player unit and callsign. local unit=self.player[id].unit --Wrapper.Unit#UNIT local callsign=self.player[id].callsign - local name=string.format("My Aircraft (%s)", callsign) -- Debug info. - self:T(PSEUDOATC.id..string.format("Creating waypoint menu for %s (ID %d).", name, id)) + self:T(PSEUDOATC.id..string.format("Creating waypoint menu for %s (ID %d).", callsign, id)) if #self.player[id].waypoints>0 then @@ -633,8 +661,8 @@ function PSEUDOATC:MenuWaypoints(id) end end - self.player[id].menu_reportalt = missionCommands.addCommandForGroup(id, "Report alt until touchdown", self.player[id].menu_main, self.AltidudeTimerToggle, self, id) - self.player[id].menu_requestalt = missionCommands.addCommandForGroup(id, "Request altitude AGL", self.player[id].menu_main, self.ReportHeight, self, id) + self.player[id].menu_reportalt = missionCommands.addCommandForGroup(id, "Talk me down", self.player[id].menu_main, self.AltidudeTimerToggle, self, id) + self.player[id].menu_requestalt = missionCommands.addCommandForGroup(id, "Request altitude", self.player[id].menu_main, self.ReportHeight, self, id) end ----------------------------------------------------------------------------------------------------------------------------------------- @@ -657,28 +685,27 @@ function PSEUDOATC:ReportWeather(id, position, location) local Pqnh=position:GetPressure(0) -- Get pressure at sea level. local Pqfe=position:GetPressure() -- Get pressure at (land) height of position. + -- Pressure conversion + local hPa2inHg=0.0295299830714 + local hPa2mmHg=0.7500615613030 + -- Unit conversion. - local _Pqnh=string.format("%.2f inHg", Pqnh * PSEUDOATC.unit.hPa2inHg) - local _Pqfe=string.format("%.2f inHg", Pqfe * PSEUDOATC.unit.hPa2inHg) + local _Pqnh=string.format("%.2f inHg", Pqnh * hPa2inHg) + local _Pqfe=string.format("%.2f inHg", Pqfe * hPa2inHg) if settings:IsMetric() then - _Pqnh=string.format("%.1f mmHg", Pqnh * PSEUDOATC.unit.hPa2mmHg) - _Pqfe=string.format("%.1f mmHg", Pqfe * PSEUDOATC.unit.hPa2mmHg) + _Pqnh=string.format("%.1f mmHg", Pqnh * hPa2mmHg) + _Pqfe=string.format("%.1f mmHg", Pqfe * hPa2mmHg) end -- Message text. text=text..string.format("QFE %.1f hPa = %s.\n", Pqfe, _Pqfe) text=text..string.format("QNH %.1f hPa = %s.\n", Pqnh, _Pqnh) - --- convert celsius to fahrenheit - local function celsius2fahrenheit(degC) - return degC*1.8+32 - end - -- Get temperature at position in degrees Celsius. local T=position:GetTemperature() -- Correct unit system. - local _T=string.format('%d°F', celsius2fahrenheit(T)) + local _T=string.format('%d°F', UTILS.CelciusToFarenheit(T)) if settings:IsMetric() then _T=string.format('%d°C', T) end @@ -696,9 +723,9 @@ function PSEUDOATC:ReportWeather(id, position, location) local Ds = string.format('%03d°', Dir) -- Velocity in player units. - local Vs=string.format('%.1f m/s', Vel) - if settings:IsImperial() then - Vs=string.format("%.1f knots", Vel*1.94384) + local Vs=string.format("%.1f knots", UTILS.MpsToKnots(Vel)) + if settings:IsMetric() then + Vs=string.format('%.1f m/s', Vel) end -- Message text. @@ -709,111 +736,6 @@ function PSEUDOATC:ReportWeather(id, position, location) end ---- Report pressure. --- @param #PSEUDOATC self --- @param #number id Group id to which the report is delivered. --- @param #string Qcode Can be "QNH" for pressure at sea level or "QFE" for pressure at field elevation. Default is QFE or more precisely pressure at position. --- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. --- @param #string location Name of the location at which the pressure is measured. -function PSEUDOATC:ReportPressure(id, Qcode, position, location) - self:F({id=id, Qcode=Qcode, position=position, location=location}) - - -- Get pressure in hPa. - local P - if Qcode=="QNH" then - P=position:GetPressure(0) -- Get pressure at sea level. - else - P=position:GetPressure() -- Get pressure at (land) height of position. - end - - -- Settings. - local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS - - -- Unit conversion. - local P_inHg=P * PSEUDOATC.unit.hPa2inHg - local P_mmHg=P * PSEUDOATC.unit.hPa2mmHg - - local P_set=string.format("%.2f inHg", P_inHg) - if settings:IsMetric() then - P_set=string.format("%.1f mmHg", P_mmHg) - end - - -- Message text. - local text=string.format("%s at %s: P = %.1f hPa = %s.", Qcode, location, P, P_set) - - -- Send message. - MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) -end - ---- Report temperature. --- @param #PSEUDOATC self --- @param #number id Group id to the report is delivered. --- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. --- @param #string location Name of the location at which the pressure is measured. -function PSEUDOATC:ReportTemperature(id, position, location) - self:F({id=id, position=position, location=location}) - - --- convert celsius to fahrenheit - local function celsius2fahrenheit(degC) - return degC*1.8+32 - end - - -- Get temperature at position in degrees Celsius. - local T=position:GetTemperature() - - -- Formatted temperature in Celsius and Fahrenheit. - local Tc=string.format('%d°C', T) - local Tf=string.format('%d°F', celsius2fahrenheit(T)) - - -- Settings. - local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS - - -- Correct unit system. - local _T=string.format('%d°F', celsius2fahrenheit(T)) - if settings:IsMetric() then - _T=string.format('%d°C', T) - end - - -- Message text. - local text=string.format("Temperature at %s is %s", location, _T) - - -- Send message to player group. - MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) -end - ---- Report wind direction and strength. --- @param #PSEUDOATC self --- @param #number id Group id to the report is delivered. --- @param Core.Point#COORDINATE position Coordinates at which the pressure is measured. --- @param #string location Name of the location at which the pressure is measured. -function PSEUDOATC:ReportWind(id, position, location) - self:F({id=id, position=position, location=location}) - - -- Get wind direction and speed. - local Dir,Vel=position:GetWind() - - -- Get Beaufort wind scale. - local Bn,Bd=UTILS.BeaufortScale(Vel) - - -- Formatted wind direction. - local Ds = string.format('%03d°', Dir) - - -- Player settings. - local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS - - -- Velocity in player units. - local Vs=string.format('%.1f m/s', Vel) - if settings:IsImperial() then - Vs=string.format("%.1f knots", Vel*1.94384) - end - - -- Message text. - local text=string.format("%s: Wind from %s at %s (%s).", location, Ds, Vs, Bd) - - -- Send message to player group. - MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) -end - --- Report absolute bearing and range form player unit to airport. -- @param #PSEUDOATC self -- @param #number id Group id to the report is delivered. @@ -838,9 +760,10 @@ function PSEUDOATC:ReportBR(id, position, location) -- Settings. local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS - local Rs=string.format("%.1f km", range/1000) - if settings:IsImperial() then - Rs=string.format("%.1f NM", range/1000 * PSEUDOATC.unit.km2nm) + + local Rs=string.format("%.1f NM", UTILS.MetersToNM(range)) + if settings:IsMetric() then + Rs=string.format("%.1f km", range/1000) end -- Message text. @@ -867,11 +790,9 @@ function PSEUDOATC:ReportHeight(id, dt, _clear) -- Return height [m] above ground level. local function get_AGL(p) local agl=0 - if p then - local vec2={x=p.x,y=p.z} - local ground=land.getHeight(vec2) - local agl=p.y-ground - end + local vec2={x=p.x,y=p.z} + local ground=land.getHeight(vec2) + local agl=p.y-ground return agl end @@ -887,16 +808,23 @@ function PSEUDOATC:ReportHeight(id, dt, _clear) -- Settings. local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS - local Hs=string.format("%d m", height) + env.info("FF height = "..height) + + -- Height string. + local Hs=string.format("%d ft", UTILS.MetersToFeet(height)) if settings:IsMetric() then - Hs=string.format("%d ft", height*PSEUDOATC.unit.meter2feet) + Hs=string.format("%d m", height) end -- Message text. - local _text=string.format("%s: Your altitude is %s AGL.", callsign, Hs) + local _text=string.format("%s, your altitude is %s AGL.", callsign, Hs) + + -- Append flight level. + if _clear==false then + _text=_text..string.format(" FL%03d.", position.y/30.48) + end -- Send message to player group. - --MESSAGE:New(text, dt):ToGroup(self.player[id].group) self:_DisplayMessageToGroup(self.player[id].unit,_text, dt,_clear) -- Return height @@ -908,7 +836,7 @@ end ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Toggle report altitude reporting on/of. +--- Toggle report altitude reporting on/off. -- @param #PSEUDOATC self. -- @param #number id Group id of player unit. function PSEUDOATC:AltidudeTimerToggle(id) @@ -932,8 +860,7 @@ function PSEUDOATC:AltitudeTimeStart(id) -- Debug info. self:T(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", id)) - -- Start timer. - --self.player[id].altimer=timer.scheduleFunction(self.ReportAltTouchdown, self, id, Tnow+2) + -- Start timer. Altitude is reported every ~3 seconds. self.player[id].altimer, self.player[id].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, id, 0.1, true}, 1, 3) end @@ -946,7 +873,6 @@ function PSEUDOATC:AltitudeTimerStop(id) self:T(PSEUDOATC.id..string.format("Stopping altitude report timer for player ID %d.", id)) -- Stop timer. - --timer.removeFunction(self.player[id].alttimer) if self.player[id].altimerid then self.player[id].altimer:Stop(self.player[id].altimerid) end @@ -1061,3 +987,16 @@ function PSEUDOATC:_DisplayMessageToGroup(_unit, _text, _time, _clear) end +--- Returns a string which consits of this callsign and the player name. +-- @param #RANGE self +-- @param #string unitname Name of the player unit. +function PSEUDOATC:_myname(unitname) + self:F2(unitname) + + local unit=UNIT:FindByName(unitname) + local pname=unit:GetPlayerName() + local csign=unit:GetCallsign() + + return string.format("%s (%s)", csign, pname) +end + diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index d5e78cdce..91f42eb48 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -42,20 +42,21 @@ -- -- # Demo Missions -- --- ### [RAT Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/Release/RAT%20-%20Random%20Air%20Traffic) --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- ### [MOOSE - ALL Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS) +-- ### [MOOSE - RAT Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/RAT%20-%20Random%20Air%20Traffic) -- -- === -- -- # YouTube Channel -- --- ### [DCS WORLD - MOOSE - RAT - Random Air Traffic](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0u4Zxywtg-mx_ov4vi68CO) +-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) +-- ### [MOOSE - RAT - Random Air Traffic](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0u4Zxywtg-mx_ov4vi68CO) -- -- === -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))** +-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- === -- @module Rat @@ -116,7 +117,7 @@ -- @field #boolean continuejourney Aircraft will continue their journey, i.e. get respawned at their destination with a new random destination. -- @field #number ngroups Number of groups to be spawned in total. -- @field #number alive Number of groups which are alive. --- @field #boolean f10menu Add an F10 menu for RAT. +-- @field #boolean f10menu If true, add an F10 radiomenu for RAT. Default is false. -- @field #table Menu F10 menu items for this RAT object. -- @field #string SubMenuName Submenu name for RAT object. -- @field #boolean respawn_at_landing Respawn aircraft the moment they land rather than at engine shutdown. @@ -350,7 +351,7 @@ RAT={ continuejourney=false, -- Aircraft will continue their journey, i.e. get respawned at their destination with a new random destination. alive=0, -- Number of groups which are alive. ngroups=nil, -- Number of groups to be spawned in total. - f10menu=true, -- Add an F10 menu for RAT. + f10menu=false, -- Add an F10 menu for RAT. Menu={}, -- F10 menu items for this RAT object. SubMenuName=nil, -- Submenu name for RAT object. respawn_at_landing=false, -- Respawn aircraft the moment they land rather than at engine shutdown. @@ -506,7 +507,7 @@ RAT.id="RAT | " --- RAT version. -- @list version RAT.version={ - version = "2.2.1", + version = "2.2.2", print = true, } @@ -1363,6 +1364,21 @@ function RAT:Immortal() self.immortal=true end +--- Radio menu On. Default is off. +-- @param #RAT self +function RAT:RadioMenuON() + self:F2() + self.f10menu=true +end + +--- Radio menu Off. This is the default setting. +-- @param #RAT self +function RAT:RadioMenuOFF() + self:F2() + self.f10menu=false +end + + --- Activate uncontrolled aircraft. -- @param #RAT self -- @param #number maxactivated Maximal numnber of activated aircraft. Absolute maximum will be the number of spawned groups. Default is 1. diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index bf8cbb193..bce0b8ef1 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -32,12 +32,13 @@ -- -- # Demo Missions -- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- ### [MOOSE - ALL Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS) -- -- === -- -- # YouTube Channel --- +-- +-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) -- ### [MOOSE - On the Range - Demonstration Video](https://www.youtube.com/watch?v=kIXcxNB9_3M) -- -- === diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index e9f42c626..8eb913930 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- **Functional** - Suppress fire of ground units when they get hit. +--- **Functional** - (R2.4) Suppress fire of ground units when they get hit. -- -- ![Banner Image](..\Presentations\SUPPRESSION\Suppression_Main.png) -- @@ -16,19 +16,19 @@ -- -- # Demo Missions -- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- ### [MOOSE - ALL Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS) -- -- ==== -- -- # YouTube Channel -- --- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) +-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) -- -- === -- -- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** -- --- ### Contributions: **[FlightControl](https://forums.eagle.ru/member.php?u=89536)** +-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- ==== -- @module Suppression @@ -194,10 +194,6 @@ -- -- ![Process](..\Presentations\SUPPRESSION\Suppression_Example_01.png) -- --- ## Suppression and Rescure --- This example shows how the event **Retreat** can be captured. Here, a transport is started which picks up the wounded troups and drives them to a safe zone. --- --- ![Process](..\Presentations\SUPPRESSION\Suppression_Rescue.png) -- -- # Customization and Fine Tuning -- The following user functions can be used to change the default values @@ -281,11 +277,11 @@ SUPPRESSION.MenuF10=nil --- Some ID to identify who we are in output of the DCS.log file. -- @field #string id -SUPPRESSION.id="SFX | " +SUPPRESSION.id="SUPPRESSION | " --- PSEUDOATC version. -- @field #number version -SUPPRESSION.version="0.7.0" +SUPPRESSION.version="0.9.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1333,6 +1329,7 @@ end -- @param #SUPPRESSION self -- @param Core.Event#EVENTDATA EventData function SUPPRESSION:_OnEventHit(EventData) + self:F(EventData) local GroupNameSelf=self.Controllable:GetName() local GroupNameTgt=EventData.TgtGroupName @@ -1343,7 +1340,7 @@ function SUPPRESSION:_OnEventHit(EventData) -- Check that correct group was hit. if GroupNameTgt == GroupNameSelf then - self:T2(SUPPRESSION.id..string.format("Hit event at t = %5.1f", timer.getTime())) + self:T(SUPPRESSION.id..string.format("Hit event at t = %5.1f", timer.getTime())) -- Flare unit that was hit. if self.flare or self.Debug then From 9ee21f80ac2c5a216ff8e6e7c9026edf8e2eccac Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 10 May 2018 08:07:28 +0200 Subject: [PATCH 094/170] comments --- Moose Development/Moose/Cargo/CargoGroup.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index c4712c10e..1bdcbf263 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -31,6 +31,20 @@ do -- CARGO_GROUP -- -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator. -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. + -- + -- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo: + -- + -- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC#AI_CARGO_APC} class. + -- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter#AI_CARGO_HELICOPTER} class. + -- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Plane#AI_CARGO_PLANE} class. + -- * AI Ships is planned. + -- + -- The above cargo classes are also used by the TASK\_CARGO\_ classes to allow human players to transport cargo as part of a tasking: + -- + -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players. + -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players. + -- + -- The -- -- @field #CARGO_GROUP CARGO_GROUP -- From 1159d11a12c8cd8d02e4de0d39ef07717be43d6a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 10 May 2018 14:39:22 +0200 Subject: [PATCH 095/170] New AI_CARGO_DISPATCHER_APC --- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 158 ++++++++++ Moose Development/Moose/Core/Database.lua | 6 +- Moose Development/Moose/Core/Set.lua | 272 ++++++++++++++++++ Moose Setup/Moose.files | 1 + 4 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua new file mode 100644 index 000000000..d9c93e936 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -0,0 +1,158 @@ +--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Dispatcher + +--- @type AI_CARGO_DISPATCHER_APC +-- @extends Core.Fsm#FSM_CONTROLLABLE + + +--- # AI\_CARGO\_DISPATCHER\_APC class, extends @{Core.Base#BASE} +-- +-- === +-- +-- AI\_CARGO\_DISPATCHER\_APC brings a dynamic cargo handling capability for AI groups. +-- +-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\_DISPATCHER\_APC module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_APC object recognize the cargo. +-- Please consult the @{Cargo} module for more information. +-- +-- +-- +-- @field #AI_CARGO_DISPATCHER_APC +AI_CARGO_DISPATCHER_APC = { + ClassName = "AI_CARGO_DISPATCHER_APC", + SetAPC = nil, + SetDeployZones = nil, + AI_CARGO_APC = {} +} + +--- @type AI_CARGO_DISPATCHER_APC.AI_CARGO_APC +-- @map + +--- @field #AI_CARGO_DISPATCHER_APC.AI_CARGO_APC +AI_CARGO_DISPATCHER_APC.AICargoAPC = {} + +--- Creates a new AI_CARGO_DISPATCHER_APC object. +-- @param #AI_CARGO_DISPATCHER_APC self +-- @param Core.Set#SET_GROUP SetAPC +-- @param Core.Set#SET_CARGO SetCargo +-- @param Core.Set#SET_ZONE SetDeployZone +-- @return #AI_CARGO_DISPATCHER_APC +-- @usage +-- +-- -- Create a new cargo dispatcher +-- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() +-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() +-- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo ) +-- +function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones ) + + local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER_APC + + self.SetAPC = SetAPC -- Core.Set#SET_GROUP + self.SetCargo = SetCargo -- Core.Set#SET_CARGO + self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE + + self:SetStartState( "APC" ) + + self:AddTransition( "*", "Monitor", "*" ) + + self:AddTransition( "*", "Pickup", "*" ) + self:AddTransition( "*", "Loading", "*" ) + self:AddTransition( "*", "Loaded", "*" ) + + self:AddTransition( "*", "Deploy", "*" ) + self:AddTransition( "*", "Unloading", "*" ) + self:AddTransition( "*", "Unloaded", "*" ) + + self.PickupTimeInterval = 120 + self.DeployRadiusInner = 200 + self.DeployRadiusOuter = 500 + + return self +end + + +--- The Start trigger event, which actually takes action at the specified time interval. +-- @param #AI_CARGO_DISPATCHER_APC self +-- @param Wrapper.Group#GROUP APC +-- @return #AI_CARGO_DISPATCHER_APC +function AI_CARGO_DISPATCHER_APC:onafterMonitor() + + for APCGroupName, APC in pairs( self.SetAPC:GetSet() ) do + local APC = APC -- Wrapper.Group#GROUP + local AICargoAPC = self.AICargoAPC[APC] + if not AICargoAPC then + -- ok, so this APC does not have yet an AI_CARGO_APC object... + -- let's create one and also declare the Loaded and UnLoaded handlers. + self.AICargoAPC[APC] = AI_CARGO_APC:New( APC, self.SetCargo, self.CombatRadius ) + AICargoAPC = self.AICargoAPC[APC] + + function AICargoAPC.OnAfterPickup( AICargoAPC, APC ) + self.AICargoAPC = AICargoAPC + self:Pickup( APC ) + end + + function AICargoAPC.OnAfterLoad( AICargoAPC, APC ) + self.AICargoAPC = AICargoAPC + self:Load( APC ) + end + + function AICargoAPC.OnAfterLoaded( AICargoAPC, APC ) + self.AICargoAPC = AICargoAPC + self:Loaded( APC ) + end + + function AICargoAPC.OnAfterDeploy( AICargoAPC, APC ) + self.AICargoAPC = AICargoAPC + self:Deploy( APC ) + end + + function AICargoAPC.OnAfterUnload( AICargoAPC, APC ) + self.AICargoAPC = AICargoAPC + self:Unload( APC ) + end + + function AICargoAPC.OnAfterUnloaded( AICargoAPC, APC ) + self.AICargoAPC = AICargoAPC + self:Unloaded( APC ) + end + end + + -- The Pickup sequence ... + -- Check if this APC need to go and Pickup something... + if not AICargoAPC:IsTransporting() == true then + -- ok, so there is a free APC + -- now find the first cargo that is Unloaded + local FirstCargoUnloaded = self.SetCargo:FirstCargoUnLoaded() + if FirstCargoUnloaded then + AICargoAPC:Pickup( FirstCargoUnloaded:GetCoordinate() ) + break + end + end + end + + return self +end + + + +--- Make a APC run for a cargo deploy action after the cargo has been loaded, by default. +-- @param #AI_CARGO_DISPATCHER_APC self +-- @param Wrapper.Group#GROUP APC +-- @return #AI_CARGO_DISPATCHER_APC +function AI_CARGO_DISPATCHER_APC:OnAfterLoaded( APC ) + + self:Deploy( self.SetDeployZones:GetRandomZone():GetCoordinate():GetRandomCoordinateInRadius( self.DeployRadiusInner, self.DeployRadiusOuter ) ) + + return self +end + diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 6173a355b..501dd0e5e 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -58,6 +58,7 @@ DATABASE = { ZONENAMES = {}, HITS = {}, DESTROYS = {}, + ZONES = {}, } local _DATABASECoalition = @@ -1075,7 +1076,6 @@ function DATABASE:_RegisterTemplates() local CoalitionSide = coalition.side[string.upper(CoalitionName)] - ---------------------------------------------- -- build nav points DB self.Navpoints[CoalitionName] = {} if coa_data.nav_points then --navpoints @@ -1090,8 +1090,9 @@ function DATABASE:_RegisterTemplates() self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0 self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y end + end end - end + ------------------------------------------------- if coa_data.country then --there is a country table for cntry_id, cntry_data in pairs(coa_data.country) do @@ -1147,6 +1148,7 @@ function DATABASE:_RegisterTemplates() for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do local ZoneName = ZoneData.name self.ZONENAMES[ZoneName] = ZoneName + self.ZONES[ZoneName] = ZONE:New( ZoneName ) end return self diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index a59d82909..b8043328d 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4336,6 +4336,48 @@ function SET_CARGO:FindNearestCargoFromPointVec2( PointVec2 ) --R2.1 return NearestCargo end +function SET_CARGO:FirstCargoWithState( State ) + + local FirstCargo = nil + + for CargoName, Cargo in pairs( self.Set ) do + if Cargo:Is( State ) then + FirstCargo = Cargo + break + end + end + + return FirstCargo +end + + +--- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is UnLoaded. +-- @param #SET_CARGO self +-- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +function SET_CARGO:FirstCargoUnLoaded() + local FirstCargo = self:FirstCargoWithState( "UnLoaded" ) + return FirstCargo +end + + +--- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is Loaded. +-- @param #SET_CARGO self +-- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +function SET_CARGO:FirstCargoLoaded() + local FirstCargo = self:FirstCargoWithState( "Loaded" ) + return FirstCargo +end + + +--- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is Deployed. +-- @param #SET_CARGO self +-- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +function SET_CARGO:FirstCargoDeployed() + local FirstCargo = self:FirstCargoWithState( "Deployed" ) + return FirstCargo +end + + --- (R2.1) @@ -4431,3 +4473,233 @@ function SET_CARGO:OnEventDeleteCargo( EventData ) --R2.1 end end + + +--- @type SET_ZONE +-- @extends Core.Set#SET_BASE + +--- # SET_ZONE class, extends @{Set#SET_BASE} +-- +-- Mission designers can use the @{Set#SET_ZONE} class to build sets of zones of various types. +-- +-- ## SET_ZONE constructor +-- +-- Create a new SET_ZONE object with the @{#SET_ZONE.New} method: +-- +-- * @{#SET_ZONE.New}: Creates a new SET_ZONE object. +-- +-- ## Add or Remove ZONEs from SET_ZONE +-- +-- ZONEs can be added and removed using the @{Set#SET_ZONE.AddZonesByName} and @{Set#SET_ZONE.RemoveZonesByName} respectively. +-- These methods take a single ZONE name or an array of ZONE names to be added or removed from SET_ZONE. +-- +-- ## 5.3) SET_ZONE filter criteria +-- +-- You can set filter criteria to build the collection of zones in SET_ZONE. +-- Filter criteria are defined by: +-- +-- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern of prefix. +-- +-- Once the filter criteria have been set for the SET_ZONE, you can start filtering using: +-- +-- * @{#SET_ZONE.FilterStart}: Starts the filtering of the zones within the SET_ZONE. +-- +-- ## 5.4) SET_ZONE iterators +-- +-- Once the filters have been defined and the SET_ZONE has been built, you can iterate the SET_ZONE with the available iterator methods. +-- The iterator methods will walk the SET_ZONE set, and call for each airbase within the set a function that you provide. +-- The following iterator methods are currently available within the SET_ZONE: +-- +-- * @{#SET_ZONE.ForEachZone}: Calls a function for each zone it finds within the SET_ZONE. +-- +-- === +-- @field #SET_ZONE SET_ZONE +SET_ZONE = { + ClassName = "SET_ZONE", + Zones = {}, + Filter = { + Prefixes = nil, + }, + FilterMeta = { + }, +} + + +--- Creates a new SET_ZONE object, building a set of zones. +-- @param #SET_ZONE self +-- @return #SET_ZONE self +-- @usage +-- -- Define a new SET_ZONE Object. The DatabaseSet will contain a reference to all Zones. +-- DatabaseSet = SET_ZONE:New() +function SET_ZONE:New() + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.ZONES ) ) + + return self +end + +--- Add ZONEs to SET_ZONE. +-- @param Core.Set#SET_ZONE self +-- @param #string AddZoneNames A single name or an array of ZONE_BASE names. +-- @return self +function SET_ZONE:AddZonesByName( AddZoneNames ) + + local AddZoneNamesArray = ( type( AddZoneNames ) == "table" ) and AddZoneNames or { AddZoneNames } + + for AddAirbaseID, AddZoneName in pairs( AddZoneNamesArray ) do + self:Add( AddZoneName, ZONE:FindByName( AddZoneName ) ) + end + + return self +end + +--- Remove ZONEs from SET_ZONE. +-- @param Core.Set#SET_ZONE self +-- @param Core.Zone#ZONE_BASE RemoveZoneNames A single name or an array of ZONE_BASE names. +-- @return self +function SET_ZONE:RemoveZonesByName( RemoveZoneNames ) + + local RemoveZoneNamesArray = ( type( RemoveZoneNames ) == "table" ) and RemoveZoneNames or { RemoveZoneNames } + + for RemoveZoneID, RemoveZoneName in pairs( RemoveZoneNamesArray ) do + self:Remove( RemoveZoneName ) + end + + return self +end + + +--- Finds a Zone based on the Zone Name. +-- @param #SET_ZONE self +-- @param #string ZoneName +-- @return Core.Zone#ZONE_BASE The found Zone. +function SET_ZONE:FindZone( ZoneName ) + + local ZoneFound = self.Set[ZoneName] + return ZoneFound +end + + +--- Get a random zone from the set. +-- @param #SET_ZONE self +-- @return Core.Zone#ZONE_BASE The random Zone. +function SET_ZONE:GetRandomZone() + + local Index = self.Index + local ZoneFound = nil + + while not ZoneFound do + local ZoneRandom = math.random( 1, #Index ) + ZoneFound = self.Set[Index[ZoneRandom]] + end + + return ZoneFound +end + + + +--- Builds a set of zones of defined zone prefixes. +-- All the zones starting with the given prefixes will be included within the set. +-- @param #SET_ZONE self +-- @param #string Prefixes The prefix of which the zone name starts with. +-- @return #SET_ZONE self +function SET_ZONE:FilterPrefixes( Prefixes ) + if not self.Filter.Prefixes then + self.Filter.Prefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.Prefixes[Prefix] = Prefix + end + return self +end + + +--- Starts the filtering. +-- @param #SET_ZONE self +-- @return #SET_ZONE self +function SET_ZONE:FilterStart() + + if _DATABASE then + + -- We initialize the first set. + for ObjectName, Object in pairs( self.Database ) do + if self:IsIncludeObject( Object ) then + self:Add( ObjectName, Object ) + else + self:RemoveZonesByName( ObjectName ) + end + end + end + + return self +end + +--- Handles the Database to check on an event (birth) that the Object was added in the Database. +-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! +-- @param #SET_ZONE self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the AIRBASE +-- @return #table The AIRBASE +function SET_ZONE:AddInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Handles the Database to check on any event that Object exists in the Database. +-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! +-- @param #SET_ZONE self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the AIRBASE +-- @return #table The AIRBASE +function SET_ZONE:FindInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Iterate the SET_ZONE and call an interator function for each ZONE, providing the ZONE and optional parameters. +-- @param #SET_ZONE self +-- @param #function IteratorFunction The function that will be called when there is an alive ZONE in the SET_ZONE. The function needs to accept a AIRBASE parameter. +-- @return #SET_ZONE self +function SET_ZONE:ForEachZone( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self:GetSet() ) + + return self +end + + +--- +-- @param #SET_ZONE self +-- @param Core.Zone#ZONE_BASE MZone +-- @return #SET_ZONE self +function SET_ZONE:IsIncludeObject( MZone ) + self:F2( MZone ) + + local MZoneInclude = true + + if MZone then + local MZoneName = MZone:GetName() + + if self.Filter.Prefixes then + local MZonePrefix = false + for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do + self:T3( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } ) + if string.find( MZoneName, ZonePrefix, 1 ) then + MZonePrefix = true + end + end + self:T( { "Evaluated Prefix", MZonePrefix } ) + MZoneInclude = MZoneInclude and MZonePrefix + end + end + + self:T2( MZoneInclude ) + return MZoneInclude +end + diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index f909972b7..45a4bff5d 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -67,6 +67,7 @@ AI/AI_Cas.lua AI/AI_Bai.lua AI/AI_Formation.lua AI/AI_Cargo_APC.lua +AI/AI_Cargo_Dispatcher_APC.lua AI/AI_Cargo_Helicopter.lua AI/AI_Cargo_Airplane.lua From 6f0507ea7f11b29ae4a25b6a5364166fdc239568 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 10 May 2018 15:40:10 +0200 Subject: [PATCH 096/170] Minor fixes. Positionalble: Added isExist because of problems with getting coords from scenery objects. Suppresson: Fixes. Added new transitions. PseudoATC: Removed eject. Artillery: Optimized debug output. --- .../Moose/Functional/Artillery.lua | 82 +++++++++++-------- .../Moose/Functional/PseudoATC.lua | 9 +- .../Moose/Functional/Suppression.lua | 15 +++- .../Moose/Wrapper/Positionable.lua | 6 +- Moose Setup/Moose.files | 3 + 5 files changed, 69 insertions(+), 46 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 418bb359a..8849c68e0 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -330,7 +330,7 @@ -- @field #ARTY ARTY={ ClassName="ARTY", - Debug=true, + Debug=false, targets={}, moves={}, currentTarget=nil, @@ -384,7 +384,7 @@ ARTY.WeaponType={ ARTY.id="ARTY | " --- Arty script version. --- @field #number version +-- @field #string version ARTY.version="0.9.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -799,7 +799,8 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:_EventFromTo("onafterStart", Event, From, To) -- Debug output. - local text=string.format("Started ARTY for group %s.", Controllable:GetName()) + local text=string.format("Started ARTY version %s for group %s.", ARTY.version, Controllable:GetName()) + self:E(ARTY.id..text) MESSAGE:New(text, 10):ToAllIf(self.Debug) -- Get Ammo. @@ -954,31 +955,31 @@ function ARTY:_OnEventShot(EventData) -- Weapon type name for current target. local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) - self:T(ARTY.id..string.format("nammo=%d, nshells=%d, nrockets=%d, nmissiles=%d", _nammo, _nshells, _nrockets, _nmissiles)) - self:T(ARTY.id..string.format("Weapontype = %s", _weapontype)) + self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.Controllable:GetName(), _nammo, _nshells, _nrockets, _nmissiles)) + self:T2(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) -- Special weapon type requested ==> Check if corresponding ammo is empty. if self.currentTarget.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then - self:T(ARTY.id.."Cannons requested but shells empty.") + self:T(ARTY.id.."Group %s, cannons requested but shells empty.", self.Controllable:GetName()) self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then - self:T(ARTY.id.."Rockets requested but rockets empty.") + self:T(ARTY.id.."Group %s, rockets requested but rockets empty.", self.Controllable:GetName()) self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - self:T(ARTY.id.."Unguided weapon requested but shells AND rockets empty.") + self:T(ARTY.id.."Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName()) self:CeaseFire(self.currentTarget) return elseif (self.currentTarget.weapontype==ARTY.WeaponType.GuidedMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then - self:T(ARTY.id.."Guided, anti-ship or cruise missiles requested but all missiles empty.") + self:T(ARTY.id.."Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName()) self:CeaseFire(self.currentTarget) return @@ -995,7 +996,7 @@ function ARTY:_OnEventShot(EventData) end else - self:E(ARTY.id..string.format("ERROR: No current target?!")) + self:E(ARTY.id..string.format("ERROR: No current target for group %s?!", self.Controllable:GetName())) end end end @@ -1042,22 +1043,20 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Group is out of ammo. if self:is("OutOfAmmo") then - env.info(string.format("FF: OutOfAmmo. ==> Rearm")) + self:T2(ARTY.id..string.format("%s: OutOfAmmo. ==> Rearm", Controllable:GetName())) self:Rearm() end -- Group is out of moving. if self:is("Moving") then - --local _speed=self.Controllable:GetVelocityKMH() - --env.info(string.format("FF: Moving. Velocity = %d km/h", _speed)) - env.info(string.format("FF: Moving")) + self:T2(ARTY.id..string.format("%s: Moving", Controllable:GetName())) end -- Group is rearming. if self:is("Rearming") then local _rearmed=self:_CheckRearmed() - env.info(string.format("FF: Rearming. _rearmed = %s", tostring(_rearmed))) if _rearmed then + self:T2(ARTY.id..string.format("%s: Rearming ==> Rearmed", Controllable:GetName())) self:Rearmed() end end @@ -1065,15 +1064,16 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Group finished rearming. if self:is("Rearmed") then local distance=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) - env.info(string.format("FF: Rearmed. Distance ARTY to InitalCoord = %d", distance)) + self:T2(ARTY.id..string.format("%s: Rearmed. Distance ARTY to InitalCoord = %d m", Controllable:GetName(), distance)) if distance <= self.RearmingDistance then + self:T2(ARTY.id..string.format("%s: Rearmed ==> CombatReady", Controllable:GetName())) self:CombatReady() end end -- Group arrived at destination. if self:is("Arrived") then - env.info(string.format("FF: Arrived. ==> CombatReady")) + self:T2(ARTY.id..string.format("%s: Arrived ==> CombatReady", Controllable:GetName())) self:CombatReady() end @@ -1093,15 +1093,18 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Get a commaned move to another location. local _move=self:_CheckMoves() - -- Group is combat ready or firing but we have a high prio timed target. + if (self:is("CombatReady") or self:is("Firing")) and _move then + -- Group is combat ready or firing but we have a move. + self:T2(ARTY.id..string.format("%s: CombatReady/Firing ==> Move", Controllable:GetName())) -- Command to move. self.currentMove=_move self:Move(_move.coord, _move.speed, _move.onroad) elseif self:is("CombatReady") or (self:is("Firing") and _timedTarget) then - env.info(string.format("FF: Combatready or firing and high prio timed target.")) + -- Group is combat ready or firing but we have a high prio timed target. + self:T2(ARTY.id..string.format("%s: CombatReady or Firing+Timed Target ==> OpenFire", Controllable:GetName())) -- Engage target. if _timedTarget then @@ -1137,7 +1140,7 @@ end function ARTY:onenterCombatReady(Controllable, From, Event, To) self:_EventFromTo("onenterCombatReady", Event, From, To) -- Debug info - self:T(string.format("FF: onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) + self:T3(ARTY.id..string.format("onenterComabReady, from=%s, event=%s, to=%s", From, Event, To)) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1882,14 +1885,16 @@ function ARTY:GetAmmo(display) local weapons=#ammotable - self:T2(ARTY.id..string.format("Number of weapons %d.", weapons)) - self:T2({ammotable=ammotable}) - - self:T(ARTY.id.."Ammotable:") - for id,bla in pairs(ammotable) do - self:T({id=id, ammo=bla}) + -- Display ammo table + if display then + self:E(ARTY.id..string.format("Number of weapons %d.", weapons)) + self:E({ammotable=ammotable}) + self:E(ARTY.id.."Ammotable:") + for id,bla in pairs(ammotable) do + self:E({id=id, ammo=bla}) + end end - + -- Loop over all weapons. for w=1,weapons do @@ -1957,7 +1962,7 @@ function ARTY:GetAmmo(display) nshells=nshells+Nammo -- Debug info. - text=text..string.format("- %d shells of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d shells of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) elseif _gotrocket then @@ -1965,7 +1970,7 @@ function ARTY:GetAmmo(display) nrockets=nrockets+Nammo -- Debug info. - text=text..string.format("- %d rockets of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d rockets of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) elseif _gotmissile then @@ -1973,12 +1978,12 @@ function ARTY:GetAmmo(display) nmissiles=nmissiles+Nammo -- Debug info. - text=text..string.format("- %d missiles of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d missiles of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) else -- Debug info. - text=text..string.format("- %d unknown ammo of type %s (category=%d mc=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d unknown ammo of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) end @@ -1986,7 +1991,11 @@ function ARTY:GetAmmo(display) end -- Debug text and send message. - self:T(ARTY.id..text) + if display then + self:E(ARTY.id..text) + else + self:T3(ARTY.id..text) + end MESSAGE:New(text, 10):ToAllIf(display) end @@ -2112,7 +2121,7 @@ function ARTY:_CheckName(givennames, name) until (unique) -- Debug output and return new name. - self:T(string.format("Original name %s, new name = %s", name, newname)) + self:T2(string.format("Original name %s, new name = %s", name, newname)) return newname end @@ -2171,6 +2180,8 @@ function ARTY:_WeaponTypeName(tnumber) name="Cruise Missiles" elseif tnumber==ARTY.WeaponType.GuidedMissile then name="Guided Missiles" + elseif tnumber==ARTY.WeaponType.AntiShipMissile then + name="Anti-Ship Missiles" end return name end @@ -2398,12 +2409,15 @@ function ARTY._PassingWaypoint(group, arty, i, final) if final then text=string.format("%s, arrived at destination.", group:GetName()) end - env.info(ARTY.id..text) + arty:T(ARTY.id..text) + + --[[ if final then MESSAGE:New(text, 10):ToCoalitionIf(group:GetCoalition(), arty.Debug or arty.report) else MESSAGE:New(text, 10):ToAllIf(arty.Debug) end + ]] -- Arrived event. if final and arty.Controllable:GetName()==group:GetName() then diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 9726f1666..ce7f4e737 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -146,7 +146,7 @@ function PSEUDOATC:Start() self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff) self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft) self:HandleEvent(EVENTS.Crash, self._PlayerLeft) - self:HandleEvent(EVENTS.Ejection, self._PlayerLeft) + --self:HandleEvent(EVENTS.Ejection, self._PlayerLeft) --self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft) else self:T(PSEUDOATC.id.."Events are handled by DCS.") @@ -280,6 +280,7 @@ function PSEUDOATC:onEvent(Event) self:_PlayerLeft(EventData) end +--[[ -- Event eject ==> player left unit if Event.id == world.event.S_EVENT_EJECTION and _playername then self:_PlayerLeft(EventData) @@ -289,7 +290,7 @@ function PSEUDOATC:onEvent(Event) if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then self:_PlayerLeft(EventData) end - +]] end --- Function called my MOOSE event handler when a player enters a unit. @@ -477,7 +478,7 @@ function PSEUDOATC:PlayerTakeOff(unit, place) -- Bye-Bye message. if place and self.chatty then - local text=string.format("%s, %s, you are airborn. Have a save trip!", place, CallSign) + local text=string.format("%s, %s, you are airborne. Have a safe trip!", place, CallSign) MESSAGE:New(text, self.mdur):ToGroup(group) end @@ -808,8 +809,6 @@ function PSEUDOATC:ReportHeight(id, dt, _clear) -- Settings. local settings=_DATABASE:GetPlayerSettings(self.player[id].playername) or _SETTINGS --Core.Settings#SETTINGS - env.info("FF height = "..height) - -- Height string. local Hs=string.format("%d ft", UTILS.MetersToFeet(height)) if settings:IsMetric() then diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index 8eb913930..41fb3dc09 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -357,6 +357,8 @@ function SUPPRESSION:New(group) self:AddTransition("Retreating", "Retreated", "Retreated") self:AddTransition("*", "Dead", "*") + self:AddTransition("TakingCover", "Hit", "TakingCover") + self:AddTransition("FallingBack", "Hit", "FallingBack") --- User function for OnBefore "Hit" event. -- @function [parent=#SUPPRESSION] OnBeforeHit @@ -1078,7 +1080,9 @@ function SUPPRESSION:onafterFallBack(Controllable, From, Event, To, AttackUnit) local Coord=DCoord:Translate(self.FallbackDist, heading) -- Place marker - local MarkerID=Coord:MarkToAll("Fall back position for group "..Controllable:GetName()) + if self.Debug then + local MarkerID=Coord:MarkToAll("Fall back position for group "..Controllable:GetName()) + end -- Smoke the coordinate. if self.smoke or self.Debug then @@ -1468,7 +1472,7 @@ end function SUPPRESSION:_Run(fin, speed, formation, wait) speed=speed or 20 - formation=formation or "Vee" + formation=formation or "Off road" wait=wait or 30 local group=self.Controllable -- Wrapper.Controllable#CONTROLLABLE @@ -1506,8 +1510,11 @@ function SUPPRESSION:_Run(fin, speed, formation, wait) -- First waypoint is the current position of the group. wp[1]=ini:WaypointGround(speed, formation) - local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName())) tasks[1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, 1, false) + + if self.Debug then + local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName())) + end self:T2(SUPPRESSION.id..string.format("Number of waypoints %d", nx)) for i=1,nx-2 do @@ -1830,7 +1837,7 @@ end -- @param #string To To state. function SUPPRESSION:_EventFromTo(BA, Event, From, To) local text=string.format("\n%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) - self:T(SUPPRESSION.id..text) + self:T2(SUPPRESSION.id..text) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index d9308e8bb..1ac85b6a4 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -391,7 +391,7 @@ function POSITIONABLE:GetVelocityVec3() local DCSPositionable = self:GetDCSObject() - if DCSPositionable then + if DCSPositionable and DCSPositionable:isExist() then local PositionableVelocityVec3 = DCSPositionable:getVelocity() self:T3( PositionableVelocityVec3 ) return PositionableVelocityVec3 @@ -433,7 +433,7 @@ function POSITIONABLE:GetVelocityKMH() local DCSPositionable = self:GetDCSObject() - if DCSPositionable then + if DCSPositionable and DCSPositionable:isExist() then local VelocityVec3 = self:GetVelocityVec3() local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec local Velocity = Velocity * 3.6 -- now it is in km/h. @@ -452,7 +452,7 @@ function POSITIONABLE:GetVelocityMPS() local DCSPositionable = self:GetDCSObject() - if DCSPositionable then + if DCSPositionable and DCSPositionable:isExist() then local VelocityVec3 = self:GetVelocityVec3() local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec self:T3( Velocity ) diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index f909972b7..1974715d9 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -54,6 +54,9 @@ Functional/Range.lua Functional/ZoneGoal.lua Functional/ZoneGoalCoalition.lua Functional/ZoneCaptureCoalition.lua +Functional/Artillery.lua +Functional/Suppression.lua +Functional/PseudoATC.lua AI/AI_Balancer.lua AI/AI_A2A.lua From 6b31ad9645cab7dea4736adaced5f4dd791f9789 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 10 May 2018 20:00:50 +0200 Subject: [PATCH 097/170] Moose file changes --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 47 +++-- .../Moose/AI/AI_Cargo_Dispatcher.lua | 188 ++++++++++++++++++ .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 112 +---------- .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 54 +++++ .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 54 +++++ Moose Development/Moose/Core/Database.lua | 1 + Moose Development/Moose/Core/Set.lua | 25 ++- Moose Setup/Moose.files | 5 +- 8 files changed, 360 insertions(+), 126 deletions(-) create mode 100644 Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua create mode 100644 Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua create mode 100644 Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index f867256b9..9e4351bee 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -190,6 +190,7 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:SetCarrier( CargoCarrier ) self.Transporting = false + self.Relocating = false return self end @@ -227,7 +228,7 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier ) self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then -- There are enemies within combat range. Unload the CargoCarrier. - AICargoTroops:Unload() + AICargoTroops:Unload( false ) end end end @@ -248,6 +249,11 @@ function AI_CARGO_APC:IsTransporting() return self.Transporting == true end +function AI_CARGO_APC:IsRelocating() + + return self.Relocating == true +end + --- Find a free Carrier within a range. -- @param #AI_CARGO_APC self -- @param Core.Point#COORDINATE Coordinate @@ -337,7 +343,7 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To ) if APC and APC:IsAlive() then if self.CarrierCoordinate then - if self:IsTransporting() then + if self:IsRelocating() == true then local Coordinate = APC:GetCoordinate() self.Zone:Scan( { Object.Category.UNIT } ) if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then @@ -348,7 +354,7 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To ) else if self:Is( "Loaded" ) then -- There are enemies within combat range. Unload the CargoCarrier. - self:__Unload( 1 ) + self:__Unload( 1, false ) else if self:Is( "Unloaded" ) then self:Follow() @@ -398,8 +404,8 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) local APCUnit = APCUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( self.CargoSet:GetSet() ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { IsUnLoaded = Cargo:IsUnLoaded(), Cargo:GetName(), APC:GetName() } ) - if Cargo:IsUnLoaded() then + self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), APC:GetName() } ) + if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then self:F( { "In radius", APCUnit:GetName() } ) APC:RouteStop() @@ -467,8 +473,8 @@ end --- @param #AI_CARGO_APC self -- @param Wrapper.Group#GROUP APC -function AI_CARGO_APC:onafterUnload( APC, From, Event, To ) - self:F( { APC, From, Event, To } ) +function AI_CARGO_APC:onafterUnload( APC, From, Event, To, Deployed ) + self:F( { APC, From, Event, To, Deployed } ) if APC and APC:IsAlive() then for _, APCUnit in pairs( APC:GetUnits() ) do @@ -476,7 +482,7 @@ function AI_CARGO_APC:onafterUnload( APC, From, Event, To ) APC:RouteStop() for _, Cargo in pairs( APCUnit:GetCargo() ) do Cargo:UnBoard() - self:__Unboard( 10, Cargo ) + self:__Unboard( 10, Cargo, Deployed ) end end end @@ -485,14 +491,14 @@ end --- @param #AI_CARGO_APC self -- @param Wrapper.Group#GROUP APC -function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo ) +function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo, Deployed ) self:F( { APC, From, Event, To, Cargo:GetName() } ) if APC and APC:IsAlive() then if not Cargo:IsUnLoaded() then - self:__Unboard( 10, Cargo ) + self:__Unboard( 10, Cargo, Deployed ) else - self:__Unloaded( 1, Cargo ) + self:__Unloaded( 1, Cargo, Deployed ) end end @@ -500,8 +506,8 @@ end --- @param #AI_CARGO_APC self -- @param Wrapper.Group#GROUP APC -function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) - self:F( { APC, From, Event, To, Cargo:GetName() } ) +function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo, Deployed ) + self:F( { APC, From, Event, To, Cargo:GetName(), Deployed = Deployed } ) local AllUnloaded = true @@ -521,6 +527,13 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) end if AllUnloaded == true then + if Deployed == true then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + Cargo:SetDeployed( true ) + end + self.APC_Cargo = {} + end self:Guard() self.CargoCarrier = APC end @@ -559,7 +572,7 @@ function AI_CARGO_APC._Pickup( APC, self ) if APC:IsAlive() then self:Load() - self.Transporting = true + self.Relocating = true end end @@ -571,9 +584,9 @@ function AI_CARGO_APC._Deploy( APC, self ) APC:F( { "AI_CARGO_APC._Deploy:", APC } ) if APC:IsAlive() then - self:Unload() + self:Unload( true ) self.Transporting = false - self.APC_Cargo = {} + self.Relocating = false end end @@ -606,6 +619,8 @@ function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, En else AI_CARGO_APC._Pickup( APC, self ) end + + self.Transporting = true end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua new file mode 100644 index 000000000..eeaffec9f --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -0,0 +1,188 @@ +--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Dispatcher + +--- @type AI_CARGO_DISPATCHER +-- @extends Core.Fsm#FSM_CONTROLLABLE + + +--- # AI\_CARGO\_DISPATCHER class, extends @{Core.Base#BASE} +-- +-- === +-- +-- AI\_CARGO\_DISPATCHER brings a dynamic cargo handling capability for AI groups. +-- +-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\_DISPATCHER module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER object recognize the cargo. +-- Please consult the @{Cargo} module for more information. +-- +-- +-- +-- @field #AI_CARGO_DISPATCHER +AI_CARGO_DISPATCHER = { + ClassName = "AI_CARGO_DISPATCHER", + SetAPC = nil, + SetDeployZones = nil, + AI_CARGO_APC = {} +} + +--- @type AI_CARGO_DISPATCHER.AI_CARGO_APC +-- @map + +--- @field #AI_CARGO_DISPATCHER.AI_CARGO_APC +AI_CARGO_DISPATCHER.AICargoAPC = {} + +--- @field #AI_CARGO_DISPATCHER.PickupCargo +AI_CARGO_DISPATCHER.PickupCargo = {} + +--- Creates a new AI_CARGO_DISPATCHER object. +-- @param #AI_CARGO_DISPATCHER self +-- @param Core.Set#SET_GROUP SetAPC +-- @param Core.Set#SET_CARGO SetCargo +-- @param Core.Set#SET_ZONE SetDeployZone +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() +-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo ) +-- +function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) + + local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER + + self.SetAPC = SetAPC -- Core.Set#SET_GROUP + self.SetCargo = SetCargo -- Core.Set#SET_CARGO + self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE + + self:SetStartState( "APC" ) + + self:AddTransition( "*", "Monitor", "*" ) + + self:AddTransition( "*", "Pickup", "*" ) + self:AddTransition( "*", "Loading", "*" ) + self:AddTransition( "*", "Loaded", "*" ) + + self:AddTransition( "*", "Deploy", "*" ) + self:AddTransition( "*", "Unloading", "*" ) + self:AddTransition( "*", "Unloaded", "*" ) + + self.MonitorTimeInterval = 120 + self.CombatRadius = 500 + self.DeployRadiusInner = 200 + self.DeployRadiusOuter = 500 + + self:Monitor( 1 ) + + return self +end + + +--- The Start trigger event, which actually takes action at the specified time interval. +-- @param #AI_CARGO_DISPATCHER self +-- @param Wrapper.Group#GROUP APC +-- @return #AI_CARGO_DISPATCHER +function AI_CARGO_DISPATCHER:onafterMonitor() + + for APCGroupName, APC in pairs( self.SetAPC:GetSet() ) do + local APC = APC -- Wrapper.Group#GROUP + local AICargoAPC = self.AICargoAPC[APC] + if not AICargoAPC then + -- ok, so this APC does not have yet an AI_CARGO_APC object... + -- let's create one and also declare the Loaded and UnLoaded handlers. + self.AICargoAPC[APC] = AI_CARGO_APC:New( APC, self.SetCargo, self.CombatRadius ) + AICargoAPC = self.AICargoAPC[APC] + + function AICargoAPC.OnAfterPickup( AICargoAPC, APC, From, Event, To, Cargo ) + self:Pickup( APC, Cargo ) + end + + function AICargoAPC.OnAfterLoad( AICargoAPC, APC ) + self:Load( APC ) + end + + function AICargoAPC.OnAfterLoaded( AICargoAPC, APC, From, Event, To, Cargo ) + self:Loaded( APC, Cargo ) + end + + function AICargoAPC.OnAfterDeploy( AICargoAPC, APC ) + self:Deploy( APC ) + end + + function AICargoAPC.OnAfterUnload( AICargoAPC, APC ) + self:Unload( APC ) + end + + function AICargoAPC.OnAfterUnloaded( AICargoAPC, APC ) + self:Unloaded( APC ) + end + end + + -- The Pickup sequence ... + -- Check if this APC need to go and Pickup something... + self:I( { IsTransporting = AICargoAPC:IsTransporting() } ) + if AICargoAPC:IsTransporting() == false then + -- ok, so there is a free APC + -- now find the first cargo that is Unloaded + + local PickupCargo = nil + + for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) do + if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then + if not self.PickupCargo[Cargo] then + self.PickupCargo[Cargo] = APC + PickupCargo = Cargo + break + end + end + end + if PickupCargo then + AICargoAPC:Pickup( PickupCargo:GetCoordinate(), 70 ) + break + end + end + end + + self:__Monitor( self.MonitorTimeInterval ) + + return self +end + + + +--- Make a APC run for a cargo deploy action after the cargo Pickup trigger has been initiated, by default. +-- @param #AI_CARGO_DISPATCHER self +-- @param Wrapper.Group#GROUP APC +-- @return #AI_CARGO_DISPATCHER +function AI_CARGO_DISPATCHER:onafterPickup( From, Event, To, APC, Cargo ) + return self +end + +--- Make a APC run for a cargo deploy action after the cargo has been loaded, by default. +-- @param #AI_CARGO_DISPATCHER self +-- @param Wrapper.Group#GROUP APC +-- @return #AI_CARGO_DISPATCHER +function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) + + self:I( { "Loaded Dispatcher", APC } ) + local RandomZone = self.SetDeployZones:GetRandomZone() + self:I( { RandomZone = RandomZone } ) + + self.AICargoAPC[APC]:Deploy( RandomZone:GetCoordinate(), 70 ) + self.PickupCargo[Cargo] = nil + + return self +end + + + + diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index d9c93e936..eb3c0d4f7 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -1,4 +1,4 @@ ---- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo. +--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using APCs. -- -- === -- @@ -6,10 +6,10 @@ -- -- === -- --- @module AI_Cargo_Dispatcher +-- @module AI_Cargo_Dispatcher_APC --- @type AI_CARGO_DISPATCHER_APC --- @extends Core.Fsm#FSM_CONTROLLABLE +-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER --- # AI\_CARGO\_DISPATCHER\_APC class, extends @{Core.Base#BASE} @@ -28,17 +28,8 @@ -- @field #AI_CARGO_DISPATCHER_APC AI_CARGO_DISPATCHER_APC = { ClassName = "AI_CARGO_DISPATCHER_APC", - SetAPC = nil, - SetDeployZones = nil, - AI_CARGO_APC = {} } ---- @type AI_CARGO_DISPATCHER_APC.AI_CARGO_APC --- @map - ---- @field #AI_CARGO_DISPATCHER_APC.AI_CARGO_APC -AI_CARGO_DISPATCHER_APC.AICargoAPC = {} - --- Creates a new AI_CARGO_DISPATCHER_APC object. -- @param #AI_CARGO_DISPATCHER_APC self -- @param Core.Set#SET_GROUP SetAPC @@ -55,104 +46,9 @@ AI_CARGO_DISPATCHER_APC.AICargoAPC = {} -- function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones ) - local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER_APC - - self.SetAPC = SetAPC -- Core.Set#SET_GROUP - self.SetCargo = SetCargo -- Core.Set#SET_CARGO - self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE - - self:SetStartState( "APC" ) - - self:AddTransition( "*", "Monitor", "*" ) - - self:AddTransition( "*", "Pickup", "*" ) - self:AddTransition( "*", "Loading", "*" ) - self:AddTransition( "*", "Loaded", "*" ) - - self:AddTransition( "*", "Deploy", "*" ) - self:AddTransition( "*", "Unloading", "*" ) - self:AddTransition( "*", "Unloaded", "*" ) - - self.PickupTimeInterval = 120 - self.DeployRadiusInner = 200 - self.DeployRadiusOuter = 500 - - return self -end - - ---- The Start trigger event, which actually takes action at the specified time interval. --- @param #AI_CARGO_DISPATCHER_APC self --- @param Wrapper.Group#GROUP APC --- @return #AI_CARGO_DISPATCHER_APC -function AI_CARGO_DISPATCHER_APC:onafterMonitor() - - for APCGroupName, APC in pairs( self.SetAPC:GetSet() ) do - local APC = APC -- Wrapper.Group#GROUP - local AICargoAPC = self.AICargoAPC[APC] - if not AICargoAPC then - -- ok, so this APC does not have yet an AI_CARGO_APC object... - -- let's create one and also declare the Loaded and UnLoaded handlers. - self.AICargoAPC[APC] = AI_CARGO_APC:New( APC, self.SetCargo, self.CombatRadius ) - AICargoAPC = self.AICargoAPC[APC] - - function AICargoAPC.OnAfterPickup( AICargoAPC, APC ) - self.AICargoAPC = AICargoAPC - self:Pickup( APC ) - end - - function AICargoAPC.OnAfterLoad( AICargoAPC, APC ) - self.AICargoAPC = AICargoAPC - self:Load( APC ) - end - - function AICargoAPC.OnAfterLoaded( AICargoAPC, APC ) - self.AICargoAPC = AICargoAPC - self:Loaded( APC ) - end - - function AICargoAPC.OnAfterDeploy( AICargoAPC, APC ) - self.AICargoAPC = AICargoAPC - self:Deploy( APC ) - end - - function AICargoAPC.OnAfterUnload( AICargoAPC, APC ) - self.AICargoAPC = AICargoAPC - self:Unload( APC ) - end - - function AICargoAPC.OnAfterUnloaded( AICargoAPC, APC ) - self.AICargoAPC = AICargoAPC - self:Unloaded( APC ) - end - end - - -- The Pickup sequence ... - -- Check if this APC need to go and Pickup something... - if not AICargoAPC:IsTransporting() == true then - -- ok, so there is a free APC - -- now find the first cargo that is Unloaded - local FirstCargoUnloaded = self.SetCargo:FirstCargoUnLoaded() - if FirstCargoUnloaded then - AICargoAPC:Pickup( FirstCargoUnloaded:GetCoordinate() ) - break - end - end - end + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_APC return self end - ---- Make a APC run for a cargo deploy action after the cargo has been loaded, by default. --- @param #AI_CARGO_DISPATCHER_APC self --- @param Wrapper.Group#GROUP APC --- @return #AI_CARGO_DISPATCHER_APC -function AI_CARGO_DISPATCHER_APC:OnAfterLoaded( APC ) - - self:Deploy( self.SetDeployZones:GetRandomZone():GetCoordinate():GetRandomCoordinateInRadius( self.DeployRadiusInner, self.DeployRadiusOuter ) ) - - return self -end - diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua new file mode 100644 index 000000000..4deaef1d9 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -0,0 +1,54 @@ +--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Dispatcher_Airplane + +--- @type AI_CARGO_DISPATCHER_AIRPLANE +-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER + + +--- # AI\_CARGO\_DISPATCHER\_AIRPLANE class, extends @{Core.Base#BASE} +-- +-- === +-- +-- AI\_CARGO\_DISPATCHER\_AIRPLANE brings a dynamic cargo handling capability for AI groups. +-- +-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\_DISPATCHER\_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_AIRPLANE object recognize the cargo. +-- Please consult the @{Cargo} module for more information. +-- +-- +-- +-- @field #AI_CARGO_DISPATCHER_AIRPLANE +AI_CARGO_DISPATCHER_AIRPLANE = { + ClassName = "AI_CARGO_DISPATCHER_AIRPLANE", +} + +--- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object. +-- @param #AI_CARGO_DISPATCHER_AIRPLANE self +-- @param Core.Set#SET_GROUP SetAirplane +-- @param Core.Set#SET_CARGO SetCargo +-- @param Core.Set#SET_ZONE SetDeployZone +-- @return #AI_CARGO_DISPATCHER_AIRPLANE +-- @usage +-- +-- -- Create a new cargo dispatcher +-- SetAirplane = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart() +-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() +-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo ) +-- +function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo, SetDeployZones ) + + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAirplane, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE + + return self +end + + diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua new file mode 100644 index 000000000..48b8bdd4c --- /dev/null +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -0,0 +1,54 @@ +--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters. +-- +-- === +-- +-- ### Author: **FlightControl** +-- +-- === +-- +-- @module AI_Cargo_Dispatcher_Helicopter + +--- @type AI_CARGO_DISPATCHER_HELICOPTER +-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER + + +--- # AI\_CARGO\_DISPATCHER\_HELICOPTER class, extends @{Core.Base#BASE} +-- +-- === +-- +-- AI\_CARGO\_DISPATCHER\_HELICOPTER brings a dynamic cargo handling capability for AI groups. +-- +-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\_DISPATCHER\_HELICOPTER module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_HELICOPTER object recognize the cargo. +-- Please consult the @{Cargo} module for more information. +-- +-- +-- +-- @field #AI_CARGO_DISPATCHER_HELICOPTER +AI_CARGO_DISPATCHER_HELICOPTER = { + ClassName = "AI_CARGO_DISPATCHER_HELICOPTER", +} + +--- Creates a new AI_CARGO_DISPATCHER_HELICOPTER object. +-- @param #AI_CARGO_DISPATCHER_HELICOPTER self +-- @param Core.Set#SET_GROUP SetAPC +-- @param Core.Set#SET_CARGO SetCargo +-- @param Core.Set#SET_ZONE SetDeployZone +-- @return #AI_CARGO_DISPATCHER_HELICOPTER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- SetHelicopter = SET_GROUP:New():FilterPrefixes( "Helicopter" ):FilterStart() +-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() +-- AICargoDispatcher = AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo ) +-- +function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZones ) + + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER + + return self +end + + diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 501dd0e5e..c7580db68 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -1149,6 +1149,7 @@ function DATABASE:_RegisterTemplates() local ZoneName = ZoneData.name self.ZONENAMES[ZoneName] = ZoneName self.ZONES[ZoneName] = ZONE:New( ZoneName ) + self:I( "Added ZONE " .. ZoneName ) end return self diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index b8043328d..b29d1d6fa 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4350,6 +4350,20 @@ function SET_CARGO:FirstCargoWithState( State ) return FirstCargo end +function SET_CARGO:FirstCargoWithStateAndNotDeployed( State ) + + local FirstCargo = nil + + for CargoName, Cargo in pairs( self.Set ) do + if Cargo:Is( State ) and not Cargo:IsDeployed() then + FirstCargo = Cargo + break + end + end + + return FirstCargo +end + --- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is UnLoaded. -- @param #SET_CARGO self @@ -4360,6 +4374,15 @@ function SET_CARGO:FirstCargoUnLoaded() end +--- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is UnLoaded and not Deployed. +-- @param #SET_CARGO self +-- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +function SET_CARGO:FirstCargoUnLoadedAndNotDeployed() + local FirstCargo = self:FirstCargoWithStateAndNotDeployed( "UnLoaded" ) + return FirstCargo +end + + --- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is Loaded. -- @param #SET_CARGO self -- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. @@ -4588,7 +4611,7 @@ function SET_ZONE:GetRandomZone() local Index = self.Index local ZoneFound = nil - while not ZoneFound do + while not ZoneFound do local ZoneRandom = math.random( 1, #Index ) ZoneFound = self.Set[Index[ZoneRandom]] end diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index 90e550a13..ea44b6326 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -70,9 +70,12 @@ AI/AI_Cas.lua AI/AI_Bai.lua AI/AI_Formation.lua AI/AI_Cargo_APC.lua -AI/AI_Cargo_Dispatcher_APC.lua AI/AI_Cargo_Helicopter.lua AI/AI_Cargo_Airplane.lua +AI/AI_Cargo_Dispatcher.lua +AI/AI_Cargo_Dispatcher_APC.lua +AI/AI_Cargo_Dispatcher_Helicopter.lua +AI/AI_Cargo_Dispatcher_Airplane.lua Actions/Act_Assign.lua Actions/Act_Route.lua From aac5efbf613c347ff13378fc676120b9504a4713 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 10 May 2018 22:48:14 +0200 Subject: [PATCH 098/170] ARTY added shots to report output --- Moose Development/Moose/Functional/Artillery.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 8849c68e0..4a00da6e5 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -936,9 +936,9 @@ function ARTY:_OnEventShot(EventData) self.Nshots=self.Nshots+1 -- Debug output. - local text=string.format("Group %s fired shot %d of %d with weapon %s on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name) + local text=string.format("%s, fired shot %d of %d with weapon %s on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name) self:T(ARTY.id..text) - MESSAGE:New(text, 5):ToAllIf(self.Debug) + MESSAGE:New(text, 5):ToAllIf(self.report or self.Debug) -- Get current ammo. local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() From bca964aca85306a9702d66a2a9ae81e7ff1826ab Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 10 May 2018 23:17:06 +0200 Subject: [PATCH 099/170] Helicopter version of AI_CARGO_DISPATCHER_HELICOPTER --- .../Moose/AI/AI_Cargo_Dispatcher.lua | 28 +++-- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 8 ++ .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 8 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 105 +++++++++--------- 4 files changed, 82 insertions(+), 67 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index eeaffec9f..91e500fbf 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -64,7 +64,7 @@ function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) self.SetCargo = SetCargo -- Core.Set#SET_CARGO self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE - self:SetStartState( "APC" ) + self:SetStartState( "Dispatch" ) self:AddTransition( "*", "Monitor", "*" ) @@ -76,13 +76,10 @@ function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) self:AddTransition( "*", "Unloading", "*" ) self:AddTransition( "*", "Unloaded", "*" ) - self.MonitorTimeInterval = 120 - self.CombatRadius = 500 + self.MonitorTimeInterval = 30 self.DeployRadiusInner = 200 self.DeployRadiusOuter = 500 - self:Monitor( 1 ) - return self end @@ -93,21 +90,22 @@ end -- @return #AI_CARGO_DISPATCHER function AI_CARGO_DISPATCHER:onafterMonitor() - for APCGroupName, APC in pairs( self.SetAPC:GetSet() ) do - local APC = APC -- Wrapper.Group#GROUP - local AICargoAPC = self.AICargoAPC[APC] + for APCGroupName, Carrier in pairs( self.SetAPC:GetSet() ) do + local Carrier = Carrier -- Wrapper.Group#GROUP + local AICargoAPC = self.AICargoAPC[Carrier] if not AICargoAPC then + -- ok, so this APC does not have yet an AI_CARGO_APC object... -- let's create one and also declare the Loaded and UnLoaded handlers. - self.AICargoAPC[APC] = AI_CARGO_APC:New( APC, self.SetCargo, self.CombatRadius ) - AICargoAPC = self.AICargoAPC[APC] + self.AICargoAPC[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius ) + AICargoAPC = self.AICargoAPC[Carrier] function AICargoAPC.OnAfterPickup( AICargoAPC, APC, From, Event, To, Cargo ) self:Pickup( APC, Cargo ) end function AICargoAPC.OnAfterLoad( AICargoAPC, APC ) - self:Load( APC ) + self:Loading( APC ) end function AICargoAPC.OnAfterLoaded( AICargoAPC, APC, From, Event, To, Cargo ) @@ -119,7 +117,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() end function AICargoAPC.OnAfterUnload( AICargoAPC, APC ) - self:Unload( APC ) + self:Unloading( APC ) end function AICargoAPC.OnAfterUnloaded( AICargoAPC, APC ) @@ -139,14 +137,14 @@ function AI_CARGO_DISPATCHER:onafterMonitor() for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) do if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then if not self.PickupCargo[Cargo] then - self.PickupCargo[Cargo] = APC + self.PickupCargo[Cargo] = Carrier PickupCargo = Cargo break end end end if PickupCargo then - AICargoAPC:Pickup( PickupCargo:GetCoordinate(), 70 ) + AICargoAPC:Pickup( PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( 25, 50 ), 70 ) break end end @@ -177,7 +175,7 @@ function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) local RandomZone = self.SetDeployZones:GetRandomZone() self:I( { RandomZone = RandomZone } ) - self.AICargoAPC[APC]:Deploy( RandomZone:GetCoordinate(), 70 ) + self.AICargoAPC[APC]:Deploy( RandomZone:GetCoordinate():GetRandomCoordinateInRadius(25,100), 70 ) self.PickupCargo[Cargo] = nil return self diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index eb3c0d4f7..67d2a2c92 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -48,7 +48,15 @@ function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones ) local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_APC + self.CombatRadius = 500 + + self:Monitor( 1 ) + return self end +function AI_CARGO_DISPATCHER_APC:AICargo( APC, SetCargo ) + + return AI_CARGO_APC:New( APC, SetCargo, self.CombatRadius ) +end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index 48b8bdd4c..56c4dae78 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -32,7 +32,7 @@ AI_CARGO_DISPATCHER_HELICOPTER = { --- Creates a new AI_CARGO_DISPATCHER_HELICOPTER object. -- @param #AI_CARGO_DISPATCHER_HELICOPTER self --- @param Core.Set#SET_GROUP SetAPC +-- @param Core.Set#SET_GROUP SetHelicopter -- @param Core.Set#SET_CARGO SetCargo -- @param Core.Set#SET_ZONE SetDeployZone -- @return #AI_CARGO_DISPATCHER_HELICOPTER @@ -48,7 +48,13 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZ local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER + self:Monitor( 1 ) + return self end +function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, SetCargo ) + + return AI_CARGO_HELICOPTER:New( Helicopter, SetCargo ) +end diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index c993755ee..e0d9d2e10 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -113,6 +113,16 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) return self end +function AI_CARGO_HELICOPTER:IsTransporting() + + return self.Transporting == true +end + +function AI_CARGO_HELICOPTER:IsRelocating() + + return self.Relocating == true +end + --- Set the Carrier. -- @param #AI_CARGO_HELICOPTER self @@ -169,31 +179,6 @@ function AI_CARGO_HELICOPTER:SetCarrier( Helicopter ) end ---- Find a free Carrier within a range. --- @param #AI_CARGO_HELICOPTER self --- @param Core.Point#COORDINATE Coordinate --- @param #number Radius --- @return Wrapper.Group#GROUP NewCarrier -function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) - - local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) - CoordinateZone:Scan( { Object.Category.UNIT } ) - for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do - local NearUnit = UNIT:Find( DCSUnit ) - self:F({NearUnit=NearUnit}) - if not NearUnit:GetState( NearUnit, "AI_CARGO_HELICOPTER" ) then - local Attributes = NearUnit:GetDesc() - self:F({Attributes=Attributes}) - if NearUnit:HasAttribute( "Trucks" ) then - return NearUnit:GetGroup() - end - end - end - - return nil - -end - --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -- @param From @@ -208,11 +193,14 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) if self.RoutePickup == true then self:Load( Helicopter:GetPointVec2() ) self.RoutePickup = false + self.Relocating = true end if self.RouteDeploy == true then - self:Unload() + self:Unload( true ) self.RouteDeploy = false + self.Transporting = false + self.Relocating = false end end @@ -230,7 +218,9 @@ end -- @param #number Speed function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed ) - if Helicopter and Helicopter:IsAlive() then + if Helicopter and Helicopter:IsAlive() ~= nil then + + Helicopter:Activate() self.RoutePickup = true @@ -270,7 +260,9 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin Route[#Route].task = Helicopter:TaskCombo( Tasks ) -- Now route the helicopter - Helicopter:Route( Route, 0.5 ) + Helicopter:Route( Route, 1 ) + + self.Transporting = true end end @@ -285,7 +277,7 @@ end -- @param #number Speed function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed ) - if Helicopter and Helicopter:IsAlive() then + if Helicopter and Helicopter:IsAlive() ~= nil then self.RouteDeploy = true @@ -325,7 +317,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin Route[#Route].task = Helicopter:TaskCombo( Tasks ) -- Now route the helicopter - Helicopter:Route( Route, 0.5 ) + Helicopter:Route( Route, 1 ) end end @@ -373,14 +365,15 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo } ) if Helicopter and Helicopter:IsAlive() then - self:F({ IsLoaded = self.Cargo:IsLoaded() } ) - if not self.Cargo:IsLoaded() then - self:__Board( 10 ) + self:F({ IsLoaded = Cargo:IsLoaded() } ) + if not Cargo:IsLoaded() then + self:__Board( 10, Cargo ) else - self:__Loaded( 1 ) + self:__Loaded( 1, Cargo ) end end @@ -388,12 +381,13 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To, Cargo ) + self:F( { APC, From, Event, To } ) local Loaded = true if Helicopter and Helicopter:IsAlive() then - for HelicopterUnit, Cargo in pairs( self.APC_Cargo ) do + for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do local Cargo = Cargo -- Cargo.Cargo#CARGO self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then @@ -410,14 +404,14 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To, Deployed ) if Helicopter and Helicopter:IsAlive() then for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do Cargo:UnBoard() - self:__Unboard( 10, Cargo ) + self:__Unboard( 10, Cargo, Deployed ) end end end @@ -427,13 +421,13 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To, Cargo, Deployed ) if Helicopter and Helicopter:IsAlive() then - if not self.Cargo:IsUnLoaded() then - self:__Unboard( 10 ) + if not Cargo:IsUnLoaded() then + self:__Unboard( 10, Cargo, Deployed ) else - self:__Unloaded( 1 ) + self:__Unloaded( 1, Cargo, Deployed ) end end @@ -441,25 +435,34 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Cargo, Deployed ) + self:F( { APC, From, Event, To, Cargo:GetName(), Deployed = Deployed } ) local AllUnloaded = true --Cargo:Regroup() if Helicopter and Helicopter:IsAlive() then - for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do - local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO - self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) - if CargoCheck:IsUnLoaded() == false then - AllUnloaded = false - break + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local CargoCheck = self.Helicopter_Cargo[HelicopterUnit] -- Cargo.Cargo#CARGO + if CargoCheck then + self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) + if CargoCheck:IsUnLoaded() == false then + AllUnloaded = false + break + end end end if AllUnloaded == true then + if Deployed == true then + for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + Cargo:SetDeployed( true ) + end + self.Helicopter_Cargo = {} + end self.Helicopter = Helicopter - self.Helicopter_Cargo = {} end end From 74668bb7dbf8b8981a8a661bbb2bcbb749a6753e Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 10 May 2018 23:42:14 +0200 Subject: [PATCH 100/170] Fixes --- .../Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 40 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 91e500fbf..9f4b1fdce 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -175,7 +175,7 @@ function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) local RandomZone = self.SetDeployZones:GetRandomZone() self:I( { RandomZone = RandomZone } ) - self.AICargoAPC[APC]:Deploy( RandomZone:GetCoordinate():GetRandomCoordinateInRadius(25,100), 70 ) + self.AICargoAPC[APC]:Deploy( RandomZone:GetCoordinate():GetRandomCoordinateInRadius( 25, 200 ), 70 ) self.PickupCargo[Cargo] = nil return self diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index e0d9d2e10..db578e33d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -227,17 +227,17 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin local Route = {} --- Calculate the target route point. - local CoordinateFrom = Helicopter:GetCoordinate() + --local CoordinateFrom = Helicopter:GetCoordinate() local CoordinateTo = Coordinate --- Create a route point of type air. - local WaypointFrom = CoordinateFrom:WaypointAir( - "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - Speed, - true - ) +-- local WaypointFrom = CoordinateFrom:WaypointAir( +-- "RADIO", +-- POINT_VEC3.RoutePointType.TurningPoint, +-- POINT_VEC3.RoutePointAction.TurningPoint, +-- Speed, +-- true +-- ) --- Create a route point of type air. local WaypointTo = CoordinateTo:WaypointAir( @@ -248,7 +248,7 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin true ) - Route[#Route+1] = WaypointFrom +-- Route[#Route+1] = WaypointFrom Route[#Route+1] = WaypointTo --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... @@ -259,6 +259,8 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) Route[#Route].task = Helicopter:TaskCombo( Tasks ) + Route[#Route+1] = WaypointTo + -- Now route the helicopter Helicopter:Route( Route, 1 ) @@ -284,17 +286,17 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin local Route = {} --- Calculate the target route point. - local CoordinateFrom = Helicopter:GetCoordinate() +-- local CoordinateFrom = Helicopter:GetCoordinate() local CoordinateTo = Coordinate --- Create a route point of type air. - local WaypointFrom = CoordinateFrom:WaypointAir( - "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - Speed, - true - ) +-- local WaypointFrom = CoordinateFrom:WaypointAir( +-- "RADIO", +-- POINT_VEC3.RoutePointType.TurningPoint, +-- POINT_VEC3.RoutePointAction.TurningPoint, +-- Speed, +-- true +-- ) --- Create a route point of type air. local WaypointTo = CoordinateTo:WaypointAir( @@ -305,7 +307,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin true ) - Route[#Route+1] = WaypointFrom +-- Route[#Route+1] = WaypointFrom Route[#Route+1] = WaypointTo --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... @@ -316,6 +318,8 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) Route[#Route].task = Helicopter:TaskCombo( Tasks ) + Route[#Route+1] = WaypointTo + -- Now route the helicopter Helicopter:Route( Route, 1 ) end From d61840d8343acb940deb3331037496b671cacf69 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 11 May 2018 12:27:55 +0200 Subject: [PATCH 101/170] Added Big Smoke Effect Added big smoke effects to COORDINATE API. --- Moose Development/Moose/Core/Point.lua | 82 +++++++++++++++++++++ Moose Development/Moose/Utilities/Utils.lua | 13 ++++ 2 files changed, 95 insertions(+) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 8ef92dc38..3385b1311 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1013,6 +1013,88 @@ do -- COORDINATE self:Smoke( SMOKECOLOR.Blue ) end + --- Big smoke and fire at the coordinate. + -- @param #COORDINATE self + -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). + -- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. + function COORDINATE:BigSmokeAndFire( preset, density ) + self:F2( { preset=preset, density=density } ) + density=density or 0.5 + trigger.action.effectSmokeBig( self:GetVec3(), preset, density ) + end + + --- Small smoke and fire at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeAndFireSmall( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density) + end + + --- Medium smoke and fire at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeAndFireMedium( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density) + end + + --- Large smoke and fire at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeAndFireLarge( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density) + end + + --- Huge smoke and fire at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeAndFireHuge( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density) + end + + --- Small smoke at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeSmall( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density) + end + + --- Medium smoke at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeMedium( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density) + end + + --- Large smoke at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeLarge( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density) + end + + --- Huge smoke at the coordinate. + -- @param #COORDINATE self + -- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + function COORDINATE:BigSmokeHuge( density ) + self:F2( { density=density } ) + density=density or 0.5 + self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density) + end + --- Flares the point in a color. -- @param #COORDINATE self -- @param Utilities.Utils#FLARECOLOR FlareColor diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index e7f730ad1..7ffb6dd44 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -29,6 +29,19 @@ SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR FLARECOLOR = trigger.flareColor -- #FLARECOLOR +--- Big smoke preset enum. +-- @type BIGSMOKEPRESET +BIGSMOKEPRESET = { + SmallSmokeAndFire=0, + MediumSmokeAndFire=1, + LargeSmokeAndFire=2, + HugeSmokeAndFire=3, + SmallSmoke=4, + MediumSmoke=5, + LargeSmoke=6, + HugeSmoke=7, +} + --- Utilities static class. -- @type UTILS UTILS = { From 230a803045f3e0ccd4ad8d6243f34019434ec193 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 11 May 2018 12:30:33 +0200 Subject: [PATCH 102/170] Corrected description. --- Moose Development/Moose/Core/Point.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 3385b1311..5060600d6 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1015,7 +1015,7 @@ do -- COORDINATE --- Big smoke and fire at the coordinate. -- @param #COORDINATE self - -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). + -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (0=small smoke and fire, 1=medium smoke and fire, 2=large smoke and fire, 3=huge smoke and fire, 4=small smoke, 5=medium smoke, 6=large smoke, 7=huge smoke). -- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. function COORDINATE:BigSmokeAndFire( preset, density ) self:F2( { preset=preset, density=density } ) From 25a6cbcf6dfe125ba2b34b68b2821c2673e327f4 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 12 May 2018 08:37:27 +0200 Subject: [PATCH 103/170] Helicopter AI_CARGO_DISPATCHER working (almost). Queueing at deploy locations working. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 33 +- .../Moose/AI/AI_Cargo_Dispatcher.lua | 89 +++- .../Moose/AI/AI_Cargo_Helicopter.lua | 400 ++++++++++++++---- Moose Development/Moose/Cargo/CargoGroup.lua | 30 ++ Moose Development/Moose/Core/Database.lua | 48 ++- Moose Development/Moose/Core/Zone.lua | 13 + .../Moose/Wrapper/Controllable.lua | 7 +- 7 files changed, 502 insertions(+), 118 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 9e4351bee..b5d0a3f8a 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -108,6 +108,7 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) self:AddTransition( "*", "Guard", "Unloaded" ) + self:AddTransition( "*", "Home", "*" ) self:AddTransition( "*", "Destroyed", "Destroyed" ) @@ -600,14 +601,14 @@ end -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -- @param #string EndPointFormation The formation at the end point of the action. -function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, EndPointFormation ) +function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() then if Coordinate then self.RoutePickup = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) @@ -634,13 +635,13 @@ end -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -- @param #string EndPointFormation The formation at the end point of the action. -function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, EndPointFormation ) +function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() then self.RouteDeploy = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) @@ -653,3 +654,27 @@ function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, En end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Group#GROUP APC +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_APC:onafterHome( APC, From, Event, To, Coordinate ) + + if APC and APC:IsAlive() ~= nil then + + self.RouteHome = true + + local Waypoints = APC:TaskGroundOnRoad( Coordinate, 120, "Line abreast" ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + + APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. + + end + +end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 9f4b1fdce..dd03c258e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -37,11 +37,13 @@ AI_CARGO_DISPATCHER = { -- @map --- @field #AI_CARGO_DISPATCHER.AI_CARGO_APC -AI_CARGO_DISPATCHER.AICargoAPC = {} +AI_CARGO_DISPATCHER.AI_Cargo = {} --- @field #AI_CARGO_DISPATCHER.PickupCargo AI_CARGO_DISPATCHER.PickupCargo = {} + + --- Creates a new AI_CARGO_DISPATCHER object. -- @param #AI_CARGO_DISPATCHER self -- @param Core.Set#SET_GROUP SetAPC @@ -54,7 +56,7 @@ AI_CARGO_DISPATCHER.PickupCargo = {} -- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() -- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) -- function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) @@ -76,14 +78,42 @@ function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) self:AddTransition( "*", "Unloading", "*" ) self:AddTransition( "*", "Unloaded", "*" ) + self:AddTransition( "*", "Home", "*" ) + self.MonitorTimeInterval = 30 self.DeployRadiusInner = 200 self.DeployRadiusOuter = 500 + self.CarrierHome = {} + return self end +--- Set the home zone. +-- When there is nothing anymore to pickup, the carriers will go to a random coordinate in this zone. +-- They will await here new orders. +-- @param #AI_CARGO_DISPATCHER self +-- @param Core.Zone#ZONE_BASE HomeZone +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the home coordinate +-- local HomeZone = ZONE:New( "Home" ) +-- AICargoDispatcher:SetHomeZone( HomeZone ) +-- +function AI_CARGO_DISPATCHER:SetHomeZone( HomeZone ) + + self.HomeZone = HomeZone + + return self +end + + + --- The Start trigger event, which actually takes action at the specified time interval. -- @param #AI_CARGO_DISPATCHER self -- @param Wrapper.Group#GROUP APC @@ -92,60 +122,78 @@ function AI_CARGO_DISPATCHER:onafterMonitor() for APCGroupName, Carrier in pairs( self.SetAPC:GetSet() ) do local Carrier = Carrier -- Wrapper.Group#GROUP - local AICargoAPC = self.AICargoAPC[Carrier] - if not AICargoAPC then + local AI_Cargo = self.AI_Cargo[Carrier] + if not AI_Cargo then -- ok, so this APC does not have yet an AI_CARGO_APC object... -- let's create one and also declare the Loaded and UnLoaded handlers. - self.AICargoAPC[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius ) - AICargoAPC = self.AICargoAPC[Carrier] + self.AI_Cargo[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius ) + AI_Cargo = self.AI_Cargo[Carrier] - function AICargoAPC.OnAfterPickup( AICargoAPC, APC, From, Event, To, Cargo ) + function AI_Cargo.OnAfterPickup( AI_Cargo, APC, From, Event, To, Cargo ) self:Pickup( APC, Cargo ) end - function AICargoAPC.OnAfterLoad( AICargoAPC, APC ) + function AI_Cargo.OnAfterLoad( AI_Cargo, APC ) self:Loading( APC ) end - function AICargoAPC.OnAfterLoaded( AICargoAPC, APC, From, Event, To, Cargo ) + function AI_Cargo.OnAfterLoaded( AI_Cargo, APC, From, Event, To, Cargo ) self:Loaded( APC, Cargo ) end - function AICargoAPC.OnAfterDeploy( AICargoAPC, APC ) + function AI_Cargo.OnAfterDeploy( AI_Cargo, APC ) self:Deploy( APC ) end - function AICargoAPC.OnAfterUnload( AICargoAPC, APC ) + function AI_Cargo.OnAfterUnload( AI_Cargo, APC ) self:Unloading( APC ) end - function AICargoAPC.OnAfterUnloaded( AICargoAPC, APC ) + function AI_Cargo.OnAfterUnloaded( AI_Cargo, APC ) self:Unloaded( APC ) end end -- The Pickup sequence ... -- Check if this APC need to go and Pickup something... - self:I( { IsTransporting = AICargoAPC:IsTransporting() } ) - if AICargoAPC:IsTransporting() == false then + self:I( { IsTransporting = AI_Cargo:IsTransporting() } ) + if AI_Cargo:IsTransporting() == false then -- ok, so there is a free APC -- now find the first cargo that is Unloaded local PickupCargo = nil for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Cargo] ~= nil } ) if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then - if not self.PickupCargo[Cargo] then - self.PickupCargo[Cargo] = Carrier + local CargoVec2 = { x = Cargo:GetX(), y = Cargo:GetY() } + local LocationFound = false + for APC, Vec2 in pairs( self.PickupCargo ) do + if Vec2.x == CargoVec2.x and Vec2.y == CargoVec2.y then + LocationFound = true + break + end + end + if LocationFound == false then + self.PickupCargo[Carrier] = CargoVec2 PickupCargo = Cargo break end end end if PickupCargo then - AICargoAPC:Pickup( PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( 25, 50 ), 70 ) + self.CarrierHome[Carrier] = nil + AI_Cargo:Pickup( PickupCargo:GetCoordinate() ) break + else + if self.HomeZone then + if not self.CarrierHome[Carrier] then + self.CarrierHome[Carrier] = true + AI_Cargo:Home( self.HomeZone:GetRandomPointVec2() ) + end + end end end end @@ -175,9 +223,10 @@ function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) local RandomZone = self.SetDeployZones:GetRandomZone() self:I( { RandomZone = RandomZone } ) - self.AICargoAPC[APC]:Deploy( RandomZone:GetCoordinate():GetRandomCoordinateInRadius( 25, 200 ), 70 ) - self.PickupCargo[Cargo] = nil - + self.AI_Cargo[APC]:Deploy( RandomZone:GetCoordinate(), 70 ) + + self.PickupCargo[APC] = nil + return self end diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index db578e33d..695deb248 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -22,6 +22,8 @@ AI_CARGO_HELICOPTER = { Coordinate = nil -- Core.Point#COORDINATE, } +AI_CARGO_HELICOPTER_QUEUE = {} + --- Creates a new AI_CARGO_HELICOPTER object. -- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter @@ -33,6 +35,8 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_HELICOPTER self.CargoSet = CargoSet -- Cargo.CargoGroup#CARGO_GROUP + + self.Zone = ZONE_GROUP:New( Helicopter:GetName(), Helicopter, 300 ) self:SetStartState( "Unloaded" ) @@ -47,6 +51,9 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) self:AddTransition( "*", "Landed", "*" ) + self:AddTransition( "*", "Queue", "*" ) + self:AddTransition( "*", "Orbit" , "*" ) + self:AddTransition( "*", "Home" , "*" ) self:AddTransition( "*", "Destroyed", "Destroyed" ) @@ -207,8 +214,6 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) end - - --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -- @param From @@ -216,57 +221,81 @@ end -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed ) +function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate ) - if Helicopter and Helicopter:IsAlive() ~= nil then + local HelicopterInZone = false - Helicopter:Activate() - - self.RoutePickup = true - - local Route = {} - - --- Calculate the target route point. - --local CoordinateFrom = Helicopter:GetCoordinate() - local CoordinateTo = Coordinate - - --- Create a route point of type air. --- local WaypointFrom = CoordinateFrom:WaypointAir( --- "RADIO", --- POINT_VEC3.RoutePointType.TurningPoint, --- POINT_VEC3.RoutePointAction.TurningPoint, --- Speed, --- true --- ) - - --- Create a route point of type air. - local WaypointTo = CoordinateTo:WaypointAir( - "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - Speed, - true - ) - --- Route[#Route+1] = WaypointFrom - Route[#Route+1] = WaypointTo - - --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... - Helicopter:WayPointInitialize( Route ) + --- @param Wrapper.Unit#UNIT ZoneUnit + local function EvaluateZone( ZoneUnit ) - local Tasks = {} + if ZoneUnit:IsAlive() then + local ZoneUnitCategory = ZoneUnit:GetDesc().category + local ZoneGroup = ZoneUnit:GetGroup() + if ZoneUnitCategory == Unit.Category.HELICOPTER then + local State = ZoneGroup:GetState( ZoneGroup, "Landing" ) + self:F({ZoneUnit=ZoneUnit:GetName(), State=State, UnitCategory = Unit.Category.HELICOPTER } ) + if State == true then + HelicopterInZone = true + return false + end + end + end - Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) - Route[#Route].task = Helicopter:TaskCombo( Tasks ) - - Route[#Route+1] = WaypointTo - - -- Now route the helicopter - Helicopter:Route( Route, 1 ) - - self.Transporting = true + return true + end + + if Helicopter and Helicopter:IsAlive() then + + local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() ) + + if Distance > 300 then + self:__Queue( -10, Coordinate ) + else + + -- This will search the zone and will call the local function "EvaluateZone", which passes a UNIT object. + local Zone = ZONE_RADIUS:New( "Deploy", Coordinate:GetVec2(), 300 ) + Zone:SearchZone( EvaluateZone ) + + self:F({HelicopterInZone=HelicopterInZone}) + + if HelicopterInZone == false then + + Helicopter:SetState( Helicopter, "Landing", true ) + + local Route = {} + +-- local CoordinateFrom = Helicopter:GetCoordinate() +-- local WaypointFrom = CoordinateFrom:WaypointAir( +-- "RADIO", +-- POINT_VEC3.RoutePointType.TurningPoint, +-- POINT_VEC3.RoutePointAction.TurningPoint, +-- Speed, +-- true +-- ) +-- Route[#Route+1] = WaypointFrom + local CoordinateTo = Coordinate + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 50, + true + ) + Route[#Route+1] = WaypointTo + + local Tasks = {} + Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) + + Route[#Route+1] = WaypointTo + + -- Now route the helicopter + Helicopter:Route( Route, 0 ) + else + self:__Queue( -10, Coordinate ) + end + end end - end @@ -277,56 +306,48 @@ end -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed ) +function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate ) - if Helicopter and Helicopter:IsAlive() ~= nil then - - self.RouteDeploy = true - - local Route = {} + if Helicopter and Helicopter:IsAlive() then - --- Calculate the target route point. --- local CoordinateFrom = Helicopter:GetCoordinate() - local CoordinateTo = Coordinate - - --- Create a route point of type air. --- local WaypointFrom = CoordinateFrom:WaypointAir( --- "RADIO", --- POINT_VEC3.RoutePointType.TurningPoint, --- POINT_VEC3.RoutePointAction.TurningPoint, --- Speed, --- true --- ) - - --- Create a route point of type air. - local WaypointTo = CoordinateTo:WaypointAir( - "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - Speed, - true - ) - --- Route[#Route+1] = WaypointFrom - Route[#Route+1] = WaypointTo + Helicopter:ClearState( Helicopter, "Landing" ) - --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... - Helicopter:WayPointInitialize( Route ) + if not self:IsTransporting() then + local Route = {} + + -- local CoordinateFrom = Helicopter:GetCoordinate() + -- local WaypointFrom = CoordinateFrom:WaypointAir( + -- "RADIO", + -- POINT_VEC3.RoutePointType.TurningPoint, + -- POINT_VEC3.RoutePointAction.TurningPoint, + -- Speed, + -- true + -- ) + -- Route[#Route+1] = WaypointFrom + local CoordinateTo = Coordinate + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 50, + true + ) + Route[#Route+1] = WaypointTo + + local Tasks = {} + Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 80 ), 0, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) - local Tasks = {} - - Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) - Route[#Route].task = Helicopter:TaskCombo( Tasks ) - - Route[#Route+1] = WaypointTo - - -- Now route the helicopter - Helicopter:Route( Route, 1 ) + Route[#Route+1] = WaypointTo + + -- Now route the helicopter + Helicopter:Route( Route, 0 ) + end end - end + --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To, Coordinate ) @@ -475,4 +496,203 @@ function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Carg end +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Group#GROUP Helicopter +function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To, Cargo, Deployed ) + + self:Orbit( Helicopter:GetCoordinate(), 50 ) + +end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Group#GROUP Helicopter +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate ) + + if Helicopter and Helicopter:IsAlive() ~= nil then + + self:ScheduleOnce( 10, Helicopter.ClearState, Helicopter, Helicopter, "Landing" ) + Helicopter:Activate() + + self.RoutePickup = true + Coordinate.y = math.random( 50, 200 ) + + local Route = {} + + --- Calculate the target route point. + local CoordinateFrom = Helicopter:GetCoordinate() + local CoordinateTo = Coordinate + + --- Create a route point of type air. + local WaypointFrom = CoordinateFrom:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 150, + true + ) + + --- Create a route point of type air. + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 150, + true + ) + + Route[#Route+1] = WaypointFrom + Route[#Route+1] = WaypointTo + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Helicopter:WayPointInitialize( Route ) + + local Tasks = {} + + Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) + + Route[#Route+1] = WaypointTo + + -- Now route the helicopter + Helicopter:Route( Route, 1 ) + + self.Transporting = true + end + +end + + +function AI_CARGO_HELICOPTER:_Deploy( AICargoHelicopter, Coordinate ) + AICargoHelicopter:__Queue( -10, Coordinate, 100 ) +end + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Group#GROUP Helicopter +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate ) + + if Helicopter and Helicopter:IsAlive() ~= nil then + + self.RouteDeploy = true + + + local Route = {} + + --- Calculate the target route point. + + Coordinate.y = math.random( 50, 200 ) + + --- Create a route point of type air. + local CoordinateFrom = Helicopter:GetCoordinate() + local WaypointFrom = CoordinateFrom:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 150, + true + ) + Route[#Route+1] = WaypointFrom + Route[#Route+1] = WaypointFrom + + --- Create a route point of type air. + local CoordinateTo = Coordinate + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 150, + true + ) + + Route[#Route+1] = WaypointTo + Route[#Route+1] = WaypointTo + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Helicopter:WayPointInitialize( Route ) + + local Tasks = {} + + Tasks[#Tasks+1] = Helicopter:TaskFunction( "AI_CARGO_HELICOPTER._Deploy", self, Coordinate ) + Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), 0, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) ) + + --Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) + + Route[#Route+1] = WaypointTo + + -- Now route the helicopter + Helicopter:Route( Route, 1 ) + + end + +end + + +--- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Group#GROUP Helicopter +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate ) + + if Helicopter and Helicopter:IsAlive() ~= nil then + + self.RouteHome = true + + local Route = {} + + --- Calculate the target route point. + + Coordinate.y = math.random( 50, 200 ) + + --- Create a route point of type air. + local CoordinateFrom = Helicopter:GetCoordinate() + local WaypointFrom = CoordinateFrom:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 150, + true + ) + Route[#Route+1] = WaypointFrom + + --- Create a route point of type air. + local CoordinateTo = Coordinate + local WaypointTo = CoordinateTo:WaypointAir( + "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + 150, + true + ) + + Route[#Route+1] = WaypointTo + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Helicopter:WayPointInitialize( Route ) + + local Tasks = {} + + Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) + Route[#Route].task = Helicopter:TaskCombo( Tasks ) + + Route[#Route+1] = WaypointTo + + -- Now route the helicopter + Helicopter:Route( Route, 1 ) + + end + +end diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 1bdcbf263..4780a8f55 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -488,6 +488,36 @@ do -- CARGO_GROUP return nil end + --- Get the x position of the cargo. + -- @param #CARGO_GROUP self + -- @return #number + function CARGO:GetX() + + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO + + if Cargo then + return Cargo:GetCoordinate().x + end + + return nil + end + + --- Get the y position of the cargo. + -- @param #CARGO_GROUP self + -- @return #number + function CARGO:GetY() + + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO + + if Cargo then + return Cargo:GetCoordinate().z + end + + return nil + end + + + --- Check if the CargoGroup is alive. -- @param #CARGO_GROUP self -- @return #boolean true if the CargoGroup is alive. diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index c7580db68..1a57a4b2b 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -244,6 +244,52 @@ function DATABASE:FindAirbase( AirbaseName ) end +do -- Zones + + --- Finds a @{Zone} based on the zone name. + -- @param #DATABASE self + -- @param #string ZoneName The name of the zone. + -- @return Core.Zone#ZONE_BASE The found ZONE. + function DATABASE:FindZone( ZoneName ) + + local ZoneFound = self.ZONES[ZoneName] + return ZoneFound + end + + --- Adds a @{Zone} based on the zone name in the DATABASE. + -- @param #DATABASE self + -- @param #string ZoneName The name of the zone. + -- @param Core.Zone#ZONE_BASE Zone The zone. + function DATABASE:AddZone( ZoneName, Zone ) + + if not self.ZONES[ZoneName] then + self.ZONES[ZoneName] = Zone + end + end + + + --- Deletes a @{Zone} from the DATABASE based on the zone name. + -- @param #DATABASE self + -- @param #string ZoneName The name of the zone. + function DATABASE:DeleteZone( ZoneName ) + + self.ZONES[ZoneName] = nil + end + + --- Finds an @{Zone} based on the zone name in the DATABASE. + -- @param #DATABASE self + -- @param #string ZoneName + -- @return Core.Zone#ZONE_BASE The found @{Zone}. + function DATABASE:FindZone( ZoneName ) + + local ZoneFound = self.ZONES[ZoneName] + return ZoneFound + end + + + +end + do -- cargo @@ -1148,7 +1194,7 @@ function DATABASE:_RegisterTemplates() for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do local ZoneName = ZoneData.name self.ZONENAMES[ZoneName] = ZoneName - self.ZONES[ZoneName] = ZONE:New( ZoneName ) + self:AddZone( ZoneName, ZONE:New( ZoneName ) ) self:I( "Added ZONE " .. ZoneName ) end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 8c05d8a14..36571c15b 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -114,6 +114,8 @@ function ZONE_BASE:New( ZoneName ) return self end + + --- Returns the name of the zone. -- @param #ZONE_BASE self -- @return #string The name of the zone. @@ -962,6 +964,17 @@ function ZONE:New( ZoneName ) return self end +--- Find a zone in the _DATABASE using the name of the zone. +-- @param #ZONE_BASE self +-- @param #string ZoneName The name of the zone. +-- @return #ZONE_BASE self +function ZONE:FindByName( ZoneName ) + + local ZoneFound = _DATABASE:FindZone( ZoneName ) + return ZoneFound +end + + --- @type ZONE_UNIT -- @field Wrapper.Unit#UNIT ZoneUNIT diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 738b04963..04576498f 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -798,15 +798,16 @@ end -- @param #CONTROLLABLE self -- @param #number Altitude The altitude to hold the position. -- @param #number Speed The speed flying when holding the position. +-- @param Core.Point#COORDINATE Coordinate The coordinate where to orbit. -- @return #CONTROLLABLE self -function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed ) +function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed, Coordinate ) self:F2( { self.ControllableName, Altitude, Speed } ) local DCSControllable = self:GetDCSObject() if DCSControllable then - local ControllablePoint = self:GetVec2() - return self:TaskOrbitCircleAtVec2( ControllablePoint, Altitude, Speed ) + local OrbitVec2 = Coordinate and Coordinate:GetVec2() or self:GetVec2() + return self:TaskOrbitCircleAtVec2( OrbitVec2, Altitude, Speed ) end return nil From 8db5351ad73c975050910d6fd356db24454ee69a Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 12 May 2018 15:42:15 +0200 Subject: [PATCH 104/170] ARTY v0.9.1 Added option to not engage an already assigned target. Fixed bug in _checkname function. --- .../Moose/Functional/Artillery.lua | 80 ++++++++++++++----- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 4a00da6e5..c38ee1fad 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -385,7 +385,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.0" +ARTY.version="0.9.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -525,12 +525,13 @@ end -- @param #string time (Optional) Day time at which the target should be engaged. Passed as a string in format "08:13:45". Current task will be canceled. -- @param #number weapontype (Optional) Type of weapon to be used to attack this target. Default ARTY.WeaponType.Auto, i.e. the DCS logic automatically determins the appropriate weapon. -- @param #string name (Optional) Name of the target. Default is LL DMS coordinate of the target. If the name was already given, the numbering "#01", "#02",... is appended automatically. +-- @param #boolean unique (Optional) Target is unique. If the target name is already known, the target is rejected. Default false. -- @return #string Name of the target. Can be used for further reference, e.g. deleting the target from the list. -- @usage paladin=ARTY:New(GROUP:FindByName("Blue Paladin")) -- paladin:AssignTargetCoord(GROUP:FindByName("Red Targets 1"):GetCoordinate(), 10, 300, 10, 1, "08:02:00", ARTY.WeaponType.Auto, "Target 1") -- paladin:Start() -function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, weapontype, name) - self:F({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype, name=name}) +function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, weapontype, name, unique) + self:F({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype, name=name, unique=unique}) -- Set default values. nshells=nshells or 5 @@ -539,13 +540,23 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w prio=prio or 50 prio=math.max( 1, prio) prio=math.min(100, prio) + if unique==nil then + unique=false + end weapontype=weapontype or ARTY.WeaponType.Auto -- Name of the target. local _name=name or coord:ToStringLLDMS() + local _unique=true -- Check if the name has already been used for another target. If so, the function returns a new unique name. - _name=self:_CheckName(self.targets, _name) + _name,_unique=self:_CheckName(self.targets, _name, not unique) + + -- Target name should be unique and is not. + if unique==true and _unique==false then + self:T(ARTY.id..string.format("%s: target %s should have a unique name but name was already given. Rejecting target!", self.Controllable:GetName(), _name)) + return nil + end -- Time in seconds. local _time=self:_ClockToSeconds(time) @@ -2085,44 +2096,71 @@ end ---- Check if a name is unique. If not, a new unique name is created by adding a running index #01, #02, ... +--- Check if a name is unique. If not, a new unique name can be created by adding a running index #01, #02, ... -- @param #ARTY self -- @param #table givennames Table with entries of already given names. Must contain a .name item. --- @param #string name Desired name. +-- @param #string name Name to check if it already exists in givennames table. +-- @param #boolean makeunique If true, a new unique name is returned by appending the running index. -- @return #string Unique name, which is not already given for another target. -function ARTY:_CheckName(givennames, name) +function ARTY:_CheckName(givennames, name, makeunique) self:F2({givennames=givennames, name=name}) local newname=name local counter=1 + local n=1 + local nmax=100 + if makeunique==nil then + makeunique=true + end + + repeat -- until a unique name is found. - repeat -- We assume the name is unique. - local unique=true + local _unique=true -- Loop over all targets already defined. for _,_target in pairs(givennames) do -- Target name. - local _givenname=givennames.name + local _givenname=_target.name + -- Name is already used by another target. if _givenname==newname then - -- Define new name = "name #01" - newname=string.format("%s #%02d", name, counter) - - -- Increase counter. - counter=counter+1 - + -- Name is already used for another target ==> try again with new name. - unique=false - end + _unique=false + + end + + -- Debug info. + self:T3(ARTY.id..string.format("%d: givenname = %s, newname=%s, unique = %s, makeunique = %s", n, tostring(_givenname), newname, tostring(_unique), tostring(makeunique))) end - until (unique) + -- Create a new name if requested and try again. + if _unique==false and makeunique==true then + + -- Define newname = "name #01" + newname=string.format("%s #%02d", name, counter) + + -- Increase counter. + counter=counter+1 + end + + -- Name is not unique and we don't want to make it unique. + if _unique==false and makeunique==false then + self:T3(ARTY.id..string.format("Name %s is not unique. Return false.", tostring(newname))) + + -- Return + return name, false + end + + -- Increase loop counter. We try max 100 times. + n=n+1 + until (_unique or n==nmax) -- Debug output and return new name. - self:T2(string.format("Original name %s, new name = %s", name, newname)) - return newname + self:T3(ARTY.id..string.format("Original name %s, new name = %s", name, newname)) + return newname, true end --- Check if target is in range. From 0e0ab3507c761928475c0b5fe38c611810a570f8 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 13 May 2018 15:57:28 +0200 Subject: [PATCH 105/170] Okay, fixed the problem with the crashing at the deploy zone. Also added methods to set and/or randomize the pickup speed, pickup radius, deploy speed, deploy radius. --- .../Moose/AI/AI_Cargo_Dispatcher.lua | 145 ++++++++++++++++-- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 5 + .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 5 + .../Moose/AI/AI_Cargo_Helicopter.lua | 55 +++---- Moose Development/Moose/Core/Zone.lua | 18 +-- 5 files changed, 172 insertions(+), 56 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index dd03c258e..ad72a1cff 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -113,6 +113,125 @@ function AI_CARGO_DISPATCHER:SetHomeZone( HomeZone ) end +--- Sets or randomizes the pickup location for the carrier around the cargo coordinate in a radius defined an outer and optional inner radius. +-- This radius is influencing the location where the carrier will land to pickup the cargo. +-- There are two aspects that are very important to remember and take into account: +-- +-- - Ensure that the outer and inner radius are within reporting radius set by the cargo. +-- For example, if the cargo has a reporting radius of 400 meters, and the outer and inner radius is set to 500 and 450 respectively, +-- then no cargo will be loaded!!! +-- - Also take care of the potential cargo position and possible reasons to crash the carrier. This is especially important +-- for locations which are crowded with other objects, like in the middle of villages or cities. +-- So, for the best operation of cargo operations, always ensure that the cargo is located at open spaces. +-- +-- The default radius is 0, so the center. In case of a polygon zone, a random location will be selected as the center in the zone. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number OuterRadius The outer radius in meters around the cargo coordinate. +-- @param #number InnerRadius (optional) The inner radius in meters around the cargo coordinate. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters! +-- AICargoDispatcher:SetPickupRadius( 500, 300 ) +-- +function AI_CARGO_DISPATCHER:SetPickupRadius( OuterRadius, InnerRadius ) + + OuterRadius = OuterRadius or 0 + InnerRadius = InnerRadius or OuterRadius + + self.PickupOuterRadius = OuterRadius + self.PickupInnerRadius = InnerRadius + + return self +end + + +--- Set the speed or randomizes the speed in km/h to pickup the cargo. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number MaxSpeed (optional) The maximum speed to move to the cargo pickup location. +-- @param #number MinSpeed The minimum speed to move to the cargo pickup location. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the minimum pickup speed to be 100 km/h and the maximum speed to be 200 km/h. +-- AICargoDispatcher:SetPickupSpeed( 200, 100 ) +-- +function AI_CARGO_DISPATCHER:SetPickupSpeed( MaxSpeed, MinSpeed ) + + MaxSpeed = MaxSpeed or 999 + MinSpeed = MinSpeed or MaxSpeed + + self.PickupMinSpeed = MinSpeed + self.PickupMaxSpeed = MaxSpeed + + return self +end + + +--- Sets or randomizes the deploy location for the carrier around the cargo coordinate in a radius defined an outer and an optional inner radius. +-- This radius is influencing the location where the carrier will land to deploy the cargo. +-- There is an aspect that is very important to remember and take into account: +-- +-- - Take care of the potential cargo position and possible reasons to crash the carrier. This is especially important +-- for locations which are crowded with other objects, like in the middle of villages or cities. +-- So, for the best operation of cargo operations, always ensure that the cargo is located at open spaces. +-- +-- The default radius is 0, so the center. In case of a polygon zone, a random location will be selected as the center in the zone. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number OuterRadius The outer radius in meters around the cargo coordinate. +-- @param #number InnerRadius (optional) The inner radius in meters around the cargo coordinate. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters! +-- AICargoDispatcher:SetDeployRadius( 500, 300 ) +-- +function AI_CARGO_DISPATCHER:SetDeployRadius( OuterRadius, InnerRadius ) + + OuterRadius = OuterRadius or 0 + InnerRadius = InnerRadius or OuterRadius + + self.DeployOuterRadius = OuterRadius + self.DeployInnerRadius = InnerRadius + + return self +end + + +--- Sets or randomizes the speed in km/h to deploy the cargo. +-- @param #AI_CARGO_DISPATCHER self +-- @param #number MaxSpeed The maximum speed to move to the cargo deploy location. +-- @param #number MinSpeed (optional) The minimum speed to move to the cargo deploy location. +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- +-- -- Set the minimum deploy speed to be 100 km/h and the maximum speed to be 200 km/h. +-- AICargoDispatcher:SetDeploySpeed( 200, 100 ) +-- +function AI_CARGO_DISPATCHER:SetDeploySpeed( MaxSpeed, MinSpeed ) + + MaxSpeed = MaxSpeed or 999 + MinSpeed = MinSpeed or MaxSpeed + + self.DeployMinSpeed = MinSpeed + self.DeployMaxSpeed = MaxSpeed + + return self +end + + --- The Start trigger event, which actually takes action at the specified time interval. -- @param #AI_CARGO_DISPATCHER self @@ -168,16 +287,16 @@ function AI_CARGO_DISPATCHER:onafterMonitor() local Cargo = Cargo -- Cargo.Cargo#CARGO self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Cargo] ~= nil } ) if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then - local CargoVec2 = { x = Cargo:GetX(), y = Cargo:GetY() } - local LocationFound = false - for APC, Vec2 in pairs( self.PickupCargo ) do - if Vec2.x == CargoVec2.x and Vec2.y == CargoVec2.y then - LocationFound = true + local CargoCoordinate = Cargo:GetCoordinate() + local CoordinateFree = true + for APC, Coordinate in pairs( self.PickupCargo ) do + if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then + CoordinateFree = false break end end - if LocationFound == false then - self.PickupCargo[Carrier] = CargoVec2 + if CoordinateFree == true then + self.PickupCargo[Carrier] = CargoCoordinate PickupCargo = Cargo break end @@ -185,13 +304,14 @@ function AI_CARGO_DISPATCHER:onafterMonitor() end if PickupCargo then self.CarrierHome[Carrier] = nil - AI_Cargo:Pickup( PickupCargo:GetCoordinate() ) + local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius ) + AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) ) break else if self.HomeZone then if not self.CarrierHome[Carrier] then self.CarrierHome[Carrier] = true - AI_Cargo:Home( self.HomeZone:GetRandomPointVec2() ) + AI_Cargo:__Home( 10, self.HomeZone:GetRandomPointVec2() ) end end end @@ -220,10 +340,11 @@ end function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) self:I( { "Loaded Dispatcher", APC } ) - local RandomZone = self.SetDeployZones:GetRandomZone() - self:I( { RandomZone = RandomZone } ) + local DeployZone = self.SetDeployZones:GetRandomZone() + self:I( { RandomZone = DeployZone } ) - self.AI_Cargo[APC]:Deploy( RandomZone:GetCoordinate(), 70 ) + local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius ) + self.AI_Cargo[APC]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) self.PickupCargo[APC] = nil diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index 67d2a2c92..7081bd45e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -50,6 +50,11 @@ function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones ) self.CombatRadius = 500 + self:SetDeploySpeed( 70, 120 ) + self:SetPickupSpeed( 70, 120 ) + self:SetPickupRadius( 0, 0 ) + self:SetDeployRadius( 0, 0 ) + self:Monitor( 1 ) return self diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index 56c4dae78..062b696a1 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -48,6 +48,11 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZ local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER + self:SetDeploySpeed( 200, 150 ) + self:SetPickupSpeed( 200, 150 ) + self:SetPickupRadius( 0, 0 ) + self:SetDeployRadius( 0, 0 ) + self:Monitor( 1 ) return self diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 695deb248..44ef641f5 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -22,7 +22,7 @@ AI_CARGO_HELICOPTER = { Coordinate = nil -- Core.Point#COORDINATE, } -AI_CARGO_HELICOPTER_QUEUE = {} +AI_CARGO_QUEUE = {} --- Creates a new AI_CARGO_HELICOPTER object. -- @param #AI_CARGO_HELICOPTER self @@ -225,43 +225,31 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina local HelicopterInZone = false - --- @param Wrapper.Unit#UNIT ZoneUnit - local function EvaluateZone( ZoneUnit ) - - if ZoneUnit:IsAlive() then - local ZoneUnitCategory = ZoneUnit:GetDesc().category - local ZoneGroup = ZoneUnit:GetGroup() - if ZoneUnitCategory == Unit.Category.HELICOPTER then - local State = ZoneGroup:GetState( ZoneGroup, "Landing" ) - self:F({ZoneUnit=ZoneUnit:GetName(), State=State, UnitCategory = Unit.Category.HELICOPTER } ) - if State == true then - HelicopterInZone = true - return false - end - end - end - - return true - end - if Helicopter and Helicopter:IsAlive() then local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() ) - if Distance > 300 then + if Distance > 500 then self:__Queue( -10, Coordinate ) else - -- This will search the zone and will call the local function "EvaluateZone", which passes a UNIT object. - local Zone = ZONE_RADIUS:New( "Deploy", Coordinate:GetVec2(), 300 ) - Zone:SearchZone( EvaluateZone ) + local ZoneFree = true + + for Helicopter, ZoneQueue in pairs( AI_CARGO_QUEUE ) do + local ZoneQueue = ZoneQueue -- Core.Zone#ZONE_RADIUS + if ZoneQueue:IsCoordinateInZone( Coordinate ) then + ZoneFree = false + end + end - self:F({HelicopterInZone=HelicopterInZone}) + self:F({ZoneFree=ZoneFree}) - if HelicopterInZone == false then + if ZoneFree == true then - Helicopter:SetState( Helicopter, "Landing", true ) - + local ZoneQueue = ZONE_RADIUS:New( Helicopter:GetName(), Coordinate:GetVec2(), 100 ) + + AI_CARGO_QUEUE[Helicopter] = ZoneQueue + local Route = {} -- local CoordinateFrom = Helicopter:GetCoordinate() @@ -310,8 +298,6 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina if Helicopter and Helicopter:IsAlive() then - Helicopter:ClearState( Helicopter, "Landing" ) - if not self:IsTransporting() then local Route = {} @@ -436,6 +422,7 @@ function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To, Deploye local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do Cargo:UnBoard() + Cargo:SetDeployed( true ) self:__Unboard( 10, Cargo, Deployed ) end end @@ -483,7 +470,6 @@ function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Carg if Deployed == true then for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - Cargo:SetDeployed( true ) end self.Helicopter_Cargo = {} end @@ -500,7 +486,9 @@ end -- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To, Cargo, Deployed ) - self:Orbit( Helicopter:GetCoordinate(), 50 ) + self:Orbit( Helicopter:GetCoordinate(), 50 ) + + AI_CARGO_QUEUE[Helicopter] = nil end @@ -515,7 +503,6 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin if Helicopter and Helicopter:IsAlive() ~= nil then - self:ScheduleOnce( 10, Helicopter.ClearState, Helicopter, Helicopter, "Landing" ) Helicopter:Activate() self.RoutePickup = true @@ -690,7 +677,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat Route[#Route+1] = WaypointTo -- Now route the helicopter - Helicopter:Route( Route, 1 ) + Helicopter:Route( Route, 0 ) end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 36571c15b..cdc58b48a 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -151,10 +151,16 @@ end -- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. -- @return #boolean true if the Vec3 is within the zone. function ZONE_BASE:IsVec3InZone( Vec3 ) - self:F2( Vec3 ) - local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) + return InZone +end +--- Returns if a Coordinate is within the zone. +-- @param #ZONE_BASE self +-- @param Core.Point#COORDINATE Coordinate The coordinate to test. +-- @return #boolean true if the coordinate is within the zone. +function ZONE_BASE:IsCoordinateInZone( Coordinate ) + local InZone = self:IsVec2InZone( Coordinate:GetVec2() ) return InZone end @@ -163,10 +169,7 @@ end -- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to test. -- @return #boolean true if the PointVec2 is within the zone. function ZONE_BASE:IsPointVec2InZone( PointVec2 ) - self:F2( PointVec2 ) - local InZone = self:IsVec2InZone( PointVec2:GetVec2() ) - return InZone end @@ -175,10 +178,7 @@ end -- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test. -- @return #boolean true if the PointVec3 is within the zone. function ZONE_BASE:IsPointVec3InZone( PointVec3 ) - self:F2( PointVec3 ) - local InZone = self:IsPointVec2InZone( PointVec3 ) - return InZone end @@ -187,8 +187,6 @@ end -- @param #ZONE_BASE self -- @return #nil. function ZONE_BASE:GetVec2() - self:F2( self.ZoneName ) - return nil end From 7598a6ce5cff11edf2bf618e16a9d1c934e142f1 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 14 May 2018 06:53:45 +0200 Subject: [PATCH 106/170] Finish Cargo/AI_Cargo_Helicopter --- Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- Moose Development/Moose/AI/AI_Cargo_Helicopter.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index ad72a1cff..5362ea8a7 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -311,7 +311,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() if self.HomeZone then if not self.CarrierHome[Carrier] then self.CarrierHome[Carrier] = true - AI_Cargo:__Home( 10, self.HomeZone:GetRandomPointVec2() ) + AI_Cargo:__Home( 60, self.HomeZone:GetRandomPointVec2() ) end end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 44ef641f5..1efa9651b 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -617,7 +617,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin Route[#Route+1] = WaypointTo -- Now route the helicopter - Helicopter:Route( Route, 1 ) + Helicopter:Route( Route, 0 ) end From 48384ac7580ab4c1c74019b6dbda62bbe06e29b4 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 14 May 2018 08:12:15 +0200 Subject: [PATCH 107/170] Added the dynamic creation of a SET_ZONE, but you still need to declare all zones within the mission script. --- Moose Development/Moose/Core/Database.lua | 27 +++++++++++++ Moose Development/Moose/Core/Event.lua | 49 +++++++++++++++++++++++ Moose Development/Moose/Core/Set.lua | 41 +++++++++++++++++++ Moose Development/Moose/Core/Zone.lua | 6 +++ 4 files changed, 123 insertions(+) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 1a57a4b2b..995d243a3 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -96,6 +96,8 @@ function DATABASE:New() self:HandleEvent( EVENTS.Hit, self.AccountHits ) self:HandleEvent( EVENTS.NewCargo ) self:HandleEvent( EVENTS.DeleteCargo ) + self:HandleEvent( EVENTS.NewZone ) + self:HandleEvent( EVENTS.DeleteZone ) -- Follow alive players and clients --self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event. @@ -1085,6 +1087,31 @@ function DATABASE:OnEventDeleteCargo( EventData ) end +--- Handles the OnEventNewZone event. +-- @param #DATABASE self +-- @param Core.Event#EVENTDATA EventData +function DATABASE:OnEventNewZone( EventData ) + self:F2( { EventData } ) + + if EventData.Zone then + self:AddZone( EventData.Zone ) + end +end + + +--- Handles the OnEventDeleteZone. +-- @param #DATABASE self +-- @param Core.Event#EVENTDATA EventData +function DATABASE:OnEventDeleteZone( EventData ) + self:F2( { EventData } ) + + if EventData.Zone then + self:DeleteZone( EventData.Zone.ZoneName ) + end +end + + + --- Gets the player settings -- @param #DATABASE self -- @param #string PlayerName diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index fafd2d2c5..007624e1a 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -179,6 +179,8 @@ EVENT = { world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000 world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001 +world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002 +world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003 --- The different types of events supported by MOOSE. -- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method. @@ -209,6 +211,8 @@ EVENTS = { ShootingEnd = world.event.S_EVENT_SHOOTING_END, NewCargo = world.event.S_EVENT_NEW_CARGO, DeleteCargo = world.event.S_EVENT_DELETE_CARGO, + NewZone = world.event.S_EVENT_NEW_ZONE, + DeleteZone = world.event.S_EVENT_DELETE_ZONE, } --- The Event structure @@ -406,6 +410,16 @@ local _EVENTMETA = { Event = "OnEventDeleteCargo", Text = "S_EVENT_DELETE_CARGO" }, + [EVENTS.NewZone] = { + Order = 1, + Event = "OnEventNewZone", + Text = "S_EVENT_NEW_ZONE" + }, + [EVENTS.DeleteZone] = { + Order = 1, + Event = "OnEventDeleteZone", + Text = "S_EVENT_DELETE_ZONE" + }, } @@ -710,6 +724,36 @@ do -- Event Creation world.onEvent( Event ) end + --- Creation of a New Zone Event. + -- @param #EVENT self + -- @param Core.Zone#ZONE_BASE Zone The Zone created. + function EVENT:CreateEventNewZone( Zone ) + self:F( { Zone } ) + + local Event = { + id = EVENTS.NewZone, + time = timer.getTime(), + zone = Zone, + } + + world.onEvent( Event ) + end + + --- Creation of a Zone Deletion Event. + -- @param #EVENT self + -- @param Core.Zone#ZONE_BASE Zone The Zone created. + function EVENT:CreateEventDeleteZone( Zone ) + self:F( { Zone } ) + + local Event = { + id = EVENTS.DeleteZone, + time = timer.getTime(), + zone = Zone, + } + + world.onEvent( Event ) + end + --- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event. -- @param #EVENT self -- @param Wrapper.Unit#UNIT PlayerUnit. @@ -873,6 +917,11 @@ function EVENT:onEvent( Event ) Event.Cargo = Event.cargo Event.CargoName = Event.cargo.Name end + + if Event.zone then + Event.Zone = Event.zone + Event.ZoneName = Event.zone.ZoneName + end local PriorityOrder = EventMeta.Order local PriorityBegin = PriorityOrder == -1 and 5 or 1 diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index b29d1d6fa..71e85a8ee 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4656,6 +4656,9 @@ function SET_ZONE:FilterStart() end end end + + self:HandleEvent( EVENTS.NewZone ) + self:HandleEvent( EVENTS.DeleteZone ) return self end @@ -4726,3 +4729,41 @@ function SET_ZONE:IsIncludeObject( MZone ) return MZoneInclude end +--- Handles the OnEventNewZone event for the Set. +-- @param #SET_ZONE self +-- @param Core.Event#EVENTDATA EventData +function SET_ZONE:OnEventNewZone( EventData ) --R2.1 + + self:F( { "New Zone", EventData } ) + + if EventData.Zone then + if EventData.Zone and self:IsIncludeObject( EventData.Zone ) then + self:Add( EventData.Zone.ZoneName , EventData.Zone ) + end + end +end + +--- Handles the OnDead or OnCrash event for alive units set. +-- @param #SET_ZONE self +-- @param Core.Event#EVENTDATA EventData +function SET_ZONE:OnEventDeleteZone( EventData ) --R2.1 + self:F3( { EventData } ) + + if EventData.Zone then + local Zone = _DATABASE:FindZone( EventData.Zone.ZoneName ) + if Zone and Zone.ZoneName then + + -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. + -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. + -- And this is a problem because it will remove all entries from the SET_ZONEs. + -- To prevent this from happening, the Zone object has a flag NoDestroy. + -- When true, the SET_ZONE won't Remove the Zone object from the set. + -- This flag is switched off after the event handlers have been called in the EVENT class. + self:F( { ZoneNoDestroy=Zone.NoDestroy } ) + if Zone.NoDestroy then + else + self:Remove( Zone.ZoneName ) + end + end + end +end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index cdc58b48a..d3239c039 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1001,6 +1001,9 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius ) self.ZoneUNIT = ZoneUNIT self.LastVec2 = ZoneUNIT:GetVec2() + -- Zone objects are added to the _DATABASE and SET_ZONE objects. + _EVENTDISPATCHER:CreateEventNewZone( self ) + return self end @@ -1089,6 +1092,9 @@ function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) self:F( { ZoneName, ZoneGROUP:GetVec2(), Radius } ) self._.ZoneGROUP = ZoneGROUP + + -- Zone objects are added to the _DATABASE and SET_ZONE objects. + _EVENTDISPATCHER:CreateEventNewZone( self ) return self end From ac72e6fad2cc1208f870074c8ff2839bbb60d2fa Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 15 May 2018 19:02:17 +0200 Subject: [PATCH 108/170] Zone probability implementation. --- Moose Development/Moose/Core/Set.lua | 35 +++++++++++++++++++++------ Moose Development/Moose/Core/Zone.lua | 21 ++++++++++++++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 71e85a8ee..e00d350db 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4606,20 +4606,39 @@ end --- Get a random zone from the set. -- @param #SET_ZONE self -- @return Core.Zone#ZONE_BASE The random Zone. +-- @return #nil if no zone in the collection. function SET_ZONE:GetRandomZone() - local Index = self.Index - local ZoneFound = nil - - while not ZoneFound do - local ZoneRandom = math.random( 1, #Index ) - ZoneFound = self.Set[Index[ZoneRandom]] - end + if self:Count() ~= 0 then - return ZoneFound + local Index = self.Index + local ZoneFound = nil -- Core.Zone#ZONE_BASE + + -- Loop until a zone has been found. + -- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected. + -- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues! + while not ZoneFound do + local ZoneRandom = math.random( 1, #Index ) + ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe() + end + + return ZoneFound + end + + return nil end +--- Set a zone probability. +-- @param #SET_ZONE self +-- @param #string ZoneName The name of the zone. +function SET_ZONE:SetZoneProbability( ZoneName, ZoneProbability ) + local Zone = self:FindZone( ZoneName ) + Zone:SetZoneProbability( ZoneProbability ) +end + + + --- Builds a set of zones of defined zone prefixes. -- All the zones starting with the given prefixes will be included within the set. diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index d3239c039..11b85b3b2 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -341,6 +341,27 @@ end -- @param #ZONE_BASE self -- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor. -- @return #nil The zone is not selected taking into account the randomization probability factor. +-- @usage +-- +-- local ZoneArray = { ZONE:New( "Zone1" ), ZONE:New( "Zone2" ) } +-- +-- -- We set a zone probability of 70% to the first zone and 30% to the second zone. +-- ZoneArray[1]:SetZoneProbability( 0.5 ) +-- ZoneArray[2]:SetZoneProbability( 0.5 ) +-- +-- local ZoneSelected = nil +-- +-- while ZoneSelected == nil do +-- for _, Zone in pairs( ZoneArray ) do +-- ZoneSelected = Zone:GetZoneMaybe() +-- if ZoneSelected ~= nil then +-- break +-- end +-- end +-- end +-- +-- -- The result should be that Zone1 would be more probable selected than Zone2. +-- function ZONE_BASE:GetZoneMaybe() self:F2() From 4309aa326f7e3bbcb97908fc01bee656a6a30d06 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 15 May 2018 19:06:55 +0200 Subject: [PATCH 109/170] Finish Cargo/AI_Cargo_Helicopter --- Moose Development/Moose/Core/Zone.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 11b85b3b2..e06713aa2 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -322,7 +322,7 @@ end -- @param #ZONE_BASE self -- @param ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. function ZONE_BASE:SetZoneProbability( ZoneProbability ) - self:F2( ZoneProbability ) + self:F( { Zone:GetName(), ZoneProbability = ZoneProbability } ) self.ZoneProbability = ZoneProbability or 1 return self From b82e85997f399a0252bc235c3a9575fbe9b2dc3d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 15 May 2018 19:13:11 +0200 Subject: [PATCH 110/170] # Conflicts: # Moose Development/Moose/Core/Zone.lua --- Moose Development/Moose/Core/Zone.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index e06713aa2..203105575 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -322,7 +322,7 @@ end -- @param #ZONE_BASE self -- @param ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. function ZONE_BASE:SetZoneProbability( ZoneProbability ) - self:F( { Zone:GetName(), ZoneProbability = ZoneProbability } ) + self:F( { self:GetName(), ZoneProbability = ZoneProbability } ) self.ZoneProbability = ZoneProbability or 1 return self From 533b5d035e1a6d95a805e3faaa136ef9db1faac9 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 17 May 2018 08:51:59 +0200 Subject: [PATCH 111/170] - Documentation - Added the methods Added and Removed to the SET - Cleanup of code. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 7 +- .../Moose/AI/AI_Cargo_Dispatcher.lua | 243 +++++++++++++----- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 66 ++++- .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 75 +++++- .../Moose/AI/AI_Cargo_Helicopter.lua | 12 +- Moose Development/Moose/Core/Set.lua | 145 ++++++++++- 6 files changed, 456 insertions(+), 92 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index b5d0a3f8a..0cb8aed9b 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -82,11 +82,11 @@ AI_CARGO_APC = { --- Creates a new AI_CARGO_APC object. -- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier +-- @param Wrapper.Group#GROUP APC -- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_APC -function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) +function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_APC @@ -189,7 +189,8 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:__Monitor( 1 ) - self:SetCarrier( CargoCarrier ) + + self:SetCarrier( APC ) self.Transporting = false self.Relocating = false diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 5362ea8a7..c0eed577e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -9,66 +9,115 @@ -- @module AI_Cargo_Dispatcher --- @type AI_CARGO_DISPATCHER --- @extends Core.Fsm#FSM_CONTROLLABLE +-- @extends Core.Fsm#FSM ---- # AI\_CARGO\_DISPATCHER class, extends @{Core.Base#BASE} +--- # AI\_CARGO\_DISPATCHER class, extends @{Core.Fsm#FSM} -- -- === -- -- AI\_CARGO\_DISPATCHER brings a dynamic cargo handling capability for AI groups. -- --- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. --- The AI\_CARGO\_DISPATCHER module uses the @{Cargo} capabilities within the MOOSE framework. +-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\_DISPATCHER module uses the @{Cargo} capabilities within the MOOSE framework, to enable Carrier GROUP objects +-- to transport @{Cargo} towards several deploy zones. -- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER object recognize the cargo. -- Please consult the @{Cargo} module for more information. -- +-- ## 1. AI\_CARGO\_DISPATCHER constructor +-- +-- * @{#AI_CARGO_DISPATCHER.New}(): Creates a new AI\_CARGO\_DISPATCHER object. -- +-- ## 2. AI\_CARGO\_DISPATCHER is a FSM -- +-- ![Process](..\Presentations\AI_PATROL\Dia2.JPG) +-- +-- ### 2.1. AI\_CARGO\_DISPATCHER States +-- +-- * **Monitoring**: The process is dispatching. +-- * **Idle**: The process is idle. +-- +-- ### 2.2. AI\_CARGO\_DISPATCHER Events +-- +-- * **Monitor**: Monitor and take action. +-- * **Start**: Start the transport process. +-- * **Stop**: Stop the transport process. +-- * **Pickup**: Pickup cargo. +-- * **Load**: Load the cargo. +-- * **Loaded**: Flag that the cargo is loaded. +-- * **Deploy**: Deploy cargo to a location. +-- * **Unload**: Unload the cargo. +-- * **Unloaded**: Flag that the cargo is unloaded. +-- * **Home**: A Carrier is going home. +-- +-- ## 3. Set the pickup parameters. +-- +-- Several parameters can be set to pickup cargo: +-- +-- * @{#AI_CARGO_DISPATCHER.SetPickupRadius}(): Sets or randomizes the pickup location for the carrier around the cargo coordinate in a radius defined an outer and optional inner radius. +-- * @{#AI_CARGO_DISPATCHER.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo. +-- +-- ## 4. Set the deploy parameters. +-- +-- Several parameters can be set to deploy cargo: +-- +-- * @{#AI_CARGO_DISPATCHER.SetDeployRadius}(): Sets or randomizes the deploy location for the carrier around the cargo coordinate in a radius defined an outer and an optional inner radius. +-- * @{#AI_CARGO_DISPATCHER.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo. +-- +-- ## 5. Set the home zone when there isn't any more cargo to pickup. +-- +-- A home zone can be specified to where the Carriers will move when there isn't any cargo left for pickup. +-- Use @{#AI_CARGO_DISPATCHER.SetHomeZone}() to specify the home zone. +-- +-- If no home zone is specified, the carriers will wait near the deploy zone for a new pickup command. +-- +-- === +-- -- @field #AI_CARGO_DISPATCHER AI_CARGO_DISPATCHER = { ClassName = "AI_CARGO_DISPATCHER", - SetAPC = nil, + SetCarrier = nil, SetDeployZones = nil, - AI_CARGO_APC = {} + AI_Cargo = {}, + PickupCargo = {} } ---- @type AI_CARGO_DISPATCHER.AI_CARGO_APC --- @map - ---- @field #AI_CARGO_DISPATCHER.AI_CARGO_APC +--- @field #AI_CARGO_DISPATCHER.AI_Cargo AI_CARGO_DISPATCHER.AI_Cargo = {} --- @field #AI_CARGO_DISPATCHER.PickupCargo AI_CARGO_DISPATCHER.PickupCargo = {} - --- Creates a new AI_CARGO_DISPATCHER object. -- @param #AI_CARGO_DISPATCHER self --- @param Core.Set#SET_GROUP SetAPC +-- @param Core.Set#SET_GROUP SetCarrier -- @param Core.Set#SET_CARGO SetCargo -- @param Core.Set#SET_ZONE SetDeployZone -- @return #AI_CARGO_DISPATCHER -- @usage -- -- -- Create a new cargo dispatcher --- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() +-- SetCarrier = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() -- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) -- -function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) +function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones ) local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER - self.SetAPC = SetAPC -- Core.Set#SET_GROUP + self.SetCarrier = SetCarrier -- Core.Set#SET_GROUP self.SetCargo = SetCargo -- Core.Set#SET_CARGO self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE - self:SetStartState( "Dispatch" ) + self:SetStartState( "Idle" ) + + self:AddTransition( "Monitoring", "Monitor", "Monitoring" ) + + self:AddTransition( "Idle", "Start", "Monitoring" ) + self:AddTransition( "Monitoring", "Stop", "Idle" ) - self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Pickup", "*" ) self:AddTransition( "*", "Loading", "*" ) @@ -84,8 +133,16 @@ function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) self.DeployRadiusInner = 200 self.DeployRadiusOuter = 500 + self.PickupCargo = {} self.CarrierHome = {} + -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset. + function SetCarrier.OnAfterRemoved( SetCarrier, From, Event, To, CarrierName, Carrier ) + self:F( { Carrier = Carrier:GetName() } ) + self.PickupCargo[Carrier] = nil + self.CarrierHome[Carrier] = nil + end + return self end @@ -99,7 +156,7 @@ end -- @usage -- -- -- Create a new cargo dispatcher --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) -- -- -- Set the home coordinate -- local HomeZone = ZONE:New( "Home" ) @@ -132,7 +189,7 @@ end -- @usage -- -- -- Create a new cargo dispatcher --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) -- -- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters! -- AICargoDispatcher:SetPickupRadius( 500, 300 ) @@ -157,7 +214,7 @@ end -- @usage -- -- -- Create a new cargo dispatcher --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) -- -- -- Set the minimum pickup speed to be 100 km/h and the maximum speed to be 200 km/h. -- AICargoDispatcher:SetPickupSpeed( 200, 100 ) @@ -190,7 +247,7 @@ end -- @usage -- -- -- Create a new cargo dispatcher --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) -- -- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters! -- AICargoDispatcher:SetDeployRadius( 500, 300 ) @@ -215,7 +272,7 @@ end -- @usage -- -- -- Create a new cargo dispatcher --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) -- -- -- Set the minimum deploy speed to be 100 km/h and the maximum speed to be 200 km/h. -- AICargoDispatcher:SetDeploySpeed( 200, 100 ) @@ -235,64 +292,66 @@ end --- The Start trigger event, which actually takes action at the specified time interval. -- @param #AI_CARGO_DISPATCHER self --- @param Wrapper.Group#GROUP APC --- @return #AI_CARGO_DISPATCHER function AI_CARGO_DISPATCHER:onafterMonitor() - for APCGroupName, Carrier in pairs( self.SetAPC:GetSet() ) do + for CarrierGroupName, Carrier in pairs( self.SetCarrier:GetSet() ) do local Carrier = Carrier -- Wrapper.Group#GROUP local AI_Cargo = self.AI_Cargo[Carrier] if not AI_Cargo then - -- ok, so this APC does not have yet an AI_CARGO_APC object... + -- ok, so this Carrier does not have yet an AI_CARGO handling object... -- let's create one and also declare the Loaded and UnLoaded handlers. self.AI_Cargo[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius ) AI_Cargo = self.AI_Cargo[Carrier] - function AI_Cargo.OnAfterPickup( AI_Cargo, APC, From, Event, To, Cargo ) - self:Pickup( APC, Cargo ) + function AI_Cargo.OnAfterPickup( AI_Cargo, Carrier, From, Event, To, Cargo ) + self:Pickup( Carrier, Cargo ) end - function AI_Cargo.OnAfterLoad( AI_Cargo, APC ) - self:Loading( APC ) + function AI_Cargo.OnAfterLoad( AI_Cargo, Carrier ) + self:Loading( Carrier ) end - function AI_Cargo.OnAfterLoaded( AI_Cargo, APC, From, Event, To, Cargo ) - self:Loaded( APC, Cargo ) + function AI_Cargo.OnAfterLoaded( AI_Cargo, Carrier, From, Event, To, Cargo ) + self:Loaded( Carrier, Cargo ) end - function AI_Cargo.OnAfterDeploy( AI_Cargo, APC ) - self:Deploy( APC ) + function AI_Cargo.OnAfterDeploy( AI_Cargo, Carrier ) + self:Deploy( Carrier ) end - function AI_Cargo.OnAfterUnload( AI_Cargo, APC ) - self:Unloading( APC ) + function AI_Cargo.OnAfterUnload( AI_Cargo, Carrier ) + self:Unloading( Carrier ) end - function AI_Cargo.OnAfterUnloaded( AI_Cargo, APC ) - self:Unloaded( APC ) + function AI_Cargo.OnAfterUnloaded( AI_Cargo, Carrier ) + self:Unloaded( Carrier ) end end -- The Pickup sequence ... - -- Check if this APC need to go and Pickup something... + -- Check if this Carrier need to go and Pickup something... self:I( { IsTransporting = AI_Cargo:IsTransporting() } ) if AI_Cargo:IsTransporting() == false then - -- ok, so there is a free APC + -- ok, so there is a free Carrier -- now find the first cargo that is Unloaded local PickupCargo = nil for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Cargo] ~= nil } ) + self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Carrier] ~= nil } ) if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then local CargoCoordinate = Cargo:GetCoordinate() local CoordinateFree = true - for APC, Coordinate in pairs( self.PickupCargo ) do - if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then - CoordinateFree = false - break + for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do + if CarrierPickup:IsAlive() == true then + if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then + CoordinateFree = false + break + end + else + self.PickupCargo[CarrierPickup] = nil end end if CoordinateFree == true then @@ -319,36 +378,90 @@ function AI_CARGO_DISPATCHER:onafterMonitor() end self:__Monitor( self.MonitorTimeInterval ) +end - return self +--- Start Handler OnBefore for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] OnBeforeStart +-- @param #AI_CARGO_DISPATCHER self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #boolean + +--- Start Handler OnAfter for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterStart +-- @param #AI_CARGO_DISPATCHER self +-- @param #string From +-- @param #string Event +-- @param #string To + +--- Start Trigger for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] Start +-- @param #AI_CARGO_DISPATCHER self + +--- Start Asynchronous Trigger for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] __Start +-- @param #AI_CARGO_DISPATCHER self +-- @param #number Delay + +function AI_CARGO_DISPATCHER:onafterStart( From, Event, To ) + self:Monitor() +end + +--- Stop Handler OnBefore for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] OnBeforeStop +-- @param #AI_CARGO_DISPATCHER self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #boolean + +--- Stop Handler OnAfter for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterStop +-- @param #AI_CARGO_DISPATCHER self +-- @param #string From +-- @param #string Event +-- @param #string To + +--- Stop Trigger for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] Stop +-- @param #AI_CARGO_DISPATCHER self + +--- Stop Asynchronous Trigger for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] __Stop +-- @param #AI_CARGO_DISPATCHER self +-- @param #number Delay + + + +--- Make a Carrier run for a cargo deploy action after the cargo Pickup trigger has been initiated, by default. +-- @param #AI_CARGO_DISPATCHER self +-- @param From +-- @param Event +-- @param To +-- @param Wrapper.Group#GROUP Carrier +-- @param Cargo.Cargo#CARGO Cargo +-- @return #AI_CARGO_DISPATCHER +function AI_CARGO_DISPATCHER:OnAfterPickup( From, Event, To, Carrier, Cargo ) end - ---- Make a APC run for a cargo deploy action after the cargo Pickup trigger has been initiated, by default. +--- Make a Carrier run for a cargo deploy action after the cargo has been loaded, by default. -- @param #AI_CARGO_DISPATCHER self --- @param Wrapper.Group#GROUP APC +-- @param From +-- @param Event +-- @param To +-- @param Wrapper.Group#GROUP Carrier +-- @param Cargo.Cargo#CARGO Cargo -- @return #AI_CARGO_DISPATCHER -function AI_CARGO_DISPATCHER:onafterPickup( From, Event, To, APC, Cargo ) - return self -end +function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo ) ---- Make a APC run for a cargo deploy action after the cargo has been loaded, by default. --- @param #AI_CARGO_DISPATCHER self --- @param Wrapper.Group#GROUP APC --- @return #AI_CARGO_DISPATCHER -function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo ) - - self:I( { "Loaded Dispatcher", APC } ) local DeployZone = self.SetDeployZones:GetRandomZone() - self:I( { RandomZone = DeployZone } ) local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius ) - self.AI_Cargo[APC]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) + self.AI_Cargo[Carrier]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) - self.PickupCargo[APC] = nil - - return self + self.PickupCargo[Carrier] = nil end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index 7081bd45e..d7b21b13d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -14,6 +14,8 @@ --- # AI\_CARGO\_DISPATCHER\_APC class, extends @{Core.Base#BASE} -- +-- ![Banner Image](..\Presentations\AI_CARGO_DISPATCHER_APC\Dia1.JPG) +-- -- === -- -- AI\_CARGO\_DISPATCHER\_APC brings a dynamic cargo handling capability for AI groups. @@ -23,7 +25,54 @@ -- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_APC object recognize the cargo. -- Please consult the @{Cargo} module for more information. -- +-- ## 1. AI\_CARGO\_DISPATCHER\_APC constructor +-- +-- * @{#AI_CARGO_DISPATCHER\_APC.New}(): Creates a new AI\_CARGO\_DISPATCHER\_APC object. -- +-- ## 2. AI\_CARGO\_DISPATCHER\_APC is a FSM +-- +-- ![Process](..\Presentations\AI_CARGO_DISPATCHER_APC\Dia3.JPG) +-- +-- ### 2.1. AI\_CARGO\_DISPATCHER\_APC States +-- +-- * **Monitoring**: The process is dispatching. +-- * **Idle**: The process is idle. +-- +-- ### 2.2. AI\_CARGO\_DISPATCHER\_APC Events +-- +-- * **Monitor**: Monitor and take action. +-- * **Start**: Start the transport process. +-- * **Stop**: Stop the transport process. +-- * **Pickup**: Pickup cargo. +-- * **Load**: Load the cargo. +-- * **Loaded**: Flag that the cargo is loaded. +-- * **Deploy**: Deploy cargo to a location. +-- * **Unload**: Unload the cargo. +-- * **Unloaded**: Flag that the cargo is unloaded. +-- * **Home**: A APC is going home. +-- +-- ## 3. Set the pickup parameters. +-- +-- Several parameters can be set to pickup cargo: +-- +-- * @{#AI_CARGO_DISPATCHER\_APC.SetPickupRadius}(): Sets or randomizes the pickup location for the APC around the cargo coordinate in a radius defined an outer and optional inner radius. +-- * @{#AI_CARGO_DISPATCHER\_APC.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo. +-- +-- ## 4. Set the deploy parameters. +-- +-- Several parameters can be set to deploy cargo: +-- +-- * @{#AI_CARGO_DISPATCHER\_APC.SetDeployRadius}(): Sets or randomizes the deploy location for the APC around the cargo coordinate in a radius defined an outer and an optional inner radius. +-- * @{#AI_CARGO_DISPATCHER\_APC.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo. +-- +-- ## 5. Set the home zone when there isn't any more cargo to pickup. +-- +-- A home zone can be specified to where the APCs will move when there isn't any cargo left for pickup. +-- Use @{#AI_CARGO_DISPATCHER\_APC.SetHomeZone}() to specify the home zone. +-- +-- If no home zone is specified, the APCs will wait near the deploy zone for a new pickup command. +-- +-- === -- -- @field #AI_CARGO_DISPATCHER_APC AI_CARGO_DISPATCHER_APC = { @@ -32,31 +81,30 @@ AI_CARGO_DISPATCHER_APC = { --- Creates a new AI_CARGO_DISPATCHER_APC object. -- @param #AI_CARGO_DISPATCHER_APC self --- @param Core.Set#SET_GROUP SetAPC --- @param Core.Set#SET_CARGO SetCargo --- @param Core.Set#SET_ZONE SetDeployZone +-- @param Core.Set#SET_GROUP SetAPC The collection of APC @{Group}s. +-- @param Core.Set#SET_CARGO SetCargo The collection of @{Cargo} derived objects. +-- @param Core.Set#SET_ZONE SetDeployZone The collection of deploy @{Zone}s, which are used to where the cargo will be deployed by the APCs. +-- @param #number CombatRadius The cargo will be unloaded from the APC and engage the enemy if the enemy is within CombatRadius range. The radius is in meters, the default value is 500 meters. -- @return #AI_CARGO_DISPATCHER_APC -- @usage -- --- -- Create a new cargo dispatcher +-- -- Create a new cargo dispatcher for the set of APCs, with a combatradius of 500. -- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() -- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() --- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, 500 ) -- -function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones ) +function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones, CombatRadius ) local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_APC - self.CombatRadius = 500 + self.CombatRadius = CombatRadius or 500 self:SetDeploySpeed( 70, 120 ) self:SetPickupSpeed( 70, 120 ) self:SetPickupRadius( 0, 0 ) self:SetDeployRadius( 0, 0 ) - self:Monitor( 1 ) - return self end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index 062b696a1..6a130eabe 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -1,5 +1,7 @@ --- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters. -- +-- The @{#AI_CARGO_DISPATCHER_HELICOPTER} classes implements the dynamic dispatching of cargo transportation tasks for helicopters. +-- -- === -- -- ### Author: **FlightControl** @@ -12,18 +14,77 @@ -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER ---- # AI\_CARGO\_DISPATCHER\_HELICOPTER class, extends @{Core.Base#BASE} +--- # AI\_CARGO\_DISPATCHER\_HELICOPTER class, extends @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} +-- +-- ![Banner Image](..\Presentations\AI_CARGO_DISPATCHER_HELICOPTER\Dia1.JPG) -- -- === -- --- AI\_CARGO\_DISPATCHER\_HELICOPTER brings a dynamic cargo handling capability for AI groups. +-- AI\_CARGO\_DISPATCHER\_HELICOPTER brings a dynamic cargo handling capability for AI helicopter groups. -- -- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI\_CARGO\_DISPATCHER\_HELICOPTER module uses the @{Cargo} capabilities within the MOOSE framework. -- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_HELICOPTER object recognize the cargo. -- Please consult the @{Cargo} module for more information. -- +-- --- -- +-- ## 1. AI\_CARGO\_DISPATCHER\_HELICOPTER constructor +-- +-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.New}(): Creates a new AI\_CARGO\_DISPATCHER\_HELICOPTER object. +-- +-- --- +-- +-- ## 2. AI\_CARGO\_DISPATCHER\_HELICOPTER is a FSM +-- +-- ![Process](..\Presentations\AI_CARGO_DISPATCHER_HELICOPTER\Dia3.JPG) +-- +-- ### 2.1. AI\_CARGO\_DISPATCHER\_HELICOPTER States +-- +-- * **Monitoring**: The process is dispatching. +-- * **Idle**: The process is idle. +-- +-- ### 2.2. AI\_CARGO\_DISPATCHER\_HELICOPTER Events +-- +-- * **Monitor**: Monitor and take action. +-- * **Start**: Start the transport process. +-- * **Stop**: Stop the transport process. +-- * **Pickup**: Pickup cargo. +-- * **Load**: Load the cargo. +-- * **Loaded**: Flag that the cargo is loaded. +-- * **Deploy**: Deploy cargo to a location. +-- * **Unload**: Unload the cargo. +-- * **Unloaded**: Flag that the cargo is unloaded. +-- * **Home**: A Helicopter is going home. +-- +-- --- +-- +-- ## 3. Set the pickup parameters. +-- +-- Several parameters can be set to pickup cargo: +-- +-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.SetPickupRadius}(): Sets or randomizes the pickup location for the helicopter around the cargo coordinate in a radius defined an outer and optional inner radius. +-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo. +-- +-- --- +-- +-- ## 4. Set the deploy parameters. +-- +-- Several parameters can be set to deploy cargo: +-- +-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.SetDeployRadius}(): Sets or randomizes the deploy location for the helicopter around the cargo coordinate in a radius defined an outer and an optional inner radius. +-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo. +-- +-- --- +-- +-- ## 5. Set the home zone when there isn't any more cargo to pickup. +-- +-- A home zone can be specified to where the Helicopters will move when there isn't any cargo left for pickup. +-- Use @{#AI_CARGO_DISPATCHER\_HELICOPTER.SetHomeZone}() to specify the home zone. +-- +-- If no home zone is specified, the helicopters will wait near the deploy zone for a new pickup command. +-- +-- === -- -- @field #AI_CARGO_DISPATCHER_HELICOPTER AI_CARGO_DISPATCHER_HELICOPTER = { @@ -32,9 +93,9 @@ AI_CARGO_DISPATCHER_HELICOPTER = { --- Creates a new AI_CARGO_DISPATCHER_HELICOPTER object. -- @param #AI_CARGO_DISPATCHER_HELICOPTER self --- @param Core.Set#SET_GROUP SetHelicopter --- @param Core.Set#SET_CARGO SetCargo --- @param Core.Set#SET_ZONE SetDeployZone +-- @param Core.Set#SET_GROUP SetHelicopter The collection of Helicopter @{Group}s. +-- @param Core.Set#SET_CARGO SetCargo The collection of @{Cargo} derived objects. +-- @param Core.Set#SET_ZONE SetDeployZone The collection of deploy @{Zone}s, which are used to where the cargo will be deployed by the Helicopters. -- @return #AI_CARGO_DISPATCHER_HELICOPTER -- @usage -- @@ -52,8 +113,8 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZ self:SetPickupSpeed( 200, 150 ) self:SetPickupRadius( 0, 0 ) self:SetDeployRadius( 0, 0 ) - - self:Monitor( 1 ) + + self:__Start( 1 ) return self end diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 1efa9651b..ced18e18e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -114,6 +114,14 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #number Delay + -- We need to capture the Crash events for the helicopters. + -- The helicopter reference is used in the semaphore AI_CARGO_QUEUEU. + -- So, we need to unlock this when the helo is not anymore ... + Helicopter:HandleEvent( EVENTS.Crash, + function( Helicopter, EventData ) + AI_CARGO_QUEUE[Helicopter] = nil + end + ) self:SetCarrier( Helicopter ) @@ -225,7 +233,7 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina local HelicopterInZone = false - if Helicopter and Helicopter:IsAlive() then + if Helicopter and Helicopter:IsAlive() == true then local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() ) @@ -283,6 +291,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina self:__Queue( -10, Coordinate ) end end + else + AI_CARGO_QUEUE[Helicopter] = nil end end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index e00d350db..21fdde9dd 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -76,10 +76,35 @@ SET_BASE = { function SET_BASE:New( Database ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE + local self = BASE:Inherit( self, FSM:New() ) -- Core.Set#SET_BASE self.Database = Database + self:SetStartState( "Started" ) + + --- Added Handler OnAfter for SET_BASE + -- @function [parent=#SET_BASE] OnAfterAdded + -- @param #SET_BASE self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #string ObjectName The name of the object. + -- @param Object The object. + + + self:AddTransition( "*", "Added", "*" ) + + --- Removed Handler OnAfter for SET_BASE + -- @function [parent=#SET_BASE] OnAfterRemoved + -- @param #SET_BASE self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #string ObjectName The name of the object. + -- @param Object The object. + + self:AddTransition( "*", "Removed", "*" ) + self.YieldInterval = 10 self.TimeInterval = 0.001 @@ -148,7 +173,8 @@ end --- Removes a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. -- @param #SET_BASE self -- @param #string ObjectName -function SET_BASE:Remove( ObjectName ) +-- @param NoTriggerEvent (optional) When `true`, the :Remove() method will not trigger a **Removed** event. +function SET_BASE:Remove( ObjectName, NoTriggerEvent ) self:F2( { ObjectName = ObjectName } ) local Object = self.Set[ObjectName] @@ -161,9 +187,11 @@ function SET_BASE:Remove( ObjectName ) break end end - + -- When NoTriggerEvent is true, then no Removed event will be triggered. + if not NoTriggerEvent then + self:Removed( ObjectName, Object ) + end end - end @@ -177,10 +205,12 @@ function SET_BASE:Add( ObjectName, Object ) -- Ensure that the existing element is removed from the Set before a new one is inserted to the Set if self.Set[ObjectName] then - self:Remove( ObjectName ) + self:Remove( ObjectName, true ) end self.Set[ObjectName] = Object table.insert( self.Index, ObjectName ) + + self:Added( ObjectName, Object ) end --- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. @@ -425,7 +455,7 @@ end -- @param #SET_BASE self -- @param Core.Event#EVENTDATA Event function SET_BASE:_EventOnDeadOrCrash( Event ) - self:F3( { Event } ) + self:F( { Event } ) if Event.IniDCSUnit then local ObjectName, Object = self:FindInDatabase( Event ) @@ -675,6 +705,52 @@ end -- * @{#SET_GROUP.ForEachGroupPartlyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. -- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. -- +-- +-- ## 5. SET_GROUP trigger events on the GROUP objects. +-- +-- The SET is derived from the FSM class, which provides extra capabilities to track the contents of the GROUP objects in the SET_GROUP. +-- +-- ### 5.1. When a GROUP object crashes or is dead, the SET_GROUP will trigger a **Dead** event. +-- +-- You can handle the event using the OnBefore and OnAfter event handlers. +-- The event handlers need to have the paramters From, Event, To, GroupObject. +-- The GroupObject is the GROUP object that is dead and within the SET_GROUP, and is passed as a parameter to the event handler. +-- See the following example: +-- +-- -- Create the SetCarrier SET_GROUP collection. +-- +-- local SetHelicopter = SET_GROUP:New():FilterPrefixes( "Helicopter" ):FilterStart() +-- +-- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset. +-- +-- function SetHelicopter:OnAfterDead( From, Event, To, GroupObject ) +-- self:F( { GroupObject = GroupObject:GetName() } ) +-- end +-- +-- While this is a good example, there is a catch. +-- Imageine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. +-- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method. +-- See the modified example: +-- +-- -- Now we have a constructor of the class AI_CARGO_DISPATCHER, that receives the SetHelicopter as a parameter. +-- -- Within that constructor, we want to set an enclosed event handler OnAfterDead for SetHelicopter. +-- -- But within the OnAfterDead method, we want to refer to the self variable of the AI_CARGO_DISPATCHER. +-- +-- function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones ) +-- +-- local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER +-- +-- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset. +-- -- Note the "." notation, and the explicit declaration of SetHelicopter, which would be using the ":" notation the implicit self variable declaration. +-- +-- function SetHelicopter.OnAfterDead( SetHelicopter, From, Event, To, GroupObject ) +-- SetHelicopter:F( { GroupObject = GroupObject:GetName() } ) +-- self.PickupCargo[GroupObject] = nil -- So here I clear the PickupCargo table entry of the self object AI_CARGO_DISPATCHER. +-- self.CarrierHome[GroupObject] = nil +-- end +-- +-- end +-- -- === -- @field #SET_GROUP SET_GROUP SET_GROUP = { @@ -946,7 +1022,7 @@ end -- @param #SET_GROUP self -- @param Core.Event#EVENTDATA Event function SET_GROUP:_EventOnDeadOrCrash( Event ) - self:F3( { Event } ) + self:F( { Event } ) if Event.IniDCSUnit then local ObjectName, Object = self:FindInDatabase( Event ) @@ -1409,6 +1485,59 @@ do -- SET_UNIT -- -- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Unit}s in the SET, delimited by a comma. -- + -- ## 4. SET_UNIT iterators + -- + -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. + -- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. + -- The following iterator methods are currently available within the SET_UNIT: + -- + -- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive group it finds within the SET_UNIT. + -- * @{#SET_UNIT.ForEachUnitInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence completely in a @{Zone}, providing the UNIT object and optional parameters to the called function. + -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence not in a @{Zone}, providing the UNIT object and optional parameters to the called function. + -- + -- ## 5. SET_UNIT trigger events on the UNIT objects. + -- + -- The SET is derived from the FSM class, which provides extra capabilities to track the contents of the UNIT objects in the SET_UNIT. + -- + -- ### 5.1. When a UNIT object crashes or is dead, the SET_UNIT will trigger a **Dead** event. + -- + -- You can handle the event using the OnBefore and OnAfter event handlers. + -- The event handlers need to have the paramters From, Event, To, GroupObject. + -- The GroupObject is the UNIT object that is dead and within the SET_UNIT, and is passed as a parameter to the event handler. + -- See the following example: + -- + -- -- Create the SetCarrier SET_UNIT collection. + -- + -- local SetHelicopter = SET_UNIT:New():FilterPrefixes( "Helicopter" ):FilterStart() + -- + -- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier unit is destroyed, that all internal parameters are reset. + -- + -- function SetHelicopter:OnAfterDead( From, Event, To, UnitObject ) + -- self:F( { UnitObject = UnitObject:GetName() } ) + -- end + -- + -- While this is a good example, there is a catch. + -- Imageine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. + -- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method. + -- See the modified example: + -- + -- -- Now we have a constructor of the class AI_CARGO_DISPATCHER, that receives the SetHelicopter as a parameter. + -- -- Within that constructor, we want to set an enclosed event handler OnAfterDead for SetHelicopter. + -- -- But within the OnAfterDead method, we want to refer to the self variable of the AI_CARGO_DISPATCHER. + -- + -- function ACLASS:New( SetCarrier, SetCargo, SetDeployZones ) + -- + -- local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER + -- + -- -- Put a Dead event handler on SetCarrier, to ensure that when a carrier is destroyed, that all internal parameters are reset. + -- -- Note the "." notation, and the explicit declaration of SetHelicopter, which would be using the ":" notation the implicit self variable declaration. + -- + -- function SetHelicopter.OnAfterDead( SetHelicopter, From, Event, To, UnitObject ) + -- SetHelicopter:F( { UnitObject = UnitObject:GetName() } ) + -- self.array[UnitObject] = nil -- So here I clear the array table entry of the self object ACLASS. + -- end + -- + -- end -- === -- @field #SET_UNIT SET_UNIT SET_UNIT = { @@ -1649,6 +1778,8 @@ do -- SET_UNIT return self end + + --- Handles the Database to check on an event (birth) that the Object was added in the Database. -- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! From d07d063265981db09ff4133b604e50e5b2bff7d4 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 17 May 2018 10:24:59 +0200 Subject: [PATCH 112/170] Removed Start(). Now Start() needs to be called outside the logic. --- Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index 6a130eabe..f7a7a07c3 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -114,8 +114,6 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZ self:SetPickupRadius( 0, 0 ) self:SetDeployRadius( 0, 0 ) - self:__Start( 1 ) - return self end From d05973f487844ef010fceac5d8587785547eed09 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 19 May 2018 06:12:37 +0200 Subject: [PATCH 113/170] Finish Cargo/AI_Cargo_Helicopter --- .../Moose/AI/AI_Cargo_Dispatcher.lua | 41 ++++++++++++------- Moose Development/Moose/Cargo/Cargo.lua | 11 +++++ Moose Development/Moose/Cargo/CargoGroup.lua | 9 ++-- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index c0eed577e..e3da2ee29 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -308,7 +308,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() self:Pickup( Carrier, Cargo ) end - function AI_Cargo.OnAfterLoad( AI_Cargo, Carrier ) + function AI_Cargo.OnAfterLoad( AI_Cargo, Carrier, From, Event, To, Cargo ) self:Loading( Carrier ) end @@ -316,16 +316,16 @@ function AI_CARGO_DISPATCHER:onafterMonitor() self:Loaded( Carrier, Cargo ) end - function AI_Cargo.OnAfterDeploy( AI_Cargo, Carrier ) - self:Deploy( Carrier ) + function AI_Cargo.OnAfterDeploy( AI_Cargo, Carrier, From, Event, To, Cargo ) + self:Deploy( Carrier, Cargo ) end - function AI_Cargo.OnAfterUnload( AI_Cargo, Carrier ) - self:Unloading( Carrier ) + function AI_Cargo.OnAfterUnload( AI_Cargo, Carrier, From, Event, To, Cargo ) + self:Unloading( Carrier, Cargo ) end - function AI_Cargo.OnAfterUnloaded( AI_Cargo, Carrier ) - self:Unloaded( Carrier ) + function AI_Cargo.OnAfterUnloaded( AI_Cargo, Carrier, From, Event, To, Cargo ) + self:Unloaded( Carrier, Cargo ) end end @@ -405,7 +405,7 @@ end -- @param #number Delay function AI_CARGO_DISPATCHER:onafterStart( From, Event, To ) - self:Monitor() + self:__Monitor( -1 ) end --- Stop Handler OnBefore for AI_CARGO_DISPATCHER @@ -434,16 +434,27 @@ end ---- Make a Carrier run for a cargo deploy action after the cargo Pickup trigger has been initiated, by default. +--- Loaded Handler OnAfter for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoaded -- @param #AI_CARGO_DISPATCHER self --- @param From --- @param Event --- @param To +-- @param #string From +-- @param #string Event +-- @param #string To -- @param Wrapper.Group#GROUP Carrier -- @param Cargo.Cargo#CARGO Cargo --- @return #AI_CARGO_DISPATCHER -function AI_CARGO_DISPATCHER:OnAfterPickup( From, Event, To, Carrier, Cargo ) -end + +--- Unloaded Handler OnAfter for AI_CARGO_DISPATCHER +-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnloaded +-- @param #AI_CARGO_DISPATCHER self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param Wrapper.Group#GROUP Carrier +-- @param Cargo.Cargo#CARGO Cargo + + + + --- Make a Carrier run for a cargo deploy action after the cargo has been loaded, by default. diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 8869a14cc..f0f99dcdb 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -352,6 +352,17 @@ do -- CARGO return self.Name end + --- Get the current active object representing or being the Cargo. + -- @param #CARGO self + -- @return Wrapper.Positionable#POSITIONABLE The object representing or being the Cargo. + function CARGO:GetObject() + if self:IsLoaded() then + return self.CargoCarrier + else + return self.CargoObject + end + end + --- Get the object name of the Cargo. -- @param #CARGO self -- @return #string The object name of the Cargo. diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 4780a8f55..ed84fd75f 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -107,7 +107,7 @@ do -- CARGO_GROUP self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) + self.CargoObject = _DATABASE:Spawn( GroupTemplate ) self:SetWeight( WeightGroup ) self.CargoLimit = 10 @@ -169,7 +169,10 @@ do -- CARGO_GROUP _DATABASE:Spawn( GroupTemplate ) end end + + self.CargoObject = nil end + end @@ -209,12 +212,12 @@ do -- CARGO_GROUP end -- Then we register the new group in the database - self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID ) self:F( { "Regroup", GroupTemplate } ) -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) + self.CargoObject = _DATABASE:Spawn( GroupTemplate ) end end From d5d5d52bd5e5e21c683a4b7c91ad7f5268fe1fc0 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 19 May 2018 06:55:19 +0200 Subject: [PATCH 114/170] Added Task Status Change Events as part of Dispatcher logic!!!! This is great! --- .../Moose/Tasking/DetectionManager.lua | 42 +++++++++++++++++++ .../Moose/Tasking/Task_A2A_Dispatcher.lua | 19 ++++++++- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 17 ++++++++ .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 18 ++++++++ .../Moose/Tasking/Task_Manager.lua | 42 +++++++++++++++++++ 5 files changed, 137 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index 6252dc0a4..5e95771dd 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -122,6 +122,48 @@ do -- DETECTION MANAGER -- @function [parent=#DETECTION_MANAGER] __Stop -- @param #DETECTION_MANAGER self -- @param #number Delay + + self:AddTransition( "Started", "Success", "Started" ) + + --- Success Handler OnAfter for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnAfterSuccess + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + + + self:AddTransition( "Started", "Failed", "Started" ) + + --- Failed Handler OnAfter for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnAfterFailed + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + + + self:AddTransition( "Started", "Aborted", "Started" ) + + --- Aborted Handler OnAfter for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnAfterAborted + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + + self:AddTransition( "Started", "Cancelled", "Started" ) + + --- Cancelled Handler OnAfter for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnAfterCancelled + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task self:AddTransition( "Started", "Report", "Started" ) diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index a3fc20c88..e385fdd02 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -200,6 +200,7 @@ do -- TASK_A2A_DISPATCHER self.Detection:SetRefreshTimeInterval( 30 ) self:AddTransition( "Started", "Assign", "Started" ) + --- OnAfter Transition Handler for Event Assign. -- @function [parent=#TASK_A2A_DISPATCHER] OnAfterAssign @@ -210,7 +211,7 @@ do -- TASK_A2A_DISPATCHER -- @param Tasking.Task_A2A#TASK_A2A Task -- @param Wrapper.Unit#UNIT TaskUnit -- @param #string PlayerName - + self:__Start( 5 ) return self @@ -561,6 +562,22 @@ do -- TASK_A2A_DISPATCHER Task:SetTargetZone( DetectedZone, DetectedItem.Coordinate.y, DetectedItem.Coordinate.Heading ) Task:SetDispatcher( self ) Mission:AddTask( Task ) + + function Task.OnEnterSuccess( Task, From, Event, To ) + self:Success( Task ) + end + + function Task.onenterCancelled( Task, From, Event, To ) + self:Cancelled( Task ) + end + + function Task.onenterFailed( Task, From, Event, To ) + self:Failed( Task ) + end + + function Task.onenterAborted( Task, From, Event, To ) + self:Aborted( Task ) + end TaskReport:Add( Task:GetName() ) else diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index 256ca2db2..dce26950b 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -761,6 +761,23 @@ do -- TASK_A2G_DISPATCHER Task:SetDispatcher( self ) Task:UpdateTaskInfo( DetectedItem ) Mission:AddTask( Task ) + + function Task.OnEnterSuccess( Task, From, Event, To ) + self:Success( Task ) + end + + function Task.onenterCancelled( Task, From, Event, To ) + self:Cancelled( Task ) + end + + function Task.onenterFailed( Task, From, Event, To ) + self:Failed( Task ) + end + + function Task.onenterAborted( Task, From, Event, To ) + self:Aborted( Task ) + end + TaskReport:Add( Task:GetName() ) else diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 7b3967d5e..1b8dd610f 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -578,6 +578,24 @@ do -- TASK_CARGO_DISPATCHER else Transport.Task:SetDeployZones( self.DefaultDeployZones or {} ) end + + function Transport.Task.OnEnterSuccess( Task, From, Event, To ) + self:Success( Task ) + end + + function Transport.Task.onenterCancelled( Task, From, Event, To ) + self:Cancelled( Task ) + end + + function Transport.Task.onenterFailed( Task, From, Event, To ) + self:Failed( Task ) + end + + function Transport.Task.onenterAborted( Task, From, Event, To ) + self:Aborted( Task ) + end + + end end diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index 340fd8233..fe61dac24 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -111,6 +111,48 @@ do -- TASK_MANAGER self:AddTransition( "Started", "Manage", "Started" ) + self:AddTransition( "Started", "Success", "Started" ) + + --- Success Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterSuccess + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + + + self:AddTransition( "Started", "Failed", "Started" ) + + --- Failed Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterFailed + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + + + self:AddTransition( "Started", "Aborted", "Started" ) + + --- Aborted Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterAborted + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + + self:AddTransition( "Started", "Cancelled", "Started" ) + + --- Cancelled Handler OnAfter for TASK_MANAGER + -- @function [parent=#TASK_MANAGER] OnAfterCancelled + -- @param #TASK_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Tasking.Task#TASK Task + self:SetRefreshTimeInterval( 30 ) return self From cdecf4a4c9879e430739ddd26ad7b2644820c6f3 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 19 May 2018 08:08:08 +0200 Subject: [PATCH 115/170] Finish Cargo/AI_Cargo_Helicopter --- Moose Development/Moose/Core/Spawn.lua | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 5797ce1d0..fca5971f5 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -444,15 +444,30 @@ end -- and any spaces before and after the resulting name are removed. -- IMPORTANT! This method MUST be the first used after :New !!! -- @param #SPAWN self +-- @param #boolean KeepUnitNames (optional) If true, the unit names are kept, false or not provided to make new unit names. -- @return #SPAWN self -function SPAWN:InitKeepUnitNames() +function SPAWN:InitKeepUnitNames( KeepUnitNames ) self:F( ) - self.SpawnInitKeepUnitNames = true + self.SpawnInitKeepUnitNames = KeepUnitNames or true return self end + +--- Flags that the spawned groups must be spawned late activated. +-- @param #SPAWN self +-- @param #boolean LateActivated (optional) If true, the spawned groups are late activated. +-- @return #SPAWN self +function SPAWN:InitLateActivated( LateActivated ) + self:F( ) + + self.LateActivated = LateActivated or true + + return self +end + + --- Defines the Heading for the new spawned units. -- The heading can be given as one fixed degree, or can be randomized between minimum and maximum degrees. -- @param #SPAWN self @@ -1915,7 +1930,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 SpawnTemplate.groupId = nil --SpawnTemplate.lateActivation = false - SpawnTemplate.lateActivation = false + SpawnTemplate.lateActivation = self.LateActivated or false if SpawnTemplate.CategoryID == Group.Category.GROUND then self:T3( "For ground units, visible needs to be false..." ) From 0b378063c0d6ca225ebad763a783c3e4285dff12 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 20 May 2018 08:37:02 +0200 Subject: [PATCH 116/170] - Fixed infantry deploying when helicopter was hit. - Fixed further landing coordinate lockups. --- .../Moose/AI/AI_Cargo_Helicopter.lua | 65 +++++++++++------ Moose Development/Moose/Wrapper/Group.lua | 72 +++++++++++++++++++ 2 files changed, 115 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index ced18e18e..643d4e529 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -115,7 +115,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- We need to capture the Crash events for the helicopters. - -- The helicopter reference is used in the semaphore AI_CARGO_QUEUEU. + -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. -- So, we need to unlock this when the helo is not anymore ... Helicopter:HandleEvent( EVENTS.Crash, function( Helicopter, EventData ) @@ -123,6 +123,20 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) end ) + -- We need to capture the Land events for the helicopters. + -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. + -- So, we need to unlock this when the helo has landed, which can be anywhere ... + -- But only free the landing coordinate after 1 minute, to ensure that all helos have left. + Helicopter:HandleEvent( EVENTS.Land, + function( Helicopter, EventData ) + self:ScheduleOnce( 60, + function( Helicopter ) + AI_CARGO_QUEUE[Helicopter] = nil + end, Helicopter + ) + end + ) + self:SetCarrier( Helicopter ) return self @@ -169,19 +183,6 @@ function AI_CARGO_HELICOPTER:SetCarrier( Helicopter ) end end - - function Helicopter:OnEventHit( EventData ) - local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" ) - if AICargoTroops then - self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) - if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then - -- There are enemies within combat range. Unload the Helicopter. - AICargoTroops:Unload() - end - end - end - - function Helicopter:OnEventLand( EventData ) AICargo:Landed() end @@ -203,19 +204,34 @@ end -- @param #number Speed function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) + Helicopter:F( { Name = Helicopter:GetName() } ) + if Helicopter and Helicopter:IsAlive() then + -- S_EVENT_LAND is directly called in two situations: + -- 1 - When the helo lands normally on the ground. + -- 2 - when the helo is hit and goes RTB or even when it is destroyed. + -- For point 2, this is an issue, the infantry may not unload in this case! + -- So we check if the helo is on the ground, and velocity< 5. + -- Only then the infantry can unload (and load too, for consistency)! + + self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } ) + if self.RoutePickup == true then - self:Load( Helicopter:GetPointVec2() ) - self.RoutePickup = false - self.Relocating = true + if Helicopter:GetHeight( true ) <= 2 and Helicopter:GetVelocityKMH() < 5 then + self:Load( Helicopter:GetPointVec2() ) + self.RoutePickup = false + self.Relocating = true + end end if self.RouteDeploy == true then - self:Unload( true ) - self.RouteDeploy = false - self.Transporting = false - self.Relocating = false + if Helicopter:GetHeight( true ) <= 2 and Helicopter:GetVelocityKMH() < 5 then + self:Unload( true ) + self.RouteDeploy = false + self.Transporting = false + self.Relocating = false + end end end @@ -498,7 +514,12 @@ function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To, Cargo self:Orbit( Helicopter:GetCoordinate(), 50 ) - AI_CARGO_QUEUE[Helicopter] = nil + -- Free the coordinate zone after 30 seconds, so that the original helicopter can fly away first. + self:ScheduleOnce( 30, + function( Helicopter ) + AI_CARGO_QUEUE[Helicopter] = nil + end, Helicopter + ) end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index c595a5dbb..6f45f873d 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -456,6 +456,78 @@ function GROUP:GetSize() return nil end + +--- Returns the average velocity Vec3 vector. +-- @param Wrapper.Group#GROUP self +-- @return Dcs.DCSTypes#Vec3 The velocity Vec3 vector +-- @return #nil The GROUP is not existing or alive. +function GROUP:GetVelocityVec3() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup and DCSGroup:isExist() then + local GroupUnits = DCSGroup:getUnits() + local GroupCount = #GroupUnits + + local VelocityVec3 = { x = 0, y = 0, z = 0 } + + for _, DCSUnit in pairs( GroupUnits ) do + local UnitVelocityVec3 = DCSUnit:getVelocity() + VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x + VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y + VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z + end + + VelocityVec3.x = VelocityVec3.x / GroupCount + VelocityVec3.y = VelocityVec3.y / GroupCount + VelocityVec3.z = VelocityVec3.z / GroupCount + + return VelocityVec3 + end + + BASE:E( { "Cannot GetVelocityVec3", Group = self, Alive = self:IsAlive() } ) + + return nil +end + + +--- Returns the average group height in meters. +-- @param Wrapper.Group#GROUP self +-- @param #boolean FromGround Measure from the ground or from sea level. Provide **true** for measuring from the ground. **false** or **nil** if you measure from sea level. +-- @return Dcs.DCSTypes#Vec3 The height of the group. +-- @return #nil The GROUP is not existing or alive. +function GROUP:GetHeight( FromGround ) + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupUnits = DCSGroup:getUnits() + local GroupCount = #GroupUnits + + local GroupHeight = 0 + + for _, DCSUnit in pairs( GroupUnits ) do + local GroupPosition = DCSUnit:getPosition() + + if FromGround == true then + local LandHeight = land.getHeight( { GroupPosition.p.x, GroupPosition.p.z } ) + GroupHeight = GroupHeight + ( GroupPosition.p.y - LandHeight ) + else + GroupHeight = GroupHeight + GroupPosition.p.y + end + end + + return GroupHeight / GroupCount + end + + return nil +end + + + + --- --- Returns the initial size of the DCS Group. -- If some of the DCS Units of the DCS Group are destroyed, the initial size of the DCS Group is unchanged. From adbbeafef9a768b282f520c103f425f572834bf8 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 20 May 2018 09:08:34 +0200 Subject: [PATCH 117/170] Removed one obscolete line. --- Moose Development/Moose/Core/Event.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 054f5617c..5b42a1d8a 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -212,7 +212,6 @@ EVENTS = { MarkAdded = world.event.S_EVENT_MARK_ADDED, MarkChange = world.event.S_EVENT_MARK_CHANGE, MarkRemoved = world.event.S_EVENT_MARK_REMOVED, - ShootingEnd = world.event.S_EVENT_SHOOTING_END, NewCargo = world.event.S_EVENT_NEW_CARGO, DeleteCargo = world.event.S_EVENT_DELETE_CARGO, NewZone = world.event.S_EVENT_NEW_ZONE, From d8a189b1fd33769d1109d67feb891bf4b655c192 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 09:02:15 +0200 Subject: [PATCH 118/170] Finish ZONE_tags --- Moose Development/Moose/Cargo/CargoGroup.lua | 2 +- Moose Development/Moose/Core/Database.lua | 51 +++++++++++++----- Moose Development/Moose/Core/Zone.lua | 56 ++++++++++++++++++++ Moose Development/Moose/Moose.lua | 3 +- 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index ed84fd75f..5af3978c4 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -78,7 +78,7 @@ do -- CARGO_GROUP self.CargoGroup:Destroy() local GroupName = CargoGroup:GetName() - self.CargoName = GroupName:match("(.*)~CARGO") or GroupName + self.CargoName = Name self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) ) local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 995d243a3..90197b34d 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -289,8 +289,37 @@ do -- Zones end + --- Private method that registers new ZONE_BASE derived objects within the DATABASE Object. + -- @param #DATABASE self + -- @return #DATABASE self + function DATABASE:_RegisterZones() -end + for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do + local ZoneName = ZoneData.name + + self:I( { "Register ZONE:", Name = ZoneName } ) + local Zone = ZONE:New( ZoneName ) + self.ZONENAMES[ZoneName] = ZoneName + self:AddZone( ZoneName, Zone ) + end + + for ZoneGroupName, ZoneGroup in pairs( self.GROUPS ) do + if ZoneGroupName:match("~ZONE_POLYGON") then + local ZoneName1 = ZoneGroupName:match("(.*)~ZONE_POLYGON") + local ZoneName2 = ZoneGroupName:match(".*~ZONE_POLYGON(.*)") + local ZoneName = ZoneName1 .. ( ZoneName2 or "" ) + + self:I( { "Register ZONE_POLYGON:", Name = ZoneName } ) + local Zone_Polygon = ZONE_POLYGON:New( ZoneName, ZoneGroup ) + self.ZONENAMES[ZoneName] = ZoneName + self:AddZone( ZoneName, Zone_Polygon ) + end + end + + end + + +end -- zone do -- cargo @@ -341,20 +370,23 @@ do -- cargo --- Private method that registers new Static Templates within the DATABASE Object. -- @param #DATABASE self -- @return #DATABASE self - function DATABASE:RegisterCargos() + function DATABASE:_RegisterCargos() for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do if self:IsCargo( CargoGroupName ) then local CargoInfo = CargoGroupName:match("~CARGO(.*)") local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") - local CargoName = CargoGroupName:match("(.*)~CARGO") + local CargoName1 = CargoGroupName:match("(.*)~CARGO%(.*%)") + local CargoName2 = CargoGroupName:match(".*~CARGO%(.*%)(.*)") + self:E({CargoName1 = CargoName1, CargoName2 = CargoName2 }) + local CargoName = CargoName1 .. ( CargoName2 or "" ) local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) - self:F({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + self:I({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius ) end end @@ -371,11 +403,11 @@ do -- cargo local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) if Category == "SLING" then - self:F({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + self:I({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) else if Category == "CRATE" then - self:F({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + self:I({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) end end @@ -1218,13 +1250,6 @@ function DATABASE:_RegisterTemplates() end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then end --for coa_name, coa_data in pairs(mission.coalition) do - for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do - local ZoneName = ZoneData.name - self.ZONENAMES[ZoneName] = ZoneName - self:AddZone( ZoneName, ZONE:New( ZoneName ) ) - self:I( "Added ZONE " .. ZoneName ) - end - return self end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 203105575..938fde87a 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -956,6 +956,30 @@ end -- The ZONE class, defined by the zone name as defined within the Mission Editor. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. -- +-- ## ZONE constructor +-- +-- * @{#ZONE.New}(): Constructor. This will search for a trigger zone with the name given, and will return for you a ZONE object. +-- +-- ## Declare a ZONE directly in the DCS mission editor! +-- +-- You can declare a ZONE using the DCS mission editor by adding a trigger zone in the mission editor. +-- +-- Then during mission startup, when loading Moose.lua, this trigger zone will be detected as a ZONE declaration. +-- Within the background, a ZONE object will be created within the @{Database}. +-- The ZONE name will be the trigger zone name. +-- +-- So, you can search yourself for the ZONE object by using the @{#ZONE.FindByName}() method. +-- In this example, `local TriggerZone = ZONE:FindByName( "DefenseZone" )` would return the ZONE object +-- that was created at mission startup, and reference it into the `TriggerZone` local object. +-- +-- Refer to mission `ZON-110` for a demonstration. +-- +-- This is especially handy if you want to quickly setup a SET_ZONE... +-- So when you would declare `local SetZone = SET_ZONE:New():FilterPrefixes( "Defense" ):FilterStart()`, +-- then SetZone would contain the ZONE object `DefenseZone` as part of the zone collection, +-- without much scripting overhead!!! +-- +-- -- @field #ZONE ZONE = { ClassName="ZONE", @@ -1455,6 +1479,26 @@ end -- The ZONE_POLYGON class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. -- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- +-- ## Declare a ZONE_POLYGON directly in the DCS mission editor! +-- +-- You can declare a ZONE_POLYGON using the DCS mission editor by adding the ~ZONE_POLYGON tag in the group name. +-- +-- So, imagine you have a group declared in the mission editor, with group name `DefenseZone~ZONE_POLYGON`. +-- Then during mission startup, when loading Moose.lua, this group will be detected as a ZONE_POLYGON declaration. +-- Within the background, a ZONE_POLYGON object will be created within the @{Database} using the properties of the group. +-- The ZONE_POLYGON name will be the group name without the ~ZONE_POLYGON tag. +-- +-- So, you can search yourself for the ZONE_POLYGON by using the @{#ZONE_POLYGON.FindByName}() method. +-- In this example, `local PolygonZone = ZONE_POLYGON:FindByName( "DefenseZone" )` would return the ZONE_POLYGON object +-- that was created at mission startup, and reference it into the `PolygonZone` local object. +-- +-- Mission `ZON-510` shows a demonstration of this feature or method. +-- +-- This is especially handy if you want to quickly setup a SET_ZONE... +-- So when you would declare `local SetZone = SET_ZONE:New():FilterPrefixes( "Defense" ):FilterStart()`, +-- then SetZone would contain the ZONE_POLYGON object `DefenseZone` as part of the zone collection, +-- without much scripting overhead!!! +-- -- @field #ZONE_POLYGON ZONE_POLYGON = { ClassName="ZONE_POLYGON", @@ -1495,3 +1539,15 @@ function ZONE_POLYGON:NewFromGroupName( GroupName ) return self end + +--- Find a polygon zone in the _DATABASE using the name of the polygon zone. +-- @param #ZONE_POLYGON self +-- @param #string ZoneName The name of the polygon zone. +-- @return #ZONE_POLYGON self +function ZONE_POLYGON:FindByName( ZoneName ) + + local ZoneFound = _DATABASE:FindZone( ZoneName ) + return ZoneFound +end + + diff --git a/Moose Development/Moose/Moose.lua b/Moose Development/Moose/Moose.lua index 6a748922a..05f3b8cf3 100644 --- a/Moose Development/Moose/Moose.lua +++ b/Moose Development/Moose/Moose.lua @@ -13,5 +13,6 @@ _DATABASE = DATABASE:New() -- Core.Database#DATABASE _SETTINGS = SETTINGS:Set() _SETTINGS:SetPlayerMenuOn() -_DATABASE:RegisterCargos() +_DATABASE:_RegisterCargos() +_DATABASE:_RegisterZones() From be48f7751cc1e2458bee278f4e5e66876a3ac5dd Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 20:39:13 +0200 Subject: [PATCH 119/170] Test --- .appveyor/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index ce7a2f7b6..e393ede16 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -61,7 +61,7 @@ build_script: $project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody } - ps: | - if( $env:appveyor_repo_branch -eq 'master' ) + if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' ) { $apiUrl = 'https://ci.appveyor.com/api' $token = 'qts80b5kpq0ooj4x6vvw' @@ -69,7 +69,7 @@ build_script: "Authorization" = "Bearer $token" "Content-type" = "application/json" } - $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = 'master'; environmentVariables = @{} } | ConvertTo-Json + $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json # get project with last build details $project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody } From 25e4d171ab92904d84fb24ce001866468d3ef137 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 21 May 2018 21:43:19 +0200 Subject: [PATCH 120/170] Added GetSpeedMax function --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 2 +- .../Moose/Wrapper/Controllable.lua | 10 +++---- Moose Development/Moose/Wrapper/Group.lua | 30 +++++++++++++++++++ Moose Development/Moose/Wrapper/Unit.lua | 17 +++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 0cb8aed9b..95a5ba04d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -609,7 +609,7 @@ function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate ) if Coordinate then self.RoutePickup = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.8, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 04576498f..0318c6c47 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1958,17 +1958,17 @@ do -- Route methods -- Route, ground waypoints along roads. local route={} - table.insert(route, FromCoordinate:WaypointGround(Speed, Formation)) + table.insert(route, FromCoordinate:WaypointGround(Speed, "Off Road")) -- Convert coordinates to ground waypoints and insert into table. for _, coord in ipairs(path) do - table.insert(route, coord:WaypointGround(Speed, Formation)) + table.insert(route, coord:WaypointGround(Speed, "On Road")) end -- Add the final coordinate because the final coordinate in path is last point on road. local dist=ToCoordinate:Get2DDistance(path[#path]) if dist>10 then - table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee")) + table.insert(route, ToCoordinate:WaypointGround(Speed, "Off Road")) end -- Route controllable to destination. @@ -2059,7 +2059,7 @@ do -- Route methods PointFrom.y = ControllablePoint.y PointFrom.type = "Turning Point" PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 + PointFrom.speed = 20 / 3.6 local PointTo = {} @@ -2084,7 +2084,7 @@ do -- Route methods if Speed then PointTo.speed = Speed else - PointTo.speed = 20 / 1.6 + PointTo.speed = 20 / 3.6 end local Points = { PointFrom, PointTo } diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 6f45f873d..dcbee2b90 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -350,6 +350,36 @@ function GROUP:GetCountry() return nil end +--- Returns the maximum speed of the group. +-- If the group is heterogenious and consists of different units, the max speed of the slowest unit is returned. +-- @param #GROUP self +-- @return #number Speed in km/h. +function GROUP:GetSpeedMax() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + if DCSGroup then + + local Units=self:GetUnits() + + local speedmax=nil + + for _,unit in pairs(Units) do + local unit=unit --Wrapper.Unit#UNIT + local speed=unit:GetSpeedMax() + if speedmax==nil then + speedmax=speed + elseif speed The list of @{Unit} objects of the @{Group}. diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 1c4236dc3..bc5a89e3f 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -401,6 +401,23 @@ function UNIT:GetNumber() return nil end + +--- Returns the unit's max speed in km/h derived from the DCS descriptors. +-- @param #UNIT self +-- @return #number Speed in km/h. +function UNIT:GetSpeedMax() + self:F2( self.UnitName ) + + local Desc = self:GetDesc() + + if Desc then + local SpeedMax = Desc.speedMax + return SpeedMax*3.6 + end + + return nil +end + --- Returns the unit's group if it exist and nil otherwise. -- @param Wrapper.Unit#UNIT self -- @return Wrapper.Group#GROUP The Group of the Unit. From 6a4741d0dce8b8dee0d60c0b2d9572a2bb205635 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 22:34:19 +0200 Subject: [PATCH 121/170] New version --- Moose Development/Moose/Dcs/DCSAirbase.lua | 2 +- Moose Development/Moose/Dcs/DCSCoalitionObject.lua | 2 +- Moose Development/Moose/Dcs/DCSCommand.lua | 2 +- Moose Development/Moose/Dcs/DCSController.lua | 2 +- Moose Development/Moose/Dcs/DCSGroup.lua | 2 +- Moose Development/Moose/Dcs/DCSObject.lua | 2 +- Moose Development/Moose/Dcs/DCSStaticObject.lua | 2 +- Moose Development/Moose/Dcs/DCSTask.lua | 2 +- Moose Development/Moose/Dcs/DCSTime.lua | 2 +- Moose Development/Moose/Dcs/DCSTypes.lua | 2 +- Moose Development/Moose/Dcs/DCSUnit.lua | 2 +- Moose Development/Moose/Dcs/DCSVec3.lua | 2 +- Moose Development/Moose/Dcs/DCSZone.lua | 2 +- Moose Development/Moose/Dcs/DCScoalition.lua | 2 +- Moose Development/Moose/Dcs/DCScountry.lua | 2 +- Moose Development/Moose/Dcs/DCSenv.lua | 2 +- Moose Development/Moose/Dcs/DCSland.lua | 2 +- Moose Development/Moose/Dcs/DCStimer.lua | 2 +- Moose Development/Moose/Dcs/DCStrigger.lua | 2 +- Moose Development/Moose/Dcs/DCSworld.lua | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Moose Development/Moose/Dcs/DCSAirbase.lua b/Moose Development/Moose/Dcs/DCSAirbase.lua index d47ddc067..192444a06 100644 --- a/Moose Development/Moose/Dcs/DCSAirbase.lua +++ b/Moose Development/Moose/Dcs/DCSAirbase.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSAirbase +-- @module DCS.DCSAirbase --- Represents airbases: airdromes, helipads and ships with flying decks or landing pads. diff --git a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua index 119c9a807..b16ca63c2 100644 --- a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua +++ b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSCoalitionObject +-- @module DCS.DCSCoalitionObject --- @type CoalitionObject -- @extends Dcs.DCSWrapper.Object#Object diff --git a/Moose Development/Moose/Dcs/DCSCommand.lua b/Moose Development/Moose/Dcs/DCSCommand.lua index 5e0040332..89b2b6f9e 100644 --- a/Moose Development/Moose/Dcs/DCSCommand.lua +++ b/Moose Development/Moose/Dcs/DCSCommand.lua @@ -1,4 +1,4 @@ ---- @module DCSCommand +--- @module DCS.DCSCommand --- @type Command diff --git a/Moose Development/Moose/Dcs/DCSController.lua b/Moose Development/Moose/Dcs/DCSController.lua index 09b8d4b1e..99666ef97 100644 --- a/Moose Development/Moose/Dcs/DCSController.lua +++ b/Moose Development/Moose/Dcs/DCSController.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSController +-- @module DCS.DCSController --- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C. -- diff --git a/Moose Development/Moose/Dcs/DCSGroup.lua b/Moose Development/Moose/Dcs/DCSGroup.lua index 04f7818bf..0e1798e07 100644 --- a/Moose Development/Moose/Dcs/DCSGroup.lua +++ b/Moose Development/Moose/Dcs/DCSGroup.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSGroup +-- @module DCS.DCSGroup --- Represents group of Units. -- @type Group diff --git a/Moose Development/Moose/Dcs/DCSObject.lua b/Moose Development/Moose/Dcs/DCSObject.lua index 281e2781a..fb09234d4 100644 --- a/Moose Development/Moose/Dcs/DCSObject.lua +++ b/Moose Development/Moose/Dcs/DCSObject.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSObject +-- @module DCS.DCSObject --- @type Object -- @field #Object.Category Category diff --git a/Moose Development/Moose/Dcs/DCSStaticObject.lua b/Moose Development/Moose/Dcs/DCSStaticObject.lua index 5dc220412..e01f017da 100644 --- a/Moose Development/Moose/Dcs/DCSStaticObject.lua +++ b/Moose Development/Moose/Dcs/DCSStaticObject.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSStaticObject +-- @module DCS.DCSStaticObject ------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Dcs/DCSTask.lua b/Moose Development/Moose/Dcs/DCSTask.lua index 4b4cd277a..825b9f0bc 100644 --- a/Moose Development/Moose/Dcs/DCSTask.lua +++ b/Moose Development/Moose/Dcs/DCSTask.lua @@ -1,4 +1,4 @@ ---- @module DCSTask +--- @module DCS.DCSTask --- A task descriptor (internal structure for DCS World) diff --git a/Moose Development/Moose/Dcs/DCSTime.lua b/Moose Development/Moose/Dcs/DCSTime.lua index d70d337ec..766f53317 100644 --- a/Moose Development/Moose/Dcs/DCSTime.lua +++ b/Moose Development/Moose/Dcs/DCSTime.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSTime +-- @module DCS.DCSTime --- @type ModelTime -- @extends #number diff --git a/Moose Development/Moose/Dcs/DCSTypes.lua b/Moose Development/Moose/Dcs/DCSTypes.lua index 176725302..bb00369e4 100644 --- a/Moose Development/Moose/Dcs/DCSTypes.lua +++ b/Moose Development/Moose/Dcs/DCSTypes.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSTypes +-- @module DCS.DCSTypes diff --git a/Moose Development/Moose/Dcs/DCSUnit.lua b/Moose Development/Moose/Dcs/DCSUnit.lua index e5e86aba2..723b653d1 100644 --- a/Moose Development/Moose/Dcs/DCSUnit.lua +++ b/Moose Development/Moose/Dcs/DCSUnit.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSUnit +-- @module DCS.DCSUnit --- @type Unit -- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject diff --git a/Moose Development/Moose/Dcs/DCSVec3.lua b/Moose Development/Moose/Dcs/DCSVec3.lua index 6de2c20aa..0128e1a7a 100644 --- a/Moose Development/Moose/Dcs/DCSVec3.lua +++ b/Moose Development/Moose/Dcs/DCSVec3.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSVec3 +-- @module DCS.DCSVec3 diff --git a/Moose Development/Moose/Dcs/DCSZone.lua b/Moose Development/Moose/Dcs/DCSZone.lua index 4b65bd76e..6070d8cc9 100644 --- a/Moose Development/Moose/Dcs/DCSZone.lua +++ b/Moose Development/Moose/Dcs/DCSZone.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSZone +-- @module DCS.DCSZone diff --git a/Moose Development/Moose/Dcs/DCScoalition.lua b/Moose Development/Moose/Dcs/DCScoalition.lua index e51508a3e..309492fd0 100644 --- a/Moose Development/Moose/Dcs/DCScoalition.lua +++ b/Moose Development/Moose/Dcs/DCScoalition.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCScoalition +-- @module DCS.DCScoalition --- @type coalition -- @field #coalition.side side diff --git a/Moose Development/Moose/Dcs/DCScountry.lua b/Moose Development/Moose/Dcs/DCScountry.lua index e390894cd..32ff4c34e 100644 --- a/Moose Development/Moose/Dcs/DCScountry.lua +++ b/Moose Development/Moose/Dcs/DCScountry.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCScountry +-- @module DCS.DCScountry --- @type country -- @field #country.id id diff --git a/Moose Development/Moose/Dcs/DCSenv.lua b/Moose Development/Moose/Dcs/DCSenv.lua index c6fe98776..8b71f0f9e 100644 --- a/Moose Development/Moose/Dcs/DCSenv.lua +++ b/Moose Development/Moose/Dcs/DCSenv.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module env +-- @module DCS.DCSenv --- @type env diff --git a/Moose Development/Moose/Dcs/DCSland.lua b/Moose Development/Moose/Dcs/DCSland.lua index 6391142af..5e4d2c77c 100644 --- a/Moose Development/Moose/Dcs/DCSland.lua +++ b/Moose Development/Moose/Dcs/DCSland.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module land +-- @module DCS.land --- @type land -- @field #land.SurfaceType SurfaceType diff --git a/Moose Development/Moose/Dcs/DCStimer.lua b/Moose Development/Moose/Dcs/DCStimer.lua index 2d0f4a16c..91fb3b93d 100644 --- a/Moose Development/Moose/Dcs/DCStimer.lua +++ b/Moose Development/Moose/Dcs/DCStimer.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCStimer +-- @module DCS.DCStimer --- @type timer diff --git a/Moose Development/Moose/Dcs/DCStrigger.lua b/Moose Development/Moose/Dcs/DCStrigger.lua index 7bf5360be..c1638c5bb 100644 --- a/Moose Development/Moose/Dcs/DCStrigger.lua +++ b/Moose Development/Moose/Dcs/DCStrigger.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCStrigger +-- @module DCS.DCStrigger trigger = {} --#timer diff --git a/Moose Development/Moose/Dcs/DCSworld.lua b/Moose Development/Moose/Dcs/DCSworld.lua index 5bcb203d2..80fed64a2 100644 --- a/Moose Development/Moose/Dcs/DCSworld.lua +++ b/Moose Development/Moose/Dcs/DCSworld.lua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module DCSWorld +-- @module DCS.DCSWorld --- @type world -- @field #world.event event From 9dc329f151eb5f80db70ab8244ed0d09c21ee99f Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 22:37:12 +0200 Subject: [PATCH 122/170] New version --- .appveyor/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index e393ede16..17c1c054b 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -1,4 +1,4 @@ -version: 3.9.1.{build} +version: 2.4.a.{build} shallow_clone: true skip_branch_with_pr: false skip_commits: @@ -69,7 +69,7 @@ build_script: "Authorization" = "Bearer $token" "Content-type" = "application/json" } - $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json + $RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json # get project with last build details $project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody } From 51192f9a4c36c2370f1ca50a86738fec5ed896c8 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 22:39:05 +0200 Subject: [PATCH 123/170] moose-docs --- .appveyor/appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index 17c1c054b..30b7b02bf 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -75,7 +75,6 @@ build_script: } - test: off # test_script: # - cmd: luacheck "Moose Development\Moose\moose.lua" "Moose Mission Setup\moose.lua" From 3d48dee23fee9b44f0f90d2739e96b6494daeaf1 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 22:42:28 +0200 Subject: [PATCH 124/170] 2.4.a --- .appveyor/appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor/appveyor.yml b/.appveyor/appveyor.yml index 30b7b02bf..7fcd96a10 100644 --- a/.appveyor/appveyor.yml +++ b/.appveyor/appveyor.yml @@ -17,6 +17,7 @@ environment: platform: - x64 + init: - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` From e78cd5675284b84fde04b006e2fd254f9c69612d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 21 May 2018 22:51:43 +0200 Subject: [PATCH 125/170] Core modules --- Moose Development/Moose/Core/Base.lua | 2 +- Moose Development/Moose/Core/Database.lua | 2 +- Moose Development/Moose/Core/Event.lua | 2 +- Moose Development/Moose/Core/Fsm.lua | 2 +- Moose Development/Moose/Core/Goal.lua | 2 +- Moose Development/Moose/Core/Menu.lua | 2 +- Moose Development/Moose/Core/Message.lua | 2 +- Moose Development/Moose/Core/Point.lua | 2 +- Moose Development/Moose/Core/Radio.lua | 2 +- Moose Development/Moose/Core/ScheduleDispatcher.lua | 2 +- Moose Development/Moose/Core/Scheduler.lua | 2 +- Moose Development/Moose/Core/Set.lua | 2 +- Moose Development/Moose/Core/Settings.lua | 2 +- Moose Development/Moose/Core/Spawn.lua | 2 +- Moose Development/Moose/Core/SpawnStatic.lua | 2 +- Moose Development/Moose/Core/Spot.lua | 2 +- Moose Development/Moose/Core/UserFlag.lua | 2 +- Moose Development/Moose/Core/UserSound.lua | 2 +- Moose Development/Moose/Core/Velocity.lua | 2 +- Moose Development/Moose/Core/Zone.lua | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 555786ab4..8dc4eb0e8 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -9,7 +9,7 @@ -- -- === -- --- @module Base +-- @module Core.Base diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 90197b34d..ecd6cddbd 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -7,7 +7,7 @@ -- -- === -- --- @module Database +-- @module Core.Database --- @type DATABASE diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 5b42a1d8a..01804da7a 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -164,7 +164,7 @@ -- -- === -- --- @module Event +-- @module Core.Event --- The EVENT structure diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 62b80aee2..e3b2aacb1 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -64,7 +64,7 @@ -- -- === -- --- @module Fsm +-- @module Core.Fsm do -- FSM diff --git a/Moose Development/Moose/Core/Goal.lua b/Moose Development/Moose/Core/Goal.lua index ff6976877..e4373438e 100644 --- a/Moose Development/Moose/Core/Goal.lua +++ b/Moose Development/Moose/Core/Goal.lua @@ -10,7 +10,7 @@ -- -- === -- --- @module Goal +-- @module Core.Goal do -- Goal diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 65c0025cd..03eb1c156 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -30,7 +30,7 @@ -- -- === -- --- @module Menu +-- @module Core.Menu MENU_INDEX = {} diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 11a1e19dc..904711e7b 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -4,7 +4,7 @@ -- -- === -- --- @module Message +-- @module Core.Message --- The MESSAGE class -- @type MESSAGE diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 5060600d6..5d914d338 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -26,7 +26,7 @@ -- -- ### Contributions: -- --- @module Point +-- @module Core.Point diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index 1d41d25b7..61eb02a76 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -32,7 +32,7 @@ -- -- ### Author: Hugues "Grey_Echo" Bousquet -- --- @module Radio +-- @module Core.Radio --- # RADIO class, extends @{Base#BASE} diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 57073a516..20f3b5185 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -30,7 +30,7 @@ -- ### Contributions: - -- ### Authors: FlightControl : Design & Programming -- --- @module ScheduleDispatcher +-- @module Core.ScheduleDispatcher --- The SCHEDULEDISPATCHER structure -- @type SCHEDULEDISPATCHER diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index e576aa2aa..246244b29 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -39,7 +39,7 @@ -- -- === -- --- @module Scheduler +-- @module Core.Scheduler --- The SCHEDULER class diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 21fdde9dd..1c7e8df5e 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -30,7 +30,7 @@ -- -- === -- --- @module Set +-- @module Core.Set --- @type SET_BASE diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index 8b8a2c601..a8b9ba76d 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -16,7 +16,7 @@ -- -- * **FlightControl**: Design & Programming -- --- @module Settings +-- @module Core.Settings --- @type SETTINGS diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index fca5971f5..c260e6c9a 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -21,7 +21,7 @@ -- -- === -- --- @module Spawn +-- @module Core.Spawn --- SPAWN Class diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 8019902af..22ae07cfc 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -29,7 +29,7 @@ -- -- === -- --- @module SpawnStatic +-- @module Core.SpawnStatic diff --git a/Moose Development/Moose/Core/Spot.lua b/Moose Development/Moose/Core/Spot.lua index 10edb6cee..19ca73263 100644 --- a/Moose Development/Moose/Core/Spot.lua +++ b/Moose Development/Moose/Core/Spot.lua @@ -38,7 +38,7 @@ -- -- === -- --- @module Spot +-- @module Core.Spot do diff --git a/Moose Development/Moose/Core/UserFlag.lua b/Moose Development/Moose/Core/UserFlag.lua index 05fc7b29e..f1b09589c 100644 --- a/Moose Development/Moose/Core/UserFlag.lua +++ b/Moose Development/Moose/Core/UserFlag.lua @@ -10,7 +10,7 @@ -- -- === -- --- @module UserFlag +-- @module Core.UserFlag do -- UserFlag diff --git a/Moose Development/Moose/Core/UserSound.lua b/Moose Development/Moose/Core/UserSound.lua index 808b78a5f..dcd6c58df 100644 --- a/Moose Development/Moose/Core/UserSound.lua +++ b/Moose Development/Moose/Core/UserSound.lua @@ -10,7 +10,7 @@ -- -- === -- --- @module UserSound +-- @module Core.UserSound do -- UserSound diff --git a/Moose Development/Moose/Core/Velocity.lua b/Moose Development/Moose/Core/Velocity.lua index 88d047126..ecc4b5ea6 100644 --- a/Moose Development/Moose/Core/Velocity.lua +++ b/Moose Development/Moose/Core/Velocity.lua @@ -7,7 +7,7 @@ -- -- === -- --- @module Velocity +-- @module Core.Velocity do -- Velocity diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 938fde87a..a8dc2f641 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -34,7 +34,7 @@ -- -- === -- --- @module Zone +-- @module Core.Zone --- @type ZONE_BASE From fe2f59660d2ae623ec7fbba6034b647ef22663da Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 22 May 2018 11:15:51 +0200 Subject: [PATCH 126/170] AI test --- Moose Development/Moose/AI/AI_A2A_Cap.lua | 2 +- Moose Development/Moose/AI/AI_A2A_Dispatcher.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 9b90b489e..6375f5ee8 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -1,6 +1,6 @@ --- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes. -- --- This is a class used in the @{AI_A2A_Dispatcher}. +-- This is a class used in the @{AI.AI_A2A_Dispatcher}. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 96fc731d1..6594ea9bb 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -155,7 +155,7 @@ -- ### Authors: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons). -- ### Authors: **Stonehouse**, **SNAFU** in terms of the advice, documentation, and the original GCICAP script. -- --- @module AI_A2A_Dispatcher +-- @module AI.AI_A2A_Dispatcher From 1b39f5d6e6ab8abbcc9a33313b6f9053dc5328c4 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 23 May 2018 10:42:27 +0200 Subject: [PATCH 127/170] Optimized comments and documentation set --- Moose Development/Moose/AI/AI_A2A.lua | 8 +- Moose Development/Moose/AI/AI_A2A_Cap.lua | 20 +-- .../Moose/AI/AI_A2A_Dispatcher.lua | 28 ++--- Moose Development/Moose/AI/AI_A2A_Gci.lua | 10 +- Moose Development/Moose/AI/AI_A2A_Patrol.lua | 20 +-- Moose Development/Moose/AI/AI_BAI.lua | 20 +-- Moose Development/Moose/AI/AI_Balancer.lua | 18 +-- Moose Development/Moose/AI/AI_CAP.lua | 18 +-- Moose Development/Moose/AI/AI_CAS.lua | 20 +-- Moose Development/Moose/AI/AI_Cargo_APC.lua | 6 +- .../Moose/AI/AI_Cargo_Airplane.lua | 4 +- .../Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 6 +- .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 4 +- .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 4 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 4 +- Moose Development/Moose/AI/AI_Formation.lua | 22 ++-- Moose Development/Moose/AI/AI_Patrol.lua | 26 ++-- .../Moose/Actions/Act_Account.lua | 12 +- .../Moose/Actions/Act_Assist.lua | 6 +- Moose Development/Moose/Actions/Act_Route.lua | 2 +- Moose Development/Moose/Cargo/Cargo.lua | 16 +-- Moose Development/Moose/Cargo/CargoCrate.lua | 8 +- Moose Development/Moose/Cargo/CargoGroup.lua | 22 ++-- .../Moose/Cargo/CargoSlingload.lua | 8 +- Moose Development/Moose/Cargo/CargoUnit.lua | 6 +- Moose Development/Moose/Core/Base.lua | 4 +- Moose Development/Moose/Core/Database.lua | 2 +- Moose Development/Moose/Core/Event.lua | 14 +-- Moose Development/Moose/Core/Fsm.lua | 10 +- Moose Development/Moose/Core/Goal.lua | 2 +- Moose Development/Moose/Core/Menu.lua | 8 +- Moose Development/Moose/Core/Message.lua | 4 +- Moose Development/Moose/Core/Point.lua | 6 +- Moose Development/Moose/Core/Radio.lua | 16 +-- Moose Development/Moose/Core/Report.lua | 13 ++ Moose Development/Moose/Core/Scheduler.lua | 2 +- Moose Development/Moose/Core/Set.lua | 96 +++++++------- Moose Development/Moose/Core/Settings.lua | 2 +- Moose Development/Moose/Core/Spawn.lua | 118 +++++++++--------- Moose Development/Moose/Core/SpawnStatic.lua | 2 +- Moose Development/Moose/Core/Spot.lua | 4 +- Moose Development/Moose/Core/UserFlag.lua | 2 +- Moose Development/Moose/Core/UserSound.lua | 6 +- Moose Development/Moose/Core/Velocity.lua | 4 +- Moose Development/Moose/Core/Zone.lua | 62 ++++----- .../Moose/Functional/ATC_Ground.lua | 6 +- .../Moose/Functional/CleanUp.lua | 4 +- .../Moose/Functional/Detection.lua | 20 +-- Moose Development/Moose/Functional/Escort.lua | 2 +- .../Moose/Functional/MissileTrainer.lua | 2 +- .../Moose/Functional/Protect.lua | 2 +- .../Moose/Functional/PseudoATC.lua | 2 +- Moose Development/Moose/Functional/RAT.lua | 4 +- Moose Development/Moose/Functional/Range.lua | 12 +- .../Moose/Functional/Scoring.lua | 28 ++--- .../Moose/Functional/ZoneGoal.lua | 2 +- .../Moose/Tasking/CommandCenter.lua | 2 +- .../Moose/Tasking/DetectionManager.lua | 16 +-- Moose Development/Moose/Tasking/Mission.lua | 4 +- Moose Development/Moose/Tasking/Task.lua | 50 ++++---- Moose Development/Moose/Tasking/TaskInfo.lua | 2 +- .../Moose/Tasking/TaskZoneCapture.lua | 4 +- Moose Development/Moose/Tasking/Task_A2A.lua | 20 +-- .../Moose/Tasking/Task_A2A_Dispatcher.lua | 10 +- Moose Development/Moose/Tasking/Task_A2G.lua | 14 +-- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 16 +-- .../Moose/Tasking/Task_CARGO.lua | 4 +- .../Moose/Tasking/Task_Cargo_CSAR.lua | 2 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 6 +- .../Moose/Tasking/Task_Cargo_Transport.lua | 2 +- .../Moose/Tasking/Task_Manager.lua | 6 +- .../Moose/Tasking/Task_Pickup.lua | 10 +- Moose Development/Moose/Wrapper/Airbase.lua | 4 +- Moose Development/Moose/Wrapper/Client.lua | 4 +- .../Moose/Wrapper/Controllable.lua | 12 +- Moose Development/Moose/Wrapper/Group.lua | 44 +++---- .../Moose/Wrapper/Identifiable.lua | 4 +- Moose Development/Moose/Wrapper/Object.lua | 4 +- .../Moose/Wrapper/Positionable.lua | 12 +- Moose Development/Moose/Wrapper/Scenery.lua | 4 +- Moose Development/Moose/Wrapper/Static.lua | 10 +- Moose Development/Moose/Wrapper/Unit.lua | 16 +-- 83 files changed, 538 insertions(+), 525 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index 1309b52bc..22507ffb3 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module AI_A2A +-- @module AI.AI_A2A --BASE:TraceClass("AI_A2A") @@ -18,7 +18,7 @@ --- # AI_A2A class, extends @{Fsm#FSM_CONTROLLABLE} -- --- The AI_A2A class implements the core functions to operate an AI @{Group} A2A tasking. +-- The AI_A2A class implements the core functions to operate an AI @{Wrapper.Group} A2A tasking. -- -- -- ## AI_A2A constructor @@ -295,8 +295,8 @@ end --- Sets (modifies) the minimum and maximum speed of the patrol. -- @param #AI_A2A self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @return #AI_A2A self function AI_A2A:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 6375f5ee8..0451051a2 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module AI_A2A_Cap +-- @module AI.AI_A2A_Cap --BASE:TraceClass("AI_A2A_CAP") @@ -16,14 +16,14 @@ -- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL ---- # AI_A2A_CAP class, extends @{AI_CAP#AI_PATROL_ZONE} +--- # AI_A2A_CAP class, extends @{AI.AI_A2A_Patrol#AI_A2A_PATROL} -- --- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group} +-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- --- The AI_A2A_CAP is assigned a @{Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event. +-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_CAP\Dia4.JPG) -- @@ -73,8 +73,8 @@ -- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Unit}. --- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task. +-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. +-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- ## 3. Set the Range of Engagement @@ -108,10 +108,10 @@ AI_A2A_CAP = { -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h. --- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Group} in km/h when engaging a target. --- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Group} in km/h when engaging a target. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2A_CAP function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType ) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 6594ea9bb..047922014 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -165,7 +165,7 @@ do -- AI_A2A_DISPATCHER -- @type AI_A2A_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER - --- # AI\_A2A\_DISPATCHER class, extends @{Tasking#DETECTION_MANAGER} + --- # AI\_A2A\_DISPATCHER class, extends @{Tasking.DetectionManage#DETECTION_MANAGER} -- -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia1.JPG) -- @@ -346,7 +346,7 @@ do -- AI_A2A_DISPATCHER -- -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia9.JPG) -- - -- If it’s a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Zone#ZONE_BASE}. + -- If it’s a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. -- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than -- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. -- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. @@ -544,7 +544,7 @@ do -- AI_A2A_DISPATCHER -- * As the CAP flights wander around within the zone waiting to be tasked, these zones need to be large enough that the aircraft are not constantly turning -- but do not have to be big and numerous enough to completely cover a border. -- - -- * CAP zones can be of any type, and are derived from the @{Zone#ZONE_BASE} class. Zones can be @{Zone#ZONE}, @{Zone#ZONE_POLYGON}, @{Zone#ZONE_UNIT}, @{Zone#ZONE_GROUP}, etc. + -- * CAP zones can be of any type, and are derived from the @{Core.Zone#ZONE_BASE} class. Zones can be @{Core.Zone#ZONE}, @{Core.Zone#ZONE_POLYGON}, @{Core.Zone#ZONE_UNIT}, @{Core.Zone#ZONE_GROUP}, etc. -- This allows to setup **static, moving and/or complex zones** wherein aircraft will perform the CAP. -- -- * Typically 20000-50000 metres width is used and they are spaced so that aircraft in the zone waiting for tasks don’t have to far to travel to protect their coalitions important targets. @@ -1142,7 +1142,7 @@ do -- AI_A2A_DISPATCHER --- Define a border area to simulate a **cold war** scenario. -- A **cold war** is one where CAP aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border. -- A **hot war** is one where CAP aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send CAP and GCI aircraft to attack it. - -- If it’s a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Zone#ZONE_BASE}. This method needs to be used for this. + -- If it’s a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this. -- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1 -- @param #AI_A2A_DISPATCHER self -- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE. @@ -1423,11 +1423,11 @@ do -- AI_A2A_DISPATCHER -- You need to specify here EXACTLY the name of the airbase as you see it in the mission editor. -- Examples are `"Batumi"` or `"Tbilisi-Lochini"`. -- EXACTLY the airbase name, between quotes `""`. - -- To ease the airbase naming when using the LDT editor and IntelliSense, the @{Airbase#AIRBASE} class contains enumerations of the airbases of each map. + -- To ease the airbase naming when using the LDT editor and IntelliSense, the @{Wrapper.Airbase#AIRBASE} class contains enumerations of the airbases of each map. -- - -- * Caucasus: @{Airbase#AIRBASE.Caucaus} - -- * Nevada or NTTR: @{Airbase#AIRBASE.Nevada} - -- * Normandy: @{Airbase#AIRBASE.Normandy} + -- * Caucasus: @{Wrapper.Airbase#AIRBASE.Caucaus} + -- * Nevada or NTTR: @{Wrapper.Airbase#AIRBASE.Nevada} + -- * Normandy: @{Wrapper.Airbase#AIRBASE.Normandy} -- -- @param #string TemplatePrefixes A string or an array of strings specifying the **prefix names of the templates** (not going to explain what is templates here again). -- Examples are `{ "104th", "105th" }` or `"104th"` or `"Template 1"` or `"BLUE PLANES"`. @@ -1512,7 +1512,7 @@ do -- AI_A2A_DISPATCHER --- Set a CAP for a Squadron. -- @param #AI_A2A_DISPATCHER self -- @param #string SquadronName The squadron name. - -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed. -- @param #number FloorAltitude The minimum altitude at which the cap can be executed. -- @param #number CeilingAltitude the maximum altitude at which the cap can be executed. -- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed. @@ -2391,7 +2391,7 @@ do -- AI_A2A_DISPATCHER --- Set the default tanker where defenders will Refuel in the air. -- @param #AI_A2A_DISPATCHER self - -- @param #strig TankerName A string defining the group name of the Tanker as defined within the Mission Editor. + -- @param #string TankerName A string defining the group name of the Tanker as defined within the Mission Editor. -- @return #AI_A2A_DISPATCHER -- @usage -- @@ -2414,7 +2414,7 @@ do -- AI_A2A_DISPATCHER --- Set the squadron tanker where defenders will Refuel in the air. -- @param #AI_A2A_DISPATCHER self -- @param #string SquadronName The name of the squadron. - -- @param #strig TankerName A string defining the group name of the Tanker as defined within the Mission Editor. + -- @param #string TankerName A string defining the group name of the Tanker as defined within the Mission Editor. -- @return #AI_A2A_DISPATCHER -- @usage -- @@ -2470,7 +2470,7 @@ do -- AI_A2A_DISPATCHER --- Creates an SWEEP task when there are targets for it. -- @param #AI_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function AI_A2A_DISPATCHER:EvaluateSWEEP( DetectedItem ) self:F( { DetectedItem.ItemID } ) @@ -2891,7 +2891,7 @@ do -- AI_A2A_DISPATCHER --- Creates an ENGAGE task when there are human friendlies airborne near the targets. -- @param #AI_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function AI_A2A_DISPATCHER:EvaluateENGAGE( DetectedItem ) self:F( { DetectedItem.ItemID } ) @@ -2918,7 +2918,7 @@ do -- AI_A2A_DISPATCHER --- Creates an GCI task when there are targets for it. -- @param #AI_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function AI_A2A_DISPATCHER:EvaluateGCI( DetectedItem ) self:F( { DetectedItem.ItemID } ) diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index e714fcfe6..98670a381 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module AI_A2A_GCI +-- @module AI.AI_A2A_GCI @@ -16,13 +16,13 @@ -- @extends AI.AI_A2A#AI_A2A ---- # AI_A2A_GCI class, extends @{AI_A2A#AI_A2A} +--- # AI_A2A_GCI class, extends @{AI.AI_A2A#AI_A2A} -- -- The AI_A2A_GCI class implements the core functions to intercept intruders. The Engage function will intercept intruders. -- -- ![Process](..\Presentations\AI_GCI\Dia3.JPG) -- --- The AI_A2A_GCI is assigned a @{Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event. +-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_GCI\Dia4.JPG) -- @@ -72,8 +72,8 @@ -- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Unit}. --- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task. +-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. +-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- ## 3. Set the Range of Engagement diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index 927c5fd32..e741e9fba 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -8,19 +8,19 @@ -- -- === -- --- @module AI_A2A_Patrol +-- @module AI.AI_A2A_Patrol --- @type AI_A2A_PATROL -- @extends AI.AI_A2A#AI_A2A ---- # AI_A2A_PATROL class, extends @{Fsm#FSM_CONTROLLABLE} +--- # AI_A2A_PATROL class, extends @{AI.AI_A2A#AI_A2A} -- --- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}. +-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}. -- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- --- The AI_A2A_PATROL is assigned a @{Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event. +-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_PATROL\Dia4.JPG) -- @@ -93,7 +93,7 @@ -- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased. -- -- The detection frequency can be set with @{#AI_A2A_PATROL.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection. --- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI. +-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Wrapper.Unit}s detected by the AI. -- -- The detection can be filtered to potential targets in a specific zone. -- Use the method @{#AI_A2A_PATROL.SetDetectionZone}() to set the zone where targets need to be detected. @@ -128,8 +128,8 @@ AI_A2A_PATROL = { -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2A_PATROL self -- @usage @@ -236,8 +236,8 @@ end --- Sets (modifies) the minimum and maximum speed of the patrol. -- @param #AI_A2A_PATROL self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. -- @return #AI_A2A_PATROL self function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) @@ -358,7 +358,7 @@ function AI_A2A_PATROL.Resume( AIPatrol ) AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } ) if AIPatrol:IsAlive() then - local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- #AI_A2A + local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- AI.AI_A2A#AI_A2A _AI_A2A:__Reset( 1 ) _AI_A2A:__Route( 5 ) end diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index ccb0603bc..5d8ed3df6 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -21,25 +21,25 @@ -- -- === -- --- @module AI_Bai +-- @module AI.AI_Bai --- AI_BAI_ZONE class -- @type AI_BAI_ZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling. -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_BAI_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE} +--- # AI_BAI_ZONE class, extends @{AI.AI_Patrol#AI_PATROL_ZONE} -- --- AI_BAI_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. +-- AI_BAI_ZONE derives from the @{AI.AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. -- --- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Controllable} or @{Group}. +-- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. -- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_BAI\Dia3.JPG) -- --- The AI_BAI_ZONE is assigned a @{Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event. +-- The AI_BAI_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event. -- -- ![Start Event](..\Presentations\AI_BAI\Dia4.JPG) -- @@ -112,8 +112,8 @@ -- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Unit}. --- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the BOMB task. +-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}. +-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task. -- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object** @@ -142,8 +142,8 @@ AI_BAI_ZONE = { -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_BAI_ZONE self diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 18bb5fa65..e14ec568f 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -21,7 +21,7 @@ -- -- === -- --- @module AI_Balancer +-- @module AI.AI_Balancer --- @type AI_BALANCER -- @field Core.Set#SET_CLIENT SetClient @@ -30,7 +30,7 @@ -- @extends Core.Fsm#FSM_SET ---- # AI_BALANCER class, extends @{Fsm#FSM_SET} +--- # AI_BALANCER class, extends @{Core.Fsm#FSM_SET} -- -- The AI_BALANCER class monitors and manages as many replacement AI groups as there are -- CLIENTS in a SET_CLIENT collection, which are not occupied by human players. @@ -78,8 +78,8 @@ -- However, there are 2 additional options that you can use to customize the destroy behaviour. -- When a human player joins a slot, you can configure to let the AI return to: -- --- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Airbase#AIRBASE}. --- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Airbase#AIRBASE}. +-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}. +-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}. -- -- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return, -- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed. @@ -141,10 +141,10 @@ function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) return self end ---- Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +--- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. --- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to. +-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. +-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Core.Set#SET_AIRBASE}s to evaluate where to return to. function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet ) self.ToNearestAirbase = true @@ -152,9 +152,9 @@ function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbas self.ReturnAirbaseSet = ReturnAirbaseSet end ---- Returns the AI to the home @{Airbase#AIRBASE}. +--- Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange ) self.ToHomeAirbase = true diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index 8dc70fd40..9df9ddf8e 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -25,23 +25,23 @@ -- -- === -- --- @module AI_Cap +-- @module AI.AI_Cap --- @type AI_CAP_ZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling. -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_CAP_ZONE class, extends @{AI_CAP#AI_PATROL_ZONE} +--- # AI_CAP_ZONE class, extends @{AI.AI_Patrol#AI_PATROL_ZONE} -- --- The AI_CAP_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group} +-- The AI_CAP_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- --- The AI_CAP_ZONE is assigned a @{Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event. +-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_CAP\Dia4.JPG) -- @@ -91,8 +91,8 @@ -- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Unit}. --- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task. +-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. +-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- ## 3. Set the Range of Engagement @@ -127,8 +127,8 @@ AI_CAP_ZONE = { -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_CAP_ZONE self function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 2450d02ff..74e18c3b5 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -23,25 +23,25 @@ -- -- === -- --- @module AI_Cas +-- @module AI.AI_Cas --- AI_CAS_ZONE class -- @type AI_CAS_ZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling. -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_CAS_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE} +--- # AI_CAS_ZONE class, extends @{AI.AI_Patrol#AI_PATROL_ZONE} -- --- AI_CAS_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. +-- AI_CAS_ZONE derives from the @{AI.AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. -- --- The AI_CAS_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Controllable} or @{Group}. +-- The AI_CAS_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. -- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_CAS\Dia3.JPG) -- --- The AI_CAS_ZONE is assigned a @{Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event. +-- The AI_CAS_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event. -- -- ![Start Event](..\Presentations\AI_CAS\Dia4.JPG) -- @@ -114,8 +114,8 @@ -- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Unit}. --- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the CAS task. +-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}. +-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task. -- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- === @@ -132,8 +132,8 @@ AI_CAS_ZONE = { -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_CAS_ZONE self diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 0cb8aed9b..db1a05e55 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -6,13 +6,13 @@ -- -- === -- --- @module AI_Cargo_APC +-- @module AI.AI_Cargo_APC --- @type AI_CARGO_APC -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_APC class, extends @{Core.Base#BASE} +--- # AI\_CARGO\_APC class, extends @{Core.Fsm#FSM_CONTROLLABLE} -- -- === -- @@ -656,7 +656,7 @@ function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate ) end ---- @param #AI_CARGO_HELICOPTER self +--- @param #AI_CARGO_APC self -- @param Wrapper.Group#GROUP APC -- @param From -- @param Event diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index a55bf0d10..e216d0aff 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -6,13 +6,13 @@ -- -- === -- --- @module AI_Cargo_Airplane +-- @module AI.AI_Cargo_Airplane --- @type AI_CARGO_AIRPLANE -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_AIRPLANE class, extends @{Core.Base@BASE} +--- # AI\_CARGO\_AIRPLANE class, extends @{Core.Fsm#FSM_CONTROLLABLE} -- -- === -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index e3da2ee29..a3858a7c7 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -6,7 +6,7 @@ -- -- === -- --- @module AI_Cargo_Dispatcher +-- @module AI.AI_Cargo_Dispatcher --- @type AI_CARGO_DISPATCHER -- @extends Core.Fsm#FSM diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index d7b21b13d..b2808924a 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -6,13 +6,13 @@ -- -- === -- --- @module AI_Cargo_Dispatcher_APC +-- @module AI.AI_Cargo_Dispatcher_APC --- @type AI_CARGO_DISPATCHER_APC -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER ---- # AI\_CARGO\_DISPATCHER\_APC class, extends @{Core.Base#BASE} +--- # AI\_CARGO\_DISPATCHER\_APC class, extends @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} -- -- ![Banner Image](..\Presentations\AI_CARGO_DISPATCHER_APC\Dia1.JPG) -- @@ -81,7 +81,7 @@ AI_CARGO_DISPATCHER_APC = { --- Creates a new AI_CARGO_DISPATCHER_APC object. -- @param #AI_CARGO_DISPATCHER_APC self --- @param Core.Set#SET_GROUP SetAPC The collection of APC @{Group}s. +-- @param Core.Set#SET_GROUP SetAPC The collection of APC @{Wrapper.Group}s. -- @param Core.Set#SET_CARGO SetCargo The collection of @{Cargo} derived objects. -- @param Core.Set#SET_ZONE SetDeployZone The collection of deploy @{Zone}s, which are used to where the cargo will be deployed by the APCs. -- @param #number CombatRadius The cargo will be unloaded from the APC and engage the enemy if the enemy is within CombatRadius range. The radius is in meters, the default value is 500 meters. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index 4deaef1d9..6007e9973 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -6,13 +6,13 @@ -- -- === -- --- @module AI_Cargo_Dispatcher_Airplane +-- @module AI.AI_Cargo_Dispatcher_Airplane --- @type AI_CARGO_DISPATCHER_AIRPLANE -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER ---- # AI\_CARGO\_DISPATCHER\_AIRPLANE class, extends @{Core.Base#BASE} +--- # AI\_CARGO\_DISPATCHER\_AIRPLANE class, extends @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} -- -- === -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index f7a7a07c3..aa3b264fc 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module AI_Cargo_Dispatcher_Helicopter +-- @module AI.AI_Cargo_Dispatcher_Helicopter --- @type AI_CARGO_DISPATCHER_HELICOPTER -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER @@ -93,7 +93,7 @@ AI_CARGO_DISPATCHER_HELICOPTER = { --- Creates a new AI_CARGO_DISPATCHER_HELICOPTER object. -- @param #AI_CARGO_DISPATCHER_HELICOPTER self --- @param Core.Set#SET_GROUP SetHelicopter The collection of Helicopter @{Group}s. +-- @param Core.Set#SET_GROUP SetHelicopter The collection of Helicopter @{Wrapper.Group}s. -- @param Core.Set#SET_CARGO SetCargo The collection of @{Cargo} derived objects. -- @param Core.Set#SET_ZONE SetDeployZone The collection of deploy @{Zone}s, which are used to where the cargo will be deployed by the Helicopters. -- @return #AI_CARGO_DISPATCHER_HELICOPTER diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 643d4e529..555cb858b 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -6,13 +6,13 @@ -- -- === -- --- @module AI_Cargo_Helicopter +-- @module AI.AI_Cargo_Helicopter --- @type AI_CARGO_HELICOPTER -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE} +--- # AI\_CARGO\_TROOPS class, extends @{Core.Fsm#FSM_CONTROLLABLE} -- -- === -- diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 7e5b2828e..db5e6edad 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -6,7 +6,7 @@ -- -- === -- --- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions. +-- AI_FORMATION makes AI @{Wrapper.Group}s fly in formation of various compositions. -- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! -- The purpose of the class is to: -- @@ -45,13 +45,13 @@ -- -- === -- --- @module AI_Formation +-- @module AI.AI_Formation --- AI_FORMATION class -- @type AI_FORMATION --- @extends Fsm#FSM_SET --- @field Unit#UNIT FollowUnit --- @field Set#SET_GROUP FollowGroupSet +-- @extends Core.Fsm#FSM_SET +-- @field Wrapper.Unit#UNIT FollowUnit +-- @field Core.Set#SET_GROUP FollowGroupSet -- @field #string FollowName -- @field #AI_FORMATION.MODE FollowMode The mode the escort is in. -- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. @@ -61,9 +61,9 @@ -- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup. ---- # AI_FORMATION class, extends @{Fsm#FSM_SET} +--- # AI_FORMATION class, extends @{Core.Fsm#FSM_SET} -- --- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader. +-- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader. -- -- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions. -- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! @@ -89,7 +89,7 @@ -- -- Create a new SPAWN object with the @{#AI_FORMATION.New} method: -- --- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Group#GROUP} for a @{Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text. +-- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text. -- -- ## Formation methods -- @@ -147,7 +147,7 @@ AI_FORMATION = { --- AI_FORMATION class constructor for an AI group -- @param #AI_FORMATION self --- @param Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet. +-- @param Wrapper.Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet. -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string FollowName Name of the escort. -- @return #AI_FORMATION self @@ -155,8 +155,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin local self = BASE:Inherit( self, FSM_SET:New( FollowGroupSet ) ) self:F( { FollowUnit, FollowGroupSet, FollowName } ) - self.FollowUnit = FollowUnit -- Unit#UNIT - self.FollowGroupSet = FollowGroupSet -- Set#SET_GROUP + self.FollowUnit = FollowUnit -- Wrapper.Unit#UNIT + self.FollowGroupSet = FollowGroupSet -- Core.Set#SET_GROUP self:SetFlightRandomization( 2 ) diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 4cc6e7d6e..77026ce02 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -30,27 +30,27 @@ -- -- === -- --- @module AI_Patrol +-- @module AI.AI_Patrol --- AI_PATROL_ZONE class -- @type AI_PATROL_ZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling. -- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @field Core.Spawn#SPAWN CoordTest -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI_PATROL_ZONE class, extends @{Fsm#FSM_CONTROLLABLE} +--- # AI_PATROL_ZONE class, extends @{Core.Fsm#FSM_CONTROLLABLE} -- --- The AI_PATROL_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}. +-- The AI_PATROL_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}. -- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- --- The AI_PATROL_ZONE is assigned a @{Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event. +-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_PATROL\Dia4.JPG) -- @@ -123,7 +123,7 @@ -- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased. -- -- The detection frequency can be set with @{#AI_PATROL_ZONE.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection. --- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI. +-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Wrapper.Unit}s detected by the AI. -- -- The detection can be filtered to potential targets in a specific zone. -- Use the method @{#AI_PATROL_ZONE.SetDetectionZone}() to set the zone where targets need to be detected. @@ -157,8 +157,8 @@ AI_PATROL_ZONE = { -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_PATROL_ZONE self -- @usage @@ -454,8 +454,8 @@ end --- Sets (modifies) the minimum and maximum speed of the patrol. -- @param #AI_PATROL_ZONE self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @return #AI_PATROL_ZONE self function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) @@ -564,7 +564,7 @@ end --- Gets a list of @{Unit#UNIT}s that were detected by the AI. -- No filtering is applied, so, ANY detected UNIT can be in this list. --- It is up to the mission designer to use the @{Unit} class and methods to filter the targets. +-- It is up to the mission designer to use the @{Wrapper.Unit} class and methods to filter the targets. -- @param #AI_PATROL_ZONE self -- @return #table The list of @{Unit#UNIT}s function AI_PATROL_ZONE:GetDetectedUnits() diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 809a28690..98b84d819 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -1,4 +1,4 @@ ---- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Unit}s. +--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Wrapper.Unit}s. -- -- ![Banner Image](..\Presentations\ACT_ACCOUNT\Dia1.JPG) -- @@ -55,7 +55,7 @@ do -- ACT_ACCOUNT -- These state transition methods need to provide a return value, which is specified at the function description. -- -- @type ACT_ACCOUNT - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Core.Fsm#FSM_PROCESS ACT_ACCOUNT = { ClassName = "ACT_ACCOUNT", @@ -151,7 +151,7 @@ do -- ACT_ACCOUNT_DEADS -- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object. -- -- @type ACT_ACCOUNT_DEADS - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends #ACT_ACCOUNT ACT_ACCOUNT_DEADS = { ClassName = "ACT_ACCOUNT_DEADS", @@ -160,7 +160,7 @@ do -- ACT_ACCOUNT_DEADS --- Creates a new DESTROY process. -- @param #ACT_ACCOUNT_DEADS self - -- @param Set#SET_UNIT TargetSetUnit + -- @param Core.Set#SET_UNIT TargetSetUnit -- @param #string TaskName function ACT_ACCOUNT_DEADS:New() -- Inherits from BASE @@ -285,7 +285,7 @@ do -- ACT_ACCOUNT_DEADS end --- @param #ACT_ACCOUNT_DEADS self - -- @param Event#EVENTDATA EventData + -- @param Core.Event#EVENTDATA EventData function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData ) self:T( { "EventDead", EventData } ) @@ -297,7 +297,7 @@ do -- ACT_ACCOUNT_DEADS --- DCS Events --- @param #ACT_ACCOUNT_DEADS self - -- @param Event#EVENTDATA EventData + -- @param Core.Event#EVENTDATA EventData function ACT_ACCOUNT_DEADS:onfuncEventCrash( EventData ) self:T( { "EventDead", EventData } ) diff --git a/Moose Development/Moose/Actions/Act_Assist.lua b/Moose Development/Moose/Actions/Act_Assist.lua index 7d4e55d85..ccd56e310 100644 --- a/Moose Development/Moose/Actions/Act_Assist.lua +++ b/Moose Development/Moose/Actions/Act_Assist.lua @@ -142,7 +142,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE --- ACT_ASSIST_SMOKE_TARGETS_ZONE class -- @type ACT_ASSIST_SMOKE_TARGETS_ZONE - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @field Core.Zone#ZONE_BASE TargetZone -- @extends #ACT_ASSIST ACT_ASSIST_SMOKE_TARGETS_ZONE = { @@ -158,7 +158,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Set#SET_UNIT TargetSetUnit + -- @param Core.Set#SET_UNIT TargetSetUnit -- @param Core.Zone#ZONE_BASE TargetZone function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone ) local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST @@ -177,7 +177,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Set#SET_UNIT TargetSetUnit + -- @param Core.Set#SET_UNIT TargetSetUnit -- @param Core.Zone#ZONE_BASE TargetZone -- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone ) diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index 3a4806468..eba201588 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -62,7 +62,7 @@ -- -- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE} -- --- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}. +-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}. -- The player receives on perioding times messages with the coordinates of the route to follow. -- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended. -- diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index f0f99dcdb..566ba7beb 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -16,7 +16,7 @@ -- -- === -- --- @module Cargo +-- @module Cargo.Cargo -- Events @@ -152,7 +152,7 @@ do -- CARGO -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - --- # (R2.4) CARGO class, extends @{Fsm#FSM_PROCESS} + --- # (R2.4) CARGO class, extends @{Core.Fsm#FSM_PROCESS} -- -- The CARGO class defines the core functions that defines a cargo object within MOOSE. -- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation. @@ -708,11 +708,11 @@ do -- CARGO return self end - --- Send a CC message to a @{Group}. + --- Send a CC message to a @{Wrapper.Group}. -- @param #CARGO self -- @param #string Message -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group. - -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. + -- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. function CARGO:MessageToGroup( Message, CarrierGroup, Name ) MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( CarrierGroup ) @@ -864,11 +864,11 @@ do -- CARGO_REPRESENTABLE return self end - --- Send a message to a @{Group} through a communication channel near the cargo. + --- Send a message to a @{Wrapper.Group} through a communication channel near the cargo. -- @param #CARGO_REPRESENTABLE self -- @param #string Message -- @param Wrapper.Group#GROUP TaskGroup - -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. + -- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. function CARGO_REPRESENTABLE:MessageToGroup( Message, TaskGroup, Name ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , self:GetCoordinate():GetVec2(), 500 ) @@ -916,11 +916,11 @@ do -- CARGO_REPORTABLE return self end - --- Send a CC message to a @{Group}. + --- Send a CC message to a @{Wrapper.Group}. -- @param #CARGO_REPORTABLE self -- @param #string Message -- @param Wrapper.Group#GROUP TaskGroup - -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. + -- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name ) MESSAGE:New( Message, 20, "Cargo " .. self:GetName() .. " reporting" ):ToGroup( TaskGroup ) diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 7fc3a7293..0256721da 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -17,7 +17,7 @@ -- -- === -- --- @module CargoCrate +-- @module Cargo.CargoCrate do -- CARGO_CRATE @@ -25,7 +25,7 @@ do -- CARGO_CRATE -- @type CARGO_CRATE -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} + --- # CARGO\_CRATE class, extends @{Cargo.Cargo#CARGO_REPRESENTABLE} -- -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. @@ -165,7 +165,7 @@ do -- CARGO_CRATE end --- Check if Cargo Crate is in the radius for the Cargo to be reported. - -- @param #CARGO self + -- @param #CARGO_CRATE self -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_CRATE:IsInReportRadius( Coordinate ) @@ -185,7 +185,7 @@ do -- CARGO_CRATE --- Check if Cargo Crate is in the radius for the Cargo to be Boarded or Loaded. - -- @param #CARGO self + -- @param #CARGO_CRATE self -- @param Core.Point#Coordinate Coordinate -- @return #boolean true if the Cargo Crate is within the loading radius. function CARGO_CRATE:IsInLoadRadius( Coordinate ) diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 5af3978c4..b2fab505c 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -1,4 +1,4 @@ ---- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Group} object. +--- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object. -- -- === -- @@ -17,7 +17,7 @@ -- -- === -- --- @module CargoGroup +-- @module Cargo.CargoGroup do -- CARGO_GROUP @@ -27,9 +27,9 @@ do -- CARGO_GROUP -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. -- @field #string GroupName The name of the CargoGroup. - --- # CARGO\_GROUP class + --- # CARGO\_GROUP class, extends @{Cargo.Cargo#CARGO_REPORTABLE} -- - -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator. + -- The CARGO\_GROUP class defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. -- -- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo: @@ -53,7 +53,7 @@ do -- CARGO_GROUP } --- CARGO_GROUP constructor. - -- This make a new CARGO_GROUP from a @{Group} object. + -- This make a new CARGO_GROUP from a @{Wrapper.Group} object. -- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. -- @param #CARGO_GROUP self -- @param Wrapper.Group#GROUP CargoGroup @@ -233,7 +233,7 @@ do -- CARGO_GROUP if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() or self:IsUnboarding() then Destroyed = true for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- #CARGO + local Cargo = CargoData -- Cargo.Cargo#CARGO if Cargo:IsAlive() then Destroyed = false else @@ -667,7 +667,7 @@ do -- CARGO_GROUP self:F( { "Respawning" } ) for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- #CARGO + local Cargo = CargoData -- Cargo.Cargo#CARGO Cargo:Destroy() Cargo:SetStartState( "UnLoaded" ) end @@ -713,7 +713,7 @@ do -- CARGO_GROUP -- @param Utilities.Utils#FLARECOLOR FlareColor function CARGO_GROUP:Flare( FlareColor ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO if Cargo then Cargo:Flare( FlareColor ) end @@ -725,7 +725,7 @@ do -- CARGO_GROUP -- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup. function CARGO_GROUP:Smoke( SmokeColor, Radius ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO if Cargo then Cargo:Smoke( SmokeColor, Radius ) @@ -733,14 +733,14 @@ do -- CARGO_GROUP end --- Check if the first element of the CargoGroup is the given @{Zone}. - -- @param #CARGO self + -- @param #CARGO_GROUP self -- @param Core.Zone#ZONE_BASE Zone -- @return #boolean **true** if the first element of the CargoGroup is in the Zone -- @return #boolean **false** if there is no element of the CargoGroup in the Zone. function CARGO_GROUP:IsInZone( Zone ) --self:F( { Zone } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO if Cargo then return Cargo:IsInZone( Zone ) diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index cb7898175..b16e1ffe6 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -17,7 +17,7 @@ -- -- === -- --- @module CargoCrate +-- @module Cargo.CargoSlingload do -- CARGO_SLINGLOAD @@ -26,7 +26,7 @@ do -- CARGO_SLINGLOAD -- @type CARGO_SLINGLOAD -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - --- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE} + --- # CARGO\_CRATE class, extends @{Cargo.Cargo#CARGO_REPRESENTABLE} -- -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- @@ -87,8 +87,8 @@ do -- CARGO_SLINGLOAD --- Check if the cargo can be Slingloaded. - -- @param #CARGO self - function CARGO:CanSlingload() + -- @param #CARGO_SLINGLOAD self + function CARGO_SLINGLOAD:CanSlingload() return true end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 85b6ea6cc..43d5a7350 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -1,4 +1,4 @@ ---- **Cargo** -- Management of single cargo logistics, which are based on a @{Unit} object. +--- **Cargo** -- Management of single cargo logistics, which are based on a @{Wrapper.Unit} object. -- -- === -- @@ -17,7 +17,7 @@ -- -- === -- --- @module CargoUnit +-- @module Cargo.CargoUnit do -- CARGO_UNIT @@ -25,7 +25,7 @@ do -- CARGO_UNIT -- @type CARGO_UNIT -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - --- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE} + --- # CARGO\_UNIT class, extends @{Cargo.Cargo#CARGO_REPRESENTABLEE} -- -- The CARGO\_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_UNIT objects to and from carriers. diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 8dc4eb0e8..f9577a7d1 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -42,8 +42,8 @@ local _ClassID = 0 -- -- ## 1.1) BASE constructor -- --- Any class derived from BASE, will use the @{Base#BASE.New} constructor embedded in the @{Base#BASE.Inherit} method. --- See an example at the @{Base#BASE.New} method how this is done. +-- Any class derived from BASE, will use the @{Core.Base#BASE.New} constructor embedded in the @{Core.Base#BASE.Inherit} method. +-- See an example at the @{Core.Base#BASE.New} method how this is done. -- -- ## 1.2) Trace information for debugging -- diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index ecd6cddbd..ec7c4c9e5 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -13,7 +13,7 @@ --- @type DATABASE -- @extends Core.Base#BASE ---- # DATABASE class, extends @{Base#BASE} +--- # DATABASE class, extends @{Core.Base#BASE} -- -- Mission designers can use the DATABASE class to refer to: -- diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 01804da7a..d786101fa 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -61,8 +61,8 @@ -- So, when the DCS event occurs, the class will be notified of that event. -- There are two functions which you use to subscribe to or unsubscribe from an event. -- --- * @{Base#BASE.HandleEvent}(): Subscribe to a DCS Event. --- * @{Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event. +-- * @{Core.Base#BASE.HandleEvent}(): Subscribe to a DCS Event. +-- * @{Core.Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event. -- -- Note that for a UNIT, the event will be handled **for that UNIT only**! -- Note that for a GROUP, the event will be handled **for all the UNITs in that GROUP only**! @@ -112,7 +112,7 @@ -- # 2) EVENTS type -- -- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the --- @{Base#BASE.HandleEvent}() method. +-- @{Core.Base#BASE.HandleEvent}() method. -- -- # 3) EVENTDATA type -- @@ -183,7 +183,7 @@ world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002 world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003 --- The different types of events supported by MOOSE. --- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method. +-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method. -- @type EVENTS EVENTS = { Shot = world.event.S_EVENT_SHOT, @@ -235,7 +235,7 @@ EVENTS = { -- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName). -- @field Dcs.DCSGroup#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}. -- @field #string IniDCSGroupName (UNIT) The initiating Group name. --- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Group#GROUP} of the initiator Group object. +-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object. -- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName). -- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot. -- @field Dcs.DCScoalition#coalition.side IniCoalition (UNIT) The coalition of the initiator. @@ -250,7 +250,7 @@ EVENTS = { -- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName). -- @field Dcs.DCSGroup#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}. -- @field #string TgtDCSGroupName (UNIT) The target Group name. --- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Group#GROUP} of the target Group object. +-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Wrapper.Group#GROUP} of the target Group object. -- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName). -- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot. -- @field Dcs.DCScoalition#coalition.side TgtCoalition (UNIT) The coalition of the target. @@ -527,7 +527,7 @@ end ---- Clears all event subscriptions for a @{Base#BASE} derived object. +--- Clears all event subscriptions for a @{Core.Base#BASE} derived object. -- @param #EVENT self -- @param Core.Base#BASE EventObject function EVENT:RemoveAll( EventObject ) diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index e3b2aacb1..e81bb9519 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -52,7 +52,7 @@ -- -- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s. -- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s. --- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s. +-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s. -- * @{#FSM_SET}: Models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here -- for multiple objects or the position of the state machine in the process. -- @@ -72,7 +72,7 @@ do -- FSM -- @extends Core.Base#BASE - --- # FSM class, extends @{Base#BASE} + --- # FSM class, extends @{Core.Base#BASE} -- -- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. -- @@ -410,7 +410,7 @@ do -- FSM return self._Transitions or {} end - --- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task. + --- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Wrapper.Controllable} by the task. -- @param #FSM self -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. -- @param #string Event The Event name. @@ -806,7 +806,7 @@ do -- FSM_CONTROLLABLE --- # FSM_CONTROLLABLE, extends @{#FSM} -- - -- FSM_CONTROLLABLE class models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s. + -- FSM_CONTROLLABLE class models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s. -- -- === -- @@ -1116,7 +1116,7 @@ do -- FSM_PROCESS - --- Assign the process to a @{Unit} and activate the process. + --- Assign the process to a @{Wrapper.Unit} and activate the process. -- @param #FSM_PROCESS self -- @param Task.Tasking#TASK Task -- @param Wrapper.Unit#UNIT ProcessUnit diff --git a/Moose Development/Moose/Core/Goal.lua b/Moose Development/Moose/Core/Goal.lua index e4373438e..ba8e9ea1d 100644 --- a/Moose Development/Moose/Core/Goal.lua +++ b/Moose Development/Moose/Core/Goal.lua @@ -18,7 +18,7 @@ do -- Goal -- @extends Core.Fsm#FSM - --- # GOAL class, extends @{Fsm#FSM} + --- # GOAL class, extends @{Core.Fsm#FSM} -- -- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized. -- diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 03eb1c156..6850b9213 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -182,7 +182,7 @@ do -- MENU_BASE --- @type MENU_BASE -- @extends Base#BASE - --- # MENU_BASE class, extends @{Base#BASE} + --- # MENU_BASE class, extends @{Core.Base#BASE} -- The MENU_BASE class defines the main MENU class where other MENU classes are derived from. -- This is an abstract class, so don't use it. -- @field #MENU_BASE @@ -286,7 +286,7 @@ do -- MENU_COMMAND_BASE -- @field #function MenuCallHandler -- @extends Core.Menu#MENU_BASE - --- # MENU_COMMAND_BASE class, extends @{Base#BASE} + --- # MENU_COMMAND_BASE class, extends @{Core.Base#BASE} -- ---------------------------------------------------------- -- The MENU_COMMAND_BASE class defines the main MENU class where other MENU COMMAND_ -- classes are derived from, in order to set commands. @@ -469,7 +469,7 @@ do -- MENU_MISSION_COMMAND --- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters. -- @param #MENU_MISSION_COMMAND self -- @param #string MenuText The text for the menu. - -- @param Menu#MENU_MISSION ParentMenu The parent menu. + -- @param Core.Menu#MENU_MISSION ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. -- @return #MENU_MISSION_COMMAND self @@ -695,7 +695,7 @@ do -- MENU_COALITION_COMMAND -- @param #MENU_COALITION_COMMAND self -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. -- @param #string MenuText The text for the menu. - -- @param Menu#MENU_COALITION ParentMenu The parent menu. + -- @param Core.Menu#MENU_COALITION ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. -- @return #MENU_COALITION_COMMAND diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 904711e7b..d2256e436 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -10,7 +10,7 @@ -- @type MESSAGE -- @extends Core.Base#BASE ---- # MESSAGE class, extends @{Base#BASE} +--- # MESSAGE class, extends @{Core.Base#BASE} -- -- Message System to display Messages to Clients, Coalitions or All. -- Messages are shown on the display panel for an amount of seconds, and will then disappear. @@ -26,7 +26,7 @@ -- Messages are sent: -- -- * To a @{Client} using @{Message#MESSAGE.ToClient}(). --- * To a @{Group} using @{Message#MESSAGE.ToGroup}() +-- * To a @{Wrapper.Group} using @{Message#MESSAGE.ToGroup}() -- * To a coalition using @{Message#MESSAGE.ToCoalition}(). -- * To the red coalition using @{Message#MESSAGE.ToRed}(). -- * To the blue coalition using @{Message#MESSAGE.ToBlue}(). diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 5d914d338..cd8390f7b 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -38,7 +38,7 @@ do -- COORDINATE -- @extends Core.Base#BASE - --- # COORDINATE class, extends @{Base#BASE} + --- # COORDINATE class, extends @{Core.Base#BASE} -- -- COORDINATE defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- @@ -57,7 +57,7 @@ do -- COORDINATE -- * @{#COORDINATE.WaypointAir}(): Build an air route point. -- * @{#COORDINATE.WaypointGround}(): Build a ground route point. -- - -- Route points can be used in the Route methods of the @{Group#GROUP} class. + -- Route points can be used in the Route methods of the @{Wrapper.Group#GROUP} class. -- -- -- ## Smoke, flare, explode, illuminate @@ -1189,7 +1189,7 @@ do -- COORDINATE --- Mark to Group -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. - -- @param Wrapper.Group#GROUP MarkGroup The @{Group} that receives the mark. + -- @param Wrapper.Group#GROUP MarkGroup The @{Wrapper.Group} that receives the mark. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index 61eb02a76..4bc0c24a1 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -18,9 +18,9 @@ -- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file), -- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission. -- --- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Unit#UNIT} or a @{Group#GROUP} or by any other @{Positionable#POSITIONABLE} +-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Positionable#POSITIONABLE} -- --- * If the transmitter is a @{Unit#UNIT} or a @{Group#GROUP}, DCS will set the power of the transmission automatically, +-- * If the transmitter is a @{Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically, -- * If the transmitter is any other @{Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped. -- -- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft, @@ -35,7 +35,7 @@ -- @module Core.Radio ---- # RADIO class, extends @{Base#BASE} +--- # RADIO class, extends @{Core.Base#BASE} -- -- ## RADIO usage -- @@ -45,14 +45,14 @@ -- * Then, you will **set the relevant parameters** to the transmission (see below), -- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function. -- --- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Group#GROUP} or any other @{Positionable#POSITIONABLE} +-- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Positionable#POSITIONABLE} -- -- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"), -- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission. -- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission. -- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead... -- --- Additional Methods to set relevant parameters if the transmiter is a @{Unit#UNIT} or a @{Group#GROUP} +-- Additional Methods to set relevant parameters if the transmiter is a @{Unit#UNIT} or a @{Wrapper.Group#GROUP} -- -- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration, -- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call @@ -64,7 +64,7 @@ -- -- What is this power thing ? -- --- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Unit#UNIT} or a @{Group#GROUP}, you can set the power of the antenna, +-- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna, -- * Otherwise, DCS sets it automatically, depending on what's available on your Unit, -- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**, -- * This an automated DCS calculation you have no say on, @@ -339,7 +339,7 @@ function RADIO:StopBroadcast() end ---- # BEACON class, extends @{Base#BASE} +--- # BEACON class, extends @{Core.Base#BASE} -- -- After attaching a @{#BEACON} to your @{Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want. -- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon. @@ -348,7 +348,7 @@ end -- -- ## AA TACAN Beacon usage -- --- This beacon only works with airborne @{Unit#UNIT} or a @{Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon. +-- This beacon only works with airborne @{Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon. -- Use @#BEACON:StopAATACAN}() to stop it. -- -- ## General Purpose Radio Beacon usage diff --git a/Moose Development/Moose/Core/Report.lua b/Moose Development/Moose/Core/Report.lua index 4b32cdaf1..c6a66fca8 100644 --- a/Moose Development/Moose/Core/Report.lua +++ b/Moose Development/Moose/Core/Report.lua @@ -1,3 +1,16 @@ +--- **Core** -- **REPORT** class provides a handy means to create messages and reports. +-- +-- === +-- +-- ### Authors: +-- +-- * FlightControl : Design & Programming +-- +-- ### Contributions: +-- +-- @module Core.Report + + --- The REPORT class -- @type REPORT -- @extends Core.Base#BASE diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index 246244b29..98b824205 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -48,7 +48,7 @@ -- @extends Core.Base#BASE ---- # SCHEDULER class, extends @{Base#BASE} +--- # SCHEDULER class, extends @{Core.Base#BASE} -- -- The SCHEDULER class creates schedule. -- diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 1c7e8df5e..800511352 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -11,10 +11,10 @@ -- -- Various types of SET_ classes are available: -- --- * @{#SET_UNIT}: Defines a colleciton of @{Unit}s filtered by filter criteria. --- * @{#SET_GROUP}: Defines a collection of @{Group}s filtered by filter criteria. +-- * @{#SET_UNIT}: Defines a colleciton of @{Wrapper.Unit}s filtered by filter criteria. +-- * @{#SET_GROUP}: Defines a collection of @{Wrapper.Group}s filtered by filter criteria. -- * @{#SET_CLIENT}: Defines a collection of @{Client}s filterd by filter criteria. --- * @{#SET_AIRBASE}: Defines a collection of @{Airbase}s filtered by filter criteria. +-- * @{#SET_AIRBASE}: Defines a collection of @{Wrapper.Airbase}s filtered by filter criteria. -- -- These classes are derived from @{#SET_BASE}, which contains the main methods to manage SETs. -- @@ -41,8 +41,8 @@ -- @extends Core.Base#BASE ---- # 1) SET_BASE class, extends @{Base#BASE} --- The @{Set#SET_BASE} class defines the core functions that define a collection of objects. +--- # 1) SET_BASE class, extends @{Core.Base#BASE} +-- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects. -- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach interator loop at defined **"intervals"** to the mail simulator loop. -- In this way, large loops can be done while not blocking the simulator main processing loop. -- The default **"yield interval"** is after 10 objects processed. @@ -50,11 +50,11 @@ -- -- ## 1.1) Add or remove objects from the SET -- --- Some key core functions are @{Set#SET_BASE.Add} and @{Set#SET_BASE.Remove} to add or remove objects from the SET in your logic. +-- Some key core functions are @{Core.Set#SET_BASE.Add} and @{Core.Set#SET_BASE.Remove} to add or remove objects from the SET in your logic. -- -- ## 1.2) Define the SET iterator **"yield interval"** and the **"time interval"** -- --- Modify the iterator intervals with the @{Set#SET_BASE.SetInteratorIntervals} method. +-- Modify the iterator intervals with the @{Core.Set#SET_BASE.SetInteratorIntervals} method. -- You can set the **"yield interval"**, and the **"time interval"**. (See above). -- -- @field #SET_BASE SET_BASE @@ -118,7 +118,7 @@ function SET_BASE:New( Database ) return self end ---- Finds an @{Base#BASE} object based on the object Name. +--- Finds an @{Core.Base#BASE} object based on the object Name. -- @param #SET_BASE self -- @param #string ObjectName -- @return Core.Base#BASE The Object found. @@ -170,7 +170,7 @@ function SET_BASE:GetSetObjects() -- R2.3 end ---- Removes a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +--- Removes a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name. -- @param #SET_BASE self -- @param #string ObjectName -- @param NoTriggerEvent (optional) When `true`, the :Remove() method will not trigger a **Removed** event. @@ -195,7 +195,7 @@ function SET_BASE:Remove( ObjectName, NoTriggerEvent ) end ---- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using a given ObjectName as the index. +--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using a given ObjectName as the index. -- @param #SET_BASE self -- @param #string ObjectName -- @param Core.Base#BASE Object @@ -213,7 +213,7 @@ function SET_BASE:Add( ObjectName, Object ) self:Added( ObjectName, Object ) end ---- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. +--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index. -- @param #SET_BASE self -- @param Wrapper.Object#OBJECT Object -- @return Core.Base#BASE The added BASE Object. @@ -229,7 +229,7 @@ end ---- Gets a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +--- Gets a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name. -- @param #SET_BASE self -- @param #string ObjectName -- @return Core.Base#BASE @@ -242,7 +242,7 @@ function SET_BASE:Get( ObjectName ) return Object end ---- Gets the first object from the @{Set#SET_BASE} and derived classes. +--- Gets the first object from the @{Core.Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetFirst() @@ -253,7 +253,7 @@ function SET_BASE:GetFirst() return FirstObject end ---- Gets the last object from the @{Set#SET_BASE} and derived classes. +--- Gets the last object from the @{Core.Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetLast() @@ -264,7 +264,7 @@ function SET_BASE:GetLast() return LastObject end ---- Gets a random object from the @{Set#SET_BASE} and derived classes. +--- Gets a random object from the @{Core.Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetRandom() @@ -275,7 +275,7 @@ function SET_BASE:GetRandom() end ---- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes. +--- Retrieves the amount of objects in the @{Core.Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return #number Count function SET_BASE:Count() @@ -647,9 +647,9 @@ end --- @type SET_GROUP -- @extends Core.Set#SET_BASE ---- # SET_GROUP class, extends @{Set#SET_BASE} +--- # SET_GROUP class, extends @{Core.Set#SET_BASE} -- --- Mission designers can use the @{Set#SET_GROUP} class to build sets of groups belonging to certain: +-- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain: -- -- * Coalitions -- * Categories @@ -664,7 +664,7 @@ end -- -- ## 2. Add or Remove GROUP(s) from SET_GROUP -- --- GROUPS can be added and removed using the @{Set#SET_GROUP.AddGroupsByName} and @{Set#SET_GROUP.RemoveGroupsByName} respectively. +-- GROUPS can be added and removed using the @{Core.Set#SET_GROUP.AddGroupsByName} and @{Core.Set#SET_GROUP.RemoveGroupsByName} respectively. -- These methods take a single GROUP name or an array of GROUP names to be added or removed from SET_GROUP. -- -- ## 3. SET_GROUP filter criteria @@ -692,7 +692,7 @@ end -- -- Planned filter criteria within development are (so these are not yet available): -- --- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Zone#ZONE}. +-- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. -- -- ## 4. SET_GROUP iterators -- @@ -1423,7 +1423,7 @@ do -- SET_UNIT --- @type SET_UNIT -- @extends Core.Set#SET_BASE - --- # 3) SET_UNIT class, extends @{Set#SET_BASE} + --- # 3) SET_UNIT class, extends @{Core.Set#SET_BASE} -- -- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: -- @@ -1441,7 +1441,7 @@ do -- SET_UNIT -- -- ## 3.2) Add or Remove UNIT(s) from SET_UNIT -- - -- UNITs can be added and removed using the @{Set#SET_UNIT.AddUnitsByName} and @{Set#SET_UNIT.RemoveUnitsByName} respectively. + -- UNITs can be added and removed using the @{Core.Set#SET_UNIT.AddUnitsByName} and @{Core.Set#SET_UNIT.RemoveUnitsByName} respectively. -- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. -- -- ## 3.3) SET_UNIT filter criteria @@ -1461,7 +1461,7 @@ do -- SET_UNIT -- -- Planned filter criteria within development are (so these are not yet available): -- - -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Zone#ZONE}. + -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. -- -- ## 3.4) SET_UNIT iterators -- @@ -1483,7 +1483,7 @@ do -- SET_UNIT -- -- Various methods exist for a SET_UNIT to perform actions or calculations and retrieve results from the SET_UNIT: -- - -- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Unit}s in the SET, delimited by a comma. + -- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Wrapper.Unit}s in the SET, delimited by a comma. -- -- ## 4. SET_UNIT iterators -- @@ -2392,10 +2392,10 @@ do -- SET_UNIT end - --- Retrieve the type names of the @{Unit}s in the SET, delimited by an optional delimiter. + --- Retrieve the type names of the @{Wrapper.Unit}s in the SET, delimited by an optional delimiter. -- @param #SET_UNIT self -- @param #string Delimiter (optional) The delimiter, which is default a comma. - -- @return #string The types of the @{Unit}s delimited. + -- @return #string The types of the @{Wrapper.Unit}s delimited. function SET_UNIT:GetTypeNames( Delimiter ) Delimiter = Delimiter or ", " @@ -2423,7 +2423,7 @@ do -- SET_STATIC --- @type SET_STATIC -- @extends Core.Set#SET_BASE - --- # 3) SET_STATIC class, extends @{Set#SET_BASE} + --- # 3) SET_STATIC class, extends @{Core.Set#SET_BASE} -- -- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain: -- @@ -2441,7 +2441,7 @@ do -- SET_STATIC -- -- ## 3.2) Add or Remove STATIC(s) from SET_STATIC -- - -- STATICs can be added and removed using the @{Set#SET_STATIC.AddStaticsByName} and @{Set#SET_STATIC.RemoveStaticsByName} respectively. + -- STATICs can be added and removed using the @{Core.Set#SET_STATIC.AddStaticsByName} and @{Core.Set#SET_STATIC.RemoveStaticsByName} respectively. -- These methods take a single STATIC name or an array of STATIC names to be added or removed from SET_STATIC. -- -- ## 3.3) SET_STATIC filter criteria @@ -2461,7 +2461,7 @@ do -- SET_STATIC -- -- Planned filter criteria within development are (so these are not yet available): -- - -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Zone#ZONE}. + -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}. -- -- ## 3.4) SET_STATIC iterators -- @@ -3099,9 +3099,9 @@ end ---- # 4) SET_CLIENT class, extends @{Set#SET_BASE} +--- # 4) SET_CLIENT class, extends @{Core.Set#SET_BASE} -- --- Mission designers can use the @{Set#SET_CLIENT} class to build sets of units belonging to certain: +-- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain: -- -- * Coalitions -- * Categories @@ -3117,7 +3117,7 @@ end -- -- ## 4.2) Add or Remove CLIENT(s) from SET_CLIENT -- --- CLIENTs can be added and removed using the @{Set#SET_CLIENT.AddClientsByName} and @{Set#SET_CLIENT.RemoveClientsByName} respectively. +-- CLIENTs can be added and removed using the @{Core.Set#SET_CLIENT.AddClientsByName} and @{Core.Set#SET_CLIENT.RemoveClientsByName} respectively. -- These methods take a single CLIENT name or an array of CLIENT names to be added or removed from SET_CLIENT. -- -- ## 4.3) SET_CLIENT filter criteria @@ -3137,7 +3137,7 @@ end -- -- Planned filter criteria within development are (so these are not yet available): -- --- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Zone#ZONE}. +-- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. -- -- ## 4.4) SET_CLIENT iterators -- @@ -3512,9 +3512,9 @@ end ---- # 4) SET_PLAYER class, extends @{Set#SET_BASE} +--- # 4) SET_PLAYER class, extends @{Core.Set#SET_BASE} -- --- Mission designers can use the @{Set#SET_PLAYER} class to build sets of units belonging to alive players: +-- Mission designers can use the @{Core.Set#SET_PLAYER} class to build sets of units belonging to alive players: -- -- ## 4.1) SET_PLAYER constructor -- @@ -3539,7 +3539,7 @@ end -- -- Planned filter criteria within development are (so these are not yet available): -- --- * @{#SET_PLAYER.FilterZones}: Builds the SET_PLAYER with the clients within a @{Zone#ZONE}. +-- * @{#SET_PLAYER.FilterZones}: Builds the SET_PLAYER with the clients within a @{Core.Zone#ZONE}. -- -- ## 4.4) SET_PLAYER iterators -- @@ -3909,9 +3909,9 @@ end --- @type SET_AIRBASE -- @extends Core.Set#SET_BASE ---- # 5) SET_AIRBASE class, extends @{Set#SET_BASE} +--- # 5) SET_AIRBASE class, extends @{Core.Set#SET_BASE} -- --- Mission designers can use the @{Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: +-- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: -- -- * Coalitions -- @@ -3923,7 +3923,7 @@ end -- -- ## 5.2) Add or Remove AIRBASEs from SET_AIRBASE -- --- AIRBASEs can be added and removed using the @{Set#SET_AIRBASE.AddAirbasesByName} and @{Set#SET_AIRBASE.RemoveAirbasesByName} respectively. +-- AIRBASEs can be added and removed using the @{Core.Set#SET_AIRBASE.AddAirbasesByName} and @{Core.Set#SET_AIRBASE.RemoveAirbasesByName} respectively. -- These methods take a single AIRBASE name or an array of AIRBASE names to be added or removed from SET_AIRBASE. -- -- ## 5.3) SET_AIRBASE filter criteria @@ -4139,10 +4139,10 @@ function SET_AIRBASE:ForEachAirbase( IteratorFunction, ... ) return self end ---- Iterate the SET_AIRBASE while identifying the nearest @{Airbase#AIRBASE} from a @{Point#POINT_VEC2}. +--- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Point#POINT_VEC2}. -- @param #SET_AIRBASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Airbase#AIRBASE}. --- @return Wrapper.Airbase#AIRBASE The closest @{Airbase#AIRBASE}. +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}. +-- @return Wrapper.Airbase#AIRBASE The closest @{Wrapper.Airbase#AIRBASE}. function SET_AIRBASE:FindNearestAirbaseFromPointVec2( PointVec2 ) self:F2( PointVec2 ) @@ -4198,9 +4198,9 @@ end --- @type SET_CARGO -- @extends Core.Set#SET_BASE ---- # (R2.1) SET_CARGO class, extends @{Set#SET_BASE} +--- # (R2.1) SET_CARGO class, extends @{Core.Set#SET_BASE} -- --- Mission designers can use the @{Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: +-- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: -- -- * Coalitions -- * Types @@ -4214,7 +4214,7 @@ end -- -- ## Add or Remove CARGOs from SET_CARGO -- --- CARGOs can be added and removed using the @{Set#SET_CARGO.AddCargosByName} and @{Set#SET_CARGO.RemoveCargosByName} respectively. +-- CARGOs can be added and removed using the @{Core.Set#SET_CARGO.AddCargosByName} and @{Core.Set#SET_CARGO.RemoveCargosByName} respectively. -- These methods take a single CARGO name or an array of CARGO names to be added or removed from SET_CARGO. -- -- ## SET_CARGO filter criteria @@ -4632,9 +4632,9 @@ end --- @type SET_ZONE -- @extends Core.Set#SET_BASE ---- # SET_ZONE class, extends @{Set#SET_BASE} +--- # SET_ZONE class, extends @{Core.Set#SET_BASE} -- --- Mission designers can use the @{Set#SET_ZONE} class to build sets of zones of various types. +-- Mission designers can use the @{Core.Set#SET_ZONE} class to build sets of zones of various types. -- -- ## SET_ZONE constructor -- @@ -4644,7 +4644,7 @@ end -- -- ## Add or Remove ZONEs from SET_ZONE -- --- ZONEs can be added and removed using the @{Set#SET_ZONE.AddZonesByName} and @{Set#SET_ZONE.RemoveZonesByName} respectively. +-- ZONEs can be added and removed using the @{Core.Set#SET_ZONE.AddZonesByName} and @{Core.Set#SET_ZONE.RemoveZonesByName} respectively. -- These methods take a single ZONE name or an array of ZONE names to be added or removed from SET_ZONE. -- -- ## 5.3) SET_ZONE filter criteria diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index a8b9ba76d..86a607fc1 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -22,7 +22,7 @@ --- @type SETTINGS -- @extends Core.Base#BASE ---- # SETTINGS class, extends @{Base#BASE} +--- # SETTINGS class, extends @{Core.Base#BASE} -- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. -- -- === diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index c260e6c9a..a42d6b7c5 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -37,7 +37,7 @@ -- @extends Core.Base#BASE ---- # SPAWN class, extends @{Base#BASE} +--- # SPAWN class, extends @{Core.Base#BASE} -- -- -- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG) -- @@ -67,8 +67,8 @@ -- **Limits** can be set on how many groups can be spawn in each SPAWN object, -- using the method @{#SPAWN.InitLimit}. SPAWN has 2 kind of limits: -- --- * The maximum amount of @{Unit}s that can be **alive** at the same time... --- * The maximum amount of @{Group}s that can be **spawned**... This is more of a **resource**-type of limit. +-- * The maximum amount of @{Wrapper.Unit}s that can be **alive** at the same time... +-- * The maximum amount of @{Wrapper.Group}s that can be **spawned**... This is more of a **resource**-type of limit. -- -- When new groups get spawned using the **Spawn** methods, -- it will be evaluated whether any limits have been reached. @@ -82,7 +82,7 @@ -- with unlimited resources = :InitLimit( 100, 0 ) and 10 groups are alive, but two groups have only one unit alive in the group, -- then a sequent Spawn(Scheduled) will allow a new group to be spawned!!! -- --- ### IMPORTANT!! If a limit has been reached, it is possible that a **Spawn** method returns **nil**, meaning, no @{Group} had been spawned!!! +-- ### IMPORTANT!! If a limit has been reached, it is possible that a **Spawn** method returns **nil**, meaning, no @{Wrapper.Group} had been spawned!!! -- -- Spawned groups get **the same name** as the name of the template group. -- Spawned units in those groups keep _by default_ **the same name** as the name of the template group. @@ -117,7 +117,7 @@ -- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods: -- -- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition). --- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition), and gives each spawned @{Group} an different name. +-- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition), and gives each spawned @{Wrapper.Group} an different name. -- -- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. -- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. @@ -149,15 +149,15 @@ -- -- ### Position randomization -- --- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. --- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius. +-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. +-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Wrapper.Unit}s in the @{Wrapper.Group} that is spawned within a **radius band**, given an Outer and Inner radius. -- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor. -- --- ### Enable / Disable AI when spawning a new @{Group} +-- ### Enable / Disable AI when spawning a new @{Wrapper.Group} -- --- * @{#SPAWN.InitAIOn}(): Turns the AI On when spawning the new @{Group} object. --- * @{#SPAWN.InitAIOff}(): Turns the AI Off when spawning the new @{Group} object. --- * @{#SPAWN.InitAIOnOff}(): Turns the AI On or Off when spawning the new @{Group} object. +-- * @{#SPAWN.InitAIOn}(): Turns the AI On when spawning the new @{Wrapper.Group} object. +-- * @{#SPAWN.InitAIOff}(): Turns the AI Off when spawning the new @{Wrapper.Group} object. +-- * @{#SPAWN.InitAIOnOff}(): Turns the AI On or Off when spawning the new @{Wrapper.Group} object. -- -- ### Limit scheduled spawning -- @@ -165,11 +165,11 @@ -- -- ### Delay initial scheduled spawn -- --- * @{#SPAWN.InitDelayOnOff}(): Turns the inital delay On/Off when scheduled spawning the first @{Group} object. --- * @{#SPAWN.InitDelayOn}(): Turns the inital delay On when scheduled spawning the first @{Group} object. --- * @{#SPAWN.InitDelayOff}(): Turns the inital delay Off when scheduled spawning the first @{Group} object. +-- * @{#SPAWN.InitDelayOnOff}(): Turns the inital delay On/Off when scheduled spawning the first @{Wrapper.Group} object. +-- * @{#SPAWN.InitDelayOn}(): Turns the inital delay On when scheduled spawning the first @{Wrapper.Group} object. +-- * @{#SPAWN.InitDelayOff}(): Turns the inital delay Off when scheduled spawning the first @{Wrapper.Group} object. -- --- ### Repeat spawned @{Group}s upon landing +-- ### Repeat spawned @{Wrapper.Group}s upon landing -- -- * @{#SPAWN.InitRepeat}() or @{#SPAWN.InitRepeatOnLanding}(): This method is used to re-spawn automatically the same group after it has landed. -- * @{#SPAWN.InitRepeatOnEngineShutDown}(): This method is used to re-spawn automatically the same group after it has landed and it shuts down the engines at the ramp. @@ -186,9 +186,9 @@ -- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air). -- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ). -- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}. --- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}. +-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Wrapper.Unit}. -- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. --- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Airbase}, which can be an airdrome, ship or helipad. +-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Wrapper.Airbase}, which can be an airdrome, ship or helipad. -- -- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. -- You can use the @{GROUP} object to do further actions with the DCSGroup. @@ -226,21 +226,21 @@ -- This models AI that has succesfully returned to their airbase, to restart their combat activities. -- Check the @{#SPAWN.InitCleanUp}() for further info. -- --- ## Catch the @{Group} Spawn Event in a callback function! +-- ## Catch the @{Wrapper.Group} Spawn Event in a callback function! -- --- When using the @{#SPAWN.SpawnScheduled)() method, new @{Group}s are created following the spawn time interval parameters. --- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. +-- When using the @{#SPAWN.SpawnScheduled)() method, new @{Wrapper.Group}s are created following the spawn time interval parameters. +-- When a new @{Wrapper.Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. -- The SPAWN class supports this functionality through the method @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ), -- which takes a function as a parameter that you can define locally. --- Whenever a new @{Group} is spawned, the given function is called, and the @{Group} that was just spawned, is given as a parameter. --- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Group} object. +-- Whenever a new @{Wrapper.Group} is spawned, the given function is called, and the @{Wrapper.Group} that was just spawned, is given as a parameter. +-- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Wrapper.Group} object. -- A coding example is provided at the description of the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method. -- -- ## Delay the initial spawning -- --- When using the @{#SPAWN.SpawnScheduled)() method, the default behaviour of this method will be that it will spawn the initial (first) @{Group} +-- When using the @{#SPAWN.SpawnScheduled)() method, the default behaviour of this method will be that it will spawn the initial (first) @{Wrapper.Group} -- immediately when :SpawnScheduled() is initiated. The methods @{#SPAWN.InitDelayOnOff}() and @{#SPAWN.InitDelayOn}() can be used to --- activate a delay before the first @{Group} is spawned. For completeness, a method @{#SPAWN.InitDelayOff}() is also available, that +-- activate a delay before the first @{Wrapper.Group} is spawned. For completeness, a method @{#SPAWN.InitDelayOff}() is also available, that -- can be used to switch off the initial delay. Because there is no delay by default, this method would only be used when a -- @{#SPAWN.SpawnScheduledStop}() ; @{#SPAWN.SpawnScheduledStart}() sequence would have been used. -- @@ -270,7 +270,7 @@ SPAWN.Takeoff = { -- @list SpawnZone ---- Creates the main object to spawn a @{Group} defined in the DCS ME. +--- Creates the main object to spawn a @{Wrapper.Group} defined in the DCS ME. -- @param #SPAWN self -- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. -- @return #SPAWN @@ -551,9 +551,9 @@ function SPAWN:InitRandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, return self end ---- Randomizes the position of @{Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. +--- Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. -- @param #SPAWN self --- @param #boolean RandomizePosition If true, SPAWN will perform the randomization of the @{Group}s position between a given outer and inner radius. +-- @param #boolean RandomizePosition If true, SPAWN will perform the randomization of the @{Wrapper.Group}s position between a given outer and inner radius. -- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. -- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. -- @return #SPAWN @@ -904,7 +904,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) end do -- AI methods - --- Turns the AI On or Off for the @{Group} when spawning. + --- Turns the AI On or Off for the @{Wrapper.Group} when spawning. -- @param #SPAWN self -- @param #boolean AIOnOff A value of true sets the AI On, a value of false sets the AI Off. -- @return #SPAWN The SPAWN object @@ -914,7 +914,7 @@ do -- AI methods return self end - --- Turns the AI On for the @{Group} when spawning. + --- Turns the AI On for the @{Wrapper.Group} when spawning. -- @param #SPAWN self -- @return #SPAWN The SPAWN object function SPAWN:InitAIOn() @@ -922,7 +922,7 @@ do -- AI methods return self:InitAIOnOff( true ) end - --- Turns the AI Off for the @{Group} when spawning. + --- Turns the AI Off for the @{Wrapper.Group} when spawning. -- @param #SPAWN self -- @return #SPAWN The SPAWN object function SPAWN:InitAIOff() @@ -933,8 +933,8 @@ do -- AI methods end -- AI methods do -- Delay methods - --- Turns the Delay On or Off for the first @{Group} scheduled spawning. - -- The default value is that for scheduled spawning, there is an initial delay when spawning the first @{Group}. + --- Turns the Delay On or Off for the first @{Wrapper.Group} scheduled spawning. + -- The default value is that for scheduled spawning, there is an initial delay when spawning the first @{Wrapper.Group}. -- @param #SPAWN self -- @param #boolean DelayOnOff A value of true sets the Delay On, a value of false sets the Delay Off. -- @return #SPAWN The SPAWN object @@ -944,7 +944,7 @@ do -- Delay methods return self end - --- Turns the Delay On for the @{Group} when spawning. + --- Turns the Delay On for the @{Wrapper.Group} when spawning. -- @param #SPAWN self -- @return #SPAWN The SPAWN object function SPAWN:InitDelayOn() @@ -952,7 +952,7 @@ do -- Delay methods return self:InitDelayOnOff( true ) end - --- Turns the Delay Off for the @{Group} when spawning. + --- Turns the Delay Off for the @{Wrapper.Group} when spawning. -- @param #SPAWN self -- @return #SPAWN The SPAWN object function SPAWN:InitDelayOff() @@ -1172,7 +1172,7 @@ end --- Allows to place a CallFunction hook when a new group spawns. -- The provided method will be called when a new group is spawned, including its given parameters. --- The first parameter of the SpawnFunction is the @{Group#GROUP} that was spawned. +-- The first parameter of the SpawnFunction is the @{Wrapper.Group#GROUP} that was spawned. -- @param #SPAWN self -- @param #function SpawnCallBackFunction The function to be called when a group spawns. -- @param SpawnFunctionArguments A random amount of arguments to be provided to the function when the group spawns. @@ -1200,28 +1200,28 @@ function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... ) return self end ---- Will spawn a group at an @{Airbase}. +--- Will spawn a group at an @{Wrapper.Airbase}. -- This method is mostly advisable to be used if you want to simulate spawning units at an airbase. -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. -- You can use the returned group to further define the route to be followed. -- --- The @{Airbase#AIRBASE} object must refer to a valid airbase known in the sim. +-- The @{Wrapper.Airbase#AIRBASE} object must refer to a valid airbase known in the sim. -- You can use the following enumerations to search for the pre-defined airbases on the current known maps of DCS: -- --- * @{Airbase#AIRBASE.Caucasus}: The airbases on the Caucasus map. --- * @{Airbase#AIRBASE.Nevada}: The airbases on the Nevada (NTTR) map. --- * @{Airbase#AIRBASE.Normandy}: The airbases on the Normandy map. +-- * @{Wrapper.Airbase#AIRBASE.Caucasus}: The airbases on the Caucasus map. +-- * @{Wrapper.Airbase#AIRBASE.Nevada}: The airbases on the Nevada (NTTR) map. +-- * @{Wrapper.Airbase#AIRBASE.Normandy}: The airbases on the Normandy map. -- --- Use the method @{Airbase#AIRBASE.FindByName}() to retrieve the airbase object. +-- Use the method @{Wrapper.Airbase#AIRBASE.FindByName}() to retrieve the airbase object. -- The known AIRBASE objects are automatically imported at mission start by MOOSE. -- Therefore, there isn't any New() constructor defined for AIRBASE objects. -- -- Ships and Farps are added within the mission, and are therefore not known. --- For these AIRBASE objects, there isn't an @{Airbase#AIRBASE} enumeration defined. --- You need to provide the **exact name** of the airbase as the parameter to the @{Airbase#AIRBASE.FindByName}() method! +-- For these AIRBASE objects, there isn't an @{Wrapper.Airbase#AIRBASE} enumeration defined. +-- You need to provide the **exact name** of the airbase as the parameter to the @{Wrapper.Airbase#AIRBASE.FindByName}() method! -- -- @param #SPAWN self --- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Airbase} where to spawn the group. +-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Wrapper.Airbase} where to spawn the group. -- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot. -- @param #number TakeoffAltitude (optional) The altitude above the ground. -- @return Wrapper.Group#GROUP that was spawned. @@ -1579,12 +1579,12 @@ function SPAWN:SpawnFromStatic( HostStatic, MinHeight, MaxHeight, SpawnIndex ) end --- Will spawn a Group within a given @{Zone}. --- The @{Zone} can be of any type derived from @{Zone#ZONE_BASE}. --- Once the @{Group} is spawned within the zone, the @{Group} will continue on its route. +-- The @{Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}. +-- Once the @{Wrapper.Group} is spawned within the zone, the @{Wrapper.Group} will continue on its route. -- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates. -- @param #SPAWN self -- @param Core.Zone#ZONE Zone The zone where the group is to be spawned. --- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone. +-- @param #boolean RandomizeGroup (optional) Randomization of the @{Wrapper.Group} position in the zone. -- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone. -- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone. -- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. @@ -1680,12 +1680,12 @@ function SPAWN:SpawnGroupName( SpawnIndex ) end ---- Will find the first alive @{Group} it has spawned, and return the alive @{Group} object and the first Index where the first alive @{Group} object has been found. +--- Will find the first alive @{Wrapper.Group} it has spawned, and return the alive @{Wrapper.Group} object and the first Index where the first alive @{Wrapper.Group} object has been found. -- @param #SPAWN self --- @return Wrapper.Group#GROUP, #number The @{Group} object found, the new Index where the group was found. +-- @return Wrapper.Group#GROUP, #number The @{Wrapper.Group} object found, the new Index where the group was found. -- @return #nil, #nil When no group is found, #nil is returned. -- @usage --- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. +-- -- Find the first alive @{Wrapper.Group} object of the SpawnPlanes SPAWN object @{Wrapper.Group} collection that it has spawned during the mission. -- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() -- while GroupPlane ~= nil do -- -- Do actions with the GroupPlane object. @@ -1705,13 +1705,13 @@ function SPAWN:GetFirstAliveGroup() end ---- Will find the next alive @{Group} object from a given Index, and return a reference to the alive @{Group} object and the next Index where the alive @{Group} has been found. +--- Will find the next alive @{Wrapper.Group} object from a given Index, and return a reference to the alive @{Wrapper.Group} object and the next Index where the alive @{Wrapper.Group} has been found. -- @param #SPAWN self --- @param #number SpawnIndexStart A Index holding the start position to search from. This method can also be used to find the first alive @{Group} object from the given Index. --- @return Wrapper.Group#GROUP, #number The next alive @{Group} object found, the next Index where the next alive @{Group} object was found. --- @return #nil, #nil When no alive @{Group} object is found from the start Index position, #nil is returned. +-- @param #number SpawnIndexStart A Index holding the start position to search from. This method can also be used to find the first alive @{Wrapper.Group} object from the given Index. +-- @return Wrapper.Group#GROUP, #number The next alive @{Wrapper.Group} object found, the next Index where the next alive @{Wrapper.Group} object was found. +-- @return #nil, #nil When no alive @{Wrapper.Group} object is found from the start Index position, #nil is returned. -- @usage --- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. +-- -- Find the first alive @{Wrapper.Group} object of the SpawnPlanes SPAWN object @{Wrapper.Group} collection that it has spawned during the mission. -- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() -- while GroupPlane ~= nil do -- -- Do actions with the GroupPlane object. @@ -1731,12 +1731,12 @@ function SPAWN:GetNextAliveGroup( SpawnIndexStart ) return nil, nil end ---- Will find the last alive @{Group} object, and will return a reference to the last live @{Group} object and the last Index where the last alive @{Group} object has been found. +--- Will find the last alive @{Wrapper.Group} object, and will return a reference to the last live @{Wrapper.Group} object and the last Index where the last alive @{Wrapper.Group} object has been found. -- @param #SPAWN self --- @return Wrapper.Group#GROUP, #number The last alive @{Group} object found, the last Index where the last alive @{Group} object was found. --- @return #nil, #nil When no alive @{Group} object is found, #nil is returned. +-- @return Wrapper.Group#GROUP, #number The last alive @{Wrapper.Group} object found, the last Index where the last alive @{Wrapper.Group} object was found. +-- @return #nil, #nil When no alive @{Wrapper.Group} object is found, #nil is returned. -- @usage --- -- Find the last alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. +-- -- Find the last alive @{Wrapper.Group} object of the SpawnPlanes SPAWN object @{Wrapper.Group} collection that it has spawned during the mission. -- local GroupPlane, Index = SpawnPlanes:GetLastAliveGroup() -- if GroupPlane then -- GroupPlane can be nil!!! -- -- Do actions with the GroupPlane object. diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 22ae07cfc..f1715465a 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -37,7 +37,7 @@ -- @extends Core.Base#BASE ---- # SPAWNSTATIC class, extends @{Base#BASE} +--- # SPAWNSTATIC class, extends @{Core.Base#BASE} -- -- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s. -- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), diff --git a/Moose Development/Moose/Core/Spot.lua b/Moose Development/Moose/Core/Spot.lua index 19ca73263..22ba7eee8 100644 --- a/Moose Development/Moose/Core/Spot.lua +++ b/Moose Development/Moose/Core/Spot.lua @@ -8,7 +8,7 @@ -- -- * Spot for a defined duration. -- * wiggle the spot at the target. --- * Provide a @{Unit} as a target, instead of a point. +-- * Provide a @{Wrapper.Unit} as a target, instead of a point. -- * Implement a status machine, LaseOn, LaseOff. -- -- === @@ -53,7 +53,7 @@ do -- -- * Mark targets for a defined duration. -- * wiggle the spot at the target. - -- * Provide a @{Unit} as a target, instead of a point. + -- * Provide a @{Wrapper.Unit} as a target, instead of a point. -- * Implement a status machine, LaseOn, LaseOff. -- -- ## 1. SPOT constructor diff --git a/Moose Development/Moose/Core/UserFlag.lua b/Moose Development/Moose/Core/UserFlag.lua index f1b09589c..8cfff730f 100644 --- a/Moose Development/Moose/Core/UserFlag.lua +++ b/Moose Development/Moose/Core/UserFlag.lua @@ -18,7 +18,7 @@ do -- UserFlag -- @extends Core.Base#BASE - --- # USERFLAG class, extends @{Base#BASE} + --- # USERFLAG class, extends @{Core.Base#BASE} -- -- Management of DCS User Flags. -- diff --git a/Moose Development/Moose/Core/UserSound.lua b/Moose Development/Moose/Core/UserSound.lua index dcd6c58df..2a7614384 100644 --- a/Moose Development/Moose/Core/UserSound.lua +++ b/Moose Development/Moose/Core/UserSound.lua @@ -18,7 +18,7 @@ do -- UserSound -- @extends Core.Base#BASE - --- # USERSOUND class, extends @{Base#BASE} + --- # USERSOUND class, extends @{Core.Base#BASE} -- -- Management of DCS User Sound. -- @@ -110,9 +110,9 @@ do -- UserSound end - --- Play the usersound to the given @{Group}. + --- Play the usersound to the given @{Wrapper.Group}. -- @param #USERSOUND self - -- @param Wrapper.Group#GROUP Group The @{Group} to play the usersound to. + -- @param Wrapper.Group#GROUP Group The @{Wrapper.Group} to play the usersound to. -- @return #USERSOUND The usersound instance. -- @usage -- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" ) diff --git a/Moose Development/Moose/Core/Velocity.lua b/Moose Development/Moose/Core/Velocity.lua index ecc4b5ea6..0888aa210 100644 --- a/Moose Development/Moose/Core/Velocity.lua +++ b/Moose Development/Moose/Core/Velocity.lua @@ -15,7 +15,7 @@ do -- Velocity -- @extends Core.Base#BASE - --- # VELOCITY class, extends @{Base#BASE} + --- # VELOCITY class, extends @{Core.Base#BASE} -- -- VELOCITY models a speed, which can be expressed in various formats according the Settings. -- @@ -125,7 +125,7 @@ do -- VELOCITY_POSITIONABLE -- @extends Core.Base#BASE - --- # VELOCITY_POSITIONABLE class, extends @{Base#BASE} + --- # VELOCITY_POSITIONABLE class, extends @{Core.Base#BASE} -- -- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings. -- diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index a8dc2f641..a6201d28a 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -12,7 +12,7 @@ -- The object classes are using the zone classes to test the zone boundaries, which can take various forms: -- -- * Test if completely within the zone. --- * Test if partly within the zone (for @{Group#GROUP} objects). +-- * Test if partly within the zone (for @{Wrapper.Group#GROUP} objects). -- * Test if not in the zone. -- * Distance to the nearest intersecting point of the zone. -- * Distance to the center of the zone. @@ -24,8 +24,8 @@ -- * @{#ZONE_RADIUS}: The ZONE_RADIUS class defined by a zone name, a location and a radius. -- * @{#ZONE}: The ZONE class, defined by the zone name as defined within the Mission Editor. -- * @{#ZONE_UNIT}: The ZONE_UNIT class defines by a zone around a @{Unit#UNIT} with a radius. --- * @{#ZONE_GROUP}: The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. --- * @{#ZONE_POLYGON}: The ZONE_POLYGON class defines by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. +-- * @{#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. -- -- === -- @@ -43,7 +43,7 @@ -- @extends Core.Base#BASE ---- # ZONE_BASE class, extends @{Base#BASE} +--- # ZONE_BASE class, extends @{Core.Base#BASE} -- -- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. -- @@ -53,7 +53,7 @@ -- * @{#ZONE_BASE.SetName}(): Sets the name of the zone. -- -- --- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}: +-- ## Each zone implements two polymorphic functions defined in @{Core.Zone#ZONE_BASE}: -- -- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a 2D vector is within the zone. -- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a 3D vector is within the zone. @@ -380,7 +380,7 @@ end -- @field Dcs.DCSTypes#Distance Radius The radius of the zone. -- @extends #ZONE_BASE ---- # ZONE_RADIUS class, extends @{Zone#ZONE_BASE} +--- # ZONE_RADIUS class, extends @{Core.Zone#ZONE_BASE} -- -- The ZONE_RADIUS class defined by a zone name, a location and a radius. -- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties. @@ -951,7 +951,7 @@ end -- @extends #ZONE_RADIUS ---- # ZONE class, extends @{Zone#ZONE_RADIUS} +--- # ZONE class, extends @{Core.Zone#ZONE_RADIUS} -- -- The ZONE class, defined by the zone name as defined within the Mission Editor. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. @@ -965,7 +965,7 @@ end -- You can declare a ZONE using the DCS mission editor by adding a trigger zone in the mission editor. -- -- Then during mission startup, when loading Moose.lua, this trigger zone will be detected as a ZONE declaration. --- Within the background, a ZONE object will be created within the @{Database}. +-- Within the background, a ZONE object will be created within the @{Core.Database}. -- The ZONE name will be the trigger zone name. -- -- So, you can search yourself for the ZONE object by using the @{#ZONE.FindByName}() method. @@ -1023,7 +1023,7 @@ end -- @field Wrapper.Unit#UNIT ZoneUNIT -- @extends Core.Zone#ZONE_RADIUS ---- # ZONE_UNIT class, extends @{Zone#ZONE_RADIUS} +--- # ZONE_UNIT class, extends @{Core.Zone#ZONE_RADIUS} -- -- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. @@ -1116,20 +1116,20 @@ end -- @extends #ZONE_RADIUS ---- # ZONE_GROUP class, extends @{Zone#ZONE_RADIUS} +--- # ZONE_GROUP class, extends @{Core.Zone#ZONE_RADIUS} -- --- The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. The current leader of the group defines the center of the zone. --- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. +-- The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. The current leader of the group defines the center of the zone. +-- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- -- @field #ZONE_GROUP ZONE_GROUP = { ClassName="ZONE_GROUP", } ---- Constructor to create a ZONE_GROUP instance, taking the zone name, a zone @{Group#GROUP} and a radius. +--- Constructor to create a ZONE_GROUP instance, taking the zone name, a zone @{Wrapper.Group#GROUP} and a radius. -- @param #ZONE_GROUP self -- @param #string ZoneName Name of the zone. --- @param Wrapper.Group#GROUP ZoneGROUP The @{Group} as the center of the zone. +-- @param Wrapper.Group#GROUP ZoneGROUP The @{Wrapper.Group} as the center of the zone. -- @param Dcs.DCSTypes#Distance Radius The radius of the zone. -- @return #ZONE_GROUP self function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) @@ -1145,9 +1145,9 @@ function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) end ---- Returns the current location of the @{Group}. +--- Returns the current location of the @{Wrapper.Group}. -- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location. +-- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Wrapper.Group} location. function ZONE_GROUP:GetVec2() self:F( self.ZoneName ) @@ -1158,9 +1158,9 @@ function ZONE_GROUP:GetVec2() return ZoneVec2 end ---- Returns a random location within the zone of the @{Group}. +--- Returns a random location within the zone of the @{Wrapper.Group}. -- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The random location of the zone based on the @{Group} location. +-- @return Dcs.DCSTypes#Vec2 The random location of the zone based on the @{Wrapper.Group} location. function ZONE_GROUP:GetRandomVec2() self:F( self.ZoneName ) @@ -1197,10 +1197,10 @@ end -- @extends #ZONE_BASE ---- # ZONE_POLYGON_BASE class, extends @{Zone#ZONE_BASE} +--- # ZONE_POLYGON_BASE class, extends @{Core.Zone#ZONE_BASE} -- --- The ZONE_POLYGON_BASE class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. +-- The ZONE_POLYGON_BASE class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. +-- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. -- -- ## Zone point randomization @@ -1221,7 +1221,7 @@ ZONE_POLYGON_BASE = { -- @list --- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{DCSTypes#Vec2}, forming a polygon. --- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. +-- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. -- @param #ZONE_POLYGON_BASE self -- @param #string ZoneName Name of the zone. -- @param #ZONE_POLYGON_BASE.ListVec2 PointsArray An array of @{DCSTypes#Vec2}, forming a polygon.. @@ -1245,7 +1245,7 @@ end --- Returns the center location of the polygon. -- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location. +-- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Wrapper.Group} location. function ZONE_POLYGON_BASE:GetVec2() self:F( self.ZoneName ) @@ -1474,10 +1474,10 @@ end -- @extends #ZONE_POLYGON_BASE ---- # ZONE_POLYGON class, extends @{Zone#ZONE_POLYGON_BASE} +--- # ZONE_POLYGON class, extends @{Core.Zone#ZONE_POLYGON_BASE} -- --- The ZONE_POLYGON class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. +-- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. +-- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- -- ## Declare a ZONE_POLYGON directly in the DCS mission editor! -- @@ -1485,7 +1485,7 @@ end -- -- So, imagine you have a group declared in the mission editor, with group name `DefenseZone~ZONE_POLYGON`. -- Then during mission startup, when loading Moose.lua, this group will be detected as a ZONE_POLYGON declaration. --- Within the background, a ZONE_POLYGON object will be created within the @{Database} using the properties of the group. +-- Within the background, a ZONE_POLYGON object will be created within the @{Core.Database} using the properties of the group. -- The ZONE_POLYGON name will be the group name without the ~ZONE_POLYGON tag. -- -- So, you can search yourself for the ZONE_POLYGON by using the @{#ZONE_POLYGON.FindByName}() method. @@ -1504,8 +1504,8 @@ ZONE_POLYGON = { ClassName="ZONE_POLYGON", } ---- Constructor to create a ZONE_POLYGON instance, taking the zone name and the @{Group#GROUP} defined within the Mission Editor. --- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. +--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the @{Wrapper.Group#GROUP} defined within the Mission Editor. +-- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. -- @param #ZONE_POLYGON self -- @param #string ZoneName Name of the zone. -- @param Wrapper.Group#GROUP ZoneGroup The GROUP waypoints as defined within the Mission Editor define the polygon shape. @@ -1521,8 +1521,8 @@ function ZONE_POLYGON:New( ZoneName, ZoneGroup ) end ---- Constructor to create a ZONE_POLYGON instance, taking the zone name and the **name** of the @{Group#GROUP} defined within the Mission Editor. --- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. +--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the **name** of the @{Wrapper.Group#GROUP} defined within the Mission Editor. +-- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. -- @param #ZONE_POLYGON self -- @param #string ZoneName Name of the zone. -- @param #string GroupName The group name of the GROUP defining the waypoints within the Mission Editor to define the polygon shape. diff --git a/Moose Development/Moose/Functional/ATC_Ground.lua b/Moose Development/Moose/Functional/ATC_Ground.lua index b27fa27f4..5709e7686 100644 --- a/Moose Development/Moose/Functional/ATC_Ground.lua +++ b/Moose Development/Moose/Functional/ATC_Ground.lua @@ -417,7 +417,7 @@ end -- # Airbases monitored -- -- The following airbases are monitored at the Caucasus region. --- Use the @{Airbase#AIRBASE.Caucasus} enumeration to select the airbases to be monitored. +-- Use the @{Wrapper.Airbase#AIRBASE.Caucasus} enumeration to select the airbases to be monitored. -- -- * `AIRBASE.Caucasus.Anapa_Vityazevo` -- * `AIRBASE.Caucasus.Batumi` @@ -1021,7 +1021,7 @@ end -- # Airbases monitored -- -- The following airbases are monitored at the Nevada region. --- Use the @{Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored. +-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored. -- -- * `AIRBASE.Nevada.Beatty_Airport` -- * `AIRBASE.Nevada.Boulder_City_Airport` @@ -1561,7 +1561,7 @@ end -- # Airbases monitored -- -- The following airbases are monitored at the Normandy region. --- Use the @{Airbase#AIRBASE.Normandy} enumeration to select the airbases to be monitored. +-- Use the @{Wrapper.Airbase#AIRBASE.Normandy} enumeration to select the airbases to be monitored. -- -- * `AIRBASE.Normandy.Azeville` -- * `AIRBASE.Normandy.Bazenville` diff --git a/Moose Development/Moose/Functional/CleanUp.lua b/Moose Development/Moose/Functional/CleanUp.lua index 016bb10ef..84ea9c413 100644 --- a/Moose Development/Moose/Functional/CleanUp.lua +++ b/Moose Development/Moose/Functional/CleanUp.lua @@ -16,7 +16,7 @@ --- @type CLEANUP_AIRBASE -- @extends #CLEANUP_AIRBASE.__ ---- # CLEANUP_AIRBASE, extends @{Base#BASE} +--- # CLEANUP_AIRBASE, extends @{Core.Base#BASE} -- -- ![Banner Image](..\Presentations\CLEANUP_AIRBASE\Dia1.JPG) -- @@ -173,7 +173,7 @@ end ---- Destroys a @{Unit} from the simulator, but checks first if it is still existing! +--- Destroys a @{Wrapper.Unit} from the simulator, but checks first if it is still existing! -- @param #CLEANUP_AIRBASE self -- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed. function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 02122a437..2c5d61a8a 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -49,7 +49,7 @@ do -- DETECTION_BASE --- DETECTION_BASE class, extends @{Fsm#FSM} -- -- The DETECTION_BASE class defines the core functions to administer detected objects. - -- The DETECTION_BASE class will detect objects within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s). + -- The DETECTION_BASE class will detect objects within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s). -- -- ## DETECTION_BASE constructor -- @@ -1255,7 +1255,7 @@ do -- DETECTION_BASE --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit -- @param Wrapper.Group#GROUP ReportGroup - -- @param Set#SET_GROUP ReportSetGroup + -- @param Core.Set#SET_GROUP ReportSetGroup local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem @@ -1595,7 +1595,7 @@ do -- DETECTION_BASE return "" end - --- Get the @{Set#SET_UNIT} of a detecttion area using a given numeric index. + --- Get the @{Core.Set#SET_UNIT} of a detecttion area using a given numeric index. -- @param #DETECTION_BASE self -- @param #DETECTION_BASE.DetectedItem DetectedItem -- @return Core.Set#SET_UNIT DetectedSet @@ -1644,7 +1644,7 @@ do -- DETECTION_BASE do -- Zones - --- Get the @{Zone#ZONE_UNIT} of a detection area using a given numeric index. + --- Get the @{Core.Zone#ZONE_UNIT} of a detection area using a given numeric index. -- @param #DETECTION_BASE self -- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem. -- @return Core.Zone#ZONE_UNIT DetectedZone @@ -1810,7 +1810,7 @@ do -- DETECTION_UNITS --- # DETECTION_UNITS class, extends @{Detection#DETECTION_BASE} -- -- The DETECTION_UNITS class will detect units within the battle zone. - -- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Set#SET_UNIT} containing ONE @{UNIT} object reference. + -- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference. -- Beware that when the amount of units detected is large, the DetectedItems list will be large also. -- -- @type DETECTION_UNITS @@ -2061,7 +2061,7 @@ do -- DETECTION_TYPES -- -- The DETECTION_TYPES class will detect units within the battle zone. -- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected. - -- Each DetectedItem will contain a field Set, which contains a @{Set#SET_UNIT} containing ONE @{UNIT} object reference. + -- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference. -- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also. -- -- @type DETECTION_TYPES @@ -2268,8 +2268,8 @@ do -- DETECTION_AREAS --- # 4) DETECTION_AREAS class, extends @{Detection#DETECTION_BASE} -- - -- The DETECTION_AREAS class will detect units within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s), - -- and will build a list (table) of @{Set#SET_UNIT}s containing the @{Unit#UNIT}s detected. + -- The DETECTION_AREAS class will detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s), + -- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Unit#UNIT}s detected. -- The class is group the detected units within zones given a DetectedZoneRange parameter. -- A set with multiple detected zones will be created as there are groups of units detected. -- @@ -2278,7 +2278,7 @@ do -- DETECTION_AREAS -- The methods to manage the DetectedItems[].Set(s) are implemented in @{Detection#DECTECTION_BASE} and -- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Detection#DETECTION_AREAS}. -- - -- Retrieve the DetectedItems[].Set with the method @{Detection#DETECTION_BASE.GetDetectedSet}(). A @{Set#SET_UNIT} object will be returned. + -- Retrieve the DetectedItems[].Set with the method @{Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned. -- -- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Detection#DETECTION_BASE.GetDetectionZones}(). -- To understand the amount of zones created, use the method @{Detection#DETECTION_BASE.GetDetectionZoneCount}(). @@ -2300,7 +2300,7 @@ do -- DETECTION_AREAS -- -- @type DETECTION_AREAS -- @field Dcs.DCSTypes#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 @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. + -- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. -- @extends #DETECTION_BASE DETECTION_AREAS = { ClassName = "DETECTION_AREAS", diff --git a/Moose Development/Moose/Functional/Escort.lua b/Moose Development/Moose/Functional/Escort.lua index 6fcddbe7c..25ecced57 100644 --- a/Moose Development/Moose/Functional/Escort.lua +++ b/Moose Development/Moose/Functional/Escort.lua @@ -82,7 +82,7 @@ -- === -- Create a new SPAWN object with the @{#ESCORT.New} method: -- --- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Group#GROUP} for a @{Client#CLIENT}, with an optional briefing text. +-- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text. -- -- ESCORT initialization methods. -- === diff --git a/Moose Development/Moose/Functional/MissileTrainer.lua b/Moose Development/Moose/Functional/MissileTrainer.lua index 7659b3c8a..abaa15d09 100644 --- a/Moose Development/Moose/Functional/MissileTrainer.lua +++ b/Moose Development/Moose/Functional/MissileTrainer.lua @@ -2,7 +2,7 @@ -- -- === -- --- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Base#BASE} +-- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Core.Base#BASE} -- === -- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft, -- the class will destroy the missile within a certain range, to avoid damage to your aircraft. diff --git a/Moose Development/Moose/Functional/Protect.lua b/Moose Development/Moose/Functional/Protect.lua index f8375b867..91c6009f3 100644 --- a/Moose Development/Moose/Functional/Protect.lua +++ b/Moose Development/Moose/Functional/Protect.lua @@ -15,7 +15,7 @@ --- @type PROTECT -- @extends #PROTECT.__ ---- # PROTECT, extends @{Base#BASE} +--- # PROTECT, extends @{Core.Base#BASE} -- -- @field #PROTECT PROTECT = { diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index ce7f4e737..78ed78f09 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -53,7 +53,7 @@ -- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. -- @extends Core.Base#BASE ----# PSEUDOATC class, extends @{Base#BASE} +---# PSEUDOATC class, extends @{Core.Base#BASE} -- The PSEUDOATC class adds some rudimentary ATC functionality via the radio menu. -- -- Local weather reports can be requested for nearby airports and player's mission waypoints. diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 91f42eb48..644dbdac0 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -152,7 +152,7 @@ -- @field #boolean useparkingdb Parking spots are added to data base once an aircraft has used it. These spots can later be used by other aircraft. Default is true. -- @extends Core.Spawn#SPAWN ----# RAT class, extends @{Spawn#SPAWN} +---# RAT class, extends @{Core.Spawn#SPAWN} -- The RAT class implements an easy to use way to randomly fill your map with AI aircraft. -- -- @@ -5238,7 +5238,7 @@ end -- @field #number managerid Managing scheduler id. -- @extends Core.Base#BASE ----# RATMANAGER class, extends @{Base#BASE} +---# RATMANAGER class, extends @{Core.Base#BASE} -- The RATMANAGER class manages spawning of multiple RAT objects in a very simple way. It is created by the @{#RATMANAGER.New}() contructor. -- RAT objects with different "tasks" can be defined as usual. However, they **must not** be spawned via the @{#RAT.Spawn}() function. -- diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index bce0b8ef1..706fe8665 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -86,7 +86,7 @@ -- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated. -- @extends Core.Base#BASE ----# RANGE class, extends @{Base#BASE} +---# RANGE class, extends @{Core.Base#BASE} -- The RANGE class enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. -- The parameter "rangename" defindes the name of the range. It has to be unique since this is also the name displayed in the radio menu. -- @@ -108,7 +108,7 @@ -- -- A strafe pit can be added to the range by the @{#RANGE.AddStrafepit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function. -- --- * The first parameter *targetnames* defines the target or targets. This has to be given as a lua table which contains the names of @{Unit} or @{Static} objects defined in the mission editor. +-- * The first parameter *targetnames* defines the target or targets. This has to be given as a lua table which contains the names of @{Wrapper.Unit} or @{Static} objects defined in the mission editor. -- * In order to perform a valid pass on the strafe pit, the pilot has to begin his run from the correct direction. Therefore, an "approach box" is defined in front -- of the strafe targets. The parameters *boxlength* and *boxwidth* define the size of the box while the parameter *heading* defines its direction. -- If the parameter *heading* is passed as **nil**, the heading is automatically taken from the heading of the first target unit as defined in the ME. @@ -118,7 +118,7 @@ -- * The last parameter *foulline* sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted! -- -- Another function to add a strafe pit is @{#RANGE.AddStrafePitGroup}(*group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*). Here, --- the first parameter *group* is a MOOSE @{Group} object and **all** units in this group define **one** strafe pit. +-- the first parameter *group* is a MOOSE @{Wrapper.Group} object and **all** units in this group define **one** strafe pit. -- -- Finally, a valid approach has to be performed below a certain maximum altitude. The default is 914 meters (3000 ft) AGL. This is a parameter valid for all -- strafing pits of the range and can be adjusted by the @{#RANGE.SetMaxStrafeAlt}(maxalt) function. @@ -126,13 +126,13 @@ -- ## Bombing targets -- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(targetnames, goodhitrange, randommove) function. -- --- * The first parameter *targetnames* has to be a lua table, which contains the names of @{Unit} and/or @{Static} objects defined in the mission editor. --- Note that the @{Range} logic **automatically** determines, if a name belongs to a @{Unit} or @{Static} object now. +-- * The first parameter *targetnames* has to be a lua table, which contains the names of @{Wrapper.Unit} and/or @{Static} objects defined in the mission editor. +-- Note that the @{Range} logic **automatically** determines, if a name belongs to a @{Wrapper.Unit} or @{Static} object now. -- * The (optional) parameter *goodhitrange* specifies the radius around the target. If a bomb or rocket falls at a distance smaller than this number, the hit is considered to be "good". -- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone. -- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired. -- --- Another possibility to add bombing targets is the @{#RANGE.AddBombingTargetGroup}(*group, goodhitrange, randommove*) function. Here the parameter *group* is a MOOSE @{Group} object +-- Another possibility to add bombing targets is the @{#RANGE.AddBombingTargetGroup}(*group, goodhitrange, randommove*) function. Here the parameter *group* is a MOOSE @{Wrapper.Group} object -- and **all** units in this group are defined as bombing targets. -- -- ## Fine Tuning diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 2ca3fd71a..092d7998f 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -10,7 +10,7 @@ -- and creates a CSV file logging the scoring events and results for use at team or squadron websites. -- -- SCORING automatically calculates the threat level of the objects hit and destroyed by players, --- which can be @{Unit}, @{Static) and @{Scenery} objects. +-- which can be @{Wrapper.Unit}, @{Static) and @{Scenery} objects. -- -- Positive score points are granted when enemy or neutral targets are destroyed. -- Negative score points or penalties are given when a friendly target is hit or destroyed. @@ -56,7 +56,7 @@ -- Use the radio menu F10 to consult the scores while running the mission. -- Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission. -- --- # 1) @{Scoring#SCORING} class, extends @{Base#BASE} +-- # 1) @{Scoring#SCORING} class, extends @{Core.Base#BASE} -- -- ## 1.1) Set the destroy score or penalty scale -- @@ -74,9 +74,9 @@ -- ## 1.2) Define special targets that will give extra scores. -- -- Special targets can be set that will give extra scores to the players when these are destroyed. --- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Unit}s. +-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s. -- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s. --- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Group}s. +-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s. -- -- local Scoring = SCORING:New( "Scoring File" ) -- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 ) @@ -93,7 +93,7 @@ -- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points. -- Use the method @{#SCORING.AddZoneScore}() to add a @{Zone} for additional scoring. -- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Zone} for additional scoring. --- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Zone#ZONE_UNIT}, +-- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Core.Zone#ZONE_UNIT}, -- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points. -- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone}, -- just large enough around that building. @@ -339,11 +339,11 @@ function SCORING:SetScaleDestroyPenalty( Scale ) return self end ---- Add a @{Unit} for additional scoring when the @{Unit} is destroyed. --- Note that if there was already a @{Unit} declared within the scoring with the same name, --- then the old @{Unit} will be replaced with the new @{Unit}. +--- Add a @{Wrapper.Unit} for additional scoring when the @{Wrapper.Unit} is destroyed. +-- Note that if there was already a @{Wrapper.Unit} declared within the scoring with the same name, +-- then the old @{Wrapper.Unit} will be replaced with the new @{Wrapper.Unit}. -- @param #SCORING self --- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given. +-- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given. -- @param #number Score The Score value. -- @return #SCORING function SCORING:AddUnitScore( ScoreUnit, Score ) @@ -355,9 +355,9 @@ function SCORING:AddUnitScore( ScoreUnit, Score ) return self end ---- Removes a @{Unit} for additional scoring when the @{Unit} is destroyed. +--- Removes a @{Wrapper.Unit} for additional scoring when the @{Wrapper.Unit} is destroyed. -- @param #SCORING self --- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given. +-- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given. -- @return #SCORING function SCORING:RemoveUnitScore( ScoreUnit ) @@ -398,9 +398,9 @@ function SCORING:RemoveStaticScore( ScoreStatic ) end ---- Specify a special additional score for a @{Group}. +--- Specify a special additional score for a @{Wrapper.Group}. -- @param #SCORING self --- @param Wrapper.Group#GROUP ScoreGroup The @{Group} for which each @{Unit} a Score is given. +-- @param Wrapper.Group#GROUP ScoreGroup The @{Wrapper.Group} for which each @{Wrapper.Unit} a Score is given. -- @param #number Score The Score value. -- @return #SCORING function SCORING:AddScoreGroup( ScoreGroup, Score ) @@ -714,7 +714,7 @@ end -- A free text can be given that is shown to the players. -- The Score can be both positive and negative. -- @param #SCORING self --- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc. +-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc. -- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel). -- @param #string Text A free text that is shown to the players. -- @param #number Score The score can be both positive or negative ( Penalty ). diff --git a/Moose Development/Moose/Functional/ZoneGoal.lua b/Moose Development/Moose/Functional/ZoneGoal.lua index 5bca12a4e..9c3d22c36 100644 --- a/Moose Development/Moose/Functional/ZoneGoal.lua +++ b/Moose Development/Moose/Functional/ZoneGoal.lua @@ -36,7 +36,7 @@ do -- Zone -- -- ### 2.2 ZONE_GOAL Events -- - -- * DestroyedUnit: A @{Unit} is destroyed in the Zone. The event will only get triggered if the method @{#ZONE_GOAL.MonitorDestroyedUnits}() is used. + -- * DestroyedUnit: A @{Wrapper.Unit} is destroyed in the Zone. The event will only get triggered if the method @{#ZONE_GOAL.MonitorDestroyedUnits}() is used. -- -- @field #ZONE_GOAL ZONE_GOAL = { diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 1e4452bec..4090980c6 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -23,7 +23,7 @@ -- @extends Core.Base#BASE ---- # COMMANDCENTER class, extends @{Base#BASE} +--- # COMMANDCENTER class, extends @{Core.Base#BASE} -- -- The COMMANDCENTER class governs multiple missions, the tasking and the reporting. -- diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index 5e95771dd..1c4f5492f 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -46,7 +46,7 @@ do -- DETECTION MANAGER --- DETECTION_MANAGER class. -- @type DETECTION_MANAGER - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. + -- @field Core.Set#SET_GROUP SetGroup The groups to which the FAC will report to. -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. -- @extends Core.Fsm#FSM DETECTION_MANAGER = { @@ -57,7 +57,7 @@ do -- DETECTION MANAGER --- FAC constructor. -- @param #DETECTION_MANAGER self - -- @param Set#SET_GROUP SetGroup + -- @param Core.Set#SET_GROUP SetGroup -- @param Functional.Detection#DETECTION_BASE Detection -- @return #DETECTION_MANAGER self function DETECTION_MANAGER:New( SetGroup, Detection ) @@ -217,7 +217,7 @@ do -- DETECTION MANAGER return self._ReportDisplayTime end - --- Reports the detected items to the @{Set#SET_GROUP}. + --- Reports the detected items to the @{Core.Set#SET_GROUP}. -- @param #DETECTION_MANAGER self -- @param Functional.Detection#DETECTION_BASE Detection -- @return #DETECTION_MANAGER self @@ -233,7 +233,7 @@ do -- DETECTION_REPORTING --- DETECTION_REPORTING class. -- @type DETECTION_REPORTING - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. + -- @field Core.Set#SET_GROUP SetGroup The groups to which the FAC will report to. -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. -- @extends #DETECTION_MANAGER DETECTION_REPORTING = { @@ -243,7 +243,7 @@ do -- DETECTION_REPORTING --- DETECTION_REPORTING constructor. -- @param #DETECTION_REPORTING self - -- @param Set#SET_GROUP SetGroup + -- @param Core.Set#SET_GROUP SetGroup -- @param Functional.Detection#DETECTION_AREAS Detection -- @return #DETECTION_REPORTING self function DETECTION_REPORTING:New( SetGroup, Detection ) @@ -257,7 +257,7 @@ do -- DETECTION_REPORTING --- Creates a string of the detected items in a @{Detection}. -- @param #DETECTION_MANAGER self - -- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object. + -- @param Core.Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object. -- @return #DETECTION_MANAGER self function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet ) self:F2() @@ -287,9 +287,9 @@ do -- DETECTION_REPORTING - --- Reports the detected items to the @{Set#SET_GROUP}. + --- Reports the detected items to the @{Core.Set#SET_GROUP}. -- @param #DETECTION_REPORTING self - -- @param Wrapper.Group#GROUP Group The @{Group} object to where the report needs to go. + -- @param Wrapper.Group#GROUP Group The @{Wrapper.Group} object to where the report needs to go. -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Detection#DETECTION_BASE} object. -- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. function DETECTION_REPORTING:ProcessDetected( Group, Detection ) diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 86ba1d410..1ac4383f8 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -458,7 +458,7 @@ do -- Group Assignment end - --- Set @{Group} assigned to the @{Mission}. + --- Set @{Wrapper.Group} assigned to the @{Mission}. -- @param #MISSION self -- @param Wrapper.Group#GROUP MissionGroup -- @return #MISSION @@ -473,7 +473,7 @@ do -- Group Assignment return self end - --- Clear the @{Group} assignment from the @{Mission}. + --- Clear the @{Wrapper.Group} assignment from the @{Mission}. -- @param #MISSION self -- @param Wrapper.Group#GROUP MissionGroup -- @return #MISSION diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index d854431a5..e68de90d3 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -21,7 +21,7 @@ -- @extends Core.Fsm#FSM_TASK --- --- # TASK class, extends @{Base#BASE} +-- # TASK class, extends @{Core.Base#BASE} -- -- ## The TASK class implements the methods for task orchestration within MOOSE. -- @@ -186,7 +186,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player. + -- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player. -- @param #string PlayerName The name of the player. -- @return #boolean @@ -196,20 +196,20 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player. + -- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player. -- @param #string PlayerName The name of the player. --- Goal Trigger for TASK -- @function [parent=#TASK] Goal -- @param #TASK self - -- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player. + -- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player. -- @param #string PlayerName The name of the player. --- Goal Asynchronous Trigger for TASK -- @function [parent=#TASK] __Goal -- @param #TASK self -- @param #number Delay - -- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player. + -- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the player. -- @param #string PlayerName The name of the player. @@ -489,7 +489,7 @@ do -- Group Assignment end - --- Set @{Group} assigned to the @{Task}. + --- Set @{Wrapper.Group} assigned to the @{Task}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup -- @return #TASK @@ -519,7 +519,7 @@ do -- Group Assignment return self end - --- Clear the @{Group} assignment from the @{Task}. + --- Clear the @{Wrapper.Group} assignment from the @{Task}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup -- @return #TASK @@ -563,7 +563,7 @@ do -- Group Assignment end - --- Assign the @{Task} to a @{Group}. + --- Assign the @{Task} to a @{Wrapper.Group}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup -- @return #TASK @@ -598,7 +598,7 @@ do -- Group Assignment return self end - --- UnAssign the @{Task} from a @{Group}. + --- UnAssign the @{Task} from a @{Wrapper.Group}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup function TASK:UnAssignFromGroup( TaskGroup ) @@ -633,7 +633,7 @@ function TASK:HasGroup( FindGroup ) end ---- Assign the @{Task} to an alive @{Unit}. +--- Assign the @{Task} to an alive @{Wrapper.Unit}. -- @param #TASK self -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK self @@ -652,7 +652,7 @@ function TASK:AssignToUnit( TaskUnit ) return self end ---- UnAssign the @{Task} from an alive @{Unit}. +--- UnAssign the @{Task} from an alive @{Wrapper.Unit}. -- @param #TASK self -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK self @@ -677,7 +677,7 @@ function TASK:SetTimeOut ( Timer ) return self end ---- Send a message of the @{Task} to the assigned @{Group}s. +--- Send a message of the @{Task} to the assigned @{Wrapper.Group}s. -- @param #TASK self function TASK:MessageToGroups( Message ) self:F( { Message = Message } ) @@ -694,7 +694,7 @@ function TASK:MessageToGroups( Message ) end ---- Send the briefng message of the @{Task} to the assigned @{Group}s. +--- Send the briefng message of the @{Task} to the assigned @{Wrapper.Group}s. -- @param #TASK self function TASK:SendBriefingToAssignedGroups() self:F2() @@ -709,7 +709,7 @@ function TASK:SendBriefingToAssignedGroups() end ---- UnAssign the @{Task} from the @{Group}s. +--- UnAssign the @{Task} from the @{Wrapper.Group}s. -- @param #TASK self function TASK:UnAssignFromGroups() self:F2() @@ -874,7 +874,7 @@ function TASK:RemoveMenu( MenuTime ) end ---- Remove the menu option of the @{Task} for a @{Group}. +--- Remove the menu option of the @{Task} for a @{Wrapper.Group}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup -- @param #number MenuTime @@ -905,7 +905,7 @@ function TASK:RefreshMenus( TaskGroup, MenuTime ) end ---- Remove the assigned menu option of the @{Task} for a @{Group}. +--- Remove the assigned menu option of the @{Task} for a @{Wrapper.Group}. -- @param #TASK self -- @param Wrapper.Group#GROUP TaskGroup -- @param #number MenuTime @@ -1001,7 +1001,7 @@ end -- TODO: Obscolete? ---- Fail processes from @{Task} with key @{Unit} +--- Fail processes from @{Task} with key @{Wrapper.Unit} -- @param #TASK self -- @param #string TaskUnitName -- @return #TASK self @@ -1013,7 +1013,7 @@ function TASK:FailProcesses( TaskUnitName ) end end ---- Add a FiniteStateMachine to @{Task} with key Task@{Unit} +--- Add a FiniteStateMachine to @{Task} with key Task@{Wrapper.Unit} -- @param #TASK self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Core.Fsm#FSM_PROCESS Fsm @@ -1026,7 +1026,7 @@ function TASK:SetStateMachine( TaskUnit, Fsm ) return Fsm end ---- Gets the FiniteStateMachine of @{Task} with key Task@{Unit} +--- Gets the FiniteStateMachine of @{Task} with key Task@{Wrapper.Unit} -- @param #TASK self -- @param Wrapper.Unit#UNIT TaskUnit -- @return Core.Fsm#FSM_PROCESS @@ -1036,7 +1036,7 @@ function TASK:GetStateMachine( TaskUnit ) return self.Fsm[TaskUnit] end ---- Remove FiniteStateMachines from @{Task} with key Task@{Unit} +--- Remove FiniteStateMachines from @{Task} with key Task@{Wrapper.Unit} -- @param #TASK self -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK self @@ -1060,7 +1060,7 @@ function TASK:RemoveStateMachine( TaskUnit ) end ---- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task} +--- Checks if there is a FiniteStateMachine assigned to Task@{Wrapper.Unit} for @{Task} -- @param #TASK self -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK self @@ -1675,7 +1675,7 @@ do -- Task Control Menu --- Init Task Control Menu -- @param #TASK self - -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player. -- @return Task Control Menu Refresh ID function TASK:InitTaskControlMenu( TaskUnit ) @@ -1686,7 +1686,7 @@ do -- Task Control Menu --- Get Task Control Menu -- @param #TASK self - -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player. -- @return Core.Menu#MENU_GROUP TaskControlMenu The Task Control Menu function TASK:GetTaskControlMenu( TaskUnit, TaskName ) @@ -1706,7 +1706,7 @@ do -- Task Control Menu --- Remove Task Control Menu -- @param #TASK self - -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player. function TASK:RemoveTaskControlMenu( TaskUnit ) if self.TaskControlMenu then @@ -1717,7 +1717,7 @@ do -- Task Control Menu --- Refresh Task Control Menu -- @param #TASK self - -- @param Wrapper.Unit#UNIT TaskUnit The @{Unit} that contains a player. + -- @param Wrapper.Unit#UNIT TaskUnit The @{Wrapper.Unit} that contains a player. -- @param MenuTime The refresh time that was used to refresh the Task Control Menu items. -- @param MenuTag The tag. function TASK:RefreshTaskControlMenu( TaskUnit, MenuTime, MenuTag ) diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 2a3c150c3..723975838 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -14,7 +14,7 @@ -- @extends Core.Base#BASE --- --- # TASKINFO class, extends @{Base#BASE} +-- # TASKINFO class, extends @{Core.Base#BASE} -- -- ## The TASKINFO class implements the methods to contain information and display information of a task. -- diff --git a/Moose Development/Moose/Tasking/TaskZoneCapture.lua b/Moose Development/Moose/Tasking/TaskZoneCapture.lua index fd5934dfd..7de3f3e04 100644 --- a/Moose Development/Moose/Tasking/TaskZoneCapture.lua +++ b/Moose Development/Moose/Tasking/TaskZoneCapture.lua @@ -24,7 +24,7 @@ do -- TASK_ZONE_GOAL -- -- * **None**: Start of the process -- * **Planned**: The A2G task is planned. - -- * **Assigned**: The A2G task is assigned to a @{Group#GROUP}. + -- * **Assigned**: The A2G task is assigned to a @{Wrapper.Group#GROUP}. -- * **Success**: The A2G task is successfully completed. -- * **Failed**: The A2G task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. -- @@ -44,7 +44,7 @@ do -- TASK_ZONE_GOAL --- Instantiates a new TASK_ZONE_GOAL. -- @param #TASK_ZONE_GOAL self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. -- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal -- @return #TASK_ZONE_GOAL self diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index 0ebc3551a..fff13b776 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -14,7 +14,7 @@ do -- TASK_A2A --- The TASK_A2A class -- @type TASK_A2A - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2A class, extends @{Task#TASK} @@ -25,7 +25,7 @@ do -- TASK_A2A -- -- * **None**: Start of the process -- * **Planned**: The A2A task is planned. - -- * **Assigned**: The A2A task is assigned to a @{Group#GROUP}. + -- * **Assigned**: The A2A task is assigned to a @{Wrapper.Group#GROUP}. -- * **Success**: The A2A task is successfully completed. -- * **Failed**: The A2A task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. -- @@ -45,9 +45,9 @@ do -- TASK_A2A --- Instantiates a new TASK_A2A. -- @param #TASK_A2A self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetAttack The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetAttack The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT UnitSetTargets + -- @param Core.Set#SET_UNIT UnitSetTargets -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. @@ -359,7 +359,7 @@ do -- TASK_A2A_INTERCEPT --- The TASK_A2A_INTERCEPT class -- @type TASK_A2A_INTERCEPT - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2A_INTERCEPT class, extends @{Task_A2A#TASK_A2A} @@ -370,7 +370,7 @@ do -- TASK_A2A_INTERCEPT -- The TASK_A2A_INTERCEPT is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks -- based on detected airborne enemy targets intruding friendly airspace. -- - -- The task is defined for a @{Mission#MISSION}, where a friendly @{Set#SET_GROUP} consisting of GROUPs with one human players each, is intercepting the targets. + -- The task is defined for a @{Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is intercepting the targets. -- The task is given a name and a briefing, that is used in the menu structure and in the reporting. -- -- @field #TASK_A2A_INTERCEPT @@ -458,7 +458,7 @@ do -- TASK_A2A_SWEEP --- The TASK_A2A_SWEEP class -- @type TASK_A2A_SWEEP - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2A_SWEEP class, extends @{Task_A2A#TASK_A2A} @@ -471,7 +471,7 @@ do -- TASK_A2A_SWEEP -- The TASK_A2A_SWEEP is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create sweep tasks -- based on detected airborne enemy targets intruding friendly airspace, for which the detection has been lost for more than 60 seconds. -- - -- The task is defined for a @{Mission#MISSION}, where a friendly @{Set#SET_GROUP} consisting of GROUPs with one human players each, is sweeping the targets. + -- The task is defined for a @{Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is sweeping the targets. -- The task is given a name and a briefing, that is used in the menu structure and in the reporting. -- -- @field #TASK_A2A_SWEEP @@ -569,7 +569,7 @@ do -- TASK_A2A_ENGAGE --- The TASK_A2A_ENGAGE class -- @type TASK_A2A_ENGAGE - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2A_ENGAGE class, extends @{Task_A2A#TASK_A2A} @@ -580,7 +580,7 @@ do -- TASK_A2A_ENGAGE -- The TASK_A2A_ENGAGE is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create engage tasks -- based on detected airborne enemy targets intruding friendly airspace. -- - -- The task is defined for a @{Mission#MISSION}, where a friendly @{Set#SET_GROUP} consisting of GROUPs with one human players each, is engaging the targets. + -- The task is defined for a @{Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is engaging the targets. -- The task is given a name and a briefing, that is used in the menu structure and in the reporting. -- -- @field #TASK_A2A_ENGAGE diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index e385fdd02..d3d0c8c39 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -182,7 +182,7 @@ do -- TASK_A2A_DISPATCHER --- TASK_A2A_DISPATCHER constructor. -- @param #TASK_A2A_DISPATCHER self -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. - -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @param Core.Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. -- @param Functional.Detection#DETECTION_BASE Detection The detection results that are used to dynamically assign new tasks to human players. -- @return #TASK_A2A_DISPATCHER self function TASK_A2A_DISPATCHER:New( Mission, SetGroup, Detection ) @@ -251,7 +251,7 @@ do -- TASK_A2A_DISPATCHER --- Creates an INTERCEPT task when there are targets for it. -- @param #TASK_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function TASK_A2A_DISPATCHER:EvaluateINTERCEPT( DetectedItem ) self:F( { DetectedItem.ItemID } ) @@ -278,7 +278,7 @@ do -- TASK_A2A_DISPATCHER --- Creates an SWEEP task when there are targets for it. -- @param #TASK_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function TASK_A2A_DISPATCHER:EvaluateSWEEP( DetectedItem ) self:F( { DetectedItem.ItemID } ) @@ -304,7 +304,7 @@ do -- TASK_A2A_DISPATCHER --- Creates an ENGAGE task when there are human friendlies airborne near the targets. -- @param #TASK_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function TASK_A2A_DISPATCHER:EvaluateENGAGE( DetectedItem ) self:F( { DetectedItem.ItemID } ) @@ -485,7 +485,7 @@ do -- TASK_A2A_DISPATCHER end - --- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}. + --- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}. -- @param #TASK_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 6b3f28986..15c33a5f8 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -14,7 +14,7 @@ do -- TASK_A2G --- The TASK_A2G class -- @type TASK_A2G - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2G class, extends @{Task#TASK} @@ -25,7 +25,7 @@ do -- TASK_A2G -- -- * **None**: Start of the process -- * **Planned**: The A2G task is planned. - -- * **Assigned**: The A2G task is assigned to a @{Group#GROUP}. + -- * **Assigned**: The A2G task is assigned to a @{Wrapper.Group#GROUP}. -- * **Success**: The A2G task is successfully completed. -- * **Failed**: The A2G task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. -- @@ -45,9 +45,9 @@ do -- TASK_A2G --- Instantiates a new TASK_A2G. -- @param #TASK_A2G self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT UnitSetTargets + -- @param Core.Set#SET_UNIT UnitSetTargets -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. @@ -364,7 +364,7 @@ do -- TASK_A2G_SEAD --- The TASK_A2G_SEAD class -- @type TASK_A2G_SEAD - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2G_SEAD class, extends @{Task_A2G#TASK_A2G} @@ -457,7 +457,7 @@ do -- TASK_A2G_BAI --- The TASK_A2G_BAI class -- @type TASK_A2G_BAI - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2G_BAI class, extends @{Task_A2G#TASK_A2G} @@ -553,7 +553,7 @@ do -- TASK_A2G_CAS --- The TASK_A2G_CAS class -- @type TASK_A2G_CAS - -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK --- # TASK_A2G_CAS class, extends @{Task_A2G#TASK_A2G} diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index dce26950b..a79825a6b 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -14,7 +14,7 @@ do -- TASK_A2G_DISPATCHER --- TASK\_A2G\_DISPATCHER class. -- @type TASK_A2G_DISPATCHER - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. + -- @field Core.Set#SET_GROUP SetGroup The groups to which the FAC will report to. -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. -- @field Tasking.Mission#MISSION Mission -- @extends Tasking.DetectionManager#DETECTION_MANAGER @@ -28,11 +28,11 @@ do -- TASK_A2G_DISPATCHER -- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon, -- in a true co-operation environment wherein **Multiple Teams** will collaborate in Missions to **achieve a common Mission Goal**. -- - -- The A2G dispatcher will dispatch the A2G Tasks to a defined @{Set} of @{Group}s that will be manned by **Players**. - -- We call this the **AttackSet** of the A2G dispatcher. So, the Players are seated in the @{Client}s of the @{Group} @{Set}. + -- The A2G dispatcher will dispatch the A2G Tasks to a defined @{Set} of @{Wrapper.Group}s that will be manned by **Players**. + -- We call this the **AttackSet** of the A2G dispatcher. So, the Players are seated in the @{Client}s of the @{Wrapper.Group} @{Set}. -- -- Depending on the actions of the enemy, preventive tasks are dispatched to the players to orchestrate the engagement in a true co-operation. - -- The detection object will group the detected targets by its grouping method, and integrates a @{Set} of @{Group}s that are Recce vehicles or air units. + -- The detection object will group the detected targets by its grouping method, and integrates a @{Set} of @{Wrapper.Group}s that are Recce vehicles or air units. -- We call this the **RecceSet** of the A2G dispatcher. -- -- Depending on the current detected tactical situation, different task types will be dispatched to the Players seated in the AttackSet.. @@ -379,8 +379,8 @@ do -- TASK_A2G_DISPATCHER -- - A @{Mission} object. Each task belongs to a Mission. -- - A @{Detection} object. There are several detection grouping methods to choose from. -- - A @{Task_A2G_Dispatcher} object. The master A2G task dispatcher. - -- - A @{Set} of @{Group} objects that will detect the emeny, the RecceSet. This is attached to the @{Detection} object. - -- - A @{Set} ob @{Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Task_A2G_Dispatcher} object. + -- - A @{Set} of @{Wrapper.Group} objects that will detect the emeny, the RecceSet. This is attached to the @{Detection} object. + -- - A @{Set} ob @{Wrapper.Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Task_A2G_Dispatcher} object. -- -- Below an example mission declaration that is defines a Task A2G Dispatcher object. -- @@ -432,7 +432,7 @@ do -- TASK_A2G_DISPATCHER --- TASK_A2G_DISPATCHER constructor. -- @param #TASK_A2G_DISPATCHER self -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. - -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @param Core.Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. -- @param Functional.Detection#DETECTION_BASE Detection The detection results that are used to dynamically assign new tasks to human players. -- @return #TASK_A2G_DISPATCHER self function TASK_A2G_DISPATCHER:New( Mission, SetGroup, Detection ) @@ -582,7 +582,7 @@ do -- TASK_A2G_DISPATCHER end - --- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}. + --- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}. -- @param #TASK_A2G_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 47ff9a6ee..7cf6bd9c1 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -133,7 +133,7 @@ do -- TASK_CARGO -- -- * **None**: Start of the process. -- * **Planned**: The cargo task is planned. - -- * **Assigned**: The cargo task is assigned to a @{Group#GROUP}. + -- * **Assigned**: The cargo task is assigned to a @{Wrapper.Group#GROUP}. -- * **Success**: The cargo task is successfully completed. -- * **Failed**: The cargo task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. -- @@ -148,7 +148,7 @@ do -- TASK_CARGO --- Instantiates a new TASK_CARGO. -- @param #TASK_CARGO self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. -- @param #string TaskType The type of Cargo task. diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index b2e2aebdb..b033ee17c 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -17,7 +17,7 @@ do -- TASK_CARGO_CSAR --- Instantiates a new TASK_CARGO_CSAR. -- @param #TASK_CARGO_CSAR self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. -- @param #string TaskBriefing The Cargo Task briefing. diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 1b8dd610f..9671798d6 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -187,7 +187,7 @@ do -- TASK_CARGO_DISPATCHER --- TASK_CARGO_DISPATCHER constructor. -- @param #TASK_CARGO_DISPATCHER self -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. - -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @param Core.Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. -- @return #TASK_CARGO_DISPATCHER self function TASK_CARGO_DISPATCHER:New( Mission, SetGroup ) @@ -498,7 +498,7 @@ do -- TASK_CARGO_DISPATCHER --- Evaluates of a CSAR task needs to be started. -- @param #TASK_CARGO_DISPATCHER self - -- @return Set#SET_CARGO The SetCargo to be rescued. + -- @return Core.Set#SET_CARGO The SetCargo to be rescued. -- @return #nil If there is no CSAR task required. function TASK_CARGO_DISPATCHER:EvaluateCSAR( CSARUnit ) @@ -515,7 +515,7 @@ do -- TASK_CARGO_DISPATCHER - --- Assigns tasks to the @{Set#SET_GROUP}. + --- Assigns tasks to the @{Core.Set#SET_GROUP}. -- @param #TASK_CARGO_DISPATCHER self -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. function TASK_CARGO_DISPATCHER:ManageTasks() diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index 21e296860..9dac77e5d 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -18,7 +18,7 @@ do -- TASK_CARGO_TRANSPORT --- Instantiates a new TASK_CARGO_TRANSPORT. -- @param #TASK_CARGO_TRANSPORT self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. -- @param #string TaskBriefing The Cargo Task briefing. diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index fe61dac24..7788fb9d1 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -35,7 +35,7 @@ do -- TASK_MANAGER --- TASK_MANAGER class. -- @type TASK_MANAGER - -- @field Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @field Core.Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. -- @extends Core.Fsm#FSM TASK_MANAGER = { ClassName = "TASK_MANAGER", @@ -44,7 +44,7 @@ do -- TASK_MANAGER --- TASK\_MANAGER constructor. -- @param #TASK_MANAGER self - -- @param Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. + -- @param Core.Set#SET_GROUP SetGroup The set of group objects containing players for which tasks are managed. -- @return #TASK_MANAGER self function TASK_MANAGER:New( SetGroup ) @@ -180,7 +180,7 @@ do -- TASK_MANAGER end - --- Manages the tasks for the @{Set#SET_GROUP}. + --- Manages the tasks for the @{Core.Set#SET_GROUP}. -- @param #TASK_MANAGER self -- @return #TASK_MANAGER self function TASK_MANAGER:ManageTasks() diff --git a/Moose Development/Moose/Tasking/Task_Pickup.lua b/Moose Development/Moose/Tasking/Task_Pickup.lua index 459f9f4a2..b33acedac 100644 --- a/Moose Development/Moose/Tasking/Task_Pickup.lua +++ b/Moose Development/Moose/Tasking/Task_Pickup.lua @@ -8,7 +8,7 @@ -- -- * **None**: Start of the process -- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Fsm.Assign#ACT_ASSIGN_ACCEPT} is started to accept the task. --- * **Assigned**: The SEAD task is assigned to a @{Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. +-- * **Assigned**: The SEAD task is assigned to a @{Wrapper.Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. -- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. -- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. -- @@ -31,10 +31,10 @@ do -- TASK_PICKUP --- Instantiates a new TASK_PICKUP. -- @param #TASK_PICKUP self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP AssignedSetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP AssignedSetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. -- @param #string TaskType BAI or CAS - -- @param Set#SET_UNIT UnitSetTargets + -- @param Core.Set#SET_UNIT UnitSetTargets -- @param Core.Zone#ZONE_BASE TargetZone -- @return #TASK_PICKUP self function TASK_PICKUP:New( Mission, AssignedSetGroup, TaskName, TaskType ) @@ -55,7 +55,7 @@ do -- TASK_PICKUP end - --- Assign the @{Task} to a @{Unit}. + --- Assign the @{Task} to a @{Wrapper.Unit}. -- @param #TASK_PICKUP self -- @param Wrapper.Unit#UNIT TaskUnit -- @return #TASK_PICKUP self @@ -97,7 +97,7 @@ do -- TASK_PICKUP -- @param #string Event -- @param #string From -- @param #string To - -- @param Event#EVENTDATA Event + -- @param Core.Event#EVENTDATA Event function TASK_PICKUP:OnNext( Fsm, From, Event, To, Event ) self:SetState( self, "State", To ) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index e6db9284c..1f7f98cbf 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -8,13 +8,13 @@ -- -- === -- --- @module Airbase +-- @module Wrapper.Airbase --- @type AIRBASE -- @extends Wrapper.Positionable#POSITIONABLE ---- # AIRBASE class, extends @{Positionable#POSITIONABLE} +--- # AIRBASE class, extends @{Wrapper.Positionable#POSITIONABLE} -- -- AIRBASE is a wrapper class to handle the DCS Airbase objects: -- diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 4ccfe98d4..4f9b80f83 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Client +-- @module Wrapper.Client --- The CLIENT class @@ -16,7 +16,7 @@ -- @extends Wrapper.Unit#UNIT ---- # CLIENT class, extends @{Unit#UNIT} +--- # CLIENT class, extends @{Wrapper.Unit#UNIT} -- -- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. -- Note that clients are NOT the same as Units, they are NOT necessarily alive. diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 04576498f..cdeac78e6 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -19,7 +19,7 @@ ---- # CONTROLLABLE class, extends @{Positionable#POSITIONABLE} +--- # CONTROLLABLE class, extends @{Wrapper.Positionable#POSITIONABLE} -- -- CONTROLLABLE is a wrapper class to handle the "DCS Controllable objects", which are Groups and Units: -- @@ -37,7 +37,7 @@ -- ## CONTROLLABLE Task methods -- -- Several controllable task methods are available that help you to prepare tasks. --- These methods return a string consisting of the task description, which can then be given to either a @{Controllable#CONTROLLABLE.PushTask} or @{Controllable#SetTask} method to assign the task to the CONTROLLABLE. +-- These methods return a string consisting of the task description, which can then be given to either a @{Wrapper.Controllable#CONTROLLABLE.PushTask} or @{Wrapper.Controllable#SetTask} method to assign the task to the CONTROLLABLE. -- Tasks are specific for the category of the CONTROLLABLE, more specific, for AIR, GROUND or AIR and GROUND. -- Each task description where applicable indicates for which controllable category the task is valid. -- There are 2 main subdivisions of tasks: Assigned tasks and EnRoute tasks. @@ -63,7 +63,7 @@ -- * @{#CONTROLLABLE.TaskHold}: (GROUND) Hold ground controllable from moving. -- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable. -- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only. --- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Zone#ZONE_RADIUS). +-- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS). -- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. -- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. -- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. @@ -932,7 +932,7 @@ function CONTROLLABLE:TaskLandAtVec2( Point, Duration ) return DCSTask end ---- (AIR) Land the controllable at a @{Zone#ZONE_RADIUS). +--- (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS). -- @param #CONTROLLABLE self -- @param Core.Zone#ZONE Zone The zone where to land. -- @param #number Duration The duration in seconds to stay on the ground. @@ -2195,7 +2195,7 @@ end ---- Return the route of a controllable by using the @{Database#DATABASE} class. +--- Return the route of a controllable by using the @{Core.Database#DATABASE} class. -- @param #CONTROLLABLE self -- @param #number Begin The route point from where the copy will start. The base route point is 0. -- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. @@ -2742,7 +2742,7 @@ end --- Retrieve the controllable mission and allow to place function hooks within the mission waypoint plan. --- Use the method @{Controllable#CONTROLLABLE:WayPointFunction} to define the hook functions for specific waypoints. +-- Use the method @{Wrapper.Controllable#CONTROLLABLE:WayPointFunction} to define the hook functions for specific waypoints. -- Use the method @{Controllable@CONTROLLABLE:WayPointExecute) to start the execution of the new mission plan. -- Note that when WayPointInitialize is called, the Mission of the controllable is RESTARTED! -- @param #CONTROLLABLE self diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 6f45f873d..c33b674a2 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -32,7 +32,7 @@ --- --- # GROUP class, extends @{Controllable#CONTROLLABLE} +-- # GROUP class, extends @{Wrapper.Controllable#CONTROLLABLE} -- -- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. -- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Group objects are spawned (using the @{SPAWN} class). @@ -51,21 +51,21 @@ -- -- ## GROUP task methods -- --- A GROUP is a @{Controllable}. See the @{Controllable} task methods section for a description of the task methods. +-- A GROUP is a @{Wrapper.Controllable}. See the @{Wrapper.Controllable} task methods section for a description of the task methods. -- -- ### Obtain the mission from group templates -- -- Group templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a group and assign it to another: -- --- * @{Controllable#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. +-- * @{Wrapper.Controllable#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. -- -- ## GROUP Command methods -- --- A GROUP is a @{Controllable}. See the @{Controllable} command methods section for a description of the command methods. +-- A GROUP is a @{Wrapper.Controllable}. See the @{Wrapper.Controllable} command methods section for a description of the command methods. -- -- ## GROUP option methods -- --- A GROUP is a @{Controllable}. See the @{Controllable} option methods section for a description of the option methods. +-- A GROUP is a @{Wrapper.Controllable}. See the @{Wrapper.Controllable} option methods section for a description of the option methods. -- -- ## GROUP Zone validation methods -- @@ -76,7 +76,7 @@ -- * @{#GROUP.IsPartlyInZone}: Returns true if some units of the group are within a @{Zone}. -- * @{#GROUP.IsNotInZone}: Returns true if none of the group units of the group are within a @{Zone}. -- --- The zone can be of any @{Zone} class derived from @{Zone#ZONE_BASE}. So, these methods are polymorphic to the zones tested on. +-- The zone can be of any @{Zone} class derived from @{Core.Zone#ZONE_BASE}. So, these methods are polymorphic to the zones tested on. -- -- ## GROUP AI methods -- @@ -112,7 +112,7 @@ GROUPTEMPLATE.Takeoff = { --- Create a new GROUP from a given GroupTemplate as a parameter. -- Note that the GroupTemplate is NOT spawned into the mission. --- It is merely added to the @{Database}. +-- It is merely added to the @{Core.Database}. -- @param #GROUP self -- @param #table GroupTemplate The GroupTemplate Structure exactly as defined within the mission editor. -- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the group. @@ -209,8 +209,8 @@ end -- * Exist at run-time. -- * Has at least one unit. -- --- When the first @{Unit} of the Group is active, it will return true. --- If the first @{Unit} of the Group is inactive, it will return false. +-- When the first @{Wrapper.Unit} of the Group is active, it will return true. +-- If the first @{Wrapper.Unit} of the Group is inactive, it will return false. -- -- @param #GROUP self -- @return #boolean true if the Group is alive and active. @@ -350,9 +350,9 @@ function GROUP:GetCountry() return nil end ---- Returns a list of @{Unit} objects of the @{Group}. +--- Returns a list of @{Wrapper.Unit} objects of the @{Wrapper.Group}. -- @param #GROUP self --- @return #list The list of @{Unit} objects of the @{Group}. +-- @return #list The list of @{Wrapper.Unit} objects of the @{Wrapper.Group}. function GROUP:GetUnits() self:F2( { self.GroupName } ) local DCSGroup = self:GetDCSObject() @@ -371,9 +371,9 @@ function GROUP:GetUnits() end ---- Returns a list of @{Unit} objects of the @{Group} that are occupied by a player. +--- Returns a list of @{Wrapper.Unit} objects of the @{Wrapper.Group} that are occupied by a player. -- @param #GROUP self --- @return #list The list of player occupied @{Unit} objects of the @{Group}. +-- @return #list The list of player occupied @{Wrapper.Unit} objects of the @{Wrapper.Group}. function GROUP:GetPlayerUnits() self:F2( { self.GroupName } ) local DCSGroup = self:GetDCSObject() @@ -770,7 +770,7 @@ do -- Is Zone methods --- Returns true if all units of the group are within a @{Zone}. -- @param #GROUP self -- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Zone#ZONE_BASE} +-- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} function GROUP:IsCompletelyInZone( Zone ) self:F2( { self.GroupName, Zone } ) @@ -790,7 +790,7 @@ end --- Returns true if some units of the group are within a @{Zone}. -- @param #GROUP self -- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is partially within the @{Zone#ZONE_BASE} +-- @return #boolean Returns true if the Group is partially within the @{Core.Zone#ZONE_BASE} function GROUP:IsPartlyInZone( Zone ) self:F2( { self.GroupName, Zone } ) @@ -818,7 +818,7 @@ end --- Returns true if none of the group units of the group are within a @{Zone}. -- @param #GROUP self -- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is not within the @{Zone#ZONE_BASE} +-- @return #boolean Returns true if the Group is not within the @{Core.Zone#ZONE_BASE} function GROUP:IsNotInZone( Zone ) self:F2( { self.GroupName, Zone } ) @@ -1164,7 +1164,7 @@ function GROUP:InitRandomizePositionRadius( OuterRadius, InnerRadius ) end ---- Respawn the @{Group} at a @{Point}. +--- Respawn the @{Wrapper.Group} at a @{Point}. -- The method will setup the new group template according the Init(Respawn) settings provided for the group. -- These settings can be provided by calling the relevant Init...() methods of the Group. -- @@ -1378,7 +1378,7 @@ function GROUP:GetTaskRoute() return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points ) end ---- Return the route of a group by using the @{Database#DATABASE} class. +--- Return the route of a group by using the @{Core.Database#DATABASE} class. -- @param #GROUP self -- @param #number Begin The route point from where the copy will start. The base route point is 0. -- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. @@ -1469,17 +1469,17 @@ end do -- Route methods - --- (AIR) Return the Group to an @{Airbase#AIRBASE}. + --- (AIR) Return the Group to an @{Wrapper.Airbase#AIRBASE}. -- The following things are to be taken into account: -- -- * The group is respawned to achieve the RTB, there may be side artefacts as a result of this. (Like weapons suddenly come back). -- * A group consisting out of more than one unit, may rejoin formation when respawned. -- * A speed can be given in km/h. If no speed is specified, the maximum speed of the first unit will be taken to return to base. - -- * When there is no @{Airbase} object specified, the group will return to the home base if the route of the group is pinned at take-off or at landing to a base. - -- * When there is no @{Airbase} object specified and the group route is not pinned to any airbase, it will return to the nearest airbase. + -- * When there is no @{Wrapper.Airbase} object specified, the group will return to the home base if the route of the group is pinned at take-off or at landing to a base. + -- * When there is no @{Wrapper.Airbase} object specified and the group route is not pinned to any airbase, it will return to the nearest airbase. -- -- @param #GROUP self - -- @param Wrapper.Airbase#AIRBASE RTBAirbase (optional) The @{Airbase} to return to. If blank, the controllable will return to the nearest friendly airbase. + -- @param Wrapper.Airbase#AIRBASE RTBAirbase (optional) The @{Wrapper.Airbase} to return to. If blank, the controllable will return to the nearest friendly airbase. -- @param #number Speed (optional) The Speed, if no Speed is given, the maximum Speed of the first unit is selected. -- @return #GROUP function GROUP:RouteRTB( RTBAirbase, Speed ) diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index edd123665..bbc6e482b 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -8,13 +8,13 @@ -- -- === -- --- @module Identifiable +-- @module Wrapper.Identifiable --- @type IDENTIFIABLE -- @extends Wrapper.Object#OBJECT -- @field #string IdentifiableName The name of the identifiable. ---- # IDENTIFIABLE class, extends @{Object#OBJECT} +--- # IDENTIFIABLE class, extends @{Wrapper.Object#OBJECT} -- -- The IDENTIFIABLE class is a wrapper class to handle the DCS Identifiable objects: -- diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index 656031e78..6438cf807 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Object +-- @module Wrapper.Object --- @type OBJECT @@ -16,7 +16,7 @@ -- @field #string ObjectName The name of the Object. ---- # OBJECT class, extends @{Base#BASE} +--- # OBJECT class, extends @{Core.Base#BASE} -- -- OBJECT handles the DCS Object objects: -- diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 1ac85b6a4..d01a7c26b 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Positionable +-- @module Wrapper.Positionable --- @type POSITIONABLE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) -- @extends Wrapper.Identifiable#IDENTIFIABLE @@ -17,7 +17,7 @@ -- @extends Wrapper.Identifiable#IDENTIFIABLE ---- # POSITIONABLE class, extends @{Identifiable#IDENTIFIABLE} +--- # POSITIONABLE class, extends @{Wrapper.Identifiable#IDENTIFIABLE} -- -- The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects: -- @@ -626,7 +626,7 @@ function POSITIONABLE:MessageToClient( Message, Duration, Client, Name ) return nil end ---- Send a message to a @{Group}. +--- Send a message to a @{Wrapper.Group}. -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text @@ -653,7 +653,7 @@ function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name ) return nil end ---- Send a message of a message type to a @{Group}. +--- Send a message of a message type to a @{Wrapper.Group}. -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text @@ -673,7 +673,7 @@ function POSITIONABLE:MessageTypeToGroup( Message, MessageType, MessageGroup, Na return nil end ---- Send a message to a @{Set#SET_GROUP}. +--- Send a message to a @{Core.Set#SET_GROUP}. -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text @@ -697,7 +697,7 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam return nil end ---- Send a message to the players in the @{Group}. +--- Send a message to the players in the @{Wrapper.Group}. -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index e999917b1..8160aa955 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Scenery +-- @module Wrapper.Scenery @@ -16,7 +16,7 @@ -- @extends Wrapper.Positionable#POSITIONABLE ---- # SCENERY class, extends @{Positionable#POSITIONABLE} +--- # SCENERY class, extends @{Wrapper.Positionable#POSITIONABLE} -- -- Scenery objects are defined on the map. -- The @{Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index ad53a16dd..bab5b8d70 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -8,13 +8,13 @@ -- -- === -- --- @module Static +-- @module Wrapper.Static --- @type STATIC -- @extends Wrapper.Positionable#POSITIONABLE ---- # STATIC class, extends @{Positionable#POSITIONABLE} +--- # STATIC class, extends @{Wrapper.Positionable#POSITIONABLE} -- -- Statics are **Static Units** defined within the Mission Editor. -- Note that Statics are almost the same as Units, but they don't have a controller. @@ -126,7 +126,7 @@ function STATIC:GetThreatLevel() return 1, "Static" end ---- Respawn the @{Unit} using a (tweaked) template of the parent Group. +--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group. -- @param #UNIT self -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param #number Heading The heading of the unit respawn. @@ -138,7 +138,7 @@ function STATIC:SpawnAt( Coordinate, Heading ) end ---- Respawn the @{Unit} at the same location with the same properties. +--- Respawn the @{Wrapper.Unit} at the same location with the same properties. -- This is useful to respawn a cargo after it has been destroyed. -- @param #UNIT self function STATIC:ReSpawn() @@ -149,7 +149,7 @@ function STATIC:ReSpawn() end ---- Respawn the @{Unit} at a defined Coordinate with an optional heading. +--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading. -- @param #UNIT self -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param #number Heading The heading of the unit respawn. diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 1c4236dc3..8d11d8723 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -17,14 +17,14 @@ -- -- === -- --- @module Unit +-- @module Wrapper.Unit --- @type UNIT -- @extends Wrapper.Controllable#CONTROLLABLE --- --- # UNIT class, extends @{Controllable#CONTROLLABLE} +-- # UNIT class, extends @{Wrapper.Controllable#CONTROLLABLE} -- -- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object. -- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Unit objects are spawned (using the @{SPAWN} class). @@ -75,7 +75,7 @@ -- -- ### Zones range -- --- To test whether the Unit is within a **zone**, use the @{#UNIT.IsInZone}() or the @{#UNIT.IsNotInZone}() methods. Any zone can be tested on, but the zone must be derived from @{Zone#ZONE_BASE}. +-- To test whether the Unit is within a **zone**, use the @{#UNIT.IsInZone}() or the @{#UNIT.IsNotInZone}() methods. Any zone can be tested on, but the zone must be derived from @{Core.Zone#ZONE_BASE}. -- -- ### Unit range -- @@ -190,7 +190,7 @@ function UNIT:Destroy( GenerateEvent ) end ---- Respawn the @{Unit} using a (tweaked) template of the parent Group. +--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group. -- -- This function will: -- @@ -556,9 +556,9 @@ function UNIT:GetFuel() return nil end ---- Returns a list of one @{Unit}. +--- Returns a list of one @{Wrapper.Unit}. -- @param #UNIT self --- @return #list A list of one @{Unit}. +-- @return #list A list of one @{Wrapper.Unit}. function UNIT:GetUnits() self:F2( { self.UnitName } ) local DCSUnit = self:GetDCSObject() @@ -778,7 +778,7 @@ end --- Returns true if the unit is within a @{Zone}. -- @param #UNIT self -- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the unit is within the @{Zone#ZONE_BASE} +-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE} function UNIT:IsInZone( Zone ) self:F2( { self.UnitName, Zone } ) @@ -793,7 +793,7 @@ end --- Returns true if the unit is not within a @{Zone}. -- @param #UNIT self -- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the unit is not within the @{Zone#ZONE_BASE} +-- @return #boolean Returns true if the unit is not within the @{Core.Zone#ZONE_BASE} function UNIT:IsNotInZone( Zone ) self:F2( { self.UnitName, Zone } ) From 5e2a5cf5e8d51c75d10206ee887e7d138f6f8913 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 23 May 2018 13:51:47 +0200 Subject: [PATCH 128/170] Tasking and Functional --- .../Moose/Functional/ATC_Ground.lua | 2 +- .../Moose/Functional/Artillery.lua | 2 +- .../Moose/Functional/CleanUp.lua | 2 +- .../Moose/Functional/Designate.lua | 2 +- .../Moose/Functional/Detection.lua | 2 +- Moose Development/Moose/Functional/Escort.lua | 3 +- .../Moose/Functional/MissileTrainer.lua | 3 +- .../Moose/Functional/Movement.lua | 2 +- .../Moose/Functional/Protect.lua | 2 +- .../Moose/Functional/PseudoATC.lua | 2 +- Moose Development/Moose/Functional/RAT.lua | 2 +- Moose Development/Moose/Functional/Range.lua | 2 +- .../Moose/Functional/Scoring.lua | 2 +- Moose Development/Moose/Functional/Sead.lua | 2 +- .../Moose/Functional/Suppression.lua | 2 +- .../Moose/Functional/ZoneCaptureCoalition.lua | 2 +- .../Moose/Functional/ZoneGoal.lua | 2 +- .../Moose/Functional/ZoneGoalCargo.lua | 2 +- .../Moose/Functional/ZoneGoalCoalition.lua | 2 +- .../Moose/Tasking/CommandCenter.lua | 2 +- .../Moose/Tasking/DetectionManager.lua | 2 +- Moose Development/Moose/Tasking/Mission.lua | 2 +- Moose Development/Moose/Tasking/Task.lua | 2 +- Moose Development/Moose/Tasking/TaskInfo.lua | 2 +- .../Moose/Tasking/TaskZoneCapture.lua | 2 +- Moose Development/Moose/Tasking/Task_A2A.lua | 2 +- .../Moose/Tasking/Task_A2A_Dispatcher.lua | 2 +- Moose Development/Moose/Tasking/Task_A2G.lua | 2 +- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 2 +- .../Moose/Tasking/Task_Cargo_CSAR.lua | 2 + .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 2 +- .../Moose/Tasking/Task_Cargo_Transport.lua | 2 +- .../Moose/Tasking/Task_Manager.lua | 2 +- .../Moose/Tasking/Task_Pickup.lua | 132 ------------------ 34 files changed, 34 insertions(+), 166 deletions(-) delete mode 100644 Moose Development/Moose/Tasking/Task_Pickup.lua diff --git a/Moose Development/Moose/Functional/ATC_Ground.lua b/Moose Development/Moose/Functional/ATC_Ground.lua index 5709e7686..707a8ff24 100644 --- a/Moose Development/Moose/Functional/ATC_Ground.lua +++ b/Moose Development/Moose/Functional/ATC_Ground.lua @@ -11,7 +11,7 @@ -- -- === -- --- @module ATC_Ground +-- @module Functional.ATC_Ground --- @type ATC_GROUND diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index c38ee1fad..59806a42c 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -38,7 +38,7 @@ -- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- ==== --- @module Arty +-- @module Functional.Arty ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- ARTY class diff --git a/Moose Development/Moose/Functional/CleanUp.lua b/Moose Development/Moose/Functional/CleanUp.lua index 84ea9c413..f7414e190 100644 --- a/Moose Development/Moose/Functional/CleanUp.lua +++ b/Moose Development/Moose/Functional/CleanUp.lua @@ -7,7 +7,7 @@ -- -- === -- --- @module CleanUp +-- @module Functional.CleanUp --- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) -- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases. diff --git a/Moose Development/Moose/Functional/Designate.lua b/Moose Development/Moose/Functional/Designate.lua index a633a8801..dce33f924 100644 --- a/Moose Development/Moose/Functional/Designate.lua +++ b/Moose Development/Moose/Functional/Designate.lua @@ -28,7 +28,7 @@ -- -- * **FlightControl**: Design & Programming -- --- @module Designate +-- @module Functional.Designate do -- DESIGNATE diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 2c5d61a8a..93755e614 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -29,7 +29,7 @@ -- -- * FlightControl : Analysis, Design, Programming, Testing -- --- @module Detection +-- @module Functional.Detection ----BASE:TraceClass("DETECTION_BASE") ----BASE:TraceClass("DETECTION_AREAS") diff --git a/Moose Development/Moose/Functional/Escort.lua b/Moose Development/Moose/Functional/Escort.lua index 25ecced57..755770c84 100644 --- a/Moose Development/Moose/Functional/Escort.lua +++ b/Moose Development/Moose/Functional/Escort.lua @@ -114,8 +114,7 @@ -- -- -- --- @module Escort --- @author FlightControl +-- @module Functional.Escort --- ESCORT class -- @type ESCORT diff --git a/Moose Development/Moose/Functional/MissileTrainer.lua b/Moose Development/Moose/Functional/MissileTrainer.lua index abaa15d09..151964515 100644 --- a/Moose Development/Moose/Functional/MissileTrainer.lua +++ b/Moose Development/Moose/Functional/MissileTrainer.lua @@ -77,8 +77,7 @@ -- Danny has shared his ideas and together we made a design. -- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback! -- --- @module MissileTrainer --- @author FlightControl +-- @module Functional.MissileTrainer --- The MISSILETRAINER class diff --git a/Moose Development/Moose/Functional/Movement.lua b/Moose Development/Moose/Functional/Movement.lua index a5d4d7058..8aabf0130 100644 --- a/Moose Development/Moose/Functional/Movement.lua +++ b/Moose Development/Moose/Functional/Movement.lua @@ -7,7 +7,7 @@ -- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if -- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units -- on defined intervals (currently every minute). --- @module Movement +-- @module Functional.Movement --- the MOVEMENT class -- @type MOVEMENT diff --git a/Moose Development/Moose/Functional/Protect.lua b/Moose Development/Moose/Functional/Protect.lua index 91c6009f3..00645edbe 100644 --- a/Moose Development/Moose/Functional/Protect.lua +++ b/Moose Development/Moose/Functional/Protect.lua @@ -7,7 +7,7 @@ -- -- === -- --- @module Protect +-- @module Functional.Protect --- @type PROTECT.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) -- @extends Core.Fsm#FSM diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 78ed78f09..c1a639029 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -38,7 +38,7 @@ -- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- ==== --- @module PseudoATC +-- @module Functional.PseudoATC ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- PSEUDOATC class diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 644dbdac0..31b3fc369 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -59,7 +59,7 @@ -- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- === --- @module Rat +-- @module Functional.Rat ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- RAT class diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 706fe8665..175574bcf 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -48,7 +48,7 @@ -- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536), [Ciribob](https://forums.eagle.ru/member.php?u=112175) -- -- === --- @module Range +-- @module Functional.Range ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- RANGE class diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 092d7998f..c6468a1e5 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -206,7 +206,7 @@ -- -- * **FlightControl**: Concept, Design & Programming. -- --- @module Scoring +-- @module Functional.Scoring --- The Scoring class diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index f1a18b8df..d9d9bfffb 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -2,7 +2,7 @@ -- -- === -- --- @module Sead +-- @module Functional.Sead --- The SEAD class -- @type SEAD diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index 41fb3dc09..929e8b718 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -31,7 +31,7 @@ -- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) -- -- ==== --- @module Suppression +-- @module Functional.Suppression ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index e093eb3ef..7c1610687 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -21,7 +21,7 @@ -- -- === -- --- @module ZoneCaptureCoalition +-- @module Functional.ZoneCaptureCoalition do -- ZONE_CAPTURE_COALITION diff --git a/Moose Development/Moose/Functional/ZoneGoal.lua b/Moose Development/Moose/Functional/ZoneGoal.lua index 9c3d22c36..60c2f6d25 100644 --- a/Moose Development/Moose/Functional/ZoneGoal.lua +++ b/Moose Development/Moose/Functional/ZoneGoal.lua @@ -11,7 +11,7 @@ -- -- === -- --- @module ZoneGoal +-- @module Functional.ZoneGoal do -- Zone diff --git a/Moose Development/Moose/Functional/ZoneGoalCargo.lua b/Moose Development/Moose/Functional/ZoneGoalCargo.lua index e5ea44310..5fc27acc6 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCargo.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCargo.lua @@ -11,7 +11,7 @@ -- -- === -- --- @module ZoneGoalCargo +-- @module Functional.ZoneGoalCargo do -- ZoneGoal diff --git a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua index 91c7df0dc..b0b737518 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua @@ -11,7 +11,7 @@ -- -- === -- --- @module ZoneGoalCoalition +-- @module Functional.ZoneGoalCoalition do -- ZoneGoal diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 4090980c6..725a634b3 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -9,7 +9,7 @@ -- -- === -- --- @module CommandCenter +-- @module Tasking.CommandCenter diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index 1c4f5492f..e6a6aaf19 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -40,7 +40,7 @@ -- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing -- ### Author: FlightControl - Framework Design & Programming -- --- @module DetectionManager +-- @module Tasking.DetectionManager do -- DETECTION MANAGER diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 1ac4383f8..e541b7bbb 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Mission +-- @module Tasking.Mission --- The MISSION class -- @type MISSION diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index e68de90d3..9dd3da5bb 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Task +-- @module Tasking.Task --- @type TASK -- @field Core.Scheduler#SCHEDULER TaskScheduler diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 723975838..349d090c1 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module TaskInfo +-- @module Tasking.TaskInfo --- @type TASKINFO -- @extends Core.Base#BASE diff --git a/Moose Development/Moose/Tasking/TaskZoneCapture.lua b/Moose Development/Moose/Tasking/TaskZoneCapture.lua index 7de3f3e04..ad563c1d5 100644 --- a/Moose Development/Moose/Tasking/TaskZoneCapture.lua +++ b/Moose Development/Moose/Tasking/TaskZoneCapture.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module TaskZoneCapture +-- @module Tasking.TaskZoneCapture do -- TASK_ZONE_GOAL diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index fff13b776..b3c268100 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Task_A2A +-- @module Tasking.Tasking.Task_A2A do -- TASK_A2A diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index d3d0c8c39..3ca89bf8e 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -10,7 +10,7 @@ -- -- === -- --- @module Task_A2A_Dispatcher +-- @module Tasking.Task_A2A_Dispatcher do -- TASK_A2A_DISPATCHER diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 15c33a5f8..59cef82ea 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Task_A2G +-- @module Tasking.Task_A2G do -- TASK_A2G diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index a79825a6b..65d1796b7 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Task_A2G_Dispatcher +-- @module Tasking.Task_A2G_Dispatcher do -- TASK_A2G_DISPATCHER diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index b033ee17c..1326cec30 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -3,6 +3,8 @@ -- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) -- -- === +-- +-- @module Tasking.Task_Cargo_CSAR do -- TASK_CARGO_CSAR diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 9671798d6..9603f5f4f 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -8,7 +8,7 @@ -- -- === -- --- @module Task_Cargo_Dispatcher +-- @module Tasking.Task_Cargo_Dispatcher do -- TASK_CARGO_DISPATCHER diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index 9dac77e5d..f906b87f8 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -3,7 +3,7 @@ -- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) -- -- === --- @module +-- @module Tasking.Task_Cargo_Transport do -- TASK_CARGO_TRANSPORT diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index 7788fb9d1..c82fa505e 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -29,7 +29,7 @@ -- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing -- ### Author: FlightControl - Framework Design & Programming -- --- @module Task_Manager +-- @module Tasking.Task_Manager do -- TASK_MANAGER diff --git a/Moose Development/Moose/Tasking/Task_Pickup.lua b/Moose Development/Moose/Tasking/Task_Pickup.lua deleted file mode 100644 index b33acedac..000000000 --- a/Moose Development/Moose/Tasking/Task_Pickup.lua +++ /dev/null @@ -1,132 +0,0 @@ ---- This module contains the TASK_PICKUP classes. --- --- 1) @{#TASK_PICKUP} class, extends @{Task#TASK} --- === --- The @{#TASK_PICKUP} class defines a pickup task of a @{Set} of @{CARGO} objects defined within the mission. --- based on the tasking capabilities defined in @{Task#TASK}. --- The TASK_PICKUP is implemented using a @{Statemachine#FSM_TASK}, and has the following statuses: --- --- * **None**: Start of the process --- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Fsm.Assign#ACT_ASSIGN_ACCEPT} is started to accept the task. --- * **Assigned**: The SEAD task is assigned to a @{Wrapper.Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. --- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. --- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task_PICKUP - - -do -- TASK_PICKUP - - --- The TASK_PICKUP class - -- @type TASK_PICKUP - -- @extends Tasking.Task#TASK - TASK_PICKUP = { - ClassName = "TASK_PICKUP", - } - - --- Instantiates a new TASK_PICKUP. - -- @param #TASK_PICKUP self - -- @param Tasking.Mission#MISSION Mission - -- @param Core.Set#SET_GROUP AssignedSetGroup The set of groups for which the Task can be assigned. - -- @param #string TaskName The name of the Task. - -- @param #string TaskType BAI or CAS - -- @param Core.Set#SET_UNIT UnitSetTargets - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #TASK_PICKUP self - function TASK_PICKUP:New( Mission, AssignedSetGroup, TaskName, TaskType ) - local self = BASE:Inherit( self, TASK:New( Mission, AssignedSetGroup, TaskName, TaskType, "PICKUP" ) ) - self:F() - - return self - end - - --- Removes a TASK_PICKUP. - -- @param #TASK_PICKUP self - -- @return #nil - function TASK_PICKUP:CleanUp() - - self:GetParent( self ):CleanUp() - - return nil - end - - - --- Assign the @{Task} to a @{Wrapper.Unit}. - -- @param #TASK_PICKUP self - -- @param Wrapper.Unit#UNIT TaskUnit - -- @return #TASK_PICKUP self - function TASK_PICKUP:AssignToUnit( TaskUnit ) - self:F( TaskUnit:GetName() ) - - local ProcessAssign = self:AddProcess( TaskUnit, ACT_ASSIGN_ACCEPT:New( self, TaskUnit, self.TaskBriefing ) ) - local ProcessPickup = self:AddProcess( TaskUnit, PROCESS_PICKUP:New( self, self.TaskType, TaskUnit ) ) - - local Process = self:AddStateMachine( TaskUnit, FSM_TASK:New( self, TaskUnit, { - initial = 'None', - events = { - { name = 'Next', from = 'None', to = 'Planned' }, - { name = 'Next', from = 'Planned', to = 'Assigned' }, - { name = 'Next', from = 'Assigned', to = 'Success' }, - { name = 'Fail', from = 'Assigned', to = 'Failed' }, - }, - callbacks = { - onNext = self.OnNext, - }, - subs = { - Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Start', returnevents = { 'Next', 'Reject' } }, - Pickup = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessDestroy.Fsm, event = 'Start', returnevents = { 'Next' } }, - } - } ) ) - - ProcessRoute:AddScore( "Failed", "failed to destroy a ground unit", -100 ) - ProcessDestroy:AddScore( "Pickup", "Picked-Up a Cargo", 25 ) - ProcessDestroy:AddScore( "Failed", "failed to destroy a ground unit", -100 ) - - Process:Next() - - return self - end - - --- StateMachine callback function for a TASK - -- @param #TASK_PICKUP self - -- @param Core.Fsm#FSM_TASK Fsm - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Event#EVENTDATA Event - function TASK_PICKUP:OnNext( Fsm, From, Event, To, Event ) - - self:SetState( self, "State", To ) - - end - - --- @param #TASK_PICKUP self - function TASK_PICKUP:GetPlannedMenuText() - return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" - end - - - --- @param #TASK_PICKUP self - function TASK_PICKUP:_Schedule() - self:F2() - - self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 ) - return self - end - - - --- @param #TASK_PICKUP self - function TASK_PICKUP._Scheduler() - self:F2() - - return true - end - -end - - - From 369ea08fd10935a942c38ac7dbb532fef79463ee Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 24 May 2018 19:36:53 +0200 Subject: [PATCH 129/170] Minor changes ARTY corrected MISSILE category. --- Moose Development/Moose/Core/Zone.lua | 5 +- .../Moose/Functional/Artillery.lua | 48 ++++++++++++++++--- Moose Development/Moose/Functional/Range.lua | 2 +- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index a8dc2f641..fafde4e43 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -431,8 +431,9 @@ end --- Bounds the zone with tires. -- @param #ZONE_RADIUS self --- @param #number Points (optional) The amount of points in the circle. --- @param #boolean UnBound If true the tyres will be destroyed. +-- @param #number Points (optional) The amount of points in the circle. Default 360. +-- @param Dcs.DCScountry#country.id CountryID The country id of the tire objects, e.g. country.id.USA for blue or country.id.RUSSIA for red. +-- @param #boolean UnBound (Optional) If true the tyres will be destroyed. -- @return #ZONE_RADIUS self function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound ) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index c38ee1fad..b14699798 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -449,6 +449,8 @@ function ARTY:New(group) local DCSunit=DCSgroup:getUnit(1) self.DCSdesc=DCSunit:getDesc() + --self.DCSdesc=group:GetDesc() + -- DCS descriptors. self:T3(ARTY.id.."DCS descriptors for group "..group:GetName()) for id,desc in pairs(self.DCSdesc) do @@ -456,7 +458,8 @@ function ARTY:New(group) end -- Maximum speed in km/h. - self.SpeedMax=self.DCSdesc.speedMax*3.6 + self.SpeedMax=group:GetSpeedMax() + --self.SpeedMax=self.DCSdesc.speedMax*3.6 -- Set speed to 0.7 of maximum. self.Speed=self.SpeedMax * 0.7 @@ -517,7 +520,7 @@ end --- Assign target coordinates to the ARTY group. Only the first parameter, i.e. the coordinate of the target is mandatory. The remaining parameters are optional and can be used to fine tune the engagement. -- @param #ARTY self --- @param Wrapper.Point#COORDINATE coord Coordinates of the target. +-- @param Core.Point#COORDINATE coord Coordinates of the target. -- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50. -- @param #number radius (Optional) Radius. Default is 100 m. -- @param #number nshells (Optional) How many shells (or rockets) are fired on target per engagement. Default 5. @@ -544,6 +547,29 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w unique=false end weapontype=weapontype or ARTY.WeaponType.Auto + + -- Check if we have a coordinate object. + local text=nil + if coord:IsInstanceOf("GROUP") then + text="WARNING: ARTY:AssignTargetCoordinate(coord, ...) needs a COORDINATE object as first parameter - you gave a GROUP. Converting to COORDINATE..." + coord=coord:GetCoordinate() + elseif coord:IsInstanceOf("UNIT") then + text="WARNING: ARTY:AssignTargetCoordinate(coord, ...) needs a COORDINATE object as first parameter - you gave a UNIT. Converting to COORDINATE..." + coord=coord:GetCoordinate() + elseif coord:IsInstanceOf("POSITIONABLE") then + text="WARNING: ARTY:AssignTargetCoordinate(coord, ...) needs a COORDINATE object as first parameter - you gave a POSITIONABLE. Converting to COORDINATE..." + coord=coord:GetCoordinate() + elseif coord:IsInstanceOf("COORDINATE") then + -- Nothing to do here. + else + text="ERROR: ARTY:AssignTargetCoordinate(coord, ...) needs a COORDINATE object as first parameter!" + MESSAGE:New(text, 30):ToAll() + self:E(ARTY.id..text) + return nil + end + if text~=nil then + self:E(ARTY.id..text) + end -- Name of the target. local _name=name or coord:ToStringLLDMS() @@ -575,7 +601,7 @@ end --- Assign coordinate to where the ARTY group should move. -- @param #ARTY self --- @param Wrapper.Point#COORDINATE coord Coordinates of the target. +-- @param Core.Point#COORDINATE coord Coordinates of the target. -- @param #string time (Optional) Day time at which the group should start moving. Passed as a string in format "08:13:45". -- @param #number speed (Optinal) Speed in km/h the group should move at. Default 50 km/h. -- @param #boolean onroad (Optional) If true, group will mainly use roads. Default off, i.e. go directly towards the specified coordinate. @@ -698,7 +724,7 @@ end --- Defines the rearming place of the ARTY group. If the place is too far away from the ARTY group it will be routed to the place. -- @param #ARTY self --- @param Wrapper.Point#COORDINATE coord Coordinates of the rearming place. +-- @param Core.Point#COORDINATE coord Coordinates of the rearming place. function ARTY:SetRearmingPlace(coord) self:F({coord=coord}) self.RearmingPlaceCoord=coord @@ -848,6 +874,10 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do text=text..string.format("- %s\n", self:_TargetInfo(target)) + if self.Debug then + local zone=ZONE_RADIUS:New(target.name, target.coord:GetVec2(), target.radius) + zone:BoundZone(180, coalition.side.NEUTRAL) + end end text=text..string.format("Moves:\n") for i=1,#self.moves do @@ -867,7 +897,11 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("- %s\n", _type) end text=text..string.format("******************************************************") - self:T(ARTY.id..text) + if self.Debug then + self:E(ARTY.id..text) + else + self:T(ARTY.id..text) + end -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) @@ -1510,7 +1544,7 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param Wrapper.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. +-- @param Core.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. -- @param #boolean OnRoad If true group should move on road mainly. -- @return #boolean If true, proceed to onafterMove. function ARTY:onbeforeMove(Controllable, From, Event, To, ToCoord, OnRoad) @@ -1961,7 +1995,7 @@ function ARTY:GetAmmo(display) end end else - if Category==Weapon.Category.ROCKET then + if Category==Weapon.Category.MISSILE then _gotmissile=true end end diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index bce0b8ef1..f815a6520 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -314,7 +314,7 @@ function RANGE:New(rangename) self.rangename=rangename or "Practice Range" -- Debug info. - local text=string.format("RANGE script version %s. Creating new RANGE object. Range name: %s.", RANGE.version, self.rangename) + local text=string.format("RANGE script version %s - creating new RANGE object of name: %s.", RANGE.version, self.rangename) self:E(RANGE.id..text) MESSAGE:New(text, 10):ToAllIf(self.Debug) From 11516228faf4f7eead6486f3c2884dfb10ff5bce Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 26 May 2018 10:56:22 +0200 Subject: [PATCH 130/170] First images --- Moose Development/Moose/AI/AI_A2A.lua | 7 ++----- Moose Development/Moose/AI/AI_A2A_Cap.lua | 9 ++------- .../Moose/AI/AI_A2A_Dispatcher.lua | 19 +++---------------- Moose Development/Moose/AI/AI_A2A_Patrol.lua | 3 +-- Moose Development/Moose/AI/AI_BAI.lua | 9 ++------- Moose Development/Moose/AI/AI_Balancer.lua | 5 +---- Moose Development/Moose/AI/AI_CAP.lua | 5 +---- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 9 ++------- 8 files changed, 14 insertions(+), 52 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index 22507ffb3..10f7507cd 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -1,7 +1,5 @@ --- **AI** -- (R2.2) - Models the process of air operations for airplanes. -- --- This is a class used in the @{AI_A2A_Dispatcher}. --- -- === -- -- ### Author: **FlightControl** @@ -9,6 +7,7 @@ -- === -- -- @module AI.AI_A2A +-- @image Air_To_Air_Dispatching.JPG --BASE:TraceClass("AI_A2A") @@ -16,9 +15,7 @@ --- @type AI_A2A -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI_A2A class, extends @{Fsm#FSM_CONTROLLABLE} --- --- The AI_A2A class implements the core functions to operate an AI @{Wrapper.Group} A2A tasking. +--- The AI_A2A class implements the core functions to operate an AI @{Wrapper.Group} A2A tasking. -- -- -- ## AI_A2A constructor diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 0451051a2..50cdf48bd 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -1,7 +1,5 @@ --- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes. -- --- This is a class used in the @{AI.AI_A2A_Dispatcher}. --- -- === -- -- ### Author: **FlightControl** @@ -9,16 +7,13 @@ -- === -- -- @module AI.AI_A2A_Cap - ---BASE:TraceClass("AI_A2A_CAP") +-- @image Combat_Air_Patrol.JPG --- @type AI_A2A_CAP -- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL ---- # AI_A2A_CAP class, extends @{AI.AI_A2A_Patrol#AI_A2A_PATROL} --- --- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} +--- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 047922014..0edff73b5 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1,11 +1,5 @@ --- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI. -- --- === --- --- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia1.JPG) --- --- === --- -- # QUICK START GUIDE -- -- There are basically two classes available to model an A2A defense system. @@ -156,6 +150,7 @@ -- ### Authors: **Stonehouse**, **SNAFU** in terms of the advice, documentation, and the original GCICAP script. -- -- @module AI.AI_A2A_Dispatcher +-- @image Air_To_Air_Dispatching.JPG @@ -165,11 +160,7 @@ do -- AI_A2A_DISPATCHER -- @type AI_A2A_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER - --- # AI\_A2A\_DISPATCHER class, extends @{Tasking.DetectionManage#DETECTION_MANAGER} - -- - -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia1.JPG) - -- - -- The @{#AI_A2A_DISPATCHER} class is designed to create an automatic air defence system for a coalition. + --- Create an automatic air defence system for a coalition. -- -- === -- @@ -3173,11 +3164,7 @@ do --- @type AI_A2A_GCICAP -- @extends #AI_A2A_DISPATCHER - --- # AI\_A2A\_GCICAP class, extends @{AI_A2A_Dispatcher#AI_A2A_DISPATCHER} - -- - -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia1.JPG) - -- - -- The AI_A2A_GCICAP class is designed to create an automatic air defence system for a coalition setting up GCI and CAP air defenses. + --- Create an automatic air defence system for a coalition setting up GCI and CAP air defenses. -- The class derives from @{AI#AI_A2A_DISPATCHER} and thus, all the methods that are defined in the @{AI#AI_A2A_DISPATCHER} class, can be used also in AI\_A2A\_GCICAP. -- -- === diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index e741e9fba..ab97e5942 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -1,7 +1,5 @@ --- **AI** -- (R2.2) - Models the process of air patrol of airplanes. -- --- This is a class used in the @{AI_A2A_Dispatcher}. --- -- === -- -- ### Author: **FlightControl** @@ -9,6 +7,7 @@ -- === -- -- @module AI.AI_A2A_Patrol +-- @image Air_Patrolling.JPG --- @type AI_A2A_PATROL diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index 5d8ed3df6..160516b8b 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -1,10 +1,6 @@ --- **AI** -- (R2.1) - Manages the independent process of Battlefield Air Interdiction (bombing) for airplanes. -- -- === --- --- ![Banner Image](..\Presentations\AI_BAI\Dia1.JPG) --- --- === -- -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BAI%20-%20Battlefield%20Air%20Interdiction) -- @@ -22,6 +18,7 @@ -- === -- -- @module AI.AI_Bai +-- @image Battlefield_Air_Interdiction.JPG --- AI_BAI_ZONE class @@ -30,9 +27,7 @@ -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_BAI_ZONE class, extends @{AI.AI_Patrol#AI_PATROL_ZONE} --- --- AI_BAI_ZONE derives from the @{AI.AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. +--- AI_BAI_ZONE derives from the @{AI.AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. -- -- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. -- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index e14ec568f..2648b4760 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -2,10 +2,6 @@ -- -- === -- --- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) --- --- === --- -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing) -- -- === @@ -22,6 +18,7 @@ -- === -- -- @module AI.AI_Balancer +-- @image AI_Balancing.JPG --- @type AI_BALANCER -- @field Core.Set#SET_CLIENT SetClient diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index 9df9ddf8e..033baa443 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -1,10 +1,6 @@ --- **AI** -- (R2.1) - Manages the independent process of Combat Air Patrol (CAP) for airplanes. -- -- === --- --- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG) --- --- === -- -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol) -- @@ -26,6 +22,7 @@ -- === -- -- @module AI.AI_Cap +-- @image Combat_Air_Patrol.JPG --- @type AI_CAP_ZONE diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index b2808924a..a78ad4ff4 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -7,18 +7,13 @@ -- === -- -- @module AI.AI_Cargo_Dispatcher_APC +-- @image Cargo_Dispatching_For_APC.JPG --- @type AI_CARGO_DISPATCHER_APC -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER ---- # AI\_CARGO\_DISPATCHER\_APC class, extends @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} --- --- ![Banner Image](..\Presentations\AI_CARGO_DISPATCHER_APC\Dia1.JPG) --- --- === --- --- AI\_CARGO\_DISPATCHER\_APC brings a dynamic cargo handling capability for AI groups. +--- A dynamic cargo transportation capability for AI groups. -- -- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI\_CARGO\_DISPATCHER\_APC module uses the @{Cargo} capabilities within the MOOSE framework. From ad75a7ddb5ebb15fc4667f5243df92a39bbea466 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 26 May 2018 14:46:23 +0200 Subject: [PATCH 131/170] RANGE v1.2 and other changes RANGE: -Optimized performance. Bombs are now only tracked if the player is within a certain distance of the range. CONTROLLABLE: - Added speed unit to @param description. Sometimes it was unclear if speed needs to be given in m/s or km/h. - Fixed some default speed and conversions. COORDINATE: - Cleaned up some speed unit stuff. - Reintroduced PathOnRoad function to contain the full path. Useful as interface to DCS API function. - Fixed some default speed and conversions. AI_CARGO_APC: Speed is not fixed any more but set to 50% of the max speed a given unit can move at. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 11 +- Moose Development/Moose/Core/Point.lua | 30 ++- .../Moose/Functional/Artillery.lua | 16 +- Moose Development/Moose/Functional/Range.lua | 224 ++++++++++-------- .../Moose/Wrapper/Controllable.lua | 121 +++++----- 5 files changed, 212 insertions(+), 190 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 51f94e4c9..9fbf1566a 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -600,8 +600,6 @@ end -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate --- @param #number Speed --- @param #string EndPointFormation The formation at the end point of the action. function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() then @@ -609,7 +607,7 @@ function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate ) if Coordinate then self.RoutePickup = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.8, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.5, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) @@ -634,15 +632,13 @@ end -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate --- @param #number Speed --- @param #string EndPointFormation The formation at the end point of the action. function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() then self.RouteDeploy = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.5, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) @@ -662,14 +658,13 @@ end -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate --- @param #number Speed function AI_CARGO_APC:onafterHome( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() ~= nil then self.RouteHome = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, 120, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.5, "Line abreast" ) self:F({Waypoints = Waypoints}) local Waypoint = Waypoints[#Waypoints] diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index cd8390f7b..286e4f79f 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -777,7 +777,7 @@ do -- COORDINATE -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param #COORDINATE.WaypointType Type The route point type. -- @param #COORDINATE.WaypointAction Action The route point action. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. Default is 500 km/h. -- @param #boolean SpeedLocked true means the speed is locked. -- @return #table The route point. function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked ) @@ -887,7 +887,7 @@ do -- COORDINATE --- Build an ground type route point. -- @param #COORDINATE self - -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number Speed (optional) Speed in km/h. The default speed is 20 km/h. -- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". -- @return #table The route point. function COORDINATE:WaypointGround( Speed, Formation ) @@ -935,22 +935,30 @@ do -- COORDINATE return COORDINATE:NewFromVec2(vec2) end - --- Returns a table of coordinates to a destination. + --- Returns a table of coordinates to a destination using only roads. + -- The first point is the closest point on road of the given coordinate. The last point is the closest point on road of the ToCoord. Hence, the coordinate itself and the final ToCoord are not necessarily included in the path. -- @param #COORDINATE self -- @param #COORDINATE ToCoord Coordinate of destination. -- @return #table Table of coordinates on road. function COORDINATE:GetPathOnRoad(ToCoord) - local Path={} + + -- DCS API function returning a table of vec2. local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z) - Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) - Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) + + --Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) + --Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) + --Path[#Path+1]=self:GetClosestPointToRoad() + --Path[#Path+1]=ToCoord:GetClosestPointToRoad() -- I've removed this stuff because it severely slows down DCS in case of paths with a lot of segments. -- Just the beginning and the end point is sufficient. --- for i, v in ipairs(path) do --- self:I(v) --- local coord=COORDINATE:NewFromVec2(v) --- Path[#Path+1]=COORDINATE:NewFromVec2(v) --- end + + local Path={} + --Path[#Path+1]=self + for i, v in ipairs(path) do + Path[#Path+1]=COORDINATE:NewFromVec2(v) + end + --Path[#Path+1]=ToCoord + return Path end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 1921787ae..f8a210b8e 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -2434,16 +2434,18 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Route group on road if requested. if OnRoad then + -- Path on road (only first and last points) local _first=cpini:GetClosestPointToRoad() local _last=ToCoord:GetClosestPointToRoad() - local _onroad=_first:GetPathOnRoad(_last) - -- Points on road. - for i=1,#_onroad do - path[#path+1]=_onroad[i]:WaypointGround(Speed, "On road") - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - end - + -- First point on road. + path[#path+1]=_first:WaypointGround(Speed, "On road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + -- Last point on road. + path[#path+1]=_last:WaypointGround(Speed, "On road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + end -- Last waypoint at ToCoord. diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 65614ebf5..c21f6656f 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -70,6 +70,7 @@ -- @field #table bombPlayerResults Table containing the bombing results of each player. -- @field #table PlayerSettings Indiviual player settings. -- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds. +-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threashold [m]. Default 25000 m. -- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec. -- @field #number strafemaxalt Maximum altitude above ground for registering for a strafe run. Default is 914 m = 3000 ft. -- @field #number ndisplayresult Number of (player) results that a displayed. Default is 10. @@ -236,6 +237,7 @@ RANGE={ bombPlayerResults = {}, PlayerSettings = {}, dtBombtrack=0.005, + BombtrackThreshold=25000, Tmsg=30, strafemaxalt=914, ndisplayresult=10, @@ -283,7 +285,7 @@ RANGE.id="RANGE | " --- Range script version. -- @field #number version -RANGE.version="1.1.1" +RANGE.version="1.2.0" --TODO list: --TODO: Add custom weapons, which can be specified by the user. @@ -451,6 +453,13 @@ function RANGE:SetRangeRadius(radius) self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius end +--- Set bomb track threshold distance. Bombs/rockets/missiles are only tracked if player-range distance is less than this distance. Default 25 km. +-- @param #RANGE self +-- @param #number distance Threshold distance in km. Default 25 km. +function RANGE:SetBombtrackThreshold(distance) + self.BombtrackThreshold=distance*1000 or 25*1000 +end + --- Set range location. If this is not done, one (random) unit position of the range is used to determine the center of the range. -- @param #RANGE self -- @param Core.Point#COORDINATE coordinate Coordinate of the center of the range. @@ -1081,6 +1090,7 @@ function RANGE:OnEventShot(EventData) local _weaponName = _weaponStrArray[#_weaponStrArray] -- Debug info. + self:T(RANGE.id.."EVENT SHOT: Range "..self.rangename) self:T(RANGE.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) self:T(RANGE.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) self:T(RANGE.id.."EVENT SHOT: Weapon type = ".._weapon) @@ -1097,129 +1107,141 @@ function RANGE:OnEventShot(EventData) -- Check if any condition applies here. local _track = (_bombs and self.trackbombs) or (_rockets and self.trackrockets) or (_missiles and self.trackmissiles) - if _track then + -- Get unit name. + local _unitName = EventData.IniUnitName + + -- Get player unit and name. + local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - -- Weapon - local _ordnance = EventData.weapon + -- Set this to larger value than the threshold. + local dPR=self.BombtrackThreshold*2 + + -- Distance player to range. + if _unit and _playername then + dPR=_unit:GetCoordinate():Get2DDistance(self.location) + self:T(RANGE.id..string.format("Range %s, player %s, player-range distance = %d km.", self.rangename, _playername, dPR/1000)) + end + + -- Only track if distance player to range is < 25 km. + if _track and dPR<=self.BombtrackThreshold then -- Tracking info and init of last bomb position. - self:T(RANGE.id..string.format("Tracking %s - %s.", _weapon, _ordnance:getName())) + self:T(RANGE.id..string.format("RANGE %s: Tracking %s - %s.", self.rangename, _weapon, EventData.weapon:getName())) -- Init bomb position. local _lastBombPos = {x=0,y=0,z=0} - - -- Get unit name. - local _unitName = EventData.IniUnitName -- Function monitoring the position of a bomb until impact. - local function trackBomb(_previousPos) + local function trackBomb(_ordnance) + + -- When the pcall returns a failure the weapon has hit. + local _status,_bombPos = pcall( + function() + return _ordnance:getPoint() + end) + + self:T3(RANGE.id..string.format("Range %s: Bomb still in air: %s", self.rangename, tostring(_status))) + if _status then - -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - local _callsign=self:_myname(_unitName) + -- Still in the air. Remember this position. + _lastBombPos = {x = _bombPos.x, y = _bombPos.y, z= _bombPos.z } - if _unit and _playername then - - -- When the pcall returns a failure the weapon has hit. - local _status,_bombPos = pcall( - function() - return _ordnance:getPoint() - end) - - if _status then + -- Check again in 0.005 seconds. + return timer.getTime() + self.dtBombtrack - -- Still in the air. Remember this position. - _lastBombPos = {x = _bombPos.x, y = _bombPos.y, z= _bombPos.z } - - -- Check again in 0.005 seconds. - return timer.getTime() + self.dtBombtrack - - else + else + + -- Bomb did hit the ground. + -- Get closet target to last position. + local _closetTarget = nil + local _distance = nil + local _hitquality = "POOR" - -- Bomb did hit the ground. - -- Get closet target to last position. - local _closetTarget = nil - local _distance = nil - local _hitquality = "POOR" - - -- Coordinate of impact point. - local impactcoord=COORDINATE:NewFromVec3(_lastBombPos) - - -- Distance from range. We dont want to smoke targets outside of the range. - local impactdist=impactcoord:Get2DDistance(self.location) - - -- Smoke impact point of bomb. - if self.PlayerSettings[_playername].smokebombimpact and impactdist10 then - table.insert(route, ToCoordinate:WaypointGround(Speed, "Off Road")) - end + -- Defaults. + Speed=Speed or 20 + DelaySeconds=DelaySeconds or 1 + OffRoadFormation=OffRoadFormation or "Off Road" + + -- Get the route task. + local route=self:TaskGroundOnRoad(ToCoordinate, Speed, OffRoadFormation) -- Route controllable to destination. self:Route( route, DelaySeconds ) @@ -1978,39 +1969,43 @@ do -- Route methods end - --- Make a task for a GROUND Controllable to drive towards a specific point using (only) roads. + --- Make a task for a GROUND Controllable to drive towards a specific point using (mostly) roads. -- @param #CONTROLLABLE self -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. - -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. - -- @param #string EndPointFormation The formation to achieve at the end point. + -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. + -- @param #string OffRoadFormation (Optional) The formation at initial and final waypoint. Default is "Off Road". -- @return Task - function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, EndPointFormation ) + function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, OffRoadFormation ) + self:F2({ToCoordinate=ToCoordinate, Speed=Speed, OffRoadFormation=OffRoadFormation}) + + -- Defaults. + Speed=Speed or 20 + OffRoadFormation=OffRoadFormation or "Off Road" -- Current coordinate. local FromCoordinate = self:GetCoordinate() - -- Formation is set to on road. - local Formation="On Road" - - -- Path on road from current position to destination coordinate. - local path=FromCoordinate:GetPathOnRoad( ToCoordinate ) + -- First point on road. + local FromOnRoad = FromCoordinate:GetClosestPointToRoad() - -- Route, ground waypoints along roads. - local Route = {} - table.insert( Route, FromCoordinate:WaypointGround( Speed, Formation ) ) + -- Last Point on road. + local ToOnRoad = ToCoordinate:GetClosestPointToRoad() + + -- Route, ground waypoints along road. + local route={} - -- Convert coordinates to ground waypoints and insert into table. - for _, coord in ipairs(path) do - table.insert( Route, coord:WaypointGround( Speed, Formation ) ) - end - - -- Add the final coordinate because the final coordinate in path is last point on road. - local dist=ToCoordinate:Get2DDistance(path[#path]) + -- Create waypoints. + table.insert(route, FromCoordinate:WaypointGround(Speed, OffRoadFormation)) + table.insert(route, FromOnRoad:WaypointGround(Speed, "On Road")) + table.insert(route, ToOnRoad:WaypointGround(Speed, "On Road")) + + -- Add the final coordinate because the final might not be on the road. + local dist=ToCoordinate:Get2DDistance(ToOnRoad) if dist>10 then - table.insert( Route, ToCoordinate:WaypointGround( Speed, EndPointFormation ) ) - end + table.insert(route, ToCoordinate:WaypointGround(Speed, OffRoadFormation)) + end - return Route + return route end @@ -2020,7 +2015,7 @@ do -- Route methods -- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type. -- @param Core.Point#COORDINATE.RoutePointType Type The route point type. -- @param Core.Point#COORDINATE.RoutePointAction Action The route point action. - -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number Speed (optional) Speed in km/h. The default speed is 500 km/h. -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. -- @return #CONTROLLABLE The CONTROLLABLE. function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds ) @@ -2043,7 +2038,7 @@ do -- Route methods -- @param #CONTROLLABLE self -- @param Core.Zone#ZONE Zone The zone where to route to. -- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. - -- @param #number Speed The speed. + -- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h. -- @param Base#FORMATION Formation The formation string. function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) self:F2( Zone ) @@ -2104,7 +2099,7 @@ do -- Route methods -- A given formation can be given. -- @param #CONTROLLABLE self -- @param #Vec2 Vec2 The Vec2 where to route to. - -- @param #number Speed The speed. + -- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h. -- @param Base#FORMATION Formation The formation string. function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) @@ -2119,7 +2114,7 @@ do -- Route methods PointFrom.y = ControllablePoint.y PointFrom.type = "Turning Point" PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 + PointFrom.speed = 20 / 3.6 local PointTo = {} @@ -2137,7 +2132,7 @@ do -- Route methods if Speed then PointTo.speed = Speed else - PointTo.speed = 60 / 3.6 + PointTo.speed = 20 / 3.6 end local Points = { PointFrom, PointTo } From 073bfbf9c97a7382e55f2c91b9a24f07ec75efdc Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 27 May 2018 08:57:44 +0200 Subject: [PATCH 132/170] Documentation Improvements --- Moose Development/Moose/AI/AI_A2A.lua | 2 +- Moose Development/Moose/AI/AI_A2A_Cap.lua | 2 +- .../Moose/AI/AI_A2A_Dispatcher.lua | 2 +- Moose Development/Moose/AI/AI_A2A_Gci.lua | 1 + Moose Development/Moose/AI/AI_A2A_Patrol.lua | 2 +- Moose Development/Moose/AI/AI_BAI.lua | 2 +- Moose Development/Moose/AI/AI_CAP.lua | 2 +- Moose Development/Moose/AI/AI_CAS.lua | 6 +- Moose Development/Moose/AI/AI_Cargo_APC.lua | 1 + .../Moose/AI/AI_Cargo_Airplane.lua | 1 + .../Moose/AI/AI_Cargo_Dispatcher.lua | 1 + .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 2 +- .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 3 +- .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 1 + .../Moose/AI/AI_Cargo_Helicopter.lua | 1 + Moose Development/Moose/AI/AI_Formation.lua | 5 +- Moose Development/Moose/AI/AI_Patrol.lua | 6 +- Moose Development/Moose/Cargo/Cargo.lua | 10 +- Moose Development/Moose/Cargo/CargoCrate.lua | 5 +- Moose Development/Moose/Cargo/CargoGroup.lua | 1 + .../Moose/Cargo/CargoSlingload.lua | 5 +- Moose Development/Moose/Cargo/CargoUnit.lua | 5 +- Moose Development/Moose/Core/Base.lua | 9 +- Moose Development/Moose/Core/Database.lua | 5 +- Moose Development/Moose/Core/Event.lua | 3 +- Moose Development/Moose/Core/Fsm.lua | 23 +--- Moose Development/Moose/Core/Goal.lua | 5 +- Moose Development/Moose/Core/Menu.lua | 40 ++----- Moose Development/Moose/Core/Message.lua | 7 +- Moose Development/Moose/Core/Point.lua | 16 +-- Moose Development/Moose/Core/Radio.lua | 3 +- Moose Development/Moose/Core/Report.lua | 1 + .../Moose/Core/ScheduleDispatcher.lua | 1 + Moose Development/Moose/Core/Scheduler.lua | 8 +- Moose Development/Moose/Core/Set.lua | 108 ++++++++---------- Moose Development/Moose/Core/Settings.lua | 56 ++++----- Moose Development/Moose/Core/Spawn.lua | 11 +- Moose Development/Moose/Core/SpawnStatic.lua | 7 +- Moose Development/Moose/Core/Spot.lua | 7 +- Moose Development/Moose/Core/UserFlag.lua | 8 +- Moose Development/Moose/Core/UserSound.lua | 7 +- Moose Development/Moose/Core/Velocity.lua | 5 +- Moose Development/Moose/Core/Zone.lua | 31 ++--- 43 files changed, 151 insertions(+), 276 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index 10f7507cd..faaeb3745 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -7,7 +7,7 @@ -- === -- -- @module AI.AI_A2A --- @image Air_To_Air_Dispatching.JPG +-- @image AI_Air_To_Air_Dispatching.JPG --BASE:TraceClass("AI_A2A") diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 50cdf48bd..5917ed848 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -7,7 +7,7 @@ -- === -- -- @module AI.AI_A2A_Cap --- @image Combat_Air_Patrol.JPG +-- @image AI_Combat_Air_Patrol.JPG --- @type AI_A2A_CAP -- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 0edff73b5..146f35d4d 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -150,7 +150,7 @@ -- ### Authors: **Stonehouse**, **SNAFU** in terms of the advice, documentation, and the original GCICAP script. -- -- @module AI.AI_A2A_Dispatcher --- @image Air_To_Air_Dispatching.JPG +-- @image AI_Air_To_Air_Dispatching.JPG diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index 98670a381..5d2e2567f 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -9,6 +9,7 @@ -- === -- -- @module AI.AI_A2A_GCI +-- @image AI_AI_Ground_Control_Intercept.JPG diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index ab97e5942..73d814ef6 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -7,7 +7,7 @@ -- === -- -- @module AI.AI_A2A_Patrol --- @image Air_Patrolling.JPG +-- @image AI_Air_Patrolling.JPG --- @type AI_A2A_PATROL diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index 160516b8b..84ef87f92 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -18,7 +18,7 @@ -- === -- -- @module AI.AI_Bai --- @image Battlefield_Air_Interdiction.JPG +-- @image AI_Battlefield_Air_Interdiction.JPG --- AI_BAI_ZONE class diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index 033baa443..af783bc37 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -22,7 +22,7 @@ -- === -- -- @module AI.AI_Cap --- @image Combat_Air_Patrol.JPG +-- @image AI_Combat_Air_Patrol.JPG --- @type AI_CAP_ZONE diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 74e18c3b5..a80e348ac 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -1,10 +1,6 @@ --- **AI** -- (R2.1) - Manages the independent process of Close Air Support for airplanes. -- -- === --- --- ![Banner Image](..\Presentations\AI_CAS\Dia1.JPG) --- --- === -- -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support) -- @@ -24,7 +20,7 @@ -- === -- -- @module AI.AI_Cas - +-- @image AI_Close_Air_Support.JPG --- AI_CAS_ZONE class -- @type AI_CAS_ZONE diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index db1a05e55..e0de55ecc 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -7,6 +7,7 @@ -- === -- -- @module AI.AI_Cargo_APC +-- @image AI_Cargo_Dispatching_For_APC.JPG --- @type AI_CARGO_APC -- @extends Core.Fsm#FSM_CONTROLLABLE diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index e216d0aff..ed10d2e5d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -7,6 +7,7 @@ -- === -- -- @module AI.AI_Cargo_Airplane +-- @image AI_Cargo_Dispatching_For_Airplanes.JPG --- @type AI_CARGO_AIRPLANE -- @extends Core.Fsm#FSM_CONTROLLABLE diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index a3858a7c7..378c881fe 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -7,6 +7,7 @@ -- === -- -- @module AI.AI_Cargo_Dispatcher +-- @image AI_Cargo_Dispatching_For_Helicopters.JPG --- @type AI_CARGO_DISPATCHER -- @extends Core.Fsm#FSM diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index a78ad4ff4..cb400cecc 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -7,7 +7,7 @@ -- === -- -- @module AI.AI_Cargo_Dispatcher_APC --- @image Cargo_Dispatching_For_APC.JPG +-- @image AI_Cargo_Dispatching_For_APC.JPG --- @type AI_CARGO_DISPATCHER_APC -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index 6007e9973..409699733 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -7,7 +7,8 @@ -- === -- -- @module AI.AI_Cargo_Dispatcher_Airplane - +-- @image AI_Cargo_Dispatching_For_Airplanes.JPG +-- --- @type AI_CARGO_DISPATCHER_AIRPLANE -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index aa3b264fc..bfa86e06e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -9,6 +9,7 @@ -- === -- -- @module AI.AI_Cargo_Dispatcher_Helicopter +-- @image AI_Cargo_Dispatching_For_Helicopters.JPG --- @type AI_CARGO_DISPATCHER_HELICOPTER -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 555cb858b..b0725cc0a 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -7,6 +7,7 @@ -- === -- -- @module AI.AI_Cargo_Helicopter +-- @image AI_Cargo_Dispatching_For_Helicopters.JPG --- @type AI_CARGO_HELICOPTER -- @extends Core.Fsm#FSM_CONTROLLABLE diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index db5e6edad..ebc5d2b6f 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -2,10 +2,6 @@ -- -- === -- --- ![Banner Image](..\Presentations\AI_FORMATION\Dia1.JPG) --- --- === --- -- AI_FORMATION makes AI @{Wrapper.Group}s fly in formation of various compositions. -- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! -- The purpose of the class is to: @@ -46,6 +42,7 @@ -- === -- -- @module AI.AI_Formation +-- @image AI_Large_Formations.JPG --- AI_FORMATION class -- @type AI_FORMATION diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 77026ce02..74e06492b 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -2,10 +2,6 @@ -- -- === -- --- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG) --- --- === --- -- AI PATROL classes makes AI Controllables execute an Patrol. -- -- There are the following types of PATROL classes defined: @@ -31,7 +27,7 @@ -- === -- -- @module AI.AI_Patrol - +-- @image AI_Air_Patrolling.JPG --- AI_PATROL_ZONE class -- @type AI_PATROL_ZONE diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 566ba7beb..31fa1644e 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -1,15 +1,6 @@ --- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers. -- -- === --- --- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) --- --- === --- --- --- This module is still under construction, but is described above works already, and will keep working ... --- --- === -- -- ### Author: **FlightControl** -- ### Contributions: @@ -17,6 +8,7 @@ -- === -- -- @module Cargo.Cargo +-- @image Cargo.JPG -- Events diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 0256721da..c3e12ddea 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -1,10 +1,6 @@ --- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. -- -- === --- --- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) --- --- === -- -- ### [Demo Missions]() -- @@ -18,6 +14,7 @@ -- === -- -- @module Cargo.CargoCrate +-- @image Cargo_Crates.JPG do -- CARGO_CRATE diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index b2fab505c..98435b25c 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -18,6 +18,7 @@ -- === -- -- @module Cargo.CargoGroup +-- @image Cargo_Groups.JPG do -- CARGO_GROUP diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index b16e1ffe6..617cc4770 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -1,10 +1,6 @@ --- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded. -- -- === --- --- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) --- --- === -- -- ### [Demo Missions]() -- @@ -18,6 +14,7 @@ -- === -- -- @module Cargo.CargoSlingload +-- @image Cargo_Slingload.JPG do -- CARGO_SLINGLOAD diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 43d5a7350..09fd9f0ce 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -1,10 +1,6 @@ --- **Cargo** -- Management of single cargo logistics, which are based on a @{Wrapper.Unit} object. -- -- === --- --- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) --- --- === -- -- ### [Demo Missions]() -- @@ -18,6 +14,7 @@ -- === -- -- @module Cargo.CargoUnit +-- @image Cargo_Units.JPG do -- CARGO_UNIT diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index f9577a7d1..12a8a5efe 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -1,15 +1,12 @@ --- **Core** -- BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE. -- --- ![Banner Image](..\Presentations\BASE\Dia1.JPG) --- --- === --- -- ### Author: **FlightControl** -- ### Contributions: -- -- === -- -- @module Core.Base +-- @image Core_Base.JPG @@ -26,9 +23,7 @@ local _ClassID = 0 -- @field ClassID The ID number of the class. -- @field ClassNameAndID The name of the class concatenated with the ID number of the class. ---- # 1) #BASE class --- --- All classes within the MOOSE framework are derived from the BASE class. +--- All classes within the MOOSE framework are derived from the BASE class. -- -- BASE provides facilities for : -- diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index ec7c4c9e5..eea110521 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -8,14 +8,13 @@ -- === -- -- @module Core.Database +-- @image Core_Database.JPG --- @type DATABASE -- @extends Core.Base#BASE ---- # DATABASE class, extends @{Core.Base#BASE} --- --- Mission designers can use the DATABASE class to refer to: +--- Mission designers can use the DATABASE class to refer to: -- -- * STATICS -- * UNITS diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index d786101fa..dd739a0d9 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -1,7 +1,5 @@ --- **Core** -- EVENT models DCS **event dispatching** using a **publish-subscribe** model. -- --- ![Banner Image](..\Presentations\EVENT\Dia1.JPG) --- -- === -- -- # 1) Event Handling Overview @@ -165,6 +163,7 @@ -- === -- -- @module Core.Event +-- @image Core_Event.JPG --- The EVENT structure diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index e81bb9519..b92beb1c1 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -1,8 +1,6 @@ --- **Core** -- The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes -- are design patterns allowing efficient (long-lasting) processes and workflows. -- --- ![Banner Image](..\Presentations\FSM\Dia1.JPG) --- -- === -- -- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. @@ -65,6 +63,7 @@ -- === -- -- @module Core.Fsm +-- @image Core_Finite_State_Machine.JPG do -- FSM @@ -72,9 +71,7 @@ do -- FSM -- @extends Core.Base#BASE - --- # FSM class, extends @{Core.Base#BASE} - -- - -- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. + --- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. -- -- A FSM can only be in one of a finite number of states. -- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. @@ -804,9 +801,7 @@ do -- FSM_CONTROLLABLE -- @field Wrapper.Controllable#CONTROLLABLE Controllable -- @extends Core.Fsm#FSM - --- # FSM_CONTROLLABLE, extends @{#FSM} - -- - -- FSM_CONTROLLABLE class models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s. + --- FSM_CONTROLLABLE class models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s. -- -- === -- @@ -939,9 +934,7 @@ do -- FSM_PROCESS -- @extends Core.Fsm#FSM_CONTROLLABLE - --- # FSM_PROCESS, extends @{#FSM} - -- - -- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s. + --- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s. -- -- === -- @@ -1184,9 +1177,7 @@ do -- FSM_TASK -- @field Tasking.Task#TASK Task -- @extends #FSM - --- # FSM_TASK, extends @{#FSM} - -- - -- FSM_TASK class models Finite State Machines for @{Task}s. + --- FSM_TASK class models Finite State Machines for @{Task}s. -- -- === -- @@ -1230,9 +1221,7 @@ do -- FSM_SET -- @extends Core.Fsm#FSM - --- # FSM_SET, extends @{#FSM} - -- - -- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here + --- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here -- for multiple objects or the position of the state machine in the process. -- -- === diff --git a/Moose Development/Moose/Core/Goal.lua b/Moose Development/Moose/Core/Goal.lua index ba8e9ea1d..608c4ecc0 100644 --- a/Moose Development/Moose/Core/Goal.lua +++ b/Moose Development/Moose/Core/Goal.lua @@ -11,6 +11,7 @@ -- === -- -- @module Core.Goal +-- @image Core_Goal.JPG do -- Goal @@ -18,9 +19,7 @@ do -- Goal -- @extends Core.Fsm#FSM - --- # GOAL class, extends @{Core.Fsm#FSM} - -- - -- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized. + --- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized. -- -- ## 1. GOAL constructor -- diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 6850b9213..b93cb59c9 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -31,6 +31,7 @@ -- === -- -- @module Core.Menu +-- @image Core_Menu.JPG MENU_INDEX = {} @@ -182,8 +183,7 @@ do -- MENU_BASE --- @type MENU_BASE -- @extends Base#BASE - --- # MENU_BASE class, extends @{Core.Base#BASE} - -- The MENU_BASE class defines the main MENU class where other MENU classes are derived from. + --- The MENU_BASE class defines the main MENU class where other MENU classes are derived from. -- This is an abstract class, so don't use it. -- @field #MENU_BASE MENU_BASE = { @@ -286,9 +286,7 @@ do -- MENU_COMMAND_BASE -- @field #function MenuCallHandler -- @extends Core.Menu#MENU_BASE - --- # MENU_COMMAND_BASE class, extends @{Core.Base#BASE} - -- ---------------------------------------------------------- - -- The MENU_COMMAND_BASE class defines the main MENU class where other MENU COMMAND_ + --- The MENU_COMMAND_BASE class defines the main MENU class where other MENU COMMAND_ -- classes are derived from, in order to set commands. -- -- @field #MENU_COMMAND_BASE @@ -358,9 +356,7 @@ do -- MENU_MISSION --- @type MENU_MISSION -- @extends Core.Menu#MENU_BASE - --- # MENU_MISSION class, extends @{Menu#MENU_BASE} - -- - -- The MENU_MISSION class manages the main menus for a complete mission. + --- The MENU_MISSION class manages the main menus for a complete mission. -- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. -- @field #MENU_MISSION @@ -455,9 +451,7 @@ do -- MENU_MISSION_COMMAND --- @type MENU_MISSION_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - --- # MENU_MISSION_COMMAND class, extends @{Menu#MENU_COMMAND_BASE} - -- - -- The MENU_MISSION_COMMAND class manages the command menus for a complete mission, which allow players to execute functions during mission execution. + --- The MENU_MISSION_COMMAND class manages the command menus for a complete mission, which allow players to execute functions during mission execution. -- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}. -- @@ -542,9 +536,7 @@ do -- MENU_COALITION --- @type MENU_COALITION -- @extends Core.Menu#MENU_BASE - --- # MENU_COALITION class, extends @{Menu#MENU_BASE} - -- - -- The @{Menu#MENU_COALITION} class manages the main menus for coalitions. + --- The @{Menu#MENU_COALITION} class manages the main menus for coalitions. -- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}. -- @@ -680,9 +672,7 @@ do -- MENU_COALITION_COMMAND --- @type MENU_COALITION_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - --- # MENU_COALITION_COMMAND class, extends @{Menu#MENU_COMMAND_BASE} - -- - -- The MENU_COALITION_COMMAND class manages the command menus for coalitions, which allow players to execute functions during mission execution. + --- The MENU_COALITION_COMMAND class manages the command menus for coalitions, which allow players to execute functions during mission execution. -- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}. -- @@ -780,9 +770,7 @@ do -- @extends Core.Menu#MENU_BASE - --- #MENU_GROUP class, extends @{Menu#MENU_BASE} - -- - -- The MENU_GROUP class manages the main menus for coalitions. + --- The MENU_GROUP class manages the main menus for coalitions. -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. -- @@ -938,9 +926,7 @@ do --- @type MENU_GROUP_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - --- # MENU_GROUP_COMMAND class, extends @{Menu#MENU_COMMAND_BASE} - -- - -- The @{Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. + --- The @{Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. -- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND.Remove}. -- @@ -1035,9 +1021,7 @@ do -- @extends Core.Menu#MENU_BASE - --- #MENU_GROUP_DELAYED class, extends @{Menu#MENU_BASE} - -- - -- The MENU_GROUP_DELAYED class manages the main menus for groups. + --- The MENU_GROUP_DELAYED class manages the main menus for groups. -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. -- The creation of the menu item is delayed however, and must be created using the @{#MENU_GROUP.Set} method. @@ -1171,9 +1155,7 @@ do --- @type MENU_GROUP_COMMAND_DELAYED -- @extends Core.Menu#MENU_COMMAND_BASE - --- # MENU_GROUP_COMMAND_DELAYED class, extends @{Menu#MENU_COMMAND_BASE} - -- - -- The @{Menu#MENU_GROUP_COMMAND_DELAYED} class manages the command menus for coalitions, which allow players to execute functions during mission execution. + --- The @{Menu#MENU_GROUP_COMMAND_DELAYED} class manages the command menus for coalitions, which allow players to execute functions during mission execution. -- You can add menus with the @{#MENU_GROUP_COMMAND_DELAYED.New} method, which constructs a MENU_GROUP_COMMAND_DELAYED object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND_DELAYED.Remove}. -- diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index d2256e436..926284332 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -1,18 +1,15 @@ --- **Core** -- MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation. -- --- ![Banner Image](..\Presentations\MESSAGE\Dia1.JPG) --- -- === -- -- @module Core.Message +-- @image Core_Message.JPG --- The MESSAGE class -- @type MESSAGE -- @extends Core.Base#BASE ---- # MESSAGE class, extends @{Core.Base#BASE} --- --- Message System to display Messages to Clients, Coalitions or All. +--- Message System to display Messages to Clients, Coalitions or All. -- Messages are shown on the display panel for an amount of seconds, and will then disappear. -- Messages can contain a category which is indicating the category of the message. -- diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index cd8390f7b..6f1f25468 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1,7 +1,5 @@ --- **Core** -- **POINT\_VEC** classes define an **extensive API** to **manage 3D points** in the simulation space. -- --- ![Banner Image](..\Presentations\POINT\Dia1.JPG) --- -- === -- -- # Demo Missions @@ -27,7 +25,7 @@ -- ### Contributions: -- -- @module Core.Point - +-- @image Core_Coordinate.JPG @@ -38,9 +36,7 @@ do -- COORDINATE -- @extends Core.Base#BASE - --- # COORDINATE class, extends @{Core.Base#BASE} - -- - -- COORDINATE defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. + --- COORDINATE defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- ## COORDINATE constructor -- @@ -1584,9 +1580,7 @@ do -- POINT_VEC3 -- @extends Core.Point#COORDINATE - --- # POINT_VEC3 class, extends @{Point#COORDINATE} - -- - -- POINT_VEC3 defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. + --- POINT_VEC3 defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. -- In order to keep the credibility of the the author, @@ -1797,9 +1791,7 @@ do -- POINT_VEC2 -- @field Dcs.DCSTypes#Distance y the y coordinate in meters. -- @extends Core.Point#COORDINATE - --- # POINT_VEC2 class, extends @{Point#COORDINATE} - -- - -- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. + --- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. -- -- ## POINT_VEC2 constructor -- diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index 4bc0c24a1..1e1d96aaf 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -1,7 +1,5 @@ --- **Core** -- The RADIO Module is responsible for everything that is related to radio transmission and you can hear in DCS, be it TACAN beacons, Radio transmissions... -- --- ![Banner Image](..\Presentations\RADIO\Dia1.JPG) --- -- === -- -- The Radio contains 2 classes : RADIO and BEACON @@ -33,6 +31,7 @@ -- ### Author: Hugues "Grey_Echo" Bousquet -- -- @module Core.Radio +-- @image Core_Radio.JPG --- # RADIO class, extends @{Core.Base#BASE} diff --git a/Moose Development/Moose/Core/Report.lua b/Moose Development/Moose/Core/Report.lua index c6a66fca8..c570bb39b 100644 --- a/Moose Development/Moose/Core/Report.lua +++ b/Moose Development/Moose/Core/Report.lua @@ -9,6 +9,7 @@ -- ### Contributions: -- -- @module Core.Report +-- @image Core_Report.JPG --- The REPORT class diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 20f3b5185..a9d27adbc 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -31,6 +31,7 @@ -- ### Authors: FlightControl : Design & Programming -- -- @module Core.ScheduleDispatcher +-- @image Core_Schedule_Dispatcher.JPG --- The SCHEDULEDISPATCHER structure -- @type SCHEDULEDISPATCHER diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index 98b824205..734c31c01 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -1,7 +1,5 @@ --- **Core** -- SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**. -- --- ![Banner Image](..\Presentations\SCHEDULER\Dia1.JPG) --- -- === -- -- SCHEDULER manages the **scheduling of functions**: @@ -40,7 +38,7 @@ -- === -- -- @module Core.Scheduler - +-- @image Core_Scheduler.JPG --- The SCHEDULER class -- @type SCHEDULER @@ -48,9 +46,7 @@ -- @extends Core.Base#BASE ---- # SCHEDULER class, extends @{Core.Base#BASE} --- --- The SCHEDULER class creates schedule. +--- The SCHEDULER class creates schedule. -- -- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**. -- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called. diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 800511352..fbaed636e 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1,7 +1,5 @@ --- **Core** -- SET_ classes define **collections** of objects to perform **bulk actions** and logically **group** objects. -- --- ![Banner Image](..\Presentations\SET\Dia1.JPG) --- -- === -- -- SET_ classes group objects of the same type into a collection, which is either: @@ -31,6 +29,7 @@ -- === -- -- @module Core.Set +-- @image Core_Sets.JPG --- @type SET_BASE @@ -41,18 +40,17 @@ -- @extends Core.Base#BASE ---- # 1) SET_BASE class, extends @{Core.Base#BASE} --- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects. +--- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects. -- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach interator loop at defined **"intervals"** to the mail simulator loop. -- In this way, large loops can be done while not blocking the simulator main processing loop. -- The default **"yield interval"** is after 10 objects processed. -- The default **"time interval"** is after 0.001 seconds. -- --- ## 1.1) Add or remove objects from the SET +-- ## Add or remove objects from the SET -- -- Some key core functions are @{Core.Set#SET_BASE.Add} and @{Core.Set#SET_BASE.Remove} to add or remove objects from the SET in your logic. -- --- ## 1.2) Define the SET iterator **"yield interval"** and the **"time interval"** +-- ## Define the SET iterator **"yield interval"** and the **"time interval"** -- -- Modify the iterator intervals with the @{Core.Set#SET_BASE.SetInteratorIntervals} method. -- You can set the **"yield interval"**, and the **"time interval"**. (See above). @@ -647,27 +645,25 @@ end --- @type SET_GROUP -- @extends Core.Set#SET_BASE ---- # SET_GROUP class, extends @{Core.Set#SET_BASE} --- --- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain: +--- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain: -- -- * Coalitions -- * Categories -- * Countries -- * Starting with certain prefix strings. -- --- ## 1. SET_GROUP constructor +-- ## SET_GROUP constructor -- -- Create a new SET_GROUP object with the @{#SET_GROUP.New} method: -- -- * @{#SET_GROUP.New}: Creates a new SET_GROUP object. -- --- ## 2. Add or Remove GROUP(s) from SET_GROUP +-- ## Add or Remove GROUP(s) from SET_GROUP -- -- GROUPS can be added and removed using the @{Core.Set#SET_GROUP.AddGroupsByName} and @{Core.Set#SET_GROUP.RemoveGroupsByName} respectively. -- These methods take a single GROUP name or an array of GROUP names to be added or removed from SET_GROUP. -- --- ## 3. SET_GROUP filter criteria +-- ## SET_GROUP filter criteria -- -- You can set filter criteria to define the set of groups within the SET_GROUP. -- Filter criteria are defined by: @@ -694,7 +690,7 @@ end -- -- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. -- --- ## 4. SET_GROUP iterators +-- ## SET_GROUP iterators -- -- Once the filters have been defined and the SET_GROUP has been built, you can iterate the SET_GROUP with the available iterator methods. -- The iterator methods will walk the SET_GROUP set, and call for each element within the set a function that you provide. @@ -706,11 +702,11 @@ end -- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. -- -- --- ## 5. SET_GROUP trigger events on the GROUP objects. +-- ## SET_GROUP trigger events on the GROUP objects. -- -- The SET is derived from the FSM class, which provides extra capabilities to track the contents of the GROUP objects in the SET_GROUP. -- --- ### 5.1. When a GROUP object crashes or is dead, the SET_GROUP will trigger a **Dead** event. +-- ### When a GROUP object crashes or is dead, the SET_GROUP will trigger a **Dead** event. -- -- You can handle the event using the OnBefore and OnAfter event handlers. -- The event handlers need to have the paramters From, Event, To, GroupObject. @@ -1423,9 +1419,7 @@ do -- SET_UNIT --- @type SET_UNIT -- @extends Core.Set#SET_BASE - --- # 3) SET_UNIT class, extends @{Core.Set#SET_BASE} - -- - -- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: + --- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: -- -- * Coalitions -- * Categories @@ -1433,18 +1427,18 @@ do -- SET_UNIT -- * Unit types -- * Starting with certain prefix strings. -- - -- ## 3.1) SET_UNIT constructor + -- ## SET_UNIT constructor -- -- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: -- -- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. -- - -- ## 3.2) Add or Remove UNIT(s) from SET_UNIT + -- ## Add or Remove UNIT(s) from SET_UNIT -- -- UNITs can be added and removed using the @{Core.Set#SET_UNIT.AddUnitsByName} and @{Core.Set#SET_UNIT.RemoveUnitsByName} respectively. -- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. -- - -- ## 3.3) SET_UNIT filter criteria + -- ## SET_UNIT filter criteria -- -- You can set filter criteria to define the set of units within the SET_UNIT. -- Filter criteria are defined by: @@ -1463,7 +1457,7 @@ do -- SET_UNIT -- -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. -- - -- ## 3.4) SET_UNIT iterators + -- ## SET_UNIT iterators -- -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. -- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. @@ -1479,13 +1473,13 @@ do -- SET_UNIT -- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. -- - -- ## 3.5 ) SET_UNIT atomic methods + -- ## SET_UNIT atomic methods -- -- Various methods exist for a SET_UNIT to perform actions or calculations and retrieve results from the SET_UNIT: -- -- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Wrapper.Unit}s in the SET, delimited by a comma. -- - -- ## 4. SET_UNIT iterators + -- ## SET_UNIT iterators -- -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. -- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. @@ -1495,11 +1489,11 @@ do -- SET_UNIT -- * @{#SET_UNIT.ForEachUnitInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence completely in a @{Zone}, providing the UNIT object and optional parameters to the called function. -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence not in a @{Zone}, providing the UNIT object and optional parameters to the called function. -- - -- ## 5. SET_UNIT trigger events on the UNIT objects. + -- ## SET_UNIT trigger events on the UNIT objects. -- -- The SET is derived from the FSM class, which provides extra capabilities to track the contents of the UNIT objects in the SET_UNIT. -- - -- ### 5.1. When a UNIT object crashes or is dead, the SET_UNIT will trigger a **Dead** event. + -- ### When a UNIT object crashes or is dead, the SET_UNIT will trigger a **Dead** event. -- -- You can handle the event using the OnBefore and OnAfter event handlers. -- The event handlers need to have the paramters From, Event, To, GroupObject. @@ -2423,9 +2417,7 @@ do -- SET_STATIC --- @type SET_STATIC -- @extends Core.Set#SET_BASE - --- # 3) SET_STATIC class, extends @{Core.Set#SET_BASE} - -- - -- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain: + --- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain: -- -- * Coalitions -- * Categories @@ -2433,18 +2425,18 @@ do -- SET_STATIC -- * Static types -- * Starting with certain prefix strings. -- - -- ## 3.1) SET_STATIC constructor + -- ## SET_STATIC constructor -- -- Create a new SET_STATIC object with the @{#SET_STATIC.New} method: -- -- * @{#SET_STATIC.New}: Creates a new SET_STATIC object. -- - -- ## 3.2) Add or Remove STATIC(s) from SET_STATIC + -- ## Add or Remove STATIC(s) from SET_STATIC -- -- STATICs can be added and removed using the @{Core.Set#SET_STATIC.AddStaticsByName} and @{Core.Set#SET_STATIC.RemoveStaticsByName} respectively. -- These methods take a single STATIC name or an array of STATIC names to be added or removed from SET_STATIC. -- - -- ## 3.3) SET_STATIC filter criteria + -- ## SET_STATIC filter criteria -- -- You can set filter criteria to define the set of units within the SET_STATIC. -- Filter criteria are defined by: @@ -2463,7 +2455,7 @@ do -- SET_STATIC -- -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}. -- - -- ## 3.4) SET_STATIC iterators + -- ## SET_STATIC iterators -- -- Once the filters have been defined and the SET_STATIC has been built, you can iterate the SET_STATIC with the available iterator methods. -- The iterator methods will walk the SET_STATIC set, and call for each element within the set a function that you provide. @@ -2479,7 +2471,7 @@ do -- SET_STATIC -- * @{#SET_STATIC.ForEachStaticCompletelyInZone}: Iterate and call an iterator function for each **alive** STATIC presence completely in a @{Zone}, providing the STATIC and optional parameters to the called function. -- * @{#SET_STATIC.ForEachStaticNotInZone}: Iterate and call an iterator function for each **alive** STATIC presence not in a @{Zone}, providing the STATIC and optional parameters to the called function. -- - -- ## 3.5 ) SET_STATIC atomic methods + -- ## SET_STATIC atomic methods -- -- Various methods exist for a SET_STATIC to perform actions or calculations and retrieve results from the SET_STATIC: -- @@ -3099,9 +3091,7 @@ end ---- # 4) SET_CLIENT class, extends @{Core.Set#SET_BASE} --- --- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain: +--- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain: -- -- * Coalitions -- * Categories @@ -3109,18 +3099,18 @@ end -- * Client types -- * Starting with certain prefix strings. -- --- ## 4.1) SET_CLIENT constructor +-- ## SET_CLIENT constructor -- -- Create a new SET_CLIENT object with the @{#SET_CLIENT.New} method: -- -- * @{#SET_CLIENT.New}: Creates a new SET_CLIENT object. -- --- ## 4.2) Add or Remove CLIENT(s) from SET_CLIENT +-- ## Add or Remove CLIENT(s) from SET_CLIENT -- -- CLIENTs can be added and removed using the @{Core.Set#SET_CLIENT.AddClientsByName} and @{Core.Set#SET_CLIENT.RemoveClientsByName} respectively. -- These methods take a single CLIENT name or an array of CLIENT names to be added or removed from SET_CLIENT. -- --- ## 4.3) SET_CLIENT filter criteria +-- ## SET_CLIENT filter criteria -- -- You can set filter criteria to define the set of clients within the SET_CLIENT. -- Filter criteria are defined by: @@ -3139,7 +3129,7 @@ end -- -- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. -- --- ## 4.4) SET_CLIENT iterators +-- ## SET_CLIENT iterators -- -- Once the filters have been defined and the SET_CLIENT has been built, you can iterate the SET_CLIENT with the available iterator methods. -- The iterator methods will walk the SET_CLIENT set, and call for each element within the set a function that you provide. @@ -3512,17 +3502,15 @@ end ---- # 4) SET_PLAYER class, extends @{Core.Set#SET_BASE} +--- Mission designers can use the @{Core.Set#SET_PLAYER} class to build sets of units belonging to alive players: -- --- Mission designers can use the @{Core.Set#SET_PLAYER} class to build sets of units belonging to alive players: --- --- ## 4.1) SET_PLAYER constructor +-- ## SET_PLAYER constructor -- -- Create a new SET_PLAYER object with the @{#SET_PLAYER.New} method: -- -- * @{#SET_PLAYER.New}: Creates a new SET_PLAYER object. -- --- ## 4.3) SET_PLAYER filter criteria +-- ## SET_PLAYER filter criteria -- -- You can set filter criteria to define the set of clients within the SET_PLAYER. -- Filter criteria are defined by: @@ -3541,7 +3529,7 @@ end -- -- * @{#SET_PLAYER.FilterZones}: Builds the SET_PLAYER with the clients within a @{Core.Zone#ZONE}. -- --- ## 4.4) SET_PLAYER iterators +-- ## SET_PLAYER iterators -- -- Once the filters have been defined and the SET_PLAYER has been built, you can iterate the SET_PLAYER with the available iterator methods. -- The iterator methods will walk the SET_PLAYER set, and call for each element within the set a function that you provide. @@ -3909,24 +3897,22 @@ end --- @type SET_AIRBASE -- @extends Core.Set#SET_BASE ---- # 5) SET_AIRBASE class, extends @{Core.Set#SET_BASE} --- --- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: +--- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: -- -- * Coalitions -- --- ## 5.1) SET_AIRBASE constructor +-- ## SET_AIRBASE constructor -- -- Create a new SET_AIRBASE object with the @{#SET_AIRBASE.New} method: -- -- * @{#SET_AIRBASE.New}: Creates a new SET_AIRBASE object. -- --- ## 5.2) Add or Remove AIRBASEs from SET_AIRBASE +-- ## Add or Remove AIRBASEs from SET_AIRBASE -- -- AIRBASEs can be added and removed using the @{Core.Set#SET_AIRBASE.AddAirbasesByName} and @{Core.Set#SET_AIRBASE.RemoveAirbasesByName} respectively. -- These methods take a single AIRBASE name or an array of AIRBASE names to be added or removed from SET_AIRBASE. -- --- ## 5.3) SET_AIRBASE filter criteria +-- ## SET_AIRBASE filter criteria -- -- You can set filter criteria to define the set of clients within the SET_AIRBASE. -- Filter criteria are defined by: @@ -3937,7 +3923,7 @@ end -- -- * @{#SET_AIRBASE.FilterStart}: Starts the filtering of the airbases within the SET_AIRBASE. -- --- ## 5.4) SET_AIRBASE iterators +-- ## SET_AIRBASE iterators -- -- Once the filters have been defined and the SET_AIRBASE has been built, you can iterate the SET_AIRBASE with the available iterator methods. -- The iterator methods will walk the SET_AIRBASE set, and call for each airbase within the set a function that you provide. @@ -4198,9 +4184,7 @@ end --- @type SET_CARGO -- @extends Core.Set#SET_BASE ---- # (R2.1) SET_CARGO class, extends @{Core.Set#SET_BASE} --- --- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: +--- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: -- -- * Coalitions -- * Types @@ -4260,7 +4244,7 @@ SET_CARGO = { } ---- (R2.1) Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories. +--- Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories. -- @param #SET_CARGO self -- @return #SET_CARGO -- @usage @@ -4632,9 +4616,7 @@ end --- @type SET_ZONE -- @extends Core.Set#SET_BASE ---- # SET_ZONE class, extends @{Core.Set#SET_BASE} --- --- Mission designers can use the @{Core.Set#SET_ZONE} class to build sets of zones of various types. +--- Mission designers can use the @{Core.Set#SET_ZONE} class to build sets of zones of various types. -- -- ## SET_ZONE constructor -- @@ -4647,7 +4629,7 @@ end -- ZONEs can be added and removed using the @{Core.Set#SET_ZONE.AddZonesByName} and @{Core.Set#SET_ZONE.RemoveZonesByName} respectively. -- These methods take a single ZONE name or an array of ZONE names to be added or removed from SET_ZONE. -- --- ## 5.3) SET_ZONE filter criteria +-- ## SET_ZONE filter criteria -- -- You can set filter criteria to build the collection of zones in SET_ZONE. -- Filter criteria are defined by: @@ -4658,7 +4640,7 @@ end -- -- * @{#SET_ZONE.FilterStart}: Starts the filtering of the zones within the SET_ZONE. -- --- ## 5.4) SET_ZONE iterators +-- ## SET_ZONE iterators -- -- Once the filters have been defined and the SET_ZONE has been built, you can iterate the SET_ZONE with the available iterator methods. -- The iterator methods will walk the SET_ZONE set, and call for each airbase within the set a function that you provide. diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index 86a607fc1..8bd51a63b 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -1,7 +1,5 @@ --- **Core** -- Manages various settings for MOOSE classes. -- --- ![Banner Image](..\Presentations\SETTINGS\Dia1.JPG) --- -- === -- -- The documentation of the SETTINGS class can be found further in this document. @@ -17,20 +15,16 @@ -- * **FlightControl**: Design & Programming -- -- @module Core.Settings +-- @image Core_Settings.JPG --- @type SETTINGS -- @extends Core.Base#BASE ---- # SETTINGS class, extends @{Core.Base#BASE} --- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. +--- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. -- -- === -- --- ![Banner Image](..\Presentations\SETTINGS\Dia1.JPG) --- --- === --- -- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. -- SETTINGS can work on 2 levels: -- @@ -39,29 +33,29 @@ -- -- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead. -- --- ## 1. \_SETTINGS object +-- ## \_SETTINGS object -- -- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission. -- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences. -- --- ## 2. SETTINGS Menu +-- ## SETTINGS Menu -- -- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**. -- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system. -- --- ### 2.1. Default settings menu +-- ### Default settings menu -- -- A menu is created automatically per Command Center that allows to modify the **Default** settings. -- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**! -- Note that the **Default settings** will only be used when a player has not choosen its own settings. -- --- ### 2.2. Player settings menu +-- ### Player settings menu -- -- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings. -- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**! -- Note that when a player has not chosen a specific setting, the **Default settings** will be used. -- --- ### 2.3. Show or Hide the Player Setting menus +-- ### Show or Hide the Player Setting menus -- -- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**. -- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus. @@ -75,14 +69,14 @@ -- -- But only when a player exits and reenters the slot these settings will have effect! -- -- --- ## 3. Settings +-- ## Settings -- -- There are different settings that are managed and applied within the MOOSE framework. -- See below a comprehensive description of each. -- --- ### 3.1. **A2G coordinates** display formatting +-- ### **A2G coordinates** display formatting -- --- #### 3.1.1. A2G coordinates setting **types** +-- #### A2G coordinates setting **types** -- -- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications. -- @@ -91,11 +85,11 @@ -- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted. -- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- --- #### 3.1.2. A2G coordinates setting **menu** +-- #### A2G coordinates setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- --- #### 3.1.3. A2G coordinates setting **methods** +-- #### A2G coordinates setting **methods** -- -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- @@ -104,14 +98,14 @@ -- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- --- #### 3.1.4. A2G coordinates setting - additional notes +-- #### A2G coordinates setting - additional notes -- -- One additional note on BR. In a situation when a BR coordinate should be given, -- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied! -- --- ### 3.2. **A2A coordinates** formatting +-- ### **A2A coordinates** formatting -- --- #### 3.2.1. A2A coordinates setting **types** +-- #### A2A coordinates setting **types** -- -- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications. -- @@ -121,11 +115,11 @@ -- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye). -- --- #### 3.2.2. A2A coordinates setting **menu** +-- #### A2A coordinates setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- --- #### 3.2.3. A2A coordinates setting **methods** +-- #### A2A coordinates setting **methods** -- -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- @@ -135,34 +129,34 @@ -- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default. -- --- #### 3.2.4. A2A coordinates settings - additional notes +-- #### A2A coordinates settings - additional notes -- -- One additional note on BRAA. In a situation when a BRAA coordinate should be given, -- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied! -- --- ### 3.3. **Measurements** formatting +-- ### **Measurements** formatting -- --- #### 3.3.1. Measurements setting **types** +-- #### Measurements setting **types** -- -- Will customize the measurements system being used as part as part of the Command Center communications. -- -- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ... -- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ... -- --- #### 3.3.2. Measurements setting **menu** +-- #### Measurements setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- --- #### 3.3.3. Measurements setting **methods** +-- #### Measurements setting **methods** -- -- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object. -- -- - @{#SETTINGS.SetMetric}(): Enable the Metric system. -- - @{#SETTINGS.SetImperial}(): Enable the Imperial system. -- --- ### 3.4. **Message** display times +-- ### **Message** display times -- --- #### 3.4.1. Message setting **types** +-- #### Message setting **types** -- -- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications. -- @@ -172,7 +166,7 @@ -- - **Overview report**: Provides a short report overview, the summary of the report. -- - **Detailed report**: Provides a complete report. -- --- #### 3.4.2. Message setting **menu** +-- #### Message setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index a42d6b7c5..919623334 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1,7 +1,5 @@ --- **Core** -- SPAWN class dynamically spawns new groups of units in your missions. -- --- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG) --- -- === -- -- The documentation of the SPAWN class can be found further in this document. @@ -22,6 +20,7 @@ -- === -- -- @module Core.Spawn +-- @image Core_Spawn.JPG --- SPAWN Class @@ -37,13 +36,7 @@ -- @extends Core.Base#BASE ---- # SPAWN class, extends @{Core.Base#BASE} --- --- -- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG) --- --- === --- --- The SPAWN class allows to spawn dynamically new groups. +--- The SPAWN class allows to spawn dynamically new groups. -- Each SPAWN object needs to be have related **template groups** setup in the Mission Editor (ME), -- which is a normal group with the **Late Activation** flag set. -- This template group will never be activated in your mission. diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index f1715465a..52df548da 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -1,7 +1,5 @@ --- **Core** -- Spawn dynamically new STATICs in your missions. -- --- ![Banner Image](..\Presentations\SPAWNSTATIC\Dia1.JPG) --- -- === -- -- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation. @@ -30,6 +28,7 @@ -- === -- -- @module Core.SpawnStatic +-- @image Core_Spawnstatic.JPG @@ -37,9 +36,7 @@ -- @extends Core.Base#BASE ---- # SPAWNSTATIC class, extends @{Core.Base#BASE} --- --- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s. +--- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s. -- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), -- SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy" -- these properties to create a new static object and place it at the desired coordinate. diff --git a/Moose Development/Moose/Core/Spot.lua b/Moose Development/Moose/Core/Spot.lua index 22ba7eee8..0af7a7b02 100644 --- a/Moose Development/Moose/Core/Spot.lua +++ b/Moose Development/Moose/Core/Spot.lua @@ -1,7 +1,5 @@ --- **Core** -- Management of SPOT logistics, that can be transported from and to transportation carriers. -- --- ![Banner Image](..\Presentations\SPOT\Dia1.JPG) --- -- === -- -- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to: @@ -39,6 +37,7 @@ -- === -- -- @module Core.Spot +-- @image Core_Spot.JPG do @@ -47,9 +46,7 @@ do -- @extends Core.Fsm#FSM - --- # SPOT class, extends @{Fsm#FSM} - -- - -- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to: + --- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to: -- -- * Mark targets for a defined duration. -- * wiggle the spot at the target. diff --git a/Moose Development/Moose/Core/UserFlag.lua b/Moose Development/Moose/Core/UserFlag.lua index 8cfff730f..9bfa5a628 100644 --- a/Moose Development/Moose/Core/UserFlag.lua +++ b/Moose Development/Moose/Core/UserFlag.lua @@ -11,6 +11,8 @@ -- === -- -- @module Core.UserFlag +-- @image Core_Userflag.JPG +-- do -- UserFlag @@ -18,11 +20,9 @@ do -- UserFlag -- @extends Core.Base#BASE - --- # USERFLAG class, extends @{Core.Base#BASE} + --- Management of DCS User Flags. -- - -- Management of DCS User Flags. - -- - -- ## 1. USERFLAG constructor + -- ## USERFLAG constructor -- -- * @{#USERFLAG.New}(): Creates a new USERFLAG object. -- diff --git a/Moose Development/Moose/Core/UserSound.lua b/Moose Development/Moose/Core/UserSound.lua index 2a7614384..9b7204b2f 100644 --- a/Moose Development/Moose/Core/UserSound.lua +++ b/Moose Development/Moose/Core/UserSound.lua @@ -11,6 +11,7 @@ -- === -- -- @module Core.UserSound +-- @image Core_Usersound.JPG do -- UserSound @@ -18,11 +19,9 @@ do -- UserSound -- @extends Core.Base#BASE - --- # USERSOUND class, extends @{Core.Base#BASE} + --- Management of DCS User Sound. -- - -- Management of DCS User Sound. - -- - -- ## 1. USERSOUND constructor + -- ## USERSOUND constructor -- -- * @{#USERSOUND.New}(): Creates a new USERSOUND object. -- diff --git a/Moose Development/Moose/Core/Velocity.lua b/Moose Development/Moose/Core/Velocity.lua index 0888aa210..c8ef325f3 100644 --- a/Moose Development/Moose/Core/Velocity.lua +++ b/Moose Development/Moose/Core/Velocity.lua @@ -8,6 +8,7 @@ -- === -- -- @module Core.Velocity +-- @image Core_Velocity.JPG do -- Velocity @@ -15,11 +16,9 @@ do -- Velocity -- @extends Core.Base#BASE - --- # VELOCITY class, extends @{Core.Base#BASE} - -- -- VELOCITY models a speed, which can be expressed in various formats according the Settings. -- - -- ## 1. VELOCITY constructor + -- ## VELOCITY constructor -- -- * @{#VELOCITY.New}(): Creates a new VELOCITY object. -- diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index a6201d28a..ee8180931 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1,7 +1,5 @@ --- **Core** -- ZONE classes define **zones** within your mission of **various forms**, with **various capabilities**. -- --- ![Banner Image](..\Presentations\ZONE\Dia1.JPG) --- -- === -- -- There are essentially two core functions that zones accomodate: @@ -35,6 +33,7 @@ -- === -- -- @module Core.Zone +-- @image Core_Zones.JPG --- @type ZONE_BASE @@ -43,9 +42,7 @@ -- @extends Core.Base#BASE ---- # ZONE_BASE class, extends @{Core.Base#BASE} --- --- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. +--- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. -- -- ## Each zone has a name: -- @@ -380,9 +377,7 @@ end -- @field Dcs.DCSTypes#Distance Radius The radius of the zone. -- @extends #ZONE_BASE ---- # ZONE_RADIUS class, extends @{Core.Zone#ZONE_BASE} --- --- The ZONE_RADIUS class defined by a zone name, a location and a radius. +--- The ZONE_RADIUS class defined by a zone name, a location and a radius. -- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties. -- -- ## ZONE_RADIUS constructor @@ -951,9 +946,7 @@ end -- @extends #ZONE_RADIUS ---- # ZONE class, extends @{Core.Zone#ZONE_RADIUS} --- --- The ZONE class, defined by the zone name as defined within the Mission Editor. +--- The ZONE class, defined by the zone name as defined within the Mission Editor. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. -- -- ## ZONE constructor @@ -1023,9 +1016,7 @@ end -- @field Wrapper.Unit#UNIT ZoneUNIT -- @extends Core.Zone#ZONE_RADIUS ---- # ZONE_UNIT class, extends @{Core.Zone#ZONE_RADIUS} --- --- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. +--- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. -- -- @field #ZONE_UNIT @@ -1116,9 +1107,7 @@ end -- @extends #ZONE_RADIUS ---- # ZONE_GROUP class, extends @{Core.Zone#ZONE_RADIUS} --- --- The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. The current leader of the group defines the center of the zone. +--- The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. The current leader of the group defines the center of the zone. -- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- -- @field #ZONE_GROUP @@ -1197,9 +1186,7 @@ end -- @extends #ZONE_BASE ---- # ZONE_POLYGON_BASE class, extends @{Core.Zone#ZONE_BASE} --- --- The ZONE_POLYGON_BASE class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. +--- The ZONE_POLYGON_BASE class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. -- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. -- @@ -1474,9 +1461,7 @@ end -- @extends #ZONE_POLYGON_BASE ---- # ZONE_POLYGON class, extends @{Core.Zone#ZONE_POLYGON_BASE} --- --- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. +--- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. -- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- -- ## Declare a ZONE_POLYGON directly in the DCS mission editor! From 4941b5ee98a52046290255db2cfc0eba046b9488 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 28 May 2018 00:33:58 +0200 Subject: [PATCH 133/170] ARTY v0.9.2 Added tactical nukes. --- .../Moose/Functional/Artillery.lua | 185 +++++++++++++++++- 1 file changed, 182 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index f8a210b8e..78978518a 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -77,7 +77,11 @@ -- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. -- @field #number Nshots Number of shots fired on current target. -- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0.5 km. --- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. +-- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. +-- @field #number nukewarhead Explosion strength of tactical nuclear warhead in kg TNT. Default 75000. +-- @field #number nukerange Demolition range of tactical nuclear explostions. +-- @field #boolean nukefire Ignite additional fires and smoke for nuclear explosions Default true. +-- @field #number nukefires Number of nuclear fires. -- @extends Core.Fsm#FSM_CONTROLLABLE ---# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE} @@ -365,6 +369,10 @@ ARTY={ Nshots=0, minrange=500, maxrange=1000000, + nukewarhead=75000, + nukerange=nil, + nukefire=true, + nukefires=nil, } --- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag @@ -376,7 +384,8 @@ ARTY.WeaponType={ UnguidedAny=805339120, GuidedMissile=268402688, CruiseMissile=2097152, - AntiShipMissile=65536, + AntiShipMissile=65536, + TacticalNuke=666, } --- Some ID to identify who we are in output of the DCS.log file. @@ -385,7 +394,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.1" +ARTY.version="0.9.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -843,6 +852,14 @@ function ARTY:onafterStart(Controllable, From, Event, To) -- Get Ammo. self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:GetAmmo(self.Debug) + -- Init nuclear explosion parameters if they were not set by user. + if self.nukerange==nil then + self.nukerange=1500/75000*self.nukewarhead -- linear dependence + end + if self.nukefires==nil then + self.nukefires=20/1000/1000*self.nukerange*self.nukerange + end + local text=string.format("\n******************************************************\n") text=text..string.format("Arty group = %s\n", Controllable:GetName()) text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery)) @@ -870,6 +887,9 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Rearming coord dist = %d m\n", dist) text=text..string.format("Rearming ARTY roads = %s\n", tostring(self.RearmingArtyOnRoad)) end + text=text..string.format("Nuclear warhead = %d tons TNT\n", self.nukewarhead/1000) + text=text..string.format("Nuclear demolition = %d m\n", self.nukerange) + text=text..string.format("Nuclear fires = %d (active=%s)\n", self.nukefires, tostring(self.nukefire)) text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do @@ -952,6 +972,115 @@ end -- Event Handling ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Model a nuclear blast/destruction by creating fires and destroy scenery. +-- @param #ARTY self +-- @param Core.Point#COORDINATE _coord Coordinate of the impact point (center of the blast). +function ARTY:_NuclearBlast(_coord) + + local S0=self.nukewarhead + local R0=self.nukerange + + -- Number of fires + local N0=self.nukefires + + -- Create an explosion at the last known position. + _coord:Explosion(S0) + + -- Huge fire at direct impact point. + if self.nukefire then + _coord:BigSmokeAndFireHuge() + end + + -- Create a table of fire coordinates within the demolition zone. + local _fires={} + for i=1,N0 do + local _fire=_coord:GetRandomCoordinateInRadius(R0) + local _dist=_fire:Get2DDistance(_coord) + table.insert(_fires, {distance=_dist, coord=_fire}) + end + + -- Sort scenery wrt to distance from impact point. + local _sort = function(a,b) return a.distance < b.distance end + table.sort(_fires,_sort) + + local function _explosion(R) + -- At R=R0 ==> explosion strength is 1% of S0 at impact point. + local alpha=math.log(100) + local strength=S0*math.exp(-alpha*R/R0) + env.info(string.format("FF: nuklear explosion strength s(%.1f m) = %.10f (s/s0=%.1f %%), alpha=%.3f", R, strength, strength/S0*100, alpha)) + return strength + end + + local function ignite(_fires) + for _,fire in pairs(_fires) do + local _fire=fire.coord --Core.Point#COORDINATE + + -- Get distance to impact and calc exponential explosion strength. + local R=_fire:Get2DDistance(_coord) + local S=_explosion(R) + env.info(string.format("FF: explosion r=%.1f, s=%.3f", R, S)) + + -- Get a random Big Smoke and fire object. + local _preset=math.random(0,7) + local _density=S/S0 --math.random()+0.1 + + _fire:BigSmokeAndFire(_preset,_density) + _fire:Explosion(S) + + end + end + + if self.nukefire then + ignite(_fires) + end + +--[[ + local ZoneNuke=ZONE_RADIUS:New("Nukezone", _coord:GetVec2(), 2000) + + -- Scan for Scenery objects. + ZoneNuke:Scan(Object.Category.SCENERY) + + -- Array with all possible hideouts, i.e. scenery objects in the vicinity of the group. + local scenery={} + + for SceneryTypeName, SceneryData in pairs(ZoneNuke:GetScannedScenery()) do + for SceneryName, SceneryObject in pairs(SceneryData) do + + local SceneryObject = SceneryObject -- Wrapper.Scenery#SCENERY + + -- Position of the scenery object. + local spos=SceneryObject:GetCoordinate() + + -- Distance from group to impact point. + local distance= spos:Get2DDistance(_coord) + + -- Place markers on every possible scenery object. + if self.Debug then + local MarkerID=spos:MarkToAll(string.format("%s scenery object %s", self.Controllable:GetName(), SceneryObject:GetTypeName())) + local text=string.format("%s scenery: %s, Coord %s", self.Controllable:GetName(), SceneryObject:GetTypeName(), SceneryObject:GetCoordinate():ToStringLLDMS()) + self:T2(SUPPRESSION.id..text) + end + + -- Add to table. + table.insert(scenery, {object=SceneryObject, distance=distance}) + + --SceneryObject:Destroy() + end + end + + -- Sort scenery wrt to distance from impact point. +-- local _sort = function(a,b) return a.distance < b.distance end +-- table.sort(scenery,_sort) + +-- for _,object in pairs(scenery) do +-- local sobject=object -- Wrapper.Scenery#SCENERY +-- sobject:Destroy() +-- end + +]] + +end + --- Eventhandler for shot event. -- @param #ARTY self -- @param Core.Event#EVENTDATA EventData @@ -985,6 +1114,49 @@ function ARTY:_OnEventShot(EventData) self:T(ARTY.id..text) MESSAGE:New(text, 5):ToAllIf(self.report or self.Debug) + -- Last known position of the weapon fired. + local _lastpos={x=0, y=0, z=0} + + --- Track the position of the weapon if it is supposed to model a tac nuke. + -- @param #table _weapon + local function _TrackWeapon(_weapon) + + -- When the pcall status returns false the weapon has hit. + local _status,_currpos = pcall( + function() + return _weapon:getPoint() + end) + + self:T(ARTY.id..string.format("ARTY %s: Weapon still in air: %s", self.Controllable:GetName(), tostring(_status))) + + if _status then + + -- Update last position. + _lastpos={x=_currpos.x, y=_currpos.y, z=_currpos.z} + + -- Check again in 0.05 seconds. + --return timer.getTime() + self.dtBombtrack + return timer.getTime() + 0.05 + + else + + local _impactcoord=COORDINATE:NewFromVec3(_lastpos) + + -- Create a "nuclear" explosion and blast at the impact point. + SCHEDULER:New(nil, ARTY._NuclearBlast, {self,_impactcoord}, 1.0) + --self:_NuclearBlast(_impactcoord) + + end + + end + + -- Start track the shell if we want to model a tactical nuke. + if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNuke then + self:T(ARTY.id..string.format("ARTY %s: Tracking of weapon starts in five seconds.", self.Controllable:GetName())) + timer.scheduleFunction(_TrackWeapon, EventData.weapon, timer.getTime() + 5.0) + end + + -- Get current ammo. local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() @@ -1725,6 +1897,11 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) -- Controllable. local group=self.Controllable --Wrapper.Group#GROUP + + -- Tactical nukes are actually cannon shells. + if weapontype==ARTY.WeaponType.TacticalNuke then + weapontype=ARTY.WeaponType.Cannon + end -- Set ROE to weapon free. group:OptionROEOpenFire() @@ -2254,6 +2431,8 @@ function ARTY:_WeaponTypeName(tnumber) name="Guided Missiles" elseif tnumber==ARTY.WeaponType.AntiShipMissile then name="Anti-Ship Missiles" + elseif tnumber==ARTY.WeaponType.TacticalNuke then + name="Tactical Nukes" end return name end From 0553e4b14eace4021e001e71f8497b16c1347ad7 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 28 May 2018 06:12:48 +0200 Subject: [PATCH 134/170] Fixing AI_CARGO_HELICOPTER to interprete the real height correctly and also allow for pickup when the helo is still speeding more than 7 km/h. --- Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua | 6 +----- .../Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua | 8 +------- Moose Development/Moose/AI/AI_Cargo_Helicopter.lua | 4 ++-- Moose Development/Moose/Wrapper/Group.lua | 2 +- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 378c881fe..6bce0816e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -13,11 +13,7 @@ -- @extends Core.Fsm#FSM ---- # AI\_CARGO\_DISPATCHER class, extends @{Core.Fsm#FSM} --- --- === --- --- AI\_CARGO\_DISPATCHER brings a dynamic cargo handling capability for AI groups. +--- A dynamic cargo handling capability for AI groups. -- -- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI\_CARGO\_DISPATCHER module uses the @{Cargo} capabilities within the MOOSE framework, to enable Carrier GROUP objects diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index bfa86e06e..8a53f1069 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -15,13 +15,7 @@ -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER ---- # AI\_CARGO\_DISPATCHER\_HELICOPTER class, extends @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} --- --- ![Banner Image](..\Presentations\AI_CARGO_DISPATCHER_HELICOPTER\Dia1.JPG) --- --- === --- --- AI\_CARGO\_DISPATCHER\_HELICOPTER brings a dynamic cargo handling capability for AI helicopter groups. +--- A dynamic cargo handling capability for AI helicopter groups. -- -- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI\_CARGO\_DISPATCHER\_HELICOPTER module uses the @{Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index b0725cc0a..1983540d5 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -219,7 +219,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } ) if self.RoutePickup == true then - if Helicopter:GetHeight( true ) <= 2 and Helicopter:GetVelocityKMH() < 5 then + if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 7 then self:Load( Helicopter:GetPointVec2() ) self.RoutePickup = false self.Relocating = true @@ -227,7 +227,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) end if self.RouteDeploy == true then - if Helicopter:GetHeight( true ) <= 2 and Helicopter:GetVelocityKMH() < 5 then + if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 7 then self:Unload( true ) self.RouteDeploy = false self.Transporting = false diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index f0abf4069..18b34e171 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -543,7 +543,7 @@ function GROUP:GetHeight( FromGround ) local GroupPosition = DCSUnit:getPosition() if FromGround == true then - local LandHeight = land.getHeight( { GroupPosition.p.x, GroupPosition.p.z } ) + local LandHeight = land.getHeight( { x = GroupPosition.p.x, y = GroupPosition.p.z } ) GroupHeight = GroupHeight + ( GroupPosition.p.y - LandHeight ) else GroupHeight = GroupHeight + GroupPosition.p.y From c5dcd63dea33899f1fd40d7cf343676f2a9b3cdf Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 28 May 2018 06:39:41 +0200 Subject: [PATCH 135/170] Updated Settings documentation. --- Moose Development/Moose/Core/Settings.lua | 50 +++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index 8bd51a63b..77de7dac2 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -33,29 +33,29 @@ -- -- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead. -- --- ## \_SETTINGS object +-- # 1) \_SETTINGS object -- -- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission. -- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences. -- --- ## SETTINGS Menu +-- # 2) SETTINGS Menu -- -- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**. -- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system. -- --- ### Default settings menu +-- ## 2.1) Default settings menu -- -- A menu is created automatically per Command Center that allows to modify the **Default** settings. -- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**! -- Note that the **Default settings** will only be used when a player has not choosen its own settings. -- --- ### Player settings menu +-- ## 2.2) Player settings menu -- -- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings. -- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**! -- Note that when a player has not chosen a specific setting, the **Default settings** will be used. -- --- ### Show or Hide the Player Setting menus +-- ## 2.3) Show or Hide the Player Setting menus -- -- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**. -- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus. @@ -69,14 +69,14 @@ -- -- But only when a player exits and reenters the slot these settings will have effect! -- -- --- ## Settings +-- # 3) Settings -- -- There are different settings that are managed and applied within the MOOSE framework. -- See below a comprehensive description of each. -- --- ### **A2G coordinates** display formatting +-- ## 3.1) **A2G coordinates** display formatting -- --- #### A2G coordinates setting **types** +-- ### 3.1.1) A2G coordinates setting **types** -- -- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications. -- @@ -85,11 +85,11 @@ -- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted. -- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- --- #### A2G coordinates setting **menu** +-- ### 3.1.2) A2G coordinates setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- --- #### A2G coordinates setting **methods** +-- ### 3.1.3) A2G coordinates setting **methods** -- -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- @@ -98,14 +98,14 @@ -- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- --- #### A2G coordinates setting - additional notes +-- ### 3.1.4) A2G coordinates setting - additional notes -- -- One additional note on BR. In a situation when a BR coordinate should be given, -- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied! -- --- ### **A2A coordinates** formatting +-- ## 3.2) **A2A coordinates** formatting -- --- #### A2A coordinates setting **types** +-- ### 3.2.1) A2A coordinates setting **types** -- -- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications. -- @@ -115,11 +115,11 @@ -- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye). -- --- #### A2A coordinates setting **menu** +-- ### 3.2.2) A2A coordinates setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- --- #### A2A coordinates setting **methods** +-- ### 3.2.3) A2A coordinates setting **methods** -- -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- @@ -129,34 +129,34 @@ -- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default. -- --- #### A2A coordinates settings - additional notes +-- ### 3.2.4) A2A coordinates settings - additional notes -- -- One additional note on BRAA. In a situation when a BRAA coordinate should be given, -- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied! -- --- ### **Measurements** formatting +-- ## 3.3) **Measurements** formatting -- --- #### Measurements setting **types** +-- ### 3.3.1) Measurements setting **types** -- -- Will customize the measurements system being used as part as part of the Command Center communications. -- -- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ... -- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ... -- --- #### Measurements setting **menu** +-- ### 3.3.2) Measurements setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- --- #### Measurements setting **methods** +-- ### 3.3.3) Measurements setting **methods** -- -- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object. -- -- - @{#SETTINGS.SetMetric}(): Enable the Metric system. -- - @{#SETTINGS.SetImperial}(): Enable the Imperial system. -- --- ### **Message** display times +-- ## 3.4) **Message** display times -- --- #### Message setting **types** +-- ### 3.4.1) Message setting **types** -- -- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications. -- @@ -166,7 +166,7 @@ -- - **Overview report**: Provides a short report overview, the summary of the report. -- - **Detailed report**: Provides a complete report. -- --- #### Message setting **menu** +-- ### 3.4.2) Message setting **menu** -- -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- @@ -175,7 +175,7 @@ -- So the player can choose its own amount of seconds how long a message should be displayed of a certain type. -- Note that **Update** messages can be chosen not to be displayed at all! -- --- #### 3.4.3. Message setting **methods** +-- ### 3.4.3) Message setting **methods** -- -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- @@ -723,7 +723,7 @@ do -- SETTINGS end --- Removes the player menu from the PlayerUnit. - --- @param #SETTINGS self + -- @param #SETTINGS self -- @param Wrapper.Client#CLIENT PlayerUnit -- @return #SETTINGS self function SETTINGS:RemovePlayerMenu( PlayerUnit ) From 21ce0cac8d15d9a26bf2636b7538f0eb00296bf2 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 28 May 2018 14:38:04 +0200 Subject: [PATCH 136/170] ARTY v0.9.3 ARTY: - Improved tac nukes implementation. Added user functions. - Added relocation option after engagements. COORDINATE: - Added get surface type function. --- Moose Development/Moose/Core/Point.lua | 10 + .../Moose/Functional/Artillery.lua | 246 ++++++++++++++---- 2 files changed, 212 insertions(+), 44 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 53e8bc543..155b2529e 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -958,6 +958,16 @@ do -- COORDINATE return Path end + --- Gets the surface type at the coordinate. + -- @param #COORDINATE self + -- @return Dcs.DCSland#SurfaceType Surface type. + function COORDINATE:GetSurfaceType() + local vec2=self:GetVec2() + local surface=land.getSurfaceType(vec2) + self:MarkToAll("Surface type = "..surface) + return surface + end + --- Creates an explosion at the point of a certain intensity. -- @param #COORDINATE self -- @param #number ExplosionIntensity diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 78978518a..1434522f4 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -53,6 +53,7 @@ -- @field #number Nshells0 Initial amount of shells of the whole group. -- @field #number Nrockets0 Initial amount of rockets of the whole group. -- @field #number Nmissiles0 Initial amount of missiles of the whole group. +-- @field #number Nukes0 Initial amount of tactical nukes of the whole group. -- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. -- @field #number StatusInterval Update interval in seconds between status updates. Default 10 seconds. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. @@ -79,9 +80,13 @@ -- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0.5 km. -- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. -- @field #number nukewarhead Explosion strength of tactical nuclear warhead in kg TNT. Default 75000. +-- @field #number Nukes Number of nuclear shells, the group has available. Default is same number as normal shells. Note that if normal shells are empty, firing nukes is also not possible any more. -- @field #number nukerange Demolition range of tactical nuclear explostions. -- @field #boolean nukefire Ignite additional fires and smoke for nuclear explosions Default true. --- @field #number nukefires Number of nuclear fires. +-- @field #number nukefires Number of nuclear fires and subexplosions. +-- @field #boolean relocateafterfire Group will relocate after each firing task. Default false. +-- @field #number relocateRmin Minimum distance in meters the group will look for places to relocate. +-- @field #number relocateRmax Maximum distance in meters the group will look for places to relocate. -- @extends Core.Fsm#FSM_CONTROLLABLE ---# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE} @@ -343,6 +348,7 @@ ARTY={ Nshells0=0, Nrockets0=0, Nmissiles0=0, + Nukes0=0, FullAmmo=0, StatusInterval=10, WaitForShotTime=300, @@ -370,9 +376,13 @@ ARTY={ minrange=500, maxrange=1000000, nukewarhead=75000, - nukerange=nil, - nukefire=true, + Nukes=nil, + nukefire=false, nukefires=nil, + nukerange=nil, + relocateafterfire=false, + relocateRmin=300, + relocateRmax=800, } --- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag @@ -385,7 +395,7 @@ ARTY.WeaponType={ GuidedMissile=268402688, CruiseMissile=2097152, AntiShipMissile=65536, - TacticalNuke=666, + TacticalNukes=666, } --- Some ID to identify who we are in output of the DCS.log file. @@ -394,7 +404,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.2" +ARTY.version="0.9.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -468,7 +478,6 @@ function ARTY:New(group) -- Maximum speed in km/h. self.SpeedMax=group:GetSpeedMax() - --self.SpeedMax=self.DCSdesc.speedMax*3.6 -- Set speed to 0.7 of maximum. self.Speed=self.SpeedMax * 0.7 @@ -610,9 +619,9 @@ end --- Assign coordinate to where the ARTY group should move. -- @param #ARTY self --- @param Core.Point#COORDINATE coord Coordinates of the target. --- @param #string time (Optional) Day time at which the group should start moving. Passed as a string in format "08:13:45". --- @param #number speed (Optinal) Speed in km/h the group should move at. Default 50 km/h. +-- @param Core.Point#COORDINATE coord Coordinates of the new position. +-- @param #string time (Optional) Day time at which the group should start moving. Passed as a string in format "08:13:45". Default is now. +-- @param #number speed (Optinal) Speed in km/h the group should move at. Default 70% of max posible speed of group. -- @param #boolean onroad (Optional) If true, group will mainly use roads. Default off, i.e. go directly towards the specified coordinate. -- @param #boolean cancel (Optional) If true, cancel any running attack when move should begin. Default is false. -- @param #string name (Optional) Name of the coordinate. Default is LL DMS string of the coordinate. If the name was already given, the numbering "#01", "#02",... is appended automatically. @@ -629,8 +638,18 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name) -- Default is current time if no time was specified. time=time or self:_SecondsToClock(timer.getAbsTime()) - -- Default speed is 50 km/h. - speed=speed or 50 + -- Get max speed of group. + local speedmax=self.Controllable:GetSpeedMax() + + -- Default speed is 70% of max speed. + if speed then + speed=math.min(speed, speedmax) + elseif self.Speed then + speed=self.Speed + else + speed=speedmax*0.7 + end + -- Default is off road. if onroad==nil then @@ -648,6 +667,10 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name) -- Prepare move array. local _move={name=_name, coord=coord, time=_time, speed=speed, onroad=onroad, cancel=cancel} + if self.Debug then + coord:MarkToAll(string.format("Battery %s move position.", self.Controllable:GetName())) + end + -- Add to table. table.insert(self.moves, _move) @@ -831,6 +854,51 @@ function ARTY:SetMissileTypes(tableofnames) end end +--- Set number of tactical nuclear warheads available to the group. +-- Note that it can be max the number of normal shells. Also if all normal shells are empty, firing nuclear shells is also not possible any more until group gets rearmed. +-- @param #ARTY self +-- @param #number n Number of warheads for the whole group. +function ARTY:SetTacNukeShells(n) + self.Nukes=n +end + +--- Set nuclear warhead explosion strength. +-- @param #ARTY self +-- @param #number strength Explosion strength in kilo tons TNT. Default is 0.075 kt. +function ARTY:SetTacNukeWarhead(strength) + self.nukewarhead=strength or 0.075 + self.nukewarhead=self.nukewarhead*1000*1000 -- convert to kg TNT. +end + +--- Set nuclear fires and extra demolition explosions. +-- @param #ARTY self +-- @param #number nfires (Optional) Number of big smoke and fire objects created in the demolition zone. +-- @param #number demolitionrange (Optional) Demolition range in meters. +function ARTY:SetTacNukeFires(nfires, range) + self.nukefire=true + self.nukefires=nfires + self.nukerange=range +end + +--- Set relocate after firing. Group will find a new location after each engagement. Default is off +-- @param #ARTY self +-- @param #number switch (Optional) If true, activate relocation. If false, deactivate relocation. +function ARTY:SetRelocateAfterEngagement(switch) + if switch==nil then + switch=true + end + self.relocateafterfire=switch +end + +--- Set relocation distance. +-- @param #ARTY self +-- @param #number rmax (Optional) Max distance in meters, the group will move to relocate. Default is 800 m. +-- @param #number rmin (Optional) Min distance in meters, the group will move to relocate. Default is 300 m. +function ARTY:SetRelocateDistance(rmax, rmin) + self.relocateRmax=rmax or 800 + self.relocateRmin=rmin or 300 +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- FSM Start Event ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -859,6 +927,11 @@ function ARTY:onafterStart(Controllable, From, Event, To) if self.nukefires==nil then self.nukefires=20/1000/1000*self.nukerange*self.nukerange end + if self.Nukes==nil then + self.Nukes0=self.Nshells0 + else + self.Nukes0=self.Nukes + end local text=string.format("\n******************************************************\n") text=text..string.format("Arty group = %s\n", Controllable:GetName()) @@ -874,6 +947,10 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Number of shells = %d\n", self.Nshells0) text=text..string.format("Number of rockets = %d\n", self.Nrockets0) text=text..string.format("Number of missiles = %d\n", self.Nmissiles0) + text=text..string.format("Number of nukes = %d\n", self.Nukes0) + text=text..string.format("Nuclear warhead = %d tons TNT\n", self.nukewarhead/1000) + text=text..string.format("Nuclear demolition = %d m\n", self.nukerange) + text=text..string.format("Nuclear fires = %d (active=%s)\n", self.nukefires, tostring(self.nukefire)) if self.RearmingGroup or self.RearmingPlaceCoord then text=text..string.format("Rearming safe dist. = %d m\n", self.RearmingDistance) end @@ -887,9 +964,9 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Rearming coord dist = %d m\n", dist) text=text..string.format("Rearming ARTY roads = %s\n", tostring(self.RearmingArtyOnRoad)) end - text=text..string.format("Nuclear warhead = %d tons TNT\n", self.nukewarhead/1000) - text=text..string.format("Nuclear demolition = %d m\n", self.nukerange) - text=text..string.format("Nuclear fires = %d (active=%s)\n", self.nukefires, tostring(self.nukefire)) + text=text..string.format("Relocate after fire = %s\n", tostring(self.relocateafterfire)) + text=text..string.format("Relocate min dist. = %d\n m", self.relocateRmin) + text=text..string.format("Relocate max dist. = %d\n m", self.relocateRmax) text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do @@ -948,6 +1025,7 @@ function ARTY:_StatusReport() text=text..string.format("Number of shells = %d\n", Nshells) text=text..string.format("Number of rockets = %d\n", Nrockets) text=text..string.format("Number of missiles = %d\n", Nmissiles) + text=text..string.format("Number of nukes = %d\n", self.Nukes) if self.currentTarget then text=text..string.format("Current Target = %s\n", tostring(self.currentTarget.name)) text=text..string.format("Curr. Tgt assigned = %d\n", Tnow-self.currentTarget.Tassigned) @@ -987,9 +1065,9 @@ function ARTY:_NuclearBlast(_coord) _coord:Explosion(S0) -- Huge fire at direct impact point. - if self.nukefire then - _coord:BigSmokeAndFireHuge() - end + --if self.nukefire then + _coord:BigSmokeAndFireHuge() + --end -- Create a table of fire coordinates within the demolition zone. local _fires={} @@ -1030,7 +1108,7 @@ function ARTY:_NuclearBlast(_coord) end end - if self.nukefire then + if self.nukefire==true then ignite(_fires) end @@ -1144,21 +1222,25 @@ function ARTY:_OnEventShot(EventData) -- Create a "nuclear" explosion and blast at the impact point. SCHEDULER:New(nil, ARTY._NuclearBlast, {self,_impactcoord}, 1.0) - --self:_NuclearBlast(_impactcoord) end end -- Start track the shell if we want to model a tactical nuke. - if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNuke then - self:T(ARTY.id..string.format("ARTY %s: Tracking of weapon starts in five seconds.", self.Controllable:GetName())) - timer.scheduleFunction(_TrackWeapon, EventData.weapon, timer.getTime() + 5.0) + if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes>0 then + self:T(ARTY.id..string.format("ARTY %s: Tracking of weapon starts in two seconds.", self.Controllable:GetName())) + timer.scheduleFunction(_TrackWeapon, EventData.weapon, timer.getTime() + 2.0) end -- Get current ammo. local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() + + -- Decrease available nukes. + if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes then + self.Nukes=self.Nukes-1 + end if _nammo==0 then @@ -1173,30 +1255,36 @@ function ARTY:_OnEventShot(EventData) -- Weapon type name for current target. local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.Controllable:GetName(), _nammo, _nshells, _nrockets, _nmissiles)) - self:T2(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) + self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) -- Special weapon type requested ==> Check if corresponding ammo is empty. if self.currentTarget.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then - self:T(ARTY.id.."Group %s, cannons requested but shells empty.", self.Controllable:GetName()) + self:T(ARTY.id..string.format("Group %s, cannons requested but shells empty.", self.Controllable:GetName())) + self:CeaseFire(self.currentTarget) + return + + elseif self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then + + self:T(ARTY.id..string.format("Group %s, tactical nukes requested but nukes empty.", self.Controllable:GetName())) self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then - self:T(ARTY.id.."Group %s, rockets requested but rockets empty.", self.Controllable:GetName()) + self:T(ARTY.id..string.format("Group %s, rockets requested but rockets empty.", self.Controllable:GetName())) self:CeaseFire(self.currentTarget) return elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - self:T(ARTY.id.."Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName()) + self:T(ARTY.id..string.format("Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName())) self:CeaseFire(self.currentTarget) return elseif (self.currentTarget.weapontype==ARTY.WeaponType.GuidedMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then - self:T(ARTY.id.."Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName()) + self:T(ARTY.id..string.format("Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName())) self:CeaseFire(self.currentTarget) return @@ -1389,6 +1477,35 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) return false end + -- Get ammo. + local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() + local nfire=Nammo + if target.weapontype==ARTY.WeaponType.Auto then + nfire=Nammo + elseif target.weapontype==ARTY.WeaponType.Cannon then + nfire=Nshells + elseif target.weapontype==ARTY.WeaponType.TacticalNukes then + nfire=self.Nukes + elseif target.weapontype==ARTY.WeaponType.Rockets then + nfire=Nrockets + elseif target.weapontype==ARTY.WeaponType.UnguidedAny then + nfire=Nshells+Nrockets + elseif target.weapontype==ARTY.WeaponType.GuidedMissile then + nfire=Nmissiles + elseif target.weapontype==ARTY.WeaponType.CruiseMissile then + nfire=Nmissiles + elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then + nfire=Nmissiles + end + + -- Adjust if less than requested ammo is left. + target.nshells=math.min(target.nshells, nfire) + + -- No ammo left ==> deny transition. + if target.nshells<1 then + return false + end + return true end @@ -1401,10 +1518,7 @@ end -- @param #table target Array holding the target info. function ARTY:onafterOpenFire(Controllable, From, Event, To, target) self:_EventFromTo("onafterOpenFire", Event, From, To) - - --local _coord=target.coord --Core.Point#COORDINATE - --_coord:MarkToAll("Arty Target") - + -- Get target array index. local id=self:_GetTargetIndexByName(target.name) @@ -1425,37 +1539,46 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() local nfire=Nammo local _type="shots" - if self.WeaponType==ARTY.WeaponType.Auto then + if target.weapontype==ARTY.WeaponType.Auto then nfire=Nammo _type="shots" - elseif self.WeaponType==ARTY.WeaponType.Cannon then + elseif target.weapontype==ARTY.WeaponType.Cannon then nfire=Nshells _type="shells" - elseif self.WeaponType==ARTY.WeaponType.Rockets then + elseif target.weapontype==ARTY.WeaponType.TacticalNukes then + nfire=self.Nukes + _type="nuclear shells" + elseif target.weapontype==ARTY.WeaponType.Rockets then nfire=Nrockets _type="rockets" - elseif self.WeaponType==ARTY.WeaponType.UnguidedAny then + elseif target.weapontype==ARTY.WeaponType.UnguidedAny then nfire=Nshells+Nrockets _type="shells or rockets" - elseif self.WeaponType==ARTY.WeaponType.GuidedMissile then + elseif target.weapontype==ARTY.WeaponType.GuidedMissile then nfire=Nmissiles _type="guided missiles" - elseif self.WeaponType==ARTY.WeaponType.CruiseMissile then + elseif target.weapontype==ARTY.WeaponType.CruiseMissile then nfire=Nmissiles _type="cruise missiles" - elseif self.WeaponType==ARTY.WeaponType.AntiShipMissile then + elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then nfire=Nmissiles _type="anti-ship missiles" end -- Adjust if less than requested ammo is left. - local _n=math.min(target.nshells, nfire) + target.nshells=math.min(target.nshells, nfire) -- Send message. - local text=string.format("%s, opening fire on target %s with %d %s. Distance %.1f km.", Controllable:GetName(), target.name, _n, _type, range/1000) + local text=string.format("%s, opening fire on target %s with %d %s. Distance %.1f km.", Controllable:GetName(), target.name, target.nshells, _type, range/1000) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) + if self.Debug then + local _coord=target.coord --Core.Point#COORDINATE + local text=string.format("ARTY %s, Target %s, n=%d, weapon=%s", self.Controllable:GetName(), target.name, target.nshells, self:_WeaponTypeName(target.weapontype)) + _coord:MarkToAll(text) + end + -- Start firing. self:_FireAtCoord(target.coord, target.radius, target.nshells, target.weapontype) @@ -1510,6 +1633,11 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) -- ARTY group has no current target any more. self.currentTarget=nil + + -- Relocate position + if self.relocateafterfire then + self:_Relocate() + end end @@ -1654,6 +1782,9 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + -- "Rearm" tactical nukes as well. + self.Nukes=self.Nukes0 + -- Route ARTY group back to where it came from (if distance is > 100 m). local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) if d1 > self.RearmingDistance then @@ -1899,7 +2030,7 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) local group=self.Controllable --Wrapper.Group#GROUP -- Tactical nukes are actually cannon shells. - if weapontype==ARTY.WeaponType.TacticalNuke then + if weapontype==ARTY.WeaponType.TacticalNukes then weapontype=ARTY.WeaponType.Cannon end @@ -1916,7 +2047,33 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) group:SetTask(fire) end +--- Relocate to another position, e.g. after an engagement to avoid couter strikes. +-- @param #ARTY self +function ARTY:_Relocate() + -- Current position. + local _pos=self.Controllable:GetCoordinate() + + local _new=nil + local _gotit=false + local _n=0 + local _nmax=1000 + repeat + -- Get a random coordinate. + _new=_pos:GetRandomCoordinateInRadius(self.relocateRmax, self.relocateRmin) + local _surface=_new:GetSurfaceType() + + -- Check that new coordinate is not water(-ish). + if _surface~=land.SurfaceType.WATER and _surface~=land.SurfaceType.SHALLOW_WATER then + _gotit=true + end + until _gotit or _n>_nmax + + -- Assign relocation + if _gotit then + self:AssignMoveCoord(_new, nil, nil, false, false) + end +end --- Sort targets with respect to priority and number of times it was already engaged. -- @param #ARTY self @@ -2042,7 +2199,8 @@ end -- @param #ARTY self -- @return #table Target which is due to be attacked now or nil if no target could be found. function ARTY:_CheckNormalTargets() - + self:F3() + -- Sort targets w.r.t. prio and number times engaged already. self:_SortTargetQueuePrio() @@ -2403,7 +2561,7 @@ function ARTY:_TargetInRange(target) end -- Remove target if ARTY group cannot move. No change to be ever in range. - if self.Speed==0 then + if self.SpeedMax<1 and _inrange==false then self:RemoveTarget(target.name) end @@ -2431,7 +2589,7 @@ function ARTY:_WeaponTypeName(tnumber) name="Guided Missiles" elseif tnumber==ARTY.WeaponType.AntiShipMissile then name="Anti-Ship Missiles" - elseif tnumber==ARTY.WeaponType.TacticalNuke then + elseif tnumber==ARTY.WeaponType.TacticalNukes then name="Tactical Nukes" end return name From cb6673332d2110cc6f61df00e8c32a50ce11663d Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 28 May 2018 16:47:32 +0200 Subject: [PATCH 137/170] ARTY v0.9.4 ARTY: improved outofammo/rearming behaviour --- Moose Development/Moose/Core/Point.lua | 1 - .../Moose/Functional/Artillery.lua | 63 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 155b2529e..0a90f6440 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -964,7 +964,6 @@ do -- COORDINATE function COORDINATE:GetSurfaceType() local vec2=self:GetVec2() local surface=land.getSurfaceType(vec2) - self:MarkToAll("Surface type = "..surface) return surface end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 1434522f4..a31ce26c0 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -404,7 +404,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.3" +ARTY.version="0.9.4" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1242,14 +1242,10 @@ function ARTY:_OnEventShot(EventData) self.Nukes=self.Nukes-1 end - if _nammo==0 then - + local _outofammo=false + if _nammo==0 then self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) - self:CeaseFire(self.currentTarget) - self:Winchester() - - -- Current target is deallocated ==> return - return + _outofammo=true end -- Weapon type name for current target. @@ -1258,47 +1254,65 @@ function ARTY:_OnEventShot(EventData) self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) -- Special weapon type requested ==> Check if corresponding ammo is empty. + local _partlyoutofammo=false if self.currentTarget.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then self:T(ARTY.id..string.format("Group %s, cannons requested but shells empty.", self.Controllable:GetName())) - self:CeaseFire(self.currentTarget) - return + _partlyoutofammo=true elseif self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then self:T(ARTY.id..string.format("Group %s, tactical nukes requested but nukes empty.", self.Controllable:GetName())) - self:CeaseFire(self.currentTarget) - return + _partlyoutofammo=true elseif self.currentTarget.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then self:T(ARTY.id..string.format("Group %s, rockets requested but rockets empty.", self.Controllable:GetName())) - self:CeaseFire(self.currentTarget) - return + _partlyoutofammo=true elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then self:T(ARTY.id..string.format("Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName())) - self:CeaseFire(self.currentTarget) - return + _partlyoutofammo=true elseif (self.currentTarget.weapontype==ARTY.WeaponType.GuidedMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then self:T(ARTY.id..string.format("Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName())) - self:CeaseFire(self.currentTarget) - return + _partlyoutofammo=true - end + end -- Check if number of shots reached max. + local _ceasefire=false if self.Nshots >= self.currentTarget.nshells then local text=string.format("Group %s stop firing on target %s.", self.Controllable:GetName(), self.currentTarget.name) self:T(ARTY.id..text) MESSAGE:New(text, 5):ToAllIf(self.Debug) -- Cease fire. + _ceasefire=true + end + + -- Check if we are (partly) out of ammo. + if _outofammo or _partlyoutofammo then + _ceasefire=true + end + + -- Cease fire on current target. + if _ceasefire then self:CeaseFire(self.currentTarget) end + + -- Group is out of ammo (or partly and can rearm) ==> Winchester (==> Rearm). + if _outofammo or (_partlyoutofammo and self.RearmingGroup ~=nil) then + self:Winchester() + return + end + + -- Relocate position + if self.Nshots >= self.currentTarget.nshells and self.relocateafterfire then + self:_Relocate() + end else self:E(ARTY.id..string.format("ERROR: No current target for group %s?!", self.Controllable:GetName())) @@ -1633,12 +1647,7 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) -- ARTY group has no current target any more. self.currentTarget=nil - - -- Relocate position - if self.relocateafterfire then - self:_Relocate() - end - + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -2776,11 +2785,11 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) local _last=ToCoord:GetClosestPointToRoad() -- First point on road. - path[#path+1]=_first:WaypointGround(Speed, "On road") + path[#path+1]=_first:WaypointGround(Speed, "On Road") task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) -- Last point on road. - path[#path+1]=_last:WaypointGround(Speed, "On road") + path[#path+1]=_last:WaypointGround(Speed, "On Road") task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) end From 89275048014ea17b3b8d322319ee1e5182ef3980 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 28 May 2018 16:51:01 +0200 Subject: [PATCH 138/170] Minor --- Moose Development/Moose/Functional/Artillery.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index a31ce26c0..b6c0b86b0 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -1085,7 +1085,7 @@ function ARTY:_NuclearBlast(_coord) -- At R=R0 ==> explosion strength is 1% of S0 at impact point. local alpha=math.log(100) local strength=S0*math.exp(-alpha*R/R0) - env.info(string.format("FF: nuklear explosion strength s(%.1f m) = %.10f (s/s0=%.1f %%), alpha=%.3f", R, strength, strength/S0*100, alpha)) + self:T2(ARTY.id..string.format("Nuclear explosion strength s(%.1f m) = %.5f (s/s0=%.1f %%), alpha=%.3f", R, strength, strength/S0*100, alpha)) return strength end @@ -1096,7 +1096,7 @@ function ARTY:_NuclearBlast(_coord) -- Get distance to impact and calc exponential explosion strength. local R=_fire:Get2DDistance(_coord) local S=_explosion(R) - env.info(string.format("FF: explosion r=%.1f, s=%.3f", R, S)) + self:T2(ARTY.id..string.format("Explosion r=%.1f, s=%.3f", R, S)) -- Get a random Big Smoke and fire object. local _preset=math.random(0,7) From 1861e742b023d00c9c4288d2bfc0a03d7359ea52 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 28 May 2018 17:07:55 +0200 Subject: [PATCH 139/170] ARTY v0.9.5 Added/fixed relocate option --- Moose Development/Moose/Functional/Artillery.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index b6c0b86b0..1242e44cd 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -404,7 +404,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.4" +ARTY.version="0.9.5" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1284,6 +1284,7 @@ function ARTY:_OnEventShot(EventData) -- Check if number of shots reached max. local _ceasefire=false + local _relocate=false if self.Nshots >= self.currentTarget.nshells then local text=string.format("Group %s stop firing on target %s.", self.Controllable:GetName(), self.currentTarget.name) self:T(ARTY.id..text) @@ -1291,6 +1292,10 @@ function ARTY:_OnEventShot(EventData) -- Cease fire. _ceasefire=true + + if self.relocateafterfire then + _relocate=true + end end -- Check if we are (partly) out of ammo. @@ -1310,7 +1315,7 @@ function ARTY:_OnEventShot(EventData) end -- Relocate position - if self.Nshots >= self.currentTarget.nshells and self.relocateafterfire then + if _relocate then self:_Relocate() end @@ -2078,7 +2083,7 @@ function ARTY:_Relocate() end until _gotit or _n>_nmax - -- Assign relocation + -- Assign relocation. if _gotit then self:AssignMoveCoord(_new, nil, nil, false, false) end From f03f9a33088676ce214d0519c8ce74f710b16818 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 28 May 2018 20:03:26 +0200 Subject: [PATCH 140/170] Landing event made a bit more loose. --- Moose Development/Moose/AI/AI_Cargo_Helicopter.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 1983540d5..a92dd1e95 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -219,7 +219,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } ) if self.RoutePickup == true then - if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 7 then + if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then self:Load( Helicopter:GetPointVec2() ) self.RoutePickup = false self.Relocating = true @@ -227,7 +227,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) end if self.RouteDeploy == true then - if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 7 then + if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then self:Unload( true ) self.RouteDeploy = false self.Transporting = false From b6ac79a9dfa4f767c345dc9c0c8ae3203b29d29c Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 28 May 2018 22:19:35 +0200 Subject: [PATCH 141/170] ARTY Mark WIP --- Moose Development/Moose/Core/Event.lua | 9 +++++ .../Moose/Functional/Artillery.lua | 37 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index dd739a0d9..57559d965 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -933,6 +933,15 @@ function EVENT:onEvent( Event ) --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() end + if Event.idx then + Event.MarkID=Event.idx + Event.MarkVec3=Event.pos + Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos) + Event.MarkText=Event.text + Event.MarkCoalition=Event.coalition + Event.MarkGroupID = Event.groupID + end + if Event.cargo then Event.Cargo = Event.cargo Event.CargoName = Event.cargo.Name diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 1242e44cd..ba6300655 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -1003,11 +1003,34 @@ function ARTY:onafterStart(Controllable, From, Event, To) -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) + self:HandleEvent(EVENTS.MarkAdded, self._OnEventMarkAdded) + + -- Add DCS event handler. + world.addEventHandler(self) -- Start checking status. self:__Status(self.StatusInterval) end +--- After "Start" event. Initialized ROE and alarm state. Starts the event handler. +-- @param #ARTY self +-- @param #table Event +function ART:onEvent(Event) + + if Event then + + if Event.id==world.event.S_EVENT_MARK_ADDED then + env.info("FF mark added") + elseif Event.id==world.event.S_EVENT_MARK_CHANGE then + env.info("FF mark changed") + elseif Event.id==world.event.S_EVENT_MARK_REMOVED then + env.info("FF mark removed") + end + + end + +end + --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self function ARTY:_StatusReport() @@ -1159,6 +1182,18 @@ function ARTY:_NuclearBlast(_coord) end +--- Eventhandler for shot event. +-- @param #ARTY self +-- @param Core.Event#EVENTDATA EventData +function ARTY:_OnMarkAdded(EventData) + self:F(EventData) + if EventData.MarkCoordinate then + local coord=EventData.MarkCoordinate --Core.Point#COORDINATE + + coord:SmokeGreen() + end +end + --- Eventhandler for shot event. -- @param #ARTY self -- @param Core.Event#EVENTDATA EventData @@ -2081,6 +2116,8 @@ function ARTY:_Relocate() if _surface~=land.SurfaceType.WATER and _surface~=land.SurfaceType.SHALLOW_WATER then _gotit=true end + -- Increase counter. + _n=_n+1 until _gotit or _n>_nmax -- Assign relocation. From 43b320ca9063877c91c5dc21c24a882d4e3e7d6d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Tue, 29 May 2018 22:34:33 +0200 Subject: [PATCH 142/170] New versions with documentation --- .../Moose/AI/AI_A2A_Dispatcher.lua | 2 +- .../Moose/Functional/Artillery.lua | 10 +--- .../Moose/Functional/CleanUp.lua | 6 +-- .../Moose/Functional/Designate.lua | 7 ++- .../Moose/Functional/Detection.lua | 11 ++-- Moose Development/Moose/Functional/Escort.lua | 54 +++++++++---------- .../Moose/Functional/MissileTrainer.lua | 3 +- .../Moose/Functional/PseudoATC.lua | 5 +- Moose Development/Moose/Functional/RAT.lua | 9 +--- Moose Development/Moose/Functional/Range.lua | 9 +--- .../Moose/Functional/Scoring.lua | 7 +-- Moose Development/Moose/Functional/Sead.lua | 1 + .../Moose/Functional/Suppression.lua | 6 +-- .../Moose/Functional/ZoneCaptureCoalition.lua | 5 +- .../Moose/Tasking/CommandCenter.lua | 5 +- .../Moose/Tasking/DetectionManager.lua | 5 +- Moose Development/Moose/Tasking/Mission.lua | 1 + Moose Development/Moose/Tasking/Task_A2A.lua | 4 +- .../Moose/Tasking/Task_A2A_Dispatcher.lua | 9 ++-- Moose Development/Moose/Tasking/Task_A2G.lua | 4 +- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 6 +-- .../Moose/Tasking/Task_Cargo_CSAR.lua | 3 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 6 +-- .../Moose/Tasking/Task_Cargo_Transport.lua | 4 +- Moose Development/Moose/Wrapper/Airbase.lua | 5 +- Moose Development/Moose/Wrapper/Client.lua | 5 +- .../Moose/Wrapper/Controllable.lua | 6 +-- Moose Development/Moose/Wrapper/Group.lua | 6 +-- .../Moose/Wrapper/Identifiable.lua | 4 +- Moose Development/Moose/Wrapper/Object.lua | 4 +- .../Moose/Wrapper/Positionable.lua | 5 +- Moose Development/Moose/Wrapper/Scenery.lua | 5 +- Moose Development/Moose/Wrapper/Static.lua | 5 +- Moose Development/Moose/Wrapper/Unit.lua | 6 +-- 34 files changed, 85 insertions(+), 148 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 146f35d4d..6f0c7045d 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -731,7 +731,7 @@ do -- AI_A2A_DISPATCHER -- -- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected. -- Then, use the method @{#AI_A2A_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher. - -- Use the method @{#AI_A2A_DISPATCHER.SetDefaultFuelTreshold}() to set the %-tage left in the defender airplane tanks when a refuel action is needed. + -- Use the method @{#AI_A2A_DISPATCHER.SetDefaultFuelThreshold}() to set the %-tage left in the defender airplane tanks when a refuel action is needed. -- -- When the tanker specified is alive and in the air, the tanker will be used for refuelling. -- diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 1242e44cd..acd0811d4 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -1,12 +1,7 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- **Functional** - (R2.4) Control artillery units. -- -- === -- --- ![Banner Image](..\Presentations\ARTY\ARTY_Main.png) --- --- ==== --- -- The ARTY class can be used to easily assign and manage targets for artillery units. -- -- ## Features: @@ -39,6 +34,7 @@ -- -- ==== -- @module Functional.Arty +-- @image Artillery.JPG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- ARTY class @@ -89,9 +85,7 @@ -- @field #number relocateRmax Maximum distance in meters the group will look for places to relocate. -- @extends Core.Fsm#FSM_CONTROLLABLE ----# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- --- The ARTY class enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can +--- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can -- interact with the process at certain events or states. -- -- A new ARTY object can be created with the @{#ARTY.New}(*group*) contructor. diff --git a/Moose Development/Moose/Functional/CleanUp.lua b/Moose Development/Moose/Functional/CleanUp.lua index f7414e190..04f4be5b6 100644 --- a/Moose Development/Moose/Functional/CleanUp.lua +++ b/Moose Development/Moose/Functional/CleanUp.lua @@ -8,6 +8,7 @@ -- === -- -- @module Functional.CleanUp +-- @image CleanUp_Airbases.JPG --- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) -- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases. @@ -16,11 +17,8 @@ --- @type CLEANUP_AIRBASE -- @extends #CLEANUP_AIRBASE.__ ---- # CLEANUP_AIRBASE, extends @{Core.Base#BASE} +--- Keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat. -- --- ![Banner Image](..\Presentations\CLEANUP_AIRBASE\Dia1.JPG) --- --- The CLEANUP_AIRBASE class keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat. -- Specific airbases need to be provided that need to be guarded. Each airbase registered, will be guarded within a zone of 8 km around the airbase. -- Any unit that fires a missile, or shoots within the zone of an airbase, will be monitored by CLEANUP_AIRBASE. -- Within the 8km zone, units cannot fire any missile, which prevents the airbase runway to receive missile or bomb hits. diff --git a/Moose Development/Moose/Functional/Designate.lua b/Moose Development/Moose/Functional/Designate.lua index dce33f924..c6818c456 100644 --- a/Moose Development/Moose/Functional/Designate.lua +++ b/Moose Development/Moose/Functional/Designate.lua @@ -2,7 +2,7 @@ -- -- === -- --- DESIGNATE is orchestrating the designation of potential targets executed by a Recce group, +-- Orchestrate the designation of potential targets executed by a Recce group, -- and communicates these to a dedicated attacking group of players, -- so that following a dynamically generated menu system, -- each detected set of potential targets can be lased or smoked... @@ -29,16 +29,15 @@ -- * **FlightControl**: Design & Programming -- -- @module Functional.Designate - +-- @image Designation.JPG do -- DESIGNATE --- @type DESIGNATE -- @extends Core.Fsm#FSM_PROCESS - --- # DESIGNATE class, extends @{Fsm#FSM} + --- Manage the designation of detected targets. -- - -- DESIGNATE is managing the designation of detected targets. -- Targets detected by recce will be communicated to a group of attacking players. -- A menu system is made available that allows to: -- diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 93755e614..30de4a170 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -2,11 +2,7 @@ -- -- === -- --- ![Banner Image](..\Presentations\DETECTION\Dia1.JPG) --- --- === --- --- DETECTION classes facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnassance Units). +-- Facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnassance Units). -- DETECTION uses the in-built detection capabilities of DCS World, but adds new functionalities. -- -- Find the DETECTION classes documentation further in this document in the globals section. @@ -30,6 +26,7 @@ -- * FlightControl : Analysis, Design, Programming, Testing -- -- @module Functional.Detection +-- @image Detection.JPG ----BASE:TraceClass("DETECTION_BASE") ----BASE:TraceClass("DETECTION_AREAS") @@ -46,9 +43,7 @@ do -- DETECTION_BASE -- @field #number DetectionRun -- @extends Core.Fsm#FSM - --- DETECTION_BASE class, extends @{Fsm#FSM} - -- - -- The DETECTION_BASE class defines the core functions to administer detected objects. + --- Defines the core functions to administer detected objects. -- The DETECTION_BASE class will detect objects within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s). -- -- ## DETECTION_BASE constructor diff --git a/Moose Development/Moose/Functional/Escort.lua b/Moose Development/Moose/Functional/Escort.lua index 755770c84..b2c27bdc9 100644 --- a/Moose Development/Moose/Functional/Escort.lua +++ b/Moose Development/Moose/Functional/Escort.lua @@ -2,61 +2,60 @@ -- -- === -- --- @{#ESCORT} class --- === --- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead. +-- Allows you to interact with escorting AI on your flight and take the lead. +-- -- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10). -- -- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes. -- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. -- --- RADIO MENUs that can be created: --- === +-- # RADIO MENUs that can be created: +-- -- Find a summary below of the current available commands: -- --- Navigation ...: --- --------------- +-- ## Navigation ...: +-- -- Escort group navigation functions: -- -- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you. -- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. -- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. -- --- Hold position ...: --- ------------------ +-- ## Hold position ...: +-- -- Escort group navigation functions: -- -- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. -- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. -- --- Report targets ...: --- ------------------- +-- ## Report targets ...: +-- -- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). -- -- * **"Report now":** Will report the current detected targets. -- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list. -- * **"Report targets off":** Will stop detecting targets. -- --- Scan targets ...: --- ----------------- +-- ## Scan targets ...: +-- -- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. -- -- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. -- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. -- --- Attack targets ...: --- ------------------- +-- ## Attack targets ...: +-- -- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. -- --- Request assistance from ...: --- ---------------------------- +-- ## Request assistance from ...: +-- -- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. -- This menu item allows to request attack support from other escorts supporting the current client group. -- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. -- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. -- --- ROE ...: --- -------- +-- ## ROE ...: +-- -- Sets the Rules of Engagement (ROE) of the escort group when in flight. -- -- * **"Hold Fire":** The escort group will hold fire. @@ -64,8 +63,8 @@ -- * **"Open Fire":** The escort group will open fire on designated targets. -- * **"Weapon Free":** The escort group will engage with any target. -- --- Evasion ...: --- ------------ +-- ## Evasion ...: +-- -- Will define the evasion techniques that the escort group will perform during flight or combat. -- -- * **"Fight until death":** The escort group will have no reaction to threats. @@ -73,19 +72,19 @@ -- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing. -- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres. -- --- Resume Mission ...: --- ------------------- +-- ## Resume Mission ...: +-- -- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. -- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission. -- --- ESCORT construction methods. --- === +-- # ESCORT construction methods. +-- -- Create a new SPAWN object with the @{#ESCORT.New} method: -- -- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text. -- --- ESCORT initialization methods. --- === +-- # ESCORT initialization methods. +-- -- The following menus are created within the RADIO MENU (F10) of an active unit hosted by a player: -- -- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client. @@ -115,6 +114,7 @@ -- -- -- @module Functional.Escort +-- @image Escorting.JPG --- ESCORT class -- @type ESCORT diff --git a/Moose Development/Moose/Functional/MissileTrainer.lua b/Moose Development/Moose/Functional/MissileTrainer.lua index 151964515..cc8830a14 100644 --- a/Moose Development/Moose/Functional/MissileTrainer.lua +++ b/Moose Development/Moose/Functional/MissileTrainer.lua @@ -2,8 +2,6 @@ -- -- === -- --- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Core.Base#BASE} --- === -- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft, -- the class will destroy the missile within a certain range, to avoid damage to your aircraft. -- It suports the following functionality: @@ -78,6 +76,7 @@ -- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback! -- -- @module Functional.MissileTrainer +-- @image Missile_Trainer.JPG --- The MISSILETRAINER class diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index c1a639029..b8a9f2cd0 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -1,4 +1,3 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- **Functional** - (R2.4) Rudimentary ATC. -- -- ![Banner Image](..\Presentations\PSEUDOATC\PSEUDOATC_Main.jpg) @@ -39,6 +38,7 @@ -- -- ==== -- @module Functional.PseudoATC +-- @image Pseudo_ATC.JPG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- PSEUDOATC class @@ -53,8 +53,7 @@ -- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. -- @extends Core.Base#BASE ----# PSEUDOATC class, extends @{Core.Base#BASE} --- The PSEUDOATC class adds some rudimentary ATC functionality via the radio menu. +--- The PSEUDOATC class adds some rudimentary ATC functionality via the radio menu. -- -- Local weather reports can be requested for nearby airports and player's mission waypoints. -- The weather report includes diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 31b3fc369..9e192a795 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -1,12 +1,7 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- **Functional** - (R2.2) - Create random airtraffic in your missions. -- -- === -- --- ![Banner Image](..\Presentations\RAT\RAT.png) --- --- === --- -- The aim of the RAT class is to fill the empty DCS world with randomized air traffic and bring more life to your airports. -- -- In particular, it is designed to spawn AI air units at random airports. These units will be assigned a random flight path to another random airport on the map. @@ -60,6 +55,7 @@ -- -- === -- @module Functional.Rat +-- @module RAT.JPG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- RAT class @@ -152,8 +148,7 @@ -- @field #boolean useparkingdb Parking spots are added to data base once an aircraft has used it. These spots can later be used by other aircraft. Default is true. -- @extends Core.Spawn#SPAWN ----# RAT class, extends @{Core.Spawn#SPAWN} --- The RAT class implements an easy to use way to randomly fill your map with AI aircraft. +--- The RAT class implements an easy to use way to randomly fill your map with AI aircraft. -- -- -- ## Airport Selection diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index c21f6656f..a7448cecd 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -1,12 +1,7 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- **Functional** - (R2.3) - Range Practice. -- -- === -- --- ![Banner Image](..\Presentations\RANGE\RANGE_Main.png) --- --- === --- -- The RANGE class enables easy set up of bombing and strafing ranges within DCS World. -- -- Implementation is based on the [Simple Range Script](https://forums.eagle.ru/showthread.php?t=157991) by [Ciribob](https://forums.eagle.ru/member.php?u=112175), which itself was motivated @@ -49,6 +44,7 @@ -- -- === -- @module Functional.Range +-- @image Range.JPG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- RANGE class @@ -87,8 +83,7 @@ -- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated. -- @extends Core.Base#BASE ----# RANGE class, extends @{Core.Base#BASE} --- The RANGE class enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. +--- The RANGE class enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. -- The parameter "rangename" defindes the name of the range. It has to be unique since this is also the name displayed in the radio menu. -- -- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated. diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index c6468a1e5..6d0204b22 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -2,11 +2,7 @@ -- -- === -- --- ![Banner Image](..\Presentations\SCORING\Dia1.JPG) --- --- === --- --- The @{#SCORING} class administers the scoring of player achievements, +-- Administers the scoring of player achievements, -- and creates a CSV file logging the scoring events and results for use at team or squadron websites. -- -- SCORING automatically calculates the threat level of the objects hit and destroyed by players, @@ -207,6 +203,7 @@ -- * **FlightControl**: Concept, Design & Programming. -- -- @module Functional.Scoring +-- @image Scoring.JPG --- The Scoring class diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index d9d9bfffb..db25b81e1 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -3,6 +3,7 @@ -- === -- -- @module Functional.Sead +-- @image SEAD.JPG --- The SEAD class -- @type SEAD diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index 929e8b718..c0d2278ef 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -1,8 +1,6 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- **Functional** - (R2.4) Suppress fire of ground units when they get hit. -- --- ![Banner Image](..\Presentations\SUPPRESSION\Suppression_Main.png) --- -- ==== -- -- When ground units get hit by (suppressive) enemy fire, they will not be able to shoot back for a certain amount of time. @@ -32,6 +30,7 @@ -- -- ==== -- @module Functional.Suppression +-- @image Suppression.JPG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -76,8 +75,7 @@ -- @extends Core.Fsm#FSM_CONTROLLABLE -- ----# SUPPRESSION class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- Mimic suppressive enemy fire and let groups flee or retreat. +--- Mimic suppressive enemy fire and let groups flee or retreat. -- -- ## Suppression Process -- diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index 7c1610687..b4551e87f 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -2,10 +2,6 @@ -- -- === -- --- ![Banner Image](..\Presentations\ZONE_CAPTURE_COALITION\Dia1.JPG) --- --- === --- -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAZ - Capture Zones) -- -- - CAZ-000 - Capture Zone: Demonstrates the basic concept of capturing a zone. @@ -22,6 +18,7 @@ -- === -- -- @module Functional.ZoneCaptureCoalition +-- @image Capture_Zones.JPG do -- ZONE_CAPTURE_COALITION diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 725a634b3..74d50dfb6 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -10,6 +10,7 @@ -- === -- -- @module Tasking.CommandCenter +-- @image Task_Command_Center.JPG @@ -23,9 +24,7 @@ -- @extends Core.Base#BASE ---- # COMMANDCENTER class, extends @{Core.Base#BASE} --- --- The COMMANDCENTER class governs multiple missions, the tasking and the reporting. +--- Governs multiple missions, the tasking and the reporting. -- -- The commandcenter communicates important messages between the various groups of human players executing tasks in missions. -- diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index e6a6aaf19..a716c11ff 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -1,9 +1,7 @@ ---- This module contains the DETECTION_MANAGER class and derived classes. +--- **Tasking** - This module contains the DETECTION_MANAGER class and derived classes. -- -- === -- --- 1) @{DetectionManager#DETECTION_MANAGER} class, extends @{Fsm#FSM} --- === -- The @{DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. -- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. -- @@ -41,6 +39,7 @@ -- ### Author: FlightControl - Framework Design & Programming -- -- @module Tasking.DetectionManager +-- @image Task_Detection_Manager.JPG do -- DETECTION MANAGER diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index e541b7bbb..ced7f3d1a 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.Mission +-- @image Task_Mission.JPG --- The MISSION class -- @type MISSION diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index b3c268100..122356bd5 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -17,9 +17,7 @@ do -- TASK_A2A -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2A class, extends @{Task#TASK} - -- - -- The TASK_A2A class defines Air To Air tasks for a @{Set} of Target Units, + --- Defines Air To Air tasks for a @{Set} of Target Units, -- based on the tasking capabilities defined in @{Task#TASK}. -- The TASK_A2A is implemented using a @{Fsm#FSM_TASK}, and has the following statuses: -- diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 3ca89bf8e..204eb87a3 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -1,6 +1,6 @@ --- **Tasking** - The TASK_A2A_DISPATCHER creates and manages player TASK_A2A tasks based on detected targets. -- --- The @{#TASK_A2A_DISPATCHER} classes implement the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of EWR installation groups. +-- Implement the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of EWR installation groups. -- -- === -- @@ -11,6 +11,7 @@ -- === -- -- @module Tasking.Task_A2A_Dispatcher +-- @image Task_A2A_Dispatcher.JPG do -- TASK_A2A_DISPATCHER @@ -18,11 +19,7 @@ do -- TASK_A2A_DISPATCHER -- @type TASK_A2A_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER - --- # TASK_A2A_DISPATCHER class, extends @{Tasking#DETECTION_MANAGER} - -- - -- ![Banner Image](..\Presentations\TASK_A2A_DISPATCHER\Dia1.JPG) - -- - -- The @{#TASK_A2A_DISPATCHER} class implements the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of EWR installation groups. + --- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of EWR installation groups. -- -- ![Banner Image](..\Presentations\TASK_A2A_DISPATCHER\Dia3.JPG) -- diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 59cef82ea..1c6fa1276 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -17,9 +17,7 @@ do -- TASK_A2G -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2G class, extends @{Task#TASK} - -- - -- The TASK_A2G class defines Air To Ground tasks for a @{Set} of Target Units, + --- The TASK_A2G class defines Air To Ground tasks for a @{Set} of Target Units, -- based on the tasking capabilities defined in @{Task#TASK}. -- The TASK_A2G is implemented using a @{Fsm#FSM_TASK}, and has the following statuses: -- diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index 65d1796b7..27493d738 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.Task_A2G_Dispatcher +-- @image Task_A2G_Dispatcher.JPG do -- TASK_A2G_DISPATCHER @@ -19,11 +20,8 @@ do -- TASK_A2G_DISPATCHER -- @field Tasking.Mission#MISSION Mission -- @extends Tasking.DetectionManager#DETECTION_MANAGER - --- # TASK\_A2G\_DISPATCHER class, extends @{DetectionManager#DETECTION_MANAGER} + --- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Detection} object. -- - -- ![](..\Presentations\TASK\_A2G\_DISPATCHER\Dia1.JPG) - -- - -- The TASK\_A2G\_DISPATCHER class orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Detection} object. -- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system. -- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon, -- in a true co-operation environment wherein **Multiple Teams** will collaborate in Missions to **achieve a common Mission Goal**. diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index 1326cec30..616f8a89b 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -1,10 +1,9 @@ --- **Tasking** -- Models tasks for players to execute CSAR @{Cargo} downed pilots. -- --- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) --- -- === -- -- @module Tasking.Task_Cargo_CSAR +-- @image Task_Cargo_CSAR.JPG do -- TASK_CARGO_CSAR diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 9603f5f4f..16dc70cf0 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -22,11 +22,7 @@ do -- TASK_CARGO_DISPATCHER -- @field Tasking.Task#TASK Task - --- # TASK_CARGO_DISPATCHER class, extends @{Task_Manager#TASK_MANAGER} - -- - -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia1.JPG) - -- - -- The @{#TASK_CARGO_DISPATCHER} class implements the dynamic dispatching of cargo tasks. + --- Implements the dynamic dispatching of cargo tasks. -- -- ![Banner Image](..\Presentations\TASK_CARGO_DISPATCHER\Dia3.JPG) -- diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index f906b87f8..88bcb0ecb 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -1,9 +1,9 @@ --- **Tasking** -- The TASK_CARGO models tasks for players to transport @{Cargo}. -- --- ![Banner Image](..\Presentations\TASK_CARGO\Dia1.JPG) --- -- === +-- -- @module Tasking.Task_Cargo_Transport +-- @image Task_Cargo_Transport.JPG do -- TASK_CARGO_TRANSPORT diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 1f7f98cbf..50c331293 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -9,14 +9,13 @@ -- === -- -- @module Wrapper.Airbase +-- @image Wrapper_Airbase.JPG --- @type AIRBASE -- @extends Wrapper.Positionable#POSITIONABLE ---- # AIRBASE class, extends @{Wrapper.Positionable#POSITIONABLE} --- --- AIRBASE is a wrapper class to handle the DCS Airbase objects: +--- AIRBASE is a wrapper class to handle the DCS Airbase objects: -- -- * Support all DCS Airbase APIs. -- * Enhance with Airbase specific APIs not in the DCS Airbase API set. diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 4f9b80f83..0c1eefdaf 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -9,6 +9,7 @@ -- === -- -- @module Wrapper.Client +-- @image Wrapper_Client.JPG --- The CLIENT class @@ -16,9 +17,7 @@ -- @extends Wrapper.Unit#UNIT ---- # CLIENT class, extends @{Wrapper.Unit#UNIT} --- --- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. +--- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. -- Note that clients are NOT the same as Units, they are NOT necessarily alive. -- The CLIENT class is a wrapper class to handle the DCS Unit objects that have the skillset defined as __Client__ or __Player__: -- diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 0bd00a060..5e7a15ef9 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -9,7 +9,7 @@ -- === -- -- @module Wrapper.Controllable - +-- @image Wrapper_Controllable.JPG --- @type CONTROLLABLE @@ -19,9 +19,7 @@ ---- # CONTROLLABLE class, extends @{Wrapper.Positionable#POSITIONABLE} --- --- CONTROLLABLE is a wrapper class to handle the "DCS Controllable objects", which are Groups and Units: +--- CONTROLLABLE is a wrapper class to handle the "DCS Controllable objects", which are Groups and Units: -- -- * Support all DCS Controllable APIs. -- * Enhance with Controllable specific APIs not in the DCS Controllable API set. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 18b34e171..fe4d5e20b 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -24,6 +24,7 @@ -- === -- -- @module Wrapper.Group +-- @image Wrapper_Group.JPG --- @type GROUP @@ -31,10 +32,7 @@ -- @field #string GroupName The name of the group. ---- --- # GROUP class, extends @{Wrapper.Controllable#CONTROLLABLE} --- --- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. +--- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. -- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Group objects are spawned (using the @{SPAWN} class). -- -- The GROUP class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index bbc6e482b..94d946f3c 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -14,9 +14,7 @@ -- @extends Wrapper.Object#OBJECT -- @field #string IdentifiableName The name of the identifiable. ---- # IDENTIFIABLE class, extends @{Wrapper.Object#OBJECT} --- --- The IDENTIFIABLE class is a wrapper class to handle the DCS Identifiable objects: +--- The IDENTIFIABLE class is a wrapper class to handle the DCS Identifiable objects: -- -- * Support all DCS Identifiable APIs. -- * Enhance with Identifiable specific APIs not in the DCS Identifiable API set. diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index 6438cf807..b2b034a30 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -16,9 +16,7 @@ -- @field #string ObjectName The name of the Object. ---- # OBJECT class, extends @{Core.Base#BASE} --- --- OBJECT handles the DCS Object objects: +--- OBJECT handles the DCS Object objects: -- -- * Support all DCS Object APIs. -- * Enhance with Object specific APIs not in the DCS Object API set. diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index d01a7c26b..296cc0119 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -9,6 +9,7 @@ -- === -- -- @module Wrapper.Positionable +-- @image Wrapper_Positionable.JPG --- @type POSITIONABLE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) -- @extends Wrapper.Identifiable#IDENTIFIABLE @@ -17,9 +18,7 @@ -- @extends Wrapper.Identifiable#IDENTIFIABLE ---- # POSITIONABLE class, extends @{Wrapper.Identifiable#IDENTIFIABLE} --- --- The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects: +--- The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects: -- -- * Support all DCS APIs. -- * Enhance with POSITIONABLE specific APIs not in the DCS API set. diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 8160aa955..31bfbf05a 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -9,6 +9,7 @@ -- === -- -- @module Wrapper.Scenery +-- @image Wrapper_Scenery.JPG @@ -16,9 +17,7 @@ -- @extends Wrapper.Positionable#POSITIONABLE ---- # SCENERY class, extends @{Wrapper.Positionable#POSITIONABLE} --- --- Scenery objects are defined on the map. +--- Scenery objects are defined on the map. -- The @{Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: -- -- * Wraps the DCS Scenery objects. diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index bab5b8d70..7ca5699b3 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -9,14 +9,13 @@ -- === -- -- @module Wrapper.Static +-- @image Wrapper_Static.JPG --- @type STATIC -- @extends Wrapper.Positionable#POSITIONABLE ---- # STATIC class, extends @{Wrapper.Positionable#POSITIONABLE} --- --- Statics are **Static Units** defined within the Mission Editor. +--- Statics are **Static Units** defined within the Mission Editor. -- Note that Statics are almost the same as Units, but they don't have a controller. -- The @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: -- diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 71bb9ecfb..03278f9c7 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -18,15 +18,13 @@ -- === -- -- @module Wrapper.Unit +-- @image Wrapper_Unit.JPG --- @type UNIT -- @extends Wrapper.Controllable#CONTROLLABLE ---- --- # UNIT class, extends @{Wrapper.Controllable#CONTROLLABLE} --- --- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object. +--- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object. -- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Unit objects are spawned (using the @{SPAWN} class). -- -- The UNIT class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference From fd4d7f49a54175ffa2676566f15a1d70043faf67 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 30 May 2018 00:39:43 +0200 Subject: [PATCH 143/170] ARTY v0.9.6 Added first WIP version with Markers. --- .../Moose/Functional/Artillery.lua | 289 ++++++++++++++++-- 1 file changed, 266 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index ba6300655..8fffe20a5 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -87,6 +87,8 @@ -- @field #boolean relocateafterfire Group will relocate after each firing task. Default false. -- @field #number relocateRmin Minimum distance in meters the group will look for places to relocate. -- @field #number relocateRmax Maximum distance in meters the group will look for places to relocate. +-- @field #boolean markallow If true, Players are allowed to assign targets and moves for ARTY group by placing markers on the F10 map. Default is false. +-- @field #number markkey Authorization key. Only player who know this key can assign targets and moves via markers on the F10 map. Default no authorization required. -- @extends Core.Fsm#FSM_CONTROLLABLE ---# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE} @@ -366,11 +368,8 @@ ARTY={ RearmingArtyOnRoad=false, InitialCoord=nil, report=true, - --ammoshells={"weapons.shells"}, ammoshells={}, - --ammorockets={"weapons.nurs"}, ammorockets={}, - --ammomissiles={"weapons.missiles"}, ammomissiles={}, Nshots=0, minrange=500, @@ -383,6 +382,8 @@ ARTY={ relocateafterfire=false, relocateRmin=300, relocateRmax=800, + markallow=false, + markkey=nil, } --- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag @@ -404,7 +405,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.5" +ARTY.version="0.9.6" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -625,16 +626,29 @@ end -- @param #boolean onroad (Optional) If true, group will mainly use roads. Default off, i.e. go directly towards the specified coordinate. -- @param #boolean cancel (Optional) If true, cancel any running attack when move should begin. Default is false. -- @param #string name (Optional) Name of the coordinate. Default is LL DMS string of the coordinate. If the name was already given, the numbering "#01", "#02",... is appended automatically. +-- @param #boolean unique (Optional) Move is unique. If the move name is already known, the move is rejected. Default false. -- @return #string Name of the move. Can be used for further reference, e.g. deleting the move from the list. -function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name) - self:F({coord=coord, time=time, speed=speed, onroad=onroad, cancel=cancel, name=name}) - - -- Name of the target. - local _name=name or coord:ToStringLLDMS() +function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) + self:F({coord=coord, time=time, speed=speed, onroad=onroad, cancel=cancel, name=name, unique=unique}) - -- Check if the name has already been used for another target. If so, the function returns a new unique name. - _name=self:_CheckName(self.moves, _name) + -- Default + if unique==nil then + unique=false + end + -- Name of the target. + local _name=name or coord:ToStringLLDMS() + local _unique=true + + -- Check if the name has already been used for another target. If so, the function returns a new unique name. + _name,_unique=self:_CheckName(self.moves, _name, not unique) + + -- Move name should be unique and is not. + if unique==true and _unique==false then + self:T(ARTY.id..string.format("%s: move %s should have a unique name but name was already given. Rejecting move!", self.Controllable:GetName(), _name)) + return nil + end + -- Default is current time if no time was specified. time=time or self:_SecondsToClock(timer.getAbsTime()) @@ -649,8 +663,7 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name) else speed=speedmax*0.7 end - - + -- Default is off road. if onroad==nil then onroad=false @@ -899,6 +912,20 @@ function ARTY:SetRelocateDistance(rmax, rmin) self.relocateRmin=rmin or 300 end +--- Enable assigning targets by placing markers on the F10 map. +-- @param #ARTY self +-- @param #number key (Optional) Authorization key. Only players knowing this key can assign targets. Default is no authorization required. +function ARTY:SetMarkTargetsOn(key) + self.markkey=key + self.markallow=true +end + +--- Disable assigning targets by placing markers on the F10 map. +-- @param #ARTY self +function ARTY:SetMarkTargetsOff() + self.markallow=false +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- FSM Start Event ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1012,23 +1039,233 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:__Status(self.StatusInterval) end +--- Extract engagement assignments and parameters from mark text. +-- @param #ARTY self +-- @param #string text Marker text to be analyzed. +-- @return #table Table with assignment parameters, e.g. number of shots, radius, time etc. +function ARTY:_Markertext(text) + self:F(text) + + -- Assignment parameters. + local assignment={} + assignment.battery={} + assignment.move=false + assignment.engage=false + assignment.time=nil + assignment.nshells=nil + assignment.prio=nil + assignment.maxengage=nil + assignment.radius=nil + assignment.weapontype=nil + assignment.speed=nil + assignment.onroad=nil + assignment.key=nil + + if text:lower():find("arty") then + env.info("FF: Found arty command:") + + if text:lower():find("engage") then + assignment.engage=true + elseif text:lower():find("move") then + assignment.move=true + else + self:E(ARTY.id.."ERROR: Neither ENGAGE nor MOVE keyword specified!") + return + end + + -- keywords are split by "," + local keywords=self:_split(text, ",") + + for _,key in pairs(keywords) do + + local s=self:_split(key, " ") + local val=s[2] + + -- Battery name, i.e. which ARTY group should fire. + if key:lower():find("battery") then + + local v=self:_split(text, '"') + + table.insert(assignment.battery, v[2]) + env.info(string.format("FF: Battery=%s.", v[2])) + + elseif key:lower():find("time") then + + if val:lower():find("now") then + assignment.time=self:_SecondsToClock(timer.getTime0()+5) + else + assignment.time=val + end + env.info(string.format("FF: Time=%s.", val)) + + elseif key:lower():find("shots") then + + assignment.nshells=tonumber(s[2]) + env.info(string.format("FF: Shots=%s.", val)) + + elseif key:lower():find("prio") then + + assignment.prio=tonumber(val) + env.info(string.format("FF: Prio=%s.", val)) + + elseif key:lower():find("maxengage") then + + assignment.maxengage=tonumber(val) + env.info(string.format("FF: Maxengage=%s.", val)) + + elseif key:lower():find("radius") then + + assignment.radius=tonumber(val) + env.info(string.format("Radius=%s.", val)) + + elseif key:lower():find("weapon") then + + if val:lower():find("cannon") then + assignment.weapontype=ARTY.WeaponType.Cannon + elseif val:lower():find("rocket") then + assignment.weapontype=ARTY.WeaponType.Rockets + elseif val:lower():find("missile") then + assignment.weapontype=ARTY.WeaponType.GuidedMissile + elseif val:lower():find("nuke") then + assignment.weapontype=ARTY.WeaponType.TacticalNukes + else + assignment.weapontype=ARTY.WeaponType.Auto + end + env.info(string.format("FF: Weapon=%s.", val)) + + elseif key:lower():find("speed") then + + assignment.speed=tonumber(val) + env.info(string.format("FF: Speed=%s.", val)) + + elseif key:lower():find("road") then + + assignment.onroad=true + env.info(string.format("FF: Onroad=true.")) + + elseif key:lower():find("key") then + + assignment.key=tonumber(val) + env.info(string.format("FF: Key=%s.", val)) + + end + + end + else + env.info("FF: This is NO arty command!") + end + + return assignment +end + --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self -- @param #table Event -function ART:onEvent(Event) +function ARTY:onEvent(Event) - if Event then + if Event == nil or Event.idx == nil then + self:T3("Skipping onEvent. Event or Event.idx unknown.") + return true + end + + local batteryname=self.Controllable:GetName() + local batterycoalition=self.Controllable:GetCoalition() - if Event.id==world.event.S_EVENT_MARK_ADDED then - env.info("FF mark added") - elseif Event.id==world.event.S_EVENT_MARK_CHANGE then - env.info("FF mark changed") - elseif Event.id==world.event.S_EVENT_MARK_REMOVED then - env.info("FF mark removed") + env.info(string.format("Event captured = %s", tostring(batteryname))) + env.info(string.format("Event id = %s", tostring(Event.id))) + env.info(string.format("Event time = %s", tostring(Event.time))) + env.info(string.format("Event idx = %s", tostring(Event.idx))) + env.info(string.format("Event coalition = %s", tostring(Event.coalition))) + env.info(string.format("Event group id = %s", tostring(Event.groupID))) + env.info(string.format("Event text = %s", tostring(Event.text))) + self:E({eventid=Event.id, vec3=Event.pos}) + if Event.initiator~=nil then + local _unitname=Event.initiator:getName() + env.info(string.format("Event ini unit name = %s", tostring(_unitname))) + end + + + if Event.id==world.event.S_EVENT_MARK_ADDED then + self:E({event="S_EVENT_MARK_ADDED", vec3=Event.pos}) + + elseif Event.id==world.event.S_EVENT_MARK_CHANGE then + self:E({event="S_EVENT_MARK_CHANGE", vec3=Event.pos}) + + -- Check if marker has a text and the "arty" keyword. + if Event.text~=nil and Event.text:lower():find("arty") then + + -- Check if we have the right coalition and text has arty keyword. + if batterycoalition==Event.coalition or self.markkey~=nil then + + -- Evaluate marker text and extract parameters. + local _assign=self:_Markertext(Event.text) + + local _n=#_assign.battery + env.info("FF: number of batteries assigned to target = ".._n) + + -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. + local _assigned=true + if _n>0 then + _assigned=false + for _,bat in pairs(_assign.battery) do + env.info(string.format("FF: compare %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) + if batteryname==bat then + _assigned=true + end + end + end + + -- We are meant. + if _assigned then + + -- Convert (wrong x-->z, z-->x) vec3 + local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} + -- Get coordinate from vec3. + local _coord=COORDINATE:NewFromVec3(vec3) + + if _assign.move then + + -- Create a new name. + local _name=string.format("Marked Move ID=%d for battery %s", Event.idx, batteryname) + self:E(ARTY.id.._name) + + -- Assign a relocation of the arty group. + self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) + + else + + -- Create a new name. + local _name=string.format("Marked Target ID=%d for battery %s", Event.idx, batteryname) + self:E(ARTY.id.._name) + + -- Assign a new firing engagement. + self:AssignTargetCoord(_coord,_assign.prio,_assign.radius,_assign.nshells,_assign.maxengage,_assign.time,_assign.weapontype, _name, true) + + end + end + + end + end + + elseif Event.id==world.event.S_EVENT_MARK_REMOVED then + self:E({event="S_EVENT_MARK_REMOVED", vec3=Event.pos}) + + -- Check if we have the right coalition. + if batterycoalition==Event.coalition and Event.text:lower():find("arty") then + + -- This should be the unique name of the target or move. + + if Event.text:lower():find("move") then + local _name=string.format("Marked Move ID=%d for battery %s", Event.idx, batteryname) + self:RemoveMove(_name) + else + local _name=string.format("Marked Target ID=%d for battery %s", Event.idx, batteryname) + self:RemoveTarget(_name) + end end end - + end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. @@ -1037,6 +1274,12 @@ function ARTY:_StatusReport() -- Get Ammo. local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() + local Nnukes + if self.Nukes==nil then + Nnukes=0 + else + Nnukes=self.Nukes + end local Tnow=timer.getTime() local Clock=self:_SecondsToClock(timer.getAbsTime()) @@ -1048,7 +1291,7 @@ function ARTY:_StatusReport() text=text..string.format("Number of shells = %d\n", Nshells) text=text..string.format("Number of rockets = %d\n", Nrockets) text=text..string.format("Number of missiles = %d\n", Nmissiles) - text=text..string.format("Number of nukes = %d\n", self.Nukes) + text=text..string.format("Number of nukes = %d\n", Nnukes) if self.currentTarget then text=text..string.format("Current Target = %s\n", tostring(self.currentTarget.name)) text=text..string.format("Curr. Tgt assigned = %d\n", Tnow-self.currentTarget.Tassigned) From da452ed8ce07a7c1636fcb019beb437e4ee4fe68 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 30 May 2018 21:17:09 +0200 Subject: [PATCH 144/170] ARTY v0.9.7 Improved Mark Target Assignments. Improved documentation. --- .../Moose/Functional/Artillery.lua | 159 +++++++++++++++--- 1 file changed, 132 insertions(+), 27 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 4ecae201b..0cbc4474d 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -12,6 +12,8 @@ -- * Special weapon types can be selected for each attack, e.g. cruise missiles for Naval units. -- * Automatic rearming once the artillery is out of ammo. -- * New targets can be added during the mission, e.g. when they are detected by recon units. +-- * Modeling of tactical nuclear shells. +-- * Targets and relocations can be assigned by placing markers on the F10 map. -- * Finite state machine implementation. Mission designer can interact when certain events occur. -- -- ==== @@ -192,9 +194,9 @@ -- Unfortunately, there is no easy way to count only those ammo types useable as artillery. Therefore, to keep the implementation general the user -- can specify the names of the ammo types by the following functions: -- --- * @{#ARTY.SetShellTypes}(*tableofnames*): Defines the ammo types for unguided cannons. Default is *tableofnames*={"weapons.shells"}, i.e. **all** types of shells are counted. --- * @{#ARTY.SetRocketTypes}(*tableofnames*): Defines the ammo types of unguided rockets. Default is *tableofnames*={"weapons.nurs"}, i.e. **all** types of rockets are counted. --- * @{#ARTY.SetMissileTypes}(*tableofnames*): Defines the ammo types of guided missiles. Default is *tableofnames*={"weapons.missiles"}, i.e. **all** types of missiles are counted. +-- * @{#ARTY.SetShellTypes}(*tableofnames*): Defines the ammo types for unguided cannons, e.g. *tableofnames*={"weapons.shells"}, i.e. **all** types of shells are counted. +-- * @{#ARTY.SetRocketTypes}(*tableofnames*): Defines the ammo types of unguided rockets, e.g. *tableofnames*={"weapons.nurs"}, i.e. **all** types of rockets are counted. +-- * @{#ARTY.SetMissileTypes}(*tableofnames*): Defines the ammo types of guided missiles, e.g. is *tableofnames*={"weapons.missiles"}, i.e. **all** types of missiles are counted. -- -- **Note** that the default parameters "weapons.shells", "weapons.nurs", "weapons.missiles" **should in priciple** capture all the corresponding ammo types. -- However, the logic searches for the string "weapon.missies" in the ammo type. Especially for missiles, this string is often not contained in the ammo type descriptor. @@ -253,10 +255,66 @@ -- -- After the rearming is complete, both groups will move back to their original positions. -- +-- ## Tactical Nukes +-- +-- ARTY groups that can fire shells can also be used to fire tactical nukes. This is simply achieved by setting the weapon type to **ARTY.WeaponType.TacticalNukes** in the +-- @{#ARTY.AssignTargetCoord}() function. +-- +-- The default explostion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT. +-- +-- By default, all available conventional shells can be used as nuclear shells. However, it is possible to restrict the number with the @{#ARTY.SetTacNukeShells}(*n*) function +-- to only have *n* nuclear shells available. Note that the group must always have convenctional shells left in order to fire a nuclear shell. +-- +-- ## Assignments via Markers on F10 Map +-- +-- Targets and relocations can be assigned by players via placing a mark on the F10 map. The marker text must contain certain keywords. +-- +-- This feature can be turned on with the @{#ARTY.SetMarkAssignmentsOn}(*key*). The parameter *key* is optional. When set, it can be used as PIN, i.e. only +-- player who know the correct key are able to assign targets or relocations. Default behavior is that all players belonging to the same coalition as the +-- ARTY group are able to assign targets and moves. +-- +-- ### Target Assignments +-- A new target can be assigned by writing **arty engage** in the marker text. This can be followed by a comma separated lists of optional keywords and parameters: +-- +-- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible. +-- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50. +-- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5. +-- * *engage* Number of times the target is engaged. Default is 1. +-- * *radius* Scattering radius of the fired shots in meters. Default is 100 m. +-- * *weapon* Type of weapon to be used. Valid parameters are *cannon*, *rocket*, *missile*, *nuke*. Default is automatic selection. +-- * *battery* Name of the ARTY group that the target is assigned to. Note that the name is case sensitive and has to be given in quotation marks. Default is all ARTY groups of the right coalition. +-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. +-- +-- Here are examples of valid marker texts: +-- arty engage! +-- arty engage! shots 20, prio 10, time 08:15, weapon cannons +-- arty engage! battery "Blue Paladin 1" "Blue MRLS 1", shots 10, time 10:15 +-- arty engage! battery "Blue Paladin 1", key 666 +-- +-- Note that the keywords and parameters are case insensitve. Only exception are the battery group names. These must be exactly the same as the names of the goups defined +-- in the mission editor. +-- +-- ### Relocation Assignments +-- +-- Markers can also be used to relocate the group with the keyphrase **arty move**. This is done in a similar way as assigning targets. Here, the (optional) keywords and parameters are: +-- +-- * *time* Time for which which the relocation/move is schedules, e.g. 08:42. Default is as soon as possible. +-- * *speed* The speed in km/h the group will drive at. Default is 70% of its max possible speed. +-- * *onroad* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate. +-- * *cancel* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over. +-- * *battery* Name of the ARTY group that the relocation is assigned to. +-- +-- Here are some examples: +-- arty move! time 23:45, speed 50, onroad, cancel +-- arty move! battery "Blue Paladin", onroad +-- arty move, cancel, speed 10, onroad +-- -- ## Fine Tuning -- -- The mission designer has a few options to tailor the ARTY object according to his needs. -- +-- * @{#ARTY.SetRelocateAfterEngagement}() will cause the ARTY group to change its position after each firing assignment. +-- * @{#ARTY.SetRelocateDistance}(*rmax*, *rmin*) sets the max/min distance for relocation of the group. Default distance is randomly between 300 and 800 m. -- * @{#ARTY.RemoveAllTargets}() removes all targets from the target queue. -- * @{#ARTY.RemoveTarget}(*name*) deletes the target with *name* from the target queue. -- * @{#ARTY.SetMaxFiringRange}(*range*) defines the maximum firing range. Targets further away than this distance are not engaged. @@ -399,7 +457,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.6" +ARTY.version="0.9.7" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -793,7 +851,7 @@ function ARTY:SetDebugOFF() self.Debug=false end ---- Delete a target from target list. +--- Delete a target from target list. If the target is currently engaged, it is cancelled. -- @param #ARTY self -- @param #string name Name of the target. function ARTY:RemoveTarget(name) @@ -804,6 +862,12 @@ function ARTY:RemoveTarget(name) table.remove(self.targets, id) end self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) + if self.currentTarget then + if self.currentTarget.name==name then + self:T(ARTY.id..string.format("Group %s: Cancelling current target %s (id=%d).", self.Controllable:GetName(), name, id)) + self:CeaseFire(self.currentTarget) + end + end end --- Delete a move from move list. @@ -906,10 +970,10 @@ function ARTY:SetRelocateDistance(rmax, rmin) self.relocateRmin=rmin or 300 end ---- Enable assigning targets by placing markers on the F10 map. +--- Enable assigning targets and moves by placing markers on the F10 map. -- @param #ARTY self -- @param #number key (Optional) Authorization key. Only players knowing this key can assign targets. Default is no authorization required. -function ARTY:SetMarkTargetsOn(key) +function ARTY:SetMarkAssignmentsOn(key) self.markkey=key self.markallow=true end @@ -918,6 +982,7 @@ end -- @param #ARTY self function ARTY:SetMarkTargetsOff() self.markallow=false + self.markkey=nil end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -962,8 +1027,8 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Number of units = %d\n", self.IniGroupStrength) text=text..string.format("Speed max = %d km/h\n", self.SpeedMax) text=text..string.format("Speed default = %d km/h\n", self.Speed) - text=text..string.format("Min range = %d km\n", self.minrange/1000) - text=text..string.format("Max range = %d km\n", self.maxrange/1000) + text=text..string.format("Min range = %.1f km\n", self.minrange/1000) + text=text..string.format("Max range = %.1f km\n", self.maxrange/1000) text=text..string.format("Total ammo count = %d\n", self.Nammo0) text=text..string.format("Number of shells = %d\n", self.Nshells0) text=text..string.format("Number of rockets = %d\n", self.Nrockets0) @@ -986,8 +1051,10 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Rearming ARTY roads = %s\n", tostring(self.RearmingArtyOnRoad)) end text=text..string.format("Relocate after fire = %s\n", tostring(self.relocateafterfire)) - text=text..string.format("Relocate min dist. = %d\n m", self.relocateRmin) - text=text..string.format("Relocate max dist. = %d\n m", self.relocateRmax) + text=text..string.format("Relocate min dist. = %d m\n", self.relocateRmin) + text=text..string.format("Relocate max dist. = %d m\n", self.relocateRmax) + text=text..string.format("Marker assignments = %s\n", tostring(self.markallow)) + text=text..string.format("Marker auth. key = %s\n", tostring(self.markkey)) text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do @@ -1055,9 +1122,7 @@ function ARTY:_Markertext(text) assignment.onroad=nil assignment.key=nil - if text:lower():find("arty") then - env.info("FF: Found arty command:") - + if text:lower():find("arty") then if text:lower():find("engage") then assignment.engage=true elseif text:lower():find("move") then @@ -1071,6 +1136,7 @@ function ARTY:_Markertext(text) local keywords=self:_split(text, ",") for _,key in pairs(keywords) do + --env.info("key="..key) local s=self:_split(key, " ") local val=s[2] @@ -1078,10 +1144,12 @@ function ARTY:_Markertext(text) -- Battery name, i.e. which ARTY group should fire. if key:lower():find("battery") then - local v=self:_split(text, '"') - - table.insert(assignment.battery, v[2]) - env.info(string.format("FF: Battery=%s.", v[2])) + local v=self:_split(key, '"') + + for i=2,#v,2 do + table.insert(assignment.battery, v[i]) + env.info(string.format("FF: Battery=%s.", v[i])) + end elseif key:lower():find("time") then @@ -1110,7 +1178,7 @@ function ARTY:_Markertext(text) elseif key:lower():find("radius") then assignment.radius=tonumber(val) - env.info(string.format("Radius=%s.", val)) + env.info(string.format("FF: Radius=%s.", val)) elseif key:lower():find("weapon") then @@ -1188,18 +1256,15 @@ function ARTY:onEvent(Event) -- Check if marker has a text and the "arty" keyword. if Event.text~=nil and Event.text:lower():find("arty") then - -- Check if we have the right coalition and text has arty keyword. - if batterycoalition==Event.coalition or self.markkey~=nil then + -- Check if the coalition is the same or an authorization key has been defined. + if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then -- Evaluate marker text and extract parameters. local _assign=self:_Markertext(Event.text) - - local _n=#_assign.battery - env.info("FF: number of batteries assigned to target = ".._n) - + -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. local _assigned=true - if _n>0 then + if #_assign.battery>0 then _assigned=false for _,bat in pairs(_assign.battery) do env.info(string.format("FF: compare %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) @@ -1209,8 +1274,27 @@ function ARTY:onEvent(Event) end end + -- Check if the authorization key is required and if it is valid. + local _validkey=true + if self.markkey~=nil then + _validkey=false + if _assign.key~=nil then + _validkey=self.markkey==_assign.key + end + self:T(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(_assign.key), tostring(_validkey))) + local text="" + if _assign.key==nil then + text=string.format("%s, authorization required but did not receive a key!", batteryname) + elseif _validkey==false then + text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(_assign.key)) + elseif _validkey==true then + text=string.format("%s, authorization successful!", batteryname) + end + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + end + -- We are meant. - if _assigned then + if _assigned and _validkey then -- Convert (wrong x-->z, z-->x) vec3 local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} @@ -1219,6 +1303,9 @@ function ARTY:onEvent(Event) if _assign.move then + local text=string.format("%s, received new relocation assignment.", batteryname) + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + -- Create a new name. local _name=string.format("Marked Move ID=%d for battery %s", Event.idx, batteryname) self:E(ARTY.id.._name) @@ -1228,6 +1315,24 @@ function ARTY:onEvent(Event) else + local text=string.format("%s, received new target assignment.", batteryname) + if _assign.time then + text=text..string.format("\nTime %s",_assign.time) + end + if _assign.prio then + text=text..string.format("\nPrio %d",_assign.prio) + end + if _assign.nshells then + text=text..string.format("\nShots %d",_assign.nshells) + end + if _assign.maxengage then + text=text..string.format("\nEngagements %d",_assign.maxengage) + end + if _assign.weapontype then + text=text..string.format("\nWeapon %s",self:_WeaponTypeName(_assign.weapontype)) + end + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + -- Create a new name. local _name=string.format("Marked Target ID=%d for battery %s", Event.idx, batteryname) self:E(ARTY.id.._name) From f556077ff6b9c4d8655e47ad9001981dd91b92c9 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 1 Jun 2018 06:52:36 +0200 Subject: [PATCH 145/170] Cleanup --- Moose Development/Moose/AI/AI_A2A.lua | 8 +- Moose Development/Moose/AI/AI_A2A_Cap.lua | 14 +- Moose Development/Moose/AI/AI_A2A_Gci.lua | 2 +- Moose Development/Moose/AI/AI_A2A_Patrol.lua | 18 +- Moose Development/Moose/AI/AI_BAI.lua | 28 +- Moose Development/Moose/AI/AI_Balancer.lua | 4 +- Moose Development/Moose/AI/AI_CAP.lua | 10 +- Moose Development/Moose/AI/AI_CAS.lua | 28 +- Moose Development/Moose/AI/AI_Patrol.lua | 26 +- .../Moose/Actions/Act_Account.lua | 4 +- .../Moose/Actions/Act_Assign.lua | 3 +- .../Moose/Actions/Act_Assist.lua | 8 +- Moose Development/Moose/Actions/Act_JTAC.lua | 198 --- .../Moose/Actions/Act_Pickup.lua | 173 --- Moose Development/Moose/Actions/Act_Route.lua | 3 +- Moose Development/Moose/Core/Base.lua | 20 +- Moose Development/Moose/Core/Database.lua | 6 +- Moose Development/Moose/Core/Event.lua | 30 +- Moose Development/Moose/Core/Menu.lua | 4 +- Moose Development/Moose/Core/Point.lua | 114 +- Moose Development/Moose/Core/Set.lua | 2 +- Moose Development/Moose/Core/Spawn.lua | 14 +- Moose Development/Moose/Core/UserSound.lua | 4 +- Moose Development/Moose/Core/Velocity.lua | 2 +- Moose Development/Moose/Core/Zone.lua | 84 +- Moose Development/Moose/DCS.lua | 1072 +++++++++++++++++ Moose Development/Moose/Dcs/DCSAirbase.lua | 54 - .../Moose/Dcs/DCSCoalitionObject.lua | 20 - Moose Development/Moose/Dcs/DCSCommand.lua | 10 - Moose Development/Moose/Dcs/DCSController.lua | 115 -- Moose Development/Moose/Dcs/DCSGroup.lua | 83 -- Moose Development/Moose/Dcs/DCSObject.lua | 73 -- .../Moose/Dcs/DCSStaticObject.lua | 34 - Moose Development/Moose/Dcs/DCSTask.lua | 15 - Moose Development/Moose/Dcs/DCSTime.lua | 8 - Moose Development/Moose/Dcs/DCSTypes.lua | 246 ---- Moose Development/Moose/Dcs/DCSUnit.lua | 241 ---- Moose Development/Moose/Dcs/DCSVec3.lua | 11 - Moose Development/Moose/Dcs/DCSZone.lua | 10 - Moose Development/Moose/Dcs/DCScoalition.lua | 16 - Moose Development/Moose/Dcs/DCScountry.lua | 27 - Moose Development/Moose/Dcs/DCSenv.lua | 27 - Moose Development/Moose/Dcs/DCSland.lua | 26 - Moose Development/Moose/Dcs/DCStimer.lua | 45 - Moose Development/Moose/Dcs/DCStrigger.lua | 8 - Moose Development/Moose/Dcs/DCSworld.lua | 35 - .../Moose/Functional/ATC_Ground.lua | 2 +- .../Moose/Functional/CleanUp.lua | 6 +- .../Moose/Functional/Detection.lua | 18 +- Moose Development/Moose/Functional/Escort.lua | 22 +- .../Moose/Functional/Movement.lua | 1 + .../Moose/Functional/Protect.lua | 305 ----- Moose Development/Moose/Functional/RAT.lua | 16 +- .../Moose/Functional/ZoneGoal.lua | 1 + .../Moose/Functional/ZoneGoalCargo.lua | 1 + .../Moose/Functional/ZoneGoalCoalition.lua | 1 + .../Moose/Tasking/CommandCenter.lua | 5 +- Moose Development/Moose/Tasking/Task.lua | 1 + Moose Development/Moose/Tasking/TaskInfo.lua | 1 + .../Moose/Tasking/TaskZoneCapture.lua | 1 + Moose Development/Moose/Tasking/Task_A2A.lua | 1 + Moose Development/Moose/Tasking/Task_A2G.lua | 1 + .../Moose/Tasking/Task_CARGO.lua | 1 + .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 1 + .../Moose/Tasking/Task_Manager.lua | 1 + .../Moose/Utilities/Routines.lua | 2 +- Moose Development/Moose/Utilities/Utils.lua | 1 + Moose Development/Moose/Wrapper/Airbase.lua | 2 +- Moose Development/Moose/Wrapper/Client.lua | 8 +- .../Moose/Wrapper/Controllable.lua | 160 +-- Moose Development/Moose/Wrapper/Group.lua | 44 +- .../Moose/Wrapper/Identifiable.lua | 13 +- Moose Development/Moose/Wrapper/Object.lua | 5 +- .../Moose/Wrapper/Positionable.lua | 46 +- Moose Development/Moose/Wrapper/Static.lua | 2 +- Moose Development/Moose/Wrapper/Unit.lua | 16 +- 76 files changed, 1486 insertions(+), 2182 deletions(-) delete mode 100644 Moose Development/Moose/Actions/Act_JTAC.lua delete mode 100644 Moose Development/Moose/Actions/Act_Pickup.lua create mode 100644 Moose Development/Moose/DCS.lua delete mode 100644 Moose Development/Moose/Dcs/DCSAirbase.lua delete mode 100644 Moose Development/Moose/Dcs/DCSCoalitionObject.lua delete mode 100644 Moose Development/Moose/Dcs/DCSCommand.lua delete mode 100644 Moose Development/Moose/Dcs/DCSController.lua delete mode 100644 Moose Development/Moose/Dcs/DCSGroup.lua delete mode 100644 Moose Development/Moose/Dcs/DCSObject.lua delete mode 100644 Moose Development/Moose/Dcs/DCSStaticObject.lua delete mode 100644 Moose Development/Moose/Dcs/DCSTask.lua delete mode 100644 Moose Development/Moose/Dcs/DCSTime.lua delete mode 100644 Moose Development/Moose/Dcs/DCSTypes.lua delete mode 100644 Moose Development/Moose/Dcs/DCSUnit.lua delete mode 100644 Moose Development/Moose/Dcs/DCSVec3.lua delete mode 100644 Moose Development/Moose/Dcs/DCSZone.lua delete mode 100644 Moose Development/Moose/Dcs/DCScoalition.lua delete mode 100644 Moose Development/Moose/Dcs/DCScountry.lua delete mode 100644 Moose Development/Moose/Dcs/DCSenv.lua delete mode 100644 Moose Development/Moose/Dcs/DCSland.lua delete mode 100644 Moose Development/Moose/Dcs/DCStimer.lua delete mode 100644 Moose Development/Moose/Dcs/DCStrigger.lua delete mode 100644 Moose Development/Moose/Dcs/DCSworld.lua delete mode 100644 Moose Development/Moose/Functional/Protect.lua diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index faaeb3745..4fbe0f37d 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -292,8 +292,8 @@ end --- Sets (modifies) the minimum and maximum speed of the patrol. -- @param #AI_A2A self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @return #AI_A2A self function AI_A2A:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) @@ -305,8 +305,8 @@ end --- Sets the floor and ceiling altitude of the patrol. -- @param #AI_A2A self --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @return #AI_A2A self function AI_A2A:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 5917ed848..e6abde8d9 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -101,13 +101,13 @@ AI_A2A_CAP = { -- @param #AI_A2A_CAP self -- @param Wrapper.Group#GROUP AICap -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. --- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. --- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. --- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2A_CAP function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType ) diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index 5d2e2567f..e968c7320 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -9,7 +9,7 @@ -- === -- -- @module AI.AI_A2A_GCI --- @image AI_AI_Ground_Control_Intercept.JPG +-- @image AI_Ground_Control_Intercept.JPG diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index 73d814ef6..e9ea266db 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -125,11 +125,11 @@ AI_A2A_PATROL = { -- @param #AI_A2A_PATROL self -- @param Wrapper.Group#GROUP AIPatrol -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. --- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2A_PATROL self -- @usage -- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol a Group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. @@ -235,8 +235,8 @@ end --- Sets (modifies) the minimum and maximum speed of the patrol. -- @param #AI_A2A_PATROL self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. -- @return #AI_A2A_PATROL self function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) @@ -249,8 +249,8 @@ end --- Sets the floor and ceiling altitude of the patrol. -- @param #AI_A2A_PATROL self --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @return #AI_A2A_PATROL self function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index 84ef87f92..d68e5b006 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -135,12 +135,12 @@ AI_BAI_ZONE = { --- Creates a new AI_BAI_ZONE object -- @param #AI_BAI_ZONE self -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. --- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_BAI_ZONE self function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) @@ -177,24 +177,24 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- @function [parent=#AI_BAI_ZONE] Engage -- @param #AI_BAI_ZONE self -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. - -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. - -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. + -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. - -- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. + -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- Asynchronous Event Trigger for Event Engage. -- @function [parent=#AI_BAI_ZONE] __Engage -- @param #AI_BAI_ZONE self -- @param #number Delay The delay in seconds. -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. - -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. - -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. + -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. - -- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. + -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- OnLeave Transition Handler for State Engaging. -- @function [parent=#AI_BAI_ZONE] OnLeaveEngaging @@ -481,10 +481,10 @@ end -- @param #string Event The Event string. -- @param #string To The To State string. -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. --- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. +-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To, EngageSpeed, EngageAltitude, diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 2648b4760..9b704e8a1 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -140,7 +140,7 @@ end --- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. +-- @param DCS#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. -- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Core.Set#SET_AIRBASE}s to evaluate where to return to. function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet ) @@ -151,7 +151,7 @@ end --- Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. +-- @param DCS#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange ) self.ToHomeAirbase = true diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index af783bc37..19d51ca81 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -122,11 +122,11 @@ AI_CAP_ZONE = { --- Creates a new AI_CAP_ZONE object -- @param #AI_CAP_ZONE self -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_CAP_ZONE self function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index a80e348ac..bb70b61df 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -126,12 +126,12 @@ AI_CAS_ZONE = { --- Creates a new AI_CAS_ZONE object -- @param #AI_CAS_ZONE self -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. --- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_CAS_ZONE self function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) @@ -167,24 +167,24 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- @function [parent=#AI_CAS_ZONE] Engage -- @param #AI_CAS_ZONE self -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. - -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. - -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. + -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. - -- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. + -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- Asynchronous Event Trigger for Event Engage. -- @function [parent=#AI_CAS_ZONE] __Engage -- @param #AI_CAS_ZONE self -- @param #number Delay The delay in seconds. -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. - -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. - -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. + -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. - -- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. + -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- OnLeave Transition Handler for State Engaging. -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging @@ -426,10 +426,10 @@ end -- @param #string Event The Event string. -- @param #string To The To State string. -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. --- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. +-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To, EngageSpeed, EngageAltitude, diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 74e06492b..1553be007 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -33,10 +33,10 @@ -- @type AI_PATROL_ZONE -- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling. -- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @field DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @field DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @field DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @field DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @field Core.Spawn#SPAWN CoordTest -- @extends Core.Fsm#FSM_CONTROLLABLE @@ -151,11 +151,11 @@ AI_PATROL_ZONE = { --- Creates a new AI_PATROL_ZONE object -- @param #AI_PATROL_ZONE self -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_PATROL_ZONE self -- @usage -- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. @@ -450,8 +450,8 @@ end --- Sets (modifies) the minimum and maximum speed of the patrol. -- @param #AI_PATROL_ZONE self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h. -- @return #AI_PATROL_ZONE self function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) @@ -464,8 +464,8 @@ end --- Sets the floor and ceiling altitude of the patrol. -- @param #AI_PATROL_ZONE self --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @return #AI_PATROL_ZONE self function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 98b84d819..0d057dc24 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -4,8 +4,8 @@ -- -- === -- --- @module Account - +-- @module Actions.Account +-- @image MOOSE.JPG do -- ACT_ACCOUNT diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 0bb843ab1..5e8984b18 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -77,7 +77,8 @@ -- -- === -- --- @module Assign +-- @module Actions.Assign +-- @image MOOSE.JPG do -- ACT_ASSIGN diff --git a/Moose Development/Moose/Actions/Act_Assist.lua b/Moose Development/Moose/Actions/Act_Assist.lua index ccd56e310..b5a473fda 100644 --- a/Moose Development/Moose/Actions/Act_Assist.lua +++ b/Moose Development/Moose/Actions/Act_Assist.lua @@ -1,9 +1,5 @@ --- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. -- --- === --- --- # @{#ACT_ASSIST} FSM class, extends @{Fsm#FSM_PROCESS} --- -- ## ACT_ASSIST state machine: -- -- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. @@ -64,7 +60,9 @@ -- -- === -- --- @module Smoke +-- @module Actions.Assist +-- @image MOOSE.JPG + do -- ACT_ASSIST diff --git a/Moose Development/Moose/Actions/Act_JTAC.lua b/Moose Development/Moose/Actions/Act_JTAC.lua deleted file mode 100644 index 86f965eb0..000000000 --- a/Moose Development/Moose/Actions/Act_JTAC.lua +++ /dev/null @@ -1,198 +0,0 @@ ---- @module Process_JTAC - ---- PROCESS_JTAC class --- @type PROCESS_JTAC --- @field Wrapper.Unit#UNIT ProcessUnit --- @field Core.Set#SET_UNIT TargetSetUnit --- @extends Core.Fsm#FSM_PROCESS -PROCESS_JTAC = { - ClassName = "PROCESS_JTAC", - Fsm = {}, - TargetSetUnit = nil, -} - - ---- Creates a new DESTROY process. --- @param #PROCESS_JTAC self --- @param Tasking.Task#TASK Task --- @param Wrapper.Unit#UNIT ProcessUnit --- @param Core.Set#SET_UNIT TargetSetUnit --- @param Wrapper.Unit#UNIT FACUnit --- @return #PROCESS_JTAC self -function PROCESS_JTAC:New( Task, ProcessUnit, TargetSetUnit, FACUnit ) - - -- Inherits from BASE - local self = BASE:Inherit( self, PROCESS:New( "JTAC", Task, ProcessUnit ) ) -- #PROCESS_JTAC - - self.TargetSetUnit = TargetSetUnit - self.FACUnit = FACUnit - - self.DisplayInterval = 60 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - self.DisplayCategory = "HQ" -- Targets is the default display category - - - self.Fsm = FSM_PROCESS:New( self, { - initial = 'Assigned', - events = { - { name = 'Start', from = 'Assigned', to = 'CreatedMenu' }, - { name = 'JTACMenuUpdate', from = 'CreatedMenu', to = 'AwaitingMenu' }, - { name = 'JTACMenuAwait', from = 'AwaitingMenu', to = 'AwaitingMenu' }, - { name = 'JTACMenuSpot', from = 'AwaitingMenu', to = 'AwaitingMenu' }, - { name = 'JTACMenuCancel', from = 'AwaitingMenu', to = 'AwaitingMenu' }, - { name = 'JTACStatus', from = 'AwaitingMenu', to = 'AwaitingMenu' }, - { name = 'Fail', from = 'AwaitingMenu', to = 'Failed' }, - { name = 'Fail', from = 'CreatedMenu', to = 'Failed' }, - }, - callbacks = { - onStart = self.OnStart, - onJTACMenuUpdate = self.OnJTACMenuUpdate, - onJTACMenuAwait = self.OnJTACMenuAwait, - onJTACMenuSpot = self.OnJTACMenuSpot, - onJTACMenuCancel = self.OnJTACMenuCancel, - }, - endstates = { 'Failed' } - } ) - - self:HandleEvent( EVENTS.Dead, self.EventDead ) - - return self -end - ---- Process Events - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_JTAC self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_JTAC:OnStart( Fsm, From, Event, To ) - - self:NextEvent( Fsm.JTACMenuUpdate ) -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_JTAC self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To ) - - local function JTACMenuSpot( MenuParam ) - self:F( MenuParam.TargetUnit.UnitName ) - local self = MenuParam.self - local TargetUnit = MenuParam.TargetUnit - - self:NextEvent( self.Fsm.JTACMenuSpot, TargetUnit ) - end - - local function JTACMenuCancel( MenuParam ) - self:F( MenuParam ) - local self = MenuParam.self - local TargetUnit = MenuParam.TargetUnit - - self:NextEvent( self.Fsm.JTACMenuCancel, TargetUnit ) - end - - - -- Loop each unit in the target set, and determine the threat levels map table. - local UnitThreatLevels = self.TargetSetUnit:GetUnitThreatLevels() - - self:F( {"UnitThreadLevels", UnitThreatLevels } ) - - local JTACMenu = self.ProcessGroup:GetState( self.ProcessGroup, "JTACMenu" ) - - if not JTACMenu then - JTACMenu = MENU_GROUP:New( self.ProcessGroup, "JTAC", self.MissionMenu ) - for ThreatLevel, ThreatLevelTable in pairs( UnitThreatLevels ) do - local JTACMenuThreatLevel = MENU_GROUP:New( self.ProcessGroup, ThreatLevelTable.UnitThreatLevelText, JTACMenu ) - for ThreatUnitName, ThreatUnit in pairs( ThreatLevelTable.Units ) do - local JTACMenuUnit = MENU_GROUP:New( self.ProcessGroup, ThreatUnit:GetTypeName(), JTACMenuThreatLevel ) - MENU_GROUP_COMMAND:New( self.ProcessGroup, "Lase Target", JTACMenuUnit, JTACMenuSpot, { self = self, TargetUnit = ThreatUnit } ) - MENU_GROUP_COMMAND:New( self.ProcessGroup, "Cancel Target", JTACMenuUnit, JTACMenuCancel, { self = self, TargetUnit = ThreatUnit } ) - end - end - end - -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_JTAC self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_JTAC:OnJTACMenuAwait( Fsm, From, Event, To ) - - if self.DisplayCount >= self.DisplayInterval then - - local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC - TaskJTAC.Spots = TaskJTAC.Spots or {} - for TargetUnitName, SpotData in pairs( TaskJTAC.Spots) do - local TargetUnit = UNIT:FindByName( TargetUnitName ) - self.FACUnit:MessageToGroup( "Lasing " .. TargetUnit:GetTypeName() .. " with laser code " .. SpotData:getCode(), 15, self.ProcessGroup ) - end - self.DisplayCount = 1 - else - self.DisplayCount = self.DisplayCount + 1 - end - - self:NextEvent( Fsm.JTACMenuAwait ) -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_JTAC self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT TargetUnit -function PROCESS_JTAC:OnJTACMenuSpot( Fsm, From, Event, To, TargetUnit ) - - local TargetUnitName = TargetUnit:GetName() - - local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC - - TaskJTAC.Spots = TaskJTAC.Spots or {} - TaskJTAC.Spots[TargetUnitName] = TaskJTAC.Spots[TargetUnitName] or {} - - local DCSFACObject = self.FACUnit:GetDCSObject() - local TargetVec3 = TargetUnit:GetVec3() - - TaskJTAC.Spots[TargetUnitName] = Spot.createInfraRed( self.FACUnit:GetDCSObject(), { x = 0, y = 1, z = 0 }, TargetUnit:GetVec3(), math.random( 1000, 9999 ) ) - - local SpotData = TaskJTAC.Spots[TargetUnitName] - self.FACUnit:MessageToGroup( "Lasing " .. TargetUnit:GetTypeName() .. " with laser code " .. SpotData:getCode(), 15, self.ProcessGroup ) - - self:NextEvent( Fsm.JTACMenuAwait ) -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_JTAC self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT TargetUnit -function PROCESS_JTAC:OnJTACMenuCancel( Fsm, From, Event, To, TargetUnit ) - - local TargetUnitName = TargetUnit:GetName() - - local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC - - TaskJTAC.Spots = TaskJTAC.Spots or {} - if TaskJTAC.Spots[TargetUnitName] then - TaskJTAC.Spots[TargetUnitName]:destroy() -- destroys the spot - TaskJTAC.Spots[TargetUnitName] = nil - end - - self.FACUnit:MessageToGroup( "Stopped lasing " .. TargetUnit:GetTypeName(), 15, self.ProcessGroup ) - - self:NextEvent( Fsm.JTACMenuAwait ) -end - - diff --git a/Moose Development/Moose/Actions/Act_Pickup.lua b/Moose Development/Moose/Actions/Act_Pickup.lua deleted file mode 100644 index 3ef76e0eb..000000000 --- a/Moose Development/Moose/Actions/Act_Pickup.lua +++ /dev/null @@ -1,173 +0,0 @@ ---- @module Process_Pickup - ---- PROCESS_PICKUP class --- @type PROCESS_PICKUP --- @field Wrapper.Unit#UNIT ProcessUnit --- @field Core.Set#SET_UNIT TargetSetUnit --- @extends Core.Fsm#FSM_PROCESS -PROCESS_PICKUP = { - ClassName = "PROCESS_PICKUP", - Fsm = {}, - TargetSetUnit = nil, -} - - ---- Creates a new DESTROY process. --- @param #PROCESS_PICKUP self --- @param Tasking.Task#TASK Task --- @param Wrapper.Unit#UNIT ProcessUnit --- @param Core.Set#SET_UNIT TargetSetUnit --- @return #PROCESS_PICKUP self -function PROCESS_PICKUP:New( Task, ProcessName, ProcessUnit ) - - -- Inherits from BASE - local self = BASE:Inherit( self, PROCESS:New( ProcessName, Task, ProcessUnit ) ) -- #PROCESS_PICKUP - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - self.DisplayCategory = "HQ" -- Targets is the default display category - - self.Fsm = FSM_PROCESS:New( self, { - initial = 'Assigned', - events = { - { name = 'Start', from = 'Assigned', to = 'Navigating' }, - { name = 'Start', from = 'Navigating', to = 'Navigating' }, - { name = 'Nearby', from = 'Navigating', to = 'Preparing' }, - { name = 'Pickup', from = 'Preparing', to = 'Loading' }, - { name = 'Load', from = 'Loading', to = 'Success' }, - { name = 'Fail', from = 'Assigned', to = 'Failed' }, - { name = 'Fail', from = 'Navigating', to = 'Failed' }, - { name = 'Fail', from = 'Preparing', to = 'Failed' }, - }, - callbacks = { - onStart = self.OnStart, - onNearby = self.OnNearby, - onPickup = self.OnPickup, - onLoad = self.OnLoad, - }, - endstates = { 'Success', 'Failed' } - } ) - - return self -end - ---- Process Events - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_PICKUP:OnStart( Fsm, From, Event, To ) - - self:NextEvent( Fsm.Start ) -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_PICKUP:OnNavigating( Fsm, From, Event, To ) - - local TaskGroup = self.ProcessUnit:GetGroup() - if self.DisplayCount >= self.DisplayInterval then - MESSAGE:New( "Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup ) - self.DisplayCount = 1 - else - self.DisplayCount = self.DisplayCount + 1 - end - - return true -- Process always the event. - -end - - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Event#EVENTDATA Event -function PROCESS_PICKUP:OnHitTarget( Fsm, From, Event, To, Event ) - - - self.TargetSetUnit:Flush( self ) - - if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then - self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName ) - local TaskGroup = self.ProcessUnit:GetGroup() - MESSAGE:New( "You hit a target. Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed.", 15, "HQ" ):ToGroup( TaskGroup ) - end - - - if self.TargetSetUnit:Count() > 0 then - self:NextEvent( Fsm.MoreTargets ) - else - self:NextEvent( Fsm.Destroyed ) - end -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_PICKUP:OnMoreTargets( Fsm, From, Event, To ) - - -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Event#EVENTDATA DCSEvent -function PROCESS_PICKUP:OnKilled( Fsm, From, Event, To ) - - self:NextEvent( Fsm.Restart ) - -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_PICKUP:OnRestart( Fsm, From, Event, To ) - - self:NextEvent( Fsm.Menu ) - -end - ---- StateMachine callback function for a PROCESS --- @param #PROCESS_PICKUP self --- @param Core.Fsm#FSM_PROCESS Fsm --- @param #string Event --- @param #string From --- @param #string To -function PROCESS_PICKUP:OnDestroyed( Fsm, From, Event, To ) - -end - ---- DCS Events - ---- @param #PROCESS_PICKUP self --- @param Core.Event#EVENTDATA Event -function PROCESS_PICKUP:EventDead( Event ) - - if Event.IniDCSUnit then - self:NextEvent( self.Fsm.HitTarget, Event ) - end -end - - diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index eba201588..87ee9a72e 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -72,7 +72,8 @@ -- -- === -- --- @module Route +-- @module Actions.Route +-- @image MOOSE.JPG do -- ACT_ROUTE diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 12a8a5efe..996376961 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -604,8 +604,8 @@ end --- Creation of a Birth Event. -- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. -- @param #string IniUnitName The initiating unit name. -- @param place -- @param subplace @@ -626,8 +626,8 @@ end --- Creation of a Crash Event. -- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. function BASE:CreateEventCrash( EventTime, Initiator ) self:F( { EventTime, Initiator } ) @@ -642,8 +642,8 @@ end --- Creation of a Dead Event. -- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. function BASE:CreateEventDead( EventTime, Initiator ) self:F( { EventTime, Initiator } ) @@ -658,8 +658,8 @@ end --- Creation of a Takeoff Event. -- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. function BASE:CreateEventTakeoff( EventTime, Initiator ) self:F( { EventTime, Initiator } ) @@ -672,10 +672,10 @@ function BASE:CreateEventTakeoff( EventTime, Initiator ) world.onEvent( Event ) end --- TODO: Complete Dcs.DCSTypes#Event structure. +-- TODO: Complete DCS#Event structure. --- The main event handling function... This function captures all events generated for the class. -- @param #BASE self --- @param Dcs.DCSTypes#Event event +-- @param DCS#Event event function BASE:onEvent(event) --self:F( { BaseEventCodes[event.id], event } ) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index eea110521..37e792279 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -587,9 +587,9 @@ end --- Private method that registers new Group Templates within the DATABASE Object. -- @param #DATABASE self -- @param #table GroupTemplate --- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the object. --- @param Dcs.DCSObject#Object.Category CategoryID The Object.category of the object. --- @param Dcs.DCScountry#country.id CountryID the country.id of the object +-- @param DCS#coalition.side CoalitionSide The coalition.side of the object. +-- @param DCS#Object.Category CategoryID The Object.category of the object. +-- @param DCS#country.id CountryID the country.id of the object -- @return #DATABASE self function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName ) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index dd739a0d9..3f1b1cd57 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -226,34 +226,34 @@ EVENTS = { -- @type EVENTDATA -- @field #number id The identifier of the event. -- --- @field Dcs.DCSUnit#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}. --- @field Dcs.DCSObject#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). --- @field Dcs.DCSUnit#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}. +-- @field DCS#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{DCS#Unit} or @{DCS#StaticObject}. +-- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). +-- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCSStaticObject#StaticObject}. -- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name. -- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Unit#UNIT} of the initiator Unit object. -- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName). --- @field Dcs.DCSGroup#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}. +-- @field DCS#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}. -- @field #string IniDCSGroupName (UNIT) The initiating Group name. -- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object. -- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName). -- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot. --- @field Dcs.DCScoalition#coalition.side IniCoalition (UNIT) The coalition of the initiator. --- @field Dcs.DCSUnit#Unit.Category IniCategory (UNIT) The category of the initiator. +-- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator. +-- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator. -- @field #string IniTypeName (UNIT) The type name of the initiator. -- --- @field Dcs.DCSUnit#Unit target (UNIT/STATIC) The target @{Dcs.DCSUnit#Unit} or @{DCSStaticObject#StaticObject}. --- @field Dcs.DCSObject#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). --- @field Dcs.DCSUnit#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}. +-- @field DCS#Unit target (UNIT/STATIC) The target @{DCS#Unit} or @{DCSStaticObject#StaticObject}. +-- @field DCS#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). +-- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCSStaticObject#StaticObject}. -- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name. -- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Unit#UNIT} of the target Unit object. -- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName). --- @field Dcs.DCSGroup#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}. +-- @field DCS#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}. -- @field #string TgtDCSGroupName (UNIT) The target Group name. -- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Wrapper.Group#GROUP} of the target Group object. -- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName). -- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot. --- @field Dcs.DCScoalition#coalition.side TgtCoalition (UNIT) The coalition of the target. --- @field Dcs.DCSUnit#Unit.Category TgtCategory (UNIT) The category of the target. +-- @field DCS#coalition.side TgtCoalition (UNIT) The coalition of the target. +-- @field DCS#Unit.Category TgtCategory (UNIT) The category of the target. -- @field #string TgtTypeName (UNIT) The type name of the target. -- -- @field weapon The weapon used during the event. @@ -457,7 +457,7 @@ end --- Initializes the Events structure for the event -- @param #EVENT self --- @param Dcs.DCSWorld#world.event EventID +-- @param DCS#world.event EventID -- @param Core.Base#BASE EventClass -- @return #EVENT.Events function EVENT:Init( EventID, EventClass ) @@ -483,7 +483,7 @@ end --- Removes a subscription -- @param #EVENT self -- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param Dcs.DCSWorld#world.event EventID +-- @param DCS#world.event EventID -- @return #EVENT.Events function EVENT:RemoveEvent( EventClass, EventID ) @@ -503,7 +503,7 @@ end --- Resets subscriptions -- @param #EVENT self -- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param Dcs.DCSWorld#world.event EventID +-- @param DCS#world.event EventID -- @return #EVENT.Events function EVENT:Reset( EventObject ) --R2.1 diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index b93cb59c9..03d95c47f 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -585,7 +585,7 @@ do -- MENU_COALITION --- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition. -- @param #MENU_COALITION self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. + -- @param DCS#coalition.side Coalition The coalition owning the menu. -- @param #string MenuText The text for the menu. -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). -- @return #MENU_COALITION self @@ -683,7 +683,7 @@ do -- MENU_COALITION_COMMAND --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. -- @param #MENU_COALITION_COMMAND self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. + -- @param DCS#coalition.side Coalition The coalition owning the menu. -- @param #string MenuText The text for the menu. -- @param Core.Menu#MENU_COALITION ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0a90f6440..be99b5d75 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -174,9 +174,9 @@ do -- COORDINATE --- COORDINATE constructor. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. - -- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing to the Right. - -- @param Dcs.DCSTypes#Distance z The z coordinate of the Vec3 point, pointing to the Right. + -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. + -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to the Right. + -- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the Right. -- @return #COORDINATE function COORDINATE:New( x, y, z ) @@ -204,8 +204,8 @@ do -- COORDINATE --- Create a new COORDINATE object from Vec2 coordinates. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. - -- @param Dcs.DCSTypes#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. + -- @param DCS#Vec2 Vec2 The Vec2 point. + -- @param DCS#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. -- @return #COORDINATE function COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) @@ -224,7 +224,7 @@ do -- COORDINATE --- Create a new COORDINATE object from Vec3 coordinates. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. + -- @param DCS#Vec3 Vec3 The Vec3 point. -- @return #COORDINATE function COORDINATE:NewFromVec3( Vec3 ) @@ -238,7 +238,7 @@ do -- COORDINATE --- Return the coordinates of the COORDINATE in Vec3 format. -- @param #COORDINATE self - -- @return Dcs.DCSTypes#Vec3 The Vec3 format coordinate. + -- @return DCS#Vec3 The Vec3 format coordinate. function COORDINATE:GetVec3() return { x = self.x, y = self.y, z = self.z } end @@ -246,7 +246,7 @@ do -- COORDINATE --- Return the coordinates of the COORDINATE in Vec2 format. -- @param #COORDINATE self - -- @return Dcs.DCSTypes#Vec2 The Vec2 format coordinate. + -- @return DCS#Vec2 The Vec2 format coordinate. function COORDINATE:GetVec2() return { x = self.x, y = self.z } end @@ -273,7 +273,7 @@ do -- COORDINATE --- Calculate the distance from a reference @{#COORDINATE}. -- @param #COORDINATE self -- @param #COORDINATE PointVec2Reference The reference @{#COORDINATE}. - -- @return Dcs.DCSTypes#Distance The distance from the reference @{#COORDINATE} in meters. + -- @return DCS#Distance The distance from the reference @{#COORDINATE} in meters. function COORDINATE:DistanceFromPointVec2( PointVec2Reference ) self:F2( PointVec2Reference ) @@ -285,8 +285,8 @@ do -- COORDINATE --- Add a Distance in meters from the COORDINATE orthonormal plane, with the given angle, and calculate the new COORDINATE. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. - -- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. + -- @param DCS#Distance Distance The Distance to be added in meters. + -- @param DCS#Angle Angle The Angle in degrees. -- @return #COORDINATE The new calculated COORDINATE. function COORDINATE:Translate( Distance, Angle ) local SX = self.x @@ -300,9 +300,9 @@ do -- COORDINATE --- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Distance OuterRadius - -- @param Dcs.DCSTypes#Distance InnerRadius - -- @return Dcs.DCSTypes#Vec2 Vec2 + -- @param DCS#Distance OuterRadius + -- @param DCS#Distance InnerRadius + -- @return DCS#Vec2 Vec2 function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius ) self:F2( { OuterRadius, InnerRadius } ) @@ -332,8 +332,8 @@ do -- COORDINATE --- Return a random Coordinate within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Distance OuterRadius - -- @param Dcs.DCSTypes#Distance InnerRadius + -- @param DCS#Distance OuterRadius + -- @param DCS#Distance InnerRadius -- @return #COORDINATE function COORDINATE:GetRandomCoordinateInRadius( OuterRadius, InnerRadius ) self:F2( { OuterRadius, InnerRadius } ) @@ -344,9 +344,9 @@ do -- COORDINATE --- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Distance OuterRadius - -- @param Dcs.DCSTypes#Distance InnerRadius - -- @return Dcs.DCSTypes#Vec3 Vec3 + -- @param DCS#Distance OuterRadius + -- @param DCS#Distance InnerRadius + -- @return DCS#Vec3 Vec3 function COORDINATE:GetRandomVec3InRadius( OuterRadius, InnerRadius ) local RandomVec2 = self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) @@ -409,7 +409,7 @@ do -- COORDINATE --- Return a direction vector Vec3 from COORDINATE to the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE TargetCoordinate The target COORDINATE. - -- @return Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. + -- @return DCS#Vec3 DirectionVec3 The direction vector in Vec3 format. function COORDINATE:GetDirectionVec3( TargetCoordinate ) return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z } end @@ -428,7 +428,7 @@ do -- COORDINATE --- Return an angle in radians from the COORDINATE using a direction vector in Vec3 format. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. + -- @param DCS#Vec3 DirectionVec3 The direction vector in Vec3 format. -- @return #number DirectionRadians The angle in radians. function COORDINATE:GetAngleRadians( DirectionVec3 ) local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x ) @@ -441,7 +441,7 @@ do -- COORDINATE --- Return an angle in degrees from the COORDINATE using a direction vector in Vec3 format. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. + -- @param DCS#Vec3 DirectionVec3 The direction vector in Vec3 format. -- @return #number DirectionRadians The angle in degrees. function COORDINATE:GetAngleDegrees( DirectionVec3 ) local AngleRadians = self:GetAngleRadians( DirectionVec3 ) @@ -453,7 +453,7 @@ do -- COORDINATE --- Return the 2D distance in meters between the target COORDINATE and the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE TargetCoordinate The target COORDINATE. - -- @return Dcs.DCSTypes#Distance Distance The distance in meters. + -- @return DCS#Distance Distance The distance in meters. function COORDINATE:Get2DDistance( TargetCoordinate ) local TargetVec3 = TargetCoordinate:GetVec3() local SourceVec3 = self:GetVec3() @@ -617,7 +617,7 @@ do -- COORDINATE --- Return the 3D distance in meters between the target COORDINATE and the COORDINATE. -- @param #COORDINATE self -- @param #COORDINATE TargetCoordinate The target COORDINATE. - -- @return Dcs.DCSTypes#Distance Distance The distance in meters. + -- @return DCS#Distance Distance The distance in meters. function COORDINATE:Get3DDistance( TargetCoordinate ) local TargetVec3 = TargetCoordinate:GetVec3() local SourceVec3 = self:GetVec3() @@ -753,8 +753,8 @@ do -- COORDINATE --- Add a Distance in meters from the COORDINATE horizontal plane, with the given angle, and calculate the new COORDINATE. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. - -- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. + -- @param DCS#Distance Distance The Distance to be added in meters. + -- @param DCS#Angle Angle The Angle in degrees. -- @return #COORDINATE The new calculated COORDINATE. function COORDINATE:Translate( Distance, Angle ) local SX = self.x @@ -773,7 +773,7 @@ do -- COORDINATE -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param #COORDINATE.WaypointType Type The route point type. -- @param #COORDINATE.WaypointAction Action The route point action. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. Default is 500 km/h. + -- @param DCS#Speed Speed Airspeed in km/h. Default is 500 km/h. -- @param #boolean SpeedLocked true means the speed is locked. -- @return #table The route point. function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked ) @@ -816,7 +816,7 @@ do -- COORDINATE --- Build a Waypoint Air "Turning Point". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTurningPoint( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed ) @@ -826,7 +826,7 @@ do -- COORDINATE --- Build a Waypoint Air "Fly Over Point". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirFlyOverPoint( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, Speed ) @@ -836,7 +836,7 @@ do -- COORDINATE --- Build a Waypoint Air "Take Off Parking Hot". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTakeOffParkingHot( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParkingHot, COORDINATE.WaypointAction.FromParkingAreaHot, Speed ) @@ -846,7 +846,7 @@ do -- COORDINATE --- Build a Waypoint Air "Take Off Parking". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTakeOffParking( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, Speed ) @@ -856,7 +856,7 @@ do -- COORDINATE --- Build a Waypoint Air "Take Off Runway". -- @param #COORDINATE self -- @param #COORDINATE.WaypointAltType AltType The altitude type. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. function COORDINATE:WaypointAirTakeOffRunway( AltType, Speed ) return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOff, COORDINATE.WaypointAction.FromRunway, Speed ) @@ -865,7 +865,7 @@ do -- COORDINATE --- Build a Waypoint Air "Landing". -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param DCS#Speed Speed Airspeed in km/h. -- @return #table The route point. -- @usage -- @@ -960,7 +960,7 @@ do -- COORDINATE --- Gets the surface type at the coordinate. -- @param #COORDINATE self - -- @return Dcs.DCSland#SurfaceType Surface type. + -- @return DCS#SurfaceType Surface type. function COORDINATE:GetSurfaceType() local vec2=self:GetVec2() local surface=land.getSurfaceType(vec2) @@ -1111,7 +1111,7 @@ do -- COORDINATE --- Flares the point in a color. -- @param #COORDINATE self -- @param Utilities.Utils#FLARECOLOR FlareColor - -- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. + -- @param DCS#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:Flare( FlareColor, Azimuth ) self:F2( { FlareColor } ) trigger.action.signalFlare( self:GetVec3(), FlareColor, Azimuth and Azimuth or 0 ) @@ -1119,7 +1119,7 @@ do -- COORDINATE --- Flare the COORDINATE White. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. + -- @param DCS#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:FlareWhite( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.White, Azimuth ) @@ -1127,7 +1127,7 @@ do -- COORDINATE --- Flare the COORDINATE Yellow. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. + -- @param DCS#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:FlareYellow( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.Yellow, Azimuth ) @@ -1135,7 +1135,7 @@ do -- COORDINATE --- Flare the COORDINATE Green. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. + -- @param DCS#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. function COORDINATE:FlareGreen( Azimuth ) self:F2( Azimuth ) self:Flare( FLARECOLOR.Green, Azimuth ) @@ -1307,7 +1307,7 @@ do -- COORDINATE --- Return a BULLS string out of the BULLS of the coalition to the COORDINATE. -- @param #COORDINATE self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition. + -- @param DCS#coalition.side Coalition The coalition. -- @return #string The BR text. function COORDINATE:ToStringBULLS( Coalition, Settings ) local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) ) @@ -1674,9 +1674,9 @@ do -- POINT_VEC3 --- Create a new POINT_VEC3 object. -- @param #POINT_VEC3 self - -- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. - -- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing Upwards. - -- @param Dcs.DCSTypes#Distance z The z coordinate of the Vec3 point, pointing to the Right. + -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. + -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing Upwards. + -- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the Right. -- @return Core.Point#POINT_VEC3 function POINT_VEC3:New( x, y, z ) @@ -1688,8 +1688,8 @@ do -- POINT_VEC3 --- Create a new POINT_VEC3 object from Vec2 coordinates. -- @param #POINT_VEC3 self - -- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. - -- @param Dcs.DCSTypes#Distance LandHeightAdd (optional) Add a landheight. + -- @param DCS#Vec2 Vec2 The Vec2 point. + -- @param DCS#Distance LandHeightAdd (optional) Add a landheight. -- @return Core.Point#POINT_VEC3 self function POINT_VEC3:NewFromVec2( Vec2, LandHeightAdd ) @@ -1702,7 +1702,7 @@ do -- POINT_VEC3 --- Create a new POINT_VEC3 object from Vec3 coordinates. -- @param #POINT_VEC3 self - -- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. + -- @param DCS#Vec3 Vec3 The Vec3 point. -- @return Core.Point#POINT_VEC3 self function POINT_VEC3:NewFromVec3( Vec3 ) @@ -1791,8 +1791,8 @@ do -- POINT_VEC3 --- Return a random POINT_VEC3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. -- @param #POINT_VEC3 self - -- @param Dcs.DCSTypes#Distance OuterRadius - -- @param Dcs.DCSTypes#Distance InnerRadius + -- @param DCS#Distance OuterRadius + -- @param DCS#Distance InnerRadius -- @return #POINT_VEC3 function POINT_VEC3:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) @@ -1804,8 +1804,8 @@ end do -- POINT_VEC2 --- @type POINT_VEC2 - -- @field Dcs.DCSTypes#Distance x The x coordinate in meters. - -- @field Dcs.DCSTypes#Distance y the y coordinate in meters. + -- @field DCS#Distance x The x coordinate in meters. + -- @field DCS#Distance y the y coordinate in meters. -- @extends Core.Point#COORDINATE --- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. @@ -1840,9 +1840,9 @@ do -- POINT_VEC2 --- POINT_VEC2 constructor. -- @param #POINT_VEC2 self - -- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. - -- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing to the Right. - -- @param Dcs.DCSTypes#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. + -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. + -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to the Right. + -- @param DCS#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. -- @return Core.Point#POINT_VEC2 function POINT_VEC2:New( x, y, LandHeightAdd ) @@ -1859,7 +1859,7 @@ do -- POINT_VEC2 --- Create a new POINT_VEC2 object from Vec2 coordinates. -- @param #POINT_VEC2 self - -- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. + -- @param DCS#Vec2 Vec2 The Vec2 point. -- @return Core.Point#POINT_VEC2 self function POINT_VEC2:NewFromVec2( Vec2, LandHeightAdd ) @@ -1876,7 +1876,7 @@ do -- POINT_VEC2 --- Create a new POINT_VEC2 object from Vec3 coordinates. -- @param #POINT_VEC2 self - -- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. + -- @param DCS#Vec3 Vec3 The Vec3 point. -- @return Core.Point#POINT_VEC2 self function POINT_VEC2:NewFromVec3( Vec3 ) @@ -1996,8 +1996,8 @@ do -- POINT_VEC2 --- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC2. -- @param #POINT_VEC2 self - -- @param Dcs.DCSTypes#Distance OuterRadius - -- @param Dcs.DCSTypes#Distance InnerRadius + -- @param DCS#Distance OuterRadius + -- @param DCS#Distance InnerRadius -- @return #POINT_VEC2 function POINT_VEC2:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) self:F2( { OuterRadius, InnerRadius } ) @@ -2009,7 +2009,7 @@ do -- POINT_VEC2 --- Calculate the distance from a reference @{#POINT_VEC2}. -- @param #POINT_VEC2 self -- @param #POINT_VEC2 PointVec2Reference The reference @{#POINT_VEC2}. - -- @return Dcs.DCSTypes#Distance The distance from the reference @{#POINT_VEC2} in meters. + -- @return DCS#Distance The distance from the reference @{#POINT_VEC2} in meters. function POINT_VEC2:DistanceFromPointVec2( PointVec2Reference ) self:F2( PointVec2Reference ) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index fbaed636e..2209dcad1 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -2186,7 +2186,7 @@ do -- SET_UNIT --- Returns if the @{Set} has targets having a radar (of a given type). -- @param #SET_UNIT self - -- @param Dcs.DCSWrapper.Unit#Unit.RadarType RadarType + -- @param DCS#Unit.RadarType RadarType -- @return #number The amount of radars in the Set with the given type function SET_UNIT:HasRadar( RadarType ) self:F2( RadarType ) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 919623334..94c3b5564 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -547,8 +547,8 @@ end --- Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. -- @param #SPAWN self -- @param #boolean RandomizePosition If true, SPAWN will perform the randomization of the @{Wrapper.Group}s position between a given outer and inner radius. --- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. --- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. +-- @param DCS#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. +-- @param DCS#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. -- @return #SPAWN function SPAWN:InitRandomizePosition( RandomizePosition, OuterRadius, InnerRadius ) self:F( { self.SpawnTemplatePrefix, RandomizePosition, OuterRadius, InnerRadius } ) @@ -568,8 +568,8 @@ end --- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius. -- @param #SPAWN self -- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{UNIT}s position within the group between a given outer and inner radius. --- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. --- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. +-- @param DCS#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. +-- @param DCS#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. -- @return #SPAWN -- @usage -- -- NATO helicopters engaging in the battle field. @@ -1344,7 +1344,7 @@ end -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. -- You can use the returned group to further define the route to be followed. -- @param #SPAWN self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 coordinates where to spawn the group. +-- @param DCS#Vec3 Vec3 The Vec3 coordinates where to spawn the group. -- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. -- @return Wrapper.Group#GROUP that was spawned. -- @return #nil Nothing was spawned. @@ -1454,7 +1454,7 @@ end -- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. -- You can use the returned group to further define the route to be followed. -- @param #SPAWN self --- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group. +-- @param DCS#Vec2 Vec2 The Vec2 coordinates where to spawn the group. -- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone. -- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone. -- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. @@ -1778,7 +1778,7 @@ end -- The method will search for a #-mark, and will return the text before the #-mark. -- It will return nil of no prefix was found. -- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#UNIT DCSUnit The @{DCSUnit} to be searched. +-- @param DCS#UNIT DCSUnit The @{DCSUnit} to be searched. -- @return #string The prefix -- @return #nil Nothing found function SPAWN:_GetPrefixFromGroup( SpawnGroup ) diff --git a/Moose Development/Moose/Core/UserSound.lua b/Moose Development/Moose/Core/UserSound.lua index 9b7204b2f..a8a6328d7 100644 --- a/Moose Development/Moose/Core/UserSound.lua +++ b/Moose Development/Moose/Core/UserSound.lua @@ -79,7 +79,7 @@ do -- UserSound --- Play the usersound to the given coalition. -- @param #USERSOUND self - -- @param Dcs.DCScoalition#coalition Coalition The coalition to play the usersound to. + -- @param DCS#coalition Coalition The coalition to play the usersound to. -- @return #USERSOUND The usersound instance. -- @usage -- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" ) @@ -95,7 +95,7 @@ do -- UserSound --- Play the usersound to the given country. -- @param #USERSOUND self - -- @param Dcs.DCScountry#country Country The country to play the usersound to. + -- @param DCS#country Country The country to play the usersound to. -- @return #USERSOUND The usersound instance. -- @usage -- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" ) diff --git a/Moose Development/Moose/Core/Velocity.lua b/Moose Development/Moose/Core/Velocity.lua index c8ef325f3..04e4675bb 100644 --- a/Moose Development/Moose/Core/Velocity.lua +++ b/Moose Development/Moose/Core/Velocity.lua @@ -8,7 +8,7 @@ -- === -- -- @module Core.Velocity --- @image Core_Velocity.JPG +-- @image MOOSE.JPG do -- Velocity diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 56e6a6765..3697c6de2 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -92,10 +92,10 @@ ZONE_BASE = { --- The ZONE_BASE.BoundingSquare -- @type ZONE_BASE.BoundingSquare --- @field Dcs.DCSTypes#Distance x1 The lower x coordinate (left down) --- @field Dcs.DCSTypes#Distance y1 The lower y coordinate (left down) --- @field Dcs.DCSTypes#Distance x2 The higher x coordinate (right up) --- @field Dcs.DCSTypes#Distance y2 The higher y coordinate (right up) +-- @field DCS#Distance x1 The lower x coordinate (left down) +-- @field DCS#Distance y1 The lower y coordinate (left down) +-- @field DCS#Distance x2 The higher x coordinate (right up) +-- @field DCS#Distance y2 The higher y coordinate (right up) --- ZONE_BASE constructor @@ -135,7 +135,7 @@ end --- Returns if a Vec2 is within the zone. -- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 to test. +-- @param DCS#Vec2 Vec2 The Vec2 to test. -- @return #boolean true if the Vec2 is within the zone. function ZONE_BASE:IsVec2InZone( Vec2 ) self:F2( Vec2 ) @@ -145,7 +145,7 @@ end --- Returns if a Vec3 is within the zone. -- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. +-- @param DCS#Vec3 Vec3 The point to test. -- @return #boolean true if the Vec3 is within the zone. function ZONE_BASE:IsVec3InZone( Vec3 ) local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) @@ -189,7 +189,7 @@ end --- Returns a @{Point#POINT_VEC2} of the zone. -- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return Core.Point#POINT_VEC2 The PointVec2 of the zone. function ZONE_BASE:GetPointVec2() self:F2( self.ZoneName ) @@ -222,8 +222,8 @@ end --- Returns the @{DCSTypes#Vec3} of the zone. -- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The Vec3 of the zone. +-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. +-- @return DCS#Vec3 The Vec3 of the zone. function ZONE_BASE:GetVec3( Height ) self:F2( self.ZoneName ) @@ -240,7 +240,7 @@ end --- Returns a @{Point#POINT_VEC3} of the zone. -- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return Core.Point#POINT_VEC3 The PointVec3 of the zone. function ZONE_BASE:GetPointVec3( Height ) self:F2( self.ZoneName ) @@ -256,7 +256,7 @@ end --- Returns a @{Point#COORDINATE} of the zone. -- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return Core.Point#COORDINATE The Coordinate of the zone. function ZONE_BASE:GetCoordinate( Height ) --R2.1 self:F2( self.ZoneName ) @@ -273,7 +273,7 @@ end --- Define a random @{DCSTypes#Vec2} within the zone. -- @param #ZONE_BASE self --- @return Dcs.DCSTypes#Vec2 The Vec2 coordinates. +-- @return DCS#Vec2 The Vec2 coordinates. function ZONE_BASE:GetRandomVec2() return nil end @@ -373,8 +373,8 @@ end --- The ZONE_RADIUS class, defined by a zone name, a location and a radius. -- @type ZONE_RADIUS --- @field Dcs.DCSTypes#Vec2 Vec2 The current location of the zone. --- @field Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @field DCS#Vec2 Vec2 The current location of the zone. +-- @field DCS#Distance Radius The radius of the zone. -- @extends #ZONE_BASE --- The ZONE_RADIUS class defined by a zone name, a location and a radius. @@ -411,8 +411,8 @@ ZONE_RADIUS = { --- Constructor of @{#ZONE_RADIUS}, taking the zone name, the zone location and a radius. -- @param #ZONE_RADIUS self -- @param #string ZoneName Name of the zone. --- @param Dcs.DCSTypes#Vec2 Vec2 The location of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @param DCS#Vec2 Vec2 The location of the zone. +-- @param DCS#Distance Radius The radius of the zone. -- @return #ZONE_RADIUS self function ZONE_RADIUS:New( ZoneName, Vec2, Radius ) local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) -- #ZONE_RADIUS @@ -427,7 +427,7 @@ end --- Bounds the zone with tires. -- @param #ZONE_RADIUS self -- @param #number Points (optional) The amount of points in the circle. Default 360. --- @param Dcs.DCScountry#country.id CountryID The country id of the tire objects, e.g. country.id.USA for blue or country.id.RUSSIA for red. +-- @param DCS#country.id CountryID The country id of the tire objects, e.g. country.id.USA for blue or country.id.RUSSIA for red. -- @param #boolean UnBound (Optional) If true the tyres will be destroyed. -- @return #ZONE_RADIUS self function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound ) @@ -507,7 +507,7 @@ end -- @param #ZONE_RADIUS self -- @param Utilities.Utils#FLARECOLOR FlareColor The flare color. -- @param #number Points (optional) The amount of points in the circle. --- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare. +-- @param DCS#Azimuth Azimuth (optional) Azimuth The azimuth of the flare. -- @param #number AddHeight (optional) The height to be added for the smoke. -- @return #ZONE_RADIUS self function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight ) @@ -535,7 +535,7 @@ end --- Returns the radius of the zone. -- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Distance The radius of the zone. +-- @return DCS#Distance The radius of the zone. function ZONE_RADIUS:GetRadius() self:F2( self.ZoneName ) @@ -546,8 +546,8 @@ end --- Sets the radius of the zone. -- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return Dcs.DCSTypes#Distance The radius of the zone. +-- @param DCS#Distance Radius The radius of the zone. +-- @return DCS#Distance The radius of the zone. function ZONE_RADIUS:SetRadius( Radius ) self:F2( self.ZoneName ) @@ -559,7 +559,7 @@ end --- Returns the @{DCSTypes#Vec2} of the zone. -- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Vec2 The location of the zone. +-- @return DCS#Vec2 The location of the zone. function ZONE_RADIUS:GetVec2() self:F2( self.ZoneName ) @@ -570,8 +570,8 @@ end --- Sets the @{DCSTypes#Vec2} of the zone. -- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec2 Vec2 The new location of the zone. --- @return Dcs.DCSTypes#Vec2 The new location of the zone. +-- @param DCS#Vec2 Vec2 The new location of the zone. +-- @return DCS#Vec2 The new location of the zone. function ZONE_RADIUS:SetVec2( Vec2 ) self:F2( self.ZoneName ) @@ -584,8 +584,8 @@ end --- Returns the @{DCSTypes#Vec3} of the ZONE_RADIUS. -- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The point of the zone. +-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. +-- @return DCS#Vec3 The point of the zone. function ZONE_RADIUS:GetVec3( Height ) self:F2( { self.ZoneName, Height } ) @@ -829,7 +829,7 @@ end --- Returns if a location is within the zone. -- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. +-- @param DCS#Vec2 Vec2 The location to test. -- @return #boolean true if the location is within the zone. function ZONE_RADIUS:IsVec2InZone( Vec2 ) self:F2( Vec2 ) @@ -847,7 +847,7 @@ end --- Returns if a point is within the zone. -- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. +-- @param DCS#Vec3 Vec3 The point to test. -- @return #boolean true if the point is within the zone. function ZONE_RADIUS:IsVec3InZone( Vec3 ) self:F2( Vec3 ) @@ -861,7 +861,7 @@ end -- @param #ZONE_RADIUS self -- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. -- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. --- @return Dcs.DCSTypes#Vec2 The random location within the zone. +-- @return DCS#Vec2 The random location within the zone. function ZONE_RADIUS:GetRandomVec2( inner, outer ) self:F( self.ZoneName, inner, outer ) @@ -898,7 +898,7 @@ end -- @param #ZONE_RADIUS self -- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. -- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. --- @return Dcs.DCSTypes#Vec3 The random location within the zone. +-- @return DCS#Vec3 The random location within the zone. function ZONE_RADIUS:GetRandomVec3( inner, outer ) self:F( self.ZoneName, inner, outer ) @@ -1029,7 +1029,7 @@ ZONE_UNIT = { -- @param #ZONE_UNIT self -- @param #string ZoneName Name of the zone. -- @param Wrapper.Unit#UNIT ZoneUNIT The unit as the center of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @param DCS#Distance Radius The radius of the zone. -- @return #ZONE_UNIT self function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius ) local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius ) ) @@ -1047,7 +1047,7 @@ end --- Returns the current location of the @{Unit#UNIT}. -- @param #ZONE_UNIT self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Unit#UNIT}location. +-- @return DCS#Vec2 The location of the zone based on the @{Unit#UNIT}location. function ZONE_UNIT:GetVec2() self:F2( self.ZoneName ) @@ -1066,7 +1066,7 @@ end --- Returns a random location within the zone. -- @param #ZONE_UNIT self --- @return Dcs.DCSTypes#Vec2 The random location within the zone. +-- @return DCS#Vec2 The random location within the zone. function ZONE_UNIT:GetRandomVec2() self:F( self.ZoneName ) @@ -1088,8 +1088,8 @@ end --- Returns the @{DCSTypes#Vec3} of the ZONE_UNIT. -- @param #ZONE_UNIT self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The point of the zone. +-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. +-- @return DCS#Vec3 The point of the zone. function ZONE_UNIT:GetVec3( Height ) self:F2( self.ZoneName ) @@ -1120,7 +1120,7 @@ ZONE_GROUP = { -- @param #ZONE_GROUP self -- @param #string ZoneName Name of the zone. -- @param Wrapper.Group#GROUP ZoneGROUP The @{Wrapper.Group} as the center of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @param DCS#Distance Radius The radius of the zone. -- @return #ZONE_GROUP self function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneGROUP:GetVec2(), Radius ) ) @@ -1137,7 +1137,7 @@ end --- Returns the current location of the @{Wrapper.Group}. -- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Wrapper.Group} location. +-- @return DCS#Vec2 The location of the zone based on the @{Wrapper.Group} location. function ZONE_GROUP:GetVec2() self:F( self.ZoneName ) @@ -1150,7 +1150,7 @@ end --- Returns a random location within the zone of the @{Wrapper.Group}. -- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The random location of the zone based on the @{Wrapper.Group} location. +-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location. function ZONE_GROUP:GetRandomVec2() self:F( self.ZoneName ) @@ -1206,7 +1206,7 @@ ZONE_POLYGON_BASE = { --- A points array. -- @type ZONE_POLYGON_BASE.ListVec2 --- @list +-- @list --- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{DCSTypes#Vec2}, forming a polygon. -- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. @@ -1233,7 +1233,7 @@ end --- Returns the center location of the polygon. -- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Wrapper.Group} location. +-- @return DCS#Vec2 The location of the zone based on the @{Wrapper.Group} location. function ZONE_POLYGON_BASE:GetVec2() self:F( self.ZoneName ) @@ -1340,7 +1340,7 @@ end --- Returns if a location is within the zone. -- Source learned and taken from: https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html -- @param #ZONE_POLYGON_BASE self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. +-- @param DCS#Vec2 Vec2 The location to test. -- @return #boolean true if the location is within the zone. function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 ) self:F2( Vec2 ) @@ -1370,7 +1370,7 @@ end --- Define a random @{DCSTypes#Vec2} within the zone. -- @param #ZONE_POLYGON_BASE self --- @return Dcs.DCSTypes#Vec2 The Vec2 coordinate. +-- @return DCS#Vec2 The Vec2 coordinate. function ZONE_POLYGON_BASE:GetRandomVec2() self:F2() diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua new file mode 100644 index 000000000..19bb8e47c --- /dev/null +++ b/Moose Development/Moose/DCS.lua @@ -0,0 +1,1072 @@ +--- DCS API prototypes +-- @module DCS +-- @image MOOSE.JPG + +do -- world + + --- @type world + -- @field #world.event event + + --- @type world.event + -- @field S_EVENT_INVALID + -- @field S_EVENT_SHOT + -- @field S_EVENT_HIT + -- @field S_EVENT_TAKEOFF + -- @field S_EVENT_LAND + -- @field S_EVENT_CRASH + -- @field S_EVENT_EJECTION + -- @field S_EVENT_REFUELING + -- @field S_EVENT_DEAD + -- @field S_EVENT_PILOT_DEAD + -- @field S_EVENT_BASE_CAPTURED + -- @field S_EVENT_MISSION_START + -- @field S_EVENT_MISSION_END + -- @field S_EVENT_TOOK_CONTROL + -- @field S_EVENT_REFUELING_STOP + -- @field S_EVENT_BIRTH + -- @field S_EVENT_HUMAN_FAILURE + -- @field S_EVENT_ENGINE_STARTUP + -- @field S_EVENT_ENGINE_SHUTDOWN + -- @field S_EVENT_PLAYER_ENTER_UNIT + -- @field S_EVENT_PLAYER_LEAVE_UNIT + -- @field S_EVENT_PLAYER_COMMENT + -- @field S_EVENT_SHOOTING_START + -- @field S_EVENT_SHOOTING_END + -- @field S_EVENT_MAX + + world = {} --#world + +end -- world + + +do -- env + + --- @type env + + --- Add message to simulator log with caption "INFO". Message box is optional. + -- @function [parent=#env] info + -- @field #string message message string to add to log. + -- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional. + + --- Add message to simulator log with caption "WARNING". Message box is optional. + -- @function [parent=#env] warning + -- @field #string message message string to add to log. + -- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional. + + --- Add message to simulator log with caption "ERROR". Message box is optional. + -- @function [parent=#env] error + -- @field #string message message string to add to log. + -- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional. + + --- Enables/disables appearance of message box each time lua error occurs. + -- @function [parent=#env] setErrorMessageBoxEnabled + -- @field #boolean on if true message box appearance is enabled. + + env = {} --#env + +end -- env + + +do -- timer + + --- @type timer + + + --- Returns model time in seconds. + -- @function [parent=#timer] getTime + -- @return #Time + + --- Returns mission time in seconds. + -- @function [parent=#timer] getAbsTime + -- @return #Time + + --- Returns mission start time in seconds. + -- @function [parent=#timer] getTime0 + -- @return #Time + + --- Schedules function to call at desired model time. + -- Time function FunctionToCall(any argument, Time time) + -- + -- ... + -- + -- return ... + -- + -- end + -- + -- Must return model time of next call or nil. Note that the DCS scheduler calls the function in protected mode and any Lua errors in the called function will be trapped and not reported. If the function triggers a Lua error then it will be terminated and not scheduled to run again. + -- @function [parent=#timer] scheduleFunction + -- @param #FunctionToCall functionToCall Lua-function to call. Must have prototype of FunctionToCall. + -- @param functionArgument Function argument of any type to pass to functionToCall. + -- @param #Time time Model time of the function call. + -- @return functionId + + --- Re-schedules function to call at another model time. + -- @function [parent=#timer] setFunctionTime + -- @param functionId Lua-function to call. Must have prototype of FunctionToCall. + -- @param #Time time Model time of the function call. + + + --- Removes the function from schedule. + -- @function [parent=#timer] removeFunction + -- @param functionId Function identifier to remove from schedule + + timer = {} --#timer + +end + + +do -- land + + --- @type land + -- @field #land.SurfaceType SurfaceType + + + --- @type land.SurfaceType + -- @field LAND + -- @field SHALLOW_WATER + -- @field WATER + -- @field ROAD + -- @field RUNWAY + + --- Returns altitude MSL of the point. + -- @function [parent=#land] getHeight + -- @param #Vec2 point point on the ground. + -- @return #Distance + + --- returns surface type at the given point. + -- @function [parent=#land] getSurfaceType + -- @param #Vec2 point Point on the land. + -- @return #land.SurfaceType + + land = {} --#land + +end -- land + +do -- country + + --- @type country + -- @field #country.id id + + --- @type country.id + -- @field RUSSIA + -- @field UKRAINE + -- @field USA + -- @field TURKEY + -- @field UK + -- @field FRANCE + -- @field GERMANY + -- @field CANADA + -- @field SPAIN + -- @field THE_NETHERLANDS + -- @field BELGIUM + -- @field NORWAY + -- @field DENMARK + -- @field ISRAEL + -- @field GEORGIA + -- @field INSURGENTS + -- @field ABKHAZIA + -- @field SOUTH_OSETIA + -- @field ITALY + + country = {} -- #country + +end -- country + +do -- Command + + --- @type Command + -- @field #string id + -- @field #Command.params params + + --- @type Command.params + +end -- Command + +do -- coalition + + --- @type coalition + -- @field #coalition.side side + + --- @type coalition.side + -- @field NEUTRAL + -- @field RED + -- @field BLUE + + --- @function [parent=#coalition] getCountryCoalition + -- @param #number countryId + -- @return #number coalitionId + + coalition = {} -- #coalition + +end -- coalition + + +do -- Types + + --- @type Desc + -- @field #TypeName typeName type name + -- @field #string displayName localized display name + -- @field #table attributes object type attributes + + --- A distance type + -- @type Distance + + --- An angle type + -- @type Angle + + --- Time is given in seconds. + -- @type Time + -- @extends #number + + --- Model time is the time that drives the simulation. Model time may be stopped, accelerated and decelerated relative real time. + -- @type ModelTime + -- @extends #number + + --- Mission time is a model time plus time of the mission start. + -- @type MissionTime + -- @extends #number + + + --- Distance is given in meters. + -- @type Distance + -- @extends #number + + --- Angle is given in radians. + -- @type Angle + -- @extends #number + + --- Azimuth is an angle of rotation around world axis y counter-clockwise. + -- @type Azimuth + -- @extends #number + + --- Mass is given in kilograms. + -- @type Mass + -- @extends #number + + --- Vec3 type is a 3D-vector. + -- DCS world has 3-dimensional coordinate system. DCS ground is an infinite plain. + -- @type Vec3 + -- @field #Distance x is directed to the north + -- @field #Distance z is directed to the east + -- @field #Distance y is directed up + + --- Vec2 is a 2D-vector for the ground plane as a reference plane. + -- @type Vec2 + -- @field #Distance x Vec2.x = Vec3.x + -- @field #Distance y Vec2.y = Vec3.z + + --- Position is a composite structure. It consists of both coordinate vector and orientation matrix. Position3 (also known as "Pos3" for short) is a table that has following format: + -- @type Position3 + -- @field #Vec3 p + -- @field #Vec3 x + -- @field #Vec3 y + -- @field #Vec3 z + + --- 3-dimensional box. + -- @type Box3 + -- @field #Vec3 min + -- @field #Vec3 max + + --- Each object belongs to a type. Object type is a named couple of properties those independent of mission and common for all units of the same type. Name of unit type is a string. Samples of unit type: "Su-27", "KAMAZ" and "M2 Bradley". + -- @type TypeName + -- @extends #string + + --- AttributeName = string + -- Each object type may have attributes. + -- Attributes are enlisted in ./Scripts/Database/db_attributes.Lua. + -- To know what attributes the object type has, look for the unit type script in sub-directories planes/, helicopter/s, vehicles, navy/ of ./Scripts/Database/ directory. + -- @type AttributeName + -- @extends #string + + --- List of @{#AttributeName} + -- @type AttributeNameArray + -- @list <#AttributeName> + + --- @type Zone + -- @field DCSVec3#Vec3 point + -- @field #number radius + + Zone = {} + + --- @type ModelTime + -- @extends #number + + --- @type Time + -- @extends #number + + --- A task descriptor (internal structure for DCS World) + -- @type Task + -- @field #string id + -- @field #Task.param param + + --- @type Task.param + + --- List of @{#Task} + -- @type TaskArray + -- @list <#Task> + + +end -- + +do -- Object + + --- @type Object + -- @field #Object.Category Category + -- @field #Object.Desc Desc + + --- @type Object.Category + -- @field UNIT + -- @field WEAPON + -- @field STATIC + -- @field SCENERY + -- @field BASE + + --- @type Object.Desc + -- @extends #Desc + -- @field #number life initial life level + -- @field #Box3 box bounding box of collision geometry + + --- @function [parent=#Object] isExist + -- @param #Object self + -- @return #boolean + + --- @function [parent=#Object] destroy + -- @param #Object self + + --- @function [parent=#Object] getCategory + -- @param #Object self + -- @return #Object.Category + + --- Returns type name of the Object. + -- @function [parent=#Object] getTypeName + -- @param #Object self + -- @return #string + + --- Returns object descriptor. + -- @function [parent=#Object] getDesc + -- @param #Object self + -- @return #Object.Desc + + --- Returns true if the object belongs to the category. + -- @function [parent=#Object] hasAttribute + -- @param #Object self + -- @param #AttributeName attributeName Attribute name to check. + -- @return #boolean + + --- Returns name of the object. This is the name that is assigned to the object in the Mission Editor. + -- @function [parent=#Object] getName + -- @param #Object self + -- @return #string + + --- Returns object coordinates for current time. + -- @function [parent=#Object] getPoint + -- @param #Object self + -- @return #Vec3 + + --- Returns object position for current time. + -- @function [parent=#Object] getPosition + -- @param #Object self + -- @return #Position3 + + --- Returns the unit's velocity vector. + -- @function [parent=#Object] getVelocity + -- @param #Object self + -- @return #Vec3 + + --- Returns true if the unit is in air. + -- @function [parent=#Object] inAir + -- @param #Object self + -- @return #boolean + + Object = {} --#Object + +end -- Object + +do -- CoalitionObject + + --- @type CoalitionObject + -- @extends #Object + + + --- Returns coalition of the object. + -- @function [parent=#CoalitionObject] getCoalition + -- @param #CoalitionObject self + -- @return #coalition.side + + --- Returns object country. + -- @function [parent=#CoalitionObject] getCountry + -- @param #CoalitionObject self + -- @return #country.id + +CoalitionObject = {} --#CoalitionObject + +end -- CoalitionObject + + +do -- Airbase + + --- Represents airbases: airdromes, helipads and ships with flying decks or landing pads. + -- @type Airbase + -- @extends #CoalitionObject + -- @field #Airbase.ID ID Identifier of an airbase. It assigned to an airbase by the Mission Editor automatically. This identifier is used in AI tasks to refer an airbase that exists (spawned and not dead) or not. + -- @field #Airbase.Category Category enum contains identifiers of airbase categories. + -- @field #Airbase.Desc Desc Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type. + + --- Enum contains identifiers of airbase categories. + -- @type Airbase.Category + -- @field AIRDROME + -- @field HELIPAD + -- @field SHIP + + --- Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type. + -- @type Airbase.Desc + -- @extends #Desc + -- @field #Airbase.Category category Category of the airbase type. + + --- Returns airbase by its name. If no airbase found the function will return nil. + -- @function [parent=#Airbase] getByName + -- @param #string name + -- @return #Airbase + + --- Returns airbase descriptor by type name. If no descriptor is found the function will return nil. + -- @function [parent=#Airbase] getDescByName + -- @param #TypeName typeName Airbase type name. + -- @return #Airbase.Desc + + --- Returns Unit that is corresponded to the airbase. Works only for ships. + -- @function [parent=#Airbase] getUnit + -- @param self + -- @return #Unit + + --- Returns identifier of the airbase. + -- @function [parent=#Airbase] getID + -- @param self + -- @return #Airbase.ID + + --- Returns the airbase's callsign - the localized string. + -- @function [parent=#Airbase] getCallsign + -- @param self + -- @return #string + + --- Returns descriptor of the airbase. + -- @function [parent=#Airbase] getDesc + -- @param self + -- @return #Airbase.Desc + + Airbase = {} --#Airbase + +end -- Airbase + + + +do -- Controller + --- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C. + -- + -- This class has 2 types of functions: + -- + -- * Tasks + -- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics. + -- @type Controller + -- @field #Controller.Detection Detection Enum contains identifiers of surface types. + + --- Enables and disables the controller. + -- Note: Now it works only for ground / naval groups! + -- @function [parent=#Controller] setOnOff + -- @param self + -- @param #boolean value Enable / Disable. + + -- Tasks + + --- Resets current task and then sets the task to the controller. Task is a table that contains task identifier and task parameters. + -- @function [parent=#Controller] setTask + -- @param self + -- @param #Task task + + --- Resets current task of the controller. + -- @function [parent=#Controller] resetTask + -- @param self + + --- Pushes the task to the front of the queue and makes the task active. Further call of function Controller.setTask() function will stop current task, clear the queue and set the new task active. If the task queue is empty the function will work like function Controller.setTask() function. + -- @function [parent=#Controller] pushTask + -- @param self + -- @param #Task task + + --- Pops current (front) task from the queue and makes active next task in the queue (if exists). If no more tasks in the queue the function works like function Controller.resetTask() function. Does nothing if the queue is empty. + -- @function [parent=#Controller] popTask + -- @param self + + --- Returns true if the controller has a task. + -- @function [parent=#Controller] hasTask + -- @param self + -- @return #boolean + + -- Commands + + --TODO: describe #Command structure + --- Sets the command to perform by controller. + -- @function [parent=#Controller] setCommand + -- @param self + -- @param #Command command Table that contains command identifier and command parameters. + + + -- Behaviours + + --- Sets the option to the controller. + -- Option is a pair of identifier and value. Behavior options are global parameters those affect controller behavior in all tasks it performs. + -- Option identifiers and values are stored in table AI.Option in subtables Air, Ground and Naval. + -- + -- OptionId = @{#AI.Option.Air.id} or @{#AI.Option.Ground.id} or @{#AI.Option.Naval.id} + -- OptionValue = AI.Option.Air.val[optionName] or AI.Option.Ground.val[optionName] or AI.Option.Naval.val[optionName] + -- + -- @function [parent=#Controller] setOption + -- @param self + -- @param #OptionId optionId Option identifier. + -- @param #OptionValue optionValue Value of the option. + + + -- Detection + + --- Enum contains identifiers of surface types. + -- @type Controller.Detection + -- @field VISUAL + -- @field OPTIC + -- @field RADAR + -- @field IRST + -- @field RWR + -- @field DLINK + + --- Detected target. + -- @type DetectedTarget + -- @field Wrapper.Object#Object object The target + -- @field #boolean visible The target is visible + -- @field #boolean type The target type is known + -- @field #boolean distance Distance to the target is known + + + --- Checks if the target is detected or not. If one or more detection method is specified the function will return true if the target is detected by at least one of these methods. If no detection methods are specified the function will return true if the target is detected by any method. + -- @function [parent=#Controller] isTargetDetected + -- @param self + -- @param Wrapper.Object#Object target Target to check + -- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN + -- @return #boolean detected True if the target is detected. + -- @return #boolean visible Has effect only if detected is true. True if the target is visible now. + -- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen. + -- @return #boolean type Has effect only if detected is true. True if the target type is known. + -- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known. + -- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen. + -- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen. + + + --- Returns list of detected targets. If one or more detection method is specified the function will return targets which were detected by at least one of these methods. If no detection methods are specified the function will return targets which were detected by any method. + -- @function [parent=#Controller] getDetectedTargets + -- @param self + -- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN + -- @return #list<#DetectedTarget> array of DetectedTarget + + --- Know a target. + -- @function [parent=#Controller] knowTarget + -- @param self + -- @param Wrapper.Object#Object object The target. + -- @param #boolean type Target type is known. + -- @param #boolean distance Distance to target is known. + + + Controller = {} --#Controller + +end -- Controller + + +do -- Unit + + --- @type Unit + -- @extends #CoalitionObject + -- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically. + -- @field #Unit.Category Category + -- @field #Unit.RefuelingSystem RefuelingSystem + -- @field #Unit.SensorType SensorType + -- @field #Unit.OpticType OpticType + -- @field #Unit.RadarType RadarType + -- @field #Unit.Desc Desc + -- @field #Unit.DescAircraft DescAircraft + -- @field #Unit.DescAirplane DescAirplane + -- @field #Unit.DescHelicopter DescHelicopter + -- @field #Unit.DescVehicle DescVehicle + -- @field #Unit.DescShip DescShip + -- @field #Unit.AmmoItem AmmoItem + -- @field #list<#Unit.AmmoItem> Ammo + -- @field #Unit.Sensor Sensor + -- @field #Unit.Optic Optic + -- @field #Unit.Radar Radar + -- @field #Unit.IRST IRST + + + --- Enum that stores unit categories. + -- @type Unit.Category + -- @field AIRPLANE + -- @field HELICOPTER + -- @field GROUND_UNIT + -- @field SHIP + -- @field STRUCTURE + + --- Enum that stores aircraft refueling system types. + -- @type Unit.RefuelingSystem + -- @field BOOM_AND_RECEPTACLE + -- @field PROBE_AND_DROGUE + + --- Enum that stores sensor types. + -- @type Unit.SensorType + -- @field OPTIC + -- @field RADAR + -- @field IRST + -- @field RWR + + --- Enum that stores types of optic sensors. + -- @type Unit.OpticType + -- @field TV TV-sensor + -- @field LLTV Low-level TV-sensor + -- @field IR Infra-Red optic sensor + + --- Enum that stores radar types. + -- @type Unit.RadarType + -- @field AS air search radar + -- @field SS surface/land search radar + + + --- A unit descriptor. + -- @type Unit.Desc + -- @extends #Object.Desc + -- @field #Unit.Category category Unit Category + -- @field #Mass massEmpty mass of empty unit + -- @field #number speedMax istance / Time, --maximal velocity + + --- An aircraft descriptor. + -- @type Unit.DescAircraft + -- @extends #Unit.Desc + -- @field #Mass fuelMassMax maximal inner fuel mass + -- @field #Distance range Operational range + -- @field #Distance Hmax Ceiling + -- @field #number VyMax #Distance / #Time, --maximal climb rate + -- @field #number NyMin minimal safe acceleration + -- @field #number NyMax maximal safe acceleration + -- @field #Unit.RefuelingSystem tankerType refueling system type + + --- An airplane descriptor. + -- @type Unit.DescAirplane + -- @extends #Unit.DescAircraft + -- @field #number speedMax0 Distance / Time maximal TAS at ground level + -- @field #number speedMax10K Distance / Time maximal TAS at altitude of 10 km + + --- A helicopter descriptor. + -- @type Unit.DescHelicopter + -- @extends #Unit.DescAircraft + -- @field #Distance HmaxStat static ceiling + + --- A vehicle descriptor. + -- @type Unit.DescVehicle + -- @extends #Unit.Desc + -- @field #Angle maxSlopeAngle maximal slope angle + -- @field #boolean riverCrossing can the vehicle cross a rivers + + --- A ship descriptor. + -- @type Unit.DescShip + -- @extends #Unit.Desc + + --- ammunition item: "type-count" pair. + -- @type Unit.AmmoItem + -- @field #Weapon.Desc desc ammunition descriptor + -- @field #number count ammunition count + + --- A unit sensor. + -- @type Unit.Sensor + -- @field #TypeName typeName + -- @field #Unit.SensorType type + + --- An optic sensor. + -- @type Unit.Optic + -- @extends #Unit.Sensor + -- @field #Unit.OpticType opticType + + --- A radar. + -- @type Unit.Radar + -- @extends #Unit.Sensor + -- @field #Distance detectionDistanceRBM detection distance for RCS=1m^2 in real-beam mapping mode, nil if radar doesn't support surface/land search + -- @field #Distance detectionDistanceHRM detection distance for RCS=1m^2 in high-resolution mapping mode, nil if radar has no HRM + -- @field #Unit.Radar.detectionDistanceAir detectionDistanceAir detection distance for RCS=1m^2 airborne target, nil if radar doesn't support air search + + --- @type Unit.Radar.detectionDistanceAir + -- @field #Unit.Radar.detectionDistanceAir.upperHemisphere upperHemisphere + -- @field #Unit.Radar.detectionDistanceAir.lowerHemisphere lowerHemisphere + + --- @type Unit.Radar.detectionDistanceAir.upperHemisphere + -- @field #Distance headOn + -- @field #Distance tailOn + + --- @type Unit.Radar.detectionDistanceAir.lowerHemisphere + -- @field #Distance headOn + -- @field #Distance tailOn + + --- An IRST. + -- @type Unit.IRST + -- @extends #Unit.Sensor + -- @field #Distance detectionDistanceIdle detection of tail-on target with heat signature = 1 in upper hemisphere, engines are in idle + -- @field #Distance detectionDistanceMaximal ..., engines are in maximal mode + -- @field #Distance detectionDistanceAfterburner ..., engines are in afterburner mode + + --- An RWR. + -- @type Unit.RWR + -- @extends #Unit.Sensor + + --- table that stores all unit sensors. + -- TODO @type Sensors + -- + + + --- Returns unit object by the name assigned to the unit in Mission Editor. If there is unit with such name or the unit is destroyed the function will return nil. The function provides access to non-activated units too. + -- @function [parent=#Unit] getByName + -- @param #string name + -- @return #Unit + + --- Returns if the unit is activated. + -- @function [parent=#Unit] isActive + -- @param #Unit self + -- @return #boolean + + --- Returns name of the player that control the unit or nil if the unit is controlled by A.I. + -- @function [parent=#Unit] getPlayerName + -- @param #Unit self + -- @return #string + + --- returns the unit's unique identifier. + -- @function [parent=#Unit] getID + -- @param #Unit self + -- @return #Unit.ID + + + --- Returns the unit's number in the group. The number is the same number the unit has in ME. It may not be changed during the mission. If any unit in the group is destroyed, the numbers of another units will not be changed. + -- @function [parent=#Unit] getNumber + -- @param #Unit self + -- @return #number + + --- Returns controller of the unit if it exist and nil otherwise + -- @function [parent=#Unit] getController + -- @param #Unit self + -- @return #Controller + + --- Returns the unit's group if it exist and nil otherwise + -- @function [parent=#Unit] getGroup + -- @param #Unit self + -- @return #Group + + --- Returns the unit's callsign - the localized string. + -- @function [parent=#Unit] getCallsign + -- @param #Unit self + -- @return #string + + --- Returns the unit's health. Dead units has health <= 1.0 + -- @function [parent=#Unit] getLife + -- @param #Unit self + -- @return #number + + --- returns the unit's initial health. + -- @function [parent=#Unit] getLife0 + -- @param #Unit self + -- @return #number + + --- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0. + -- @function [parent=#Unit] getFuel + -- @param #Unit self + -- @return #number + + --- Returns the unit ammunition. + -- @function [parent=#Unit] getAmmo + -- @param #Unit self + -- @return #Unit.Ammo + + --- Returns the unit sensors. + -- @function [parent=#Unit] getSensors + -- @param #Unit self + -- @return #Unit.Sensors + + --- Returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors. + -- @function [parent=#Unit] hasSensors + -- @param #Unit self + -- @param #Unit.SensorType sensorType (= nil) Sensor type. + -- @param ... Additional parameters. + -- @return #boolean + -- @usage + -- If sensorType is Unit.SensorType.OPTIC, additional parameters are optic sensor types. Following example checks if the unit has LLTV or IR optics: + -- unit:hasSensors(Unit.SensorType.OPTIC, Unit.OpticType.LLTV, Unit.OpticType.IR) + -- If sensorType is Unit.SensorType.RADAR, additional parameters are radar types. Following example checks if the unit has air search radars: + -- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS) + -- If no additional parameters are specified the function returns true if the unit has at least one sensor of specified type. + -- If sensor type is not specified the function returns true if the unit has at least one sensor of any type. + -- + + --- returns two values: + -- First value indicates if at least one of the unit's radar(s) is on. + -- Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. + -- @function [parent=#Unit] getRadar + -- @param #Unit self + -- @return #boolean, Wrapper.Object#Object + + --- Returns unit descriptor. Descriptor type depends on unit category. + -- @function [parent=#Unit] getDesc + -- @param #Unit self + -- @return #Unit.Desc + + + Unit = {} --#Unit + +end -- Unit + + +do -- Group + + --- Represents group of Units. + -- @type Group + -- @field #ID ID Identifier of a group. It is assigned to a group by Mission Editor automatically. + -- @field #Group.Category Category Enum contains identifiers of group types. + + --- Enum contains identifiers of group types. + -- @type Group.Category + -- @field AIRPLANE + -- @field HELICOPTER + -- @field GROUND + -- @field SHIP + + -- Static Functions + + --- Returns group by the name assigned to the group in Mission Editor. + -- @function [parent=#Group] getByName + -- @param #string name + -- @return #Group + + -- Member Functions + + --- returns true if the group exist or false otherwise. + -- @function [parent=#Group] isExist + -- @param #Group self + -- @return #boolean + + --- Destroys the group and all of its units. + -- @function [parent=#Group] destroy + -- @param #Group self + + --- Returns category of the group. + -- @function [parent=#Group] getCategory + -- @param #Group self + -- @return #Group.Category + + --TODO check coalition.side + + --- Returns the coalition of the group. + -- @function [parent=#Group] getCoalition + -- @param #Group self + -- @return #coalition.side + + --- Returns the group's name. This is the same name assigned to the group in Mission Editor. + -- @function [parent=#Group] getName + -- @param #Group self + -- @return #string + + --- Returns the group identifier. + -- @function [parent=#Group] getID + -- @param #Group self + -- @return #ID + + --- Returns the unit with number unitNumber. If the unit is not exists the function will return nil. + -- @function [parent=#Group] getUnit + -- @param #Group self + -- @param #number unitNumber + -- @return #Unit + + --- Returns current size of the group. If some of the units will be destroyed, As units are destroyed the size of the group will be changed. + -- @function [parent=#Group] getSize + -- @param #Group self + -- @return #number + + --- Returns initial size of the group. If some of the units will be destroyed, initial size of the group will not be changed. Initial size limits the unitNumber parameter for Group.getUnit() function. + -- @function [parent=#Group] getInitialSize + -- @param #Group self + -- @return #number + + --- Returns array of the units present in the group now. Destroyed units will not be enlisted at all. + -- @function [parent=#Group] getUnits + -- @param #Group self + -- @return #list<#Unit> array of Units + + --- Returns controller of the group. + -- @function [parent=#Group] getController + -- @param #Group self + -- @return #Controller + + Group = {} --#Group + +end -- Group + + +do -- AI + + --- @type AI + -- @field #AI.Skill Skill + -- @field #AI.Task Task + -- @field #AI.Option Option + + --- @type AI.Skill + -- @field AVERAGE + -- @field GOOD + -- @field HIGH + -- @field EXCELLENT + -- @field PLAYER + -- @field CLIENT + + --- @type AI.Task + -- @field #AI.Task.WeaponExpend WeaponExpend + -- @field #AI.Task.OrbitPattern OrbitPattern + -- @field #AI.Task.Designation Designation + -- @field #AI.Task.WaypointType WaypointType + -- @field #AI.Task.TurnMethod TurnMethod + -- @field #AI.Task.AltitudeType AltitudeType + -- @field #AI.Task.VehicleFormation VehicleFormation + + --- @type AI.Task.WeaponExpend + -- @field ONE + -- @field TWO + -- @field FOUR + -- @field QUARTER + -- @field HALF + -- @field ALL + + --- @type AI.Task.OrbitPattern + -- @field CIRCLE + -- @field RACE_TRACK + + --- @type AI.Task.Designation + -- @field NO + -- @field AUTO + -- @field WP + -- @field IR_POINTER + -- @field LASER + + --- @type AI.Task.WaypointType + -- @field TAKEOFF + -- @field TAKEOFF_PARKING + -- @field TURNING_POINT + -- @field LAND + + --- @type AI.Task.TurnMethod + -- @field FLY_OVER_POINT + -- @field FIN_POINT + + --- @type AI.Task.AltitudeType + -- @field BARO + -- @field RADIO + + --- @type AI.Task.VehicleFormation + -- @field OFF_ROAD + -- @field ON_ROAD + -- @field RANK + -- @field CONE + -- @field DIAMOND + -- @field VEE + -- @field ECHELON_LEFT + -- @field ECHELON_RIGHT + + --- @type AI.Option + -- @field #AI.Option.Air Air + -- @field #AI.Option.Ground Ground + -- @field #AI.Option.Naval Naval + + --- @type AI.Option.Air + -- @field #AI.Option.Air.id id + -- @field #AI.Option.Air.val val + + --- @type AI.Option.Ground + -- @field #AI.Option.Ground.id id + -- @field #AI.Option.Ground.val val + + --- @type AI.Option.Naval + -- @field #AI.Option.Naval.id id + -- @field #AI.Option.Naval.val val + + --TODO: work on formation + --- @type AI.Option.Air.id + -- @field NO_OPTION + -- @field ROE + -- @field REACTION_ON_THREAT + -- @field RADAR_USING + -- @field FLARE_USING + -- @field FORMATION + -- @field RTB_ON_BINGO + -- @field SILENCE + + --- @type AI.Option.Air.val + -- @field #AI.Option.Air.val.ROE ROE + -- @field #AI.Option.Air.val.REACTION_ON_THREAT REACTION_ON_THREAT + -- @field #AI.Option.Air.val.RADAR_USING RADAR_USING + -- @field #AI.Option.Air.val.FLARE_USING FLARE_USING + + --- @type AI.Option.Air.val.ROE + -- @field WEAPON_FREE + -- @field OPEN_FIRE_WEAPON_FREE + -- @field OPEN_FIRE + -- @field RETURN_FIRE + -- @field WEAPON_HOLD + + --- @type AI.Option.Air.val.REACTION_ON_THREAT + -- @field NO_REACTION + -- @field PASSIVE_DEFENCE + -- @field EVADE_FIRE + -- @field BYPASS_AND_ESCAPE + -- @field ALLOW_ABORT_MISSION + + --- @type AI.Option.Air.val.RADAR_USING + -- @field NEVER + -- @field FOR_ATTACK_ONLY + -- @field FOR_SEARCH_IF_REQUIRED + -- @field FOR_CONTINUOUS_SEARCH + + --- @type AI.Option.Air.val.FLARE_USING + -- @field NEVER + -- @field AGAINST_FIRED_MISSILE + -- @field WHEN_FLYING_IN_SAM_WEZ + -- @field WHEN_FLYING_NEAR_ENEMIES + + --- @type AI.Option.Ground.id + -- @field NO_OPTION + -- @field ROE @{#AI.Option.Ground.val.ROE} + -- @field DISPERSE_ON_ATTACK true or false + -- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE} + + --- @type AI.Option.Ground.val + -- @field #AI.Option.Ground.val.ROE ROE + -- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE + + --- @type AI.Option.Ground.val.ROE + -- @field OPEN_FIRE + -- @field RETURN_FIRE + -- @field WEAPON_HOLD + + --- @type AI.Option.Ground.val.ALARM_STATE + -- @field AUTO + -- @field GREEN + -- @field RED + + --- @type AI.Option.Naval.id + -- @field NO_OPTION + -- @field ROE + + --- @type AI.Option.Naval.val + -- @field #AI.Option.Naval.val.ROE ROE + + --- @type AI.Option.Naval.val.ROE + -- @field OPEN_FIRE + -- @field RETURN_FIRE + -- @field WEAPON_HOLD + + AI = {} --#AI + +end -- AI + + + diff --git a/Moose Development/Moose/Dcs/DCSAirbase.lua b/Moose Development/Moose/Dcs/DCSAirbase.lua deleted file mode 100644 index 192444a06..000000000 --- a/Moose Development/Moose/Dcs/DCSAirbase.lua +++ /dev/null @@ -1,54 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSAirbase - - ---- Represents airbases: airdromes, helipads and ships with flying decks or landing pads. --- @type Airbase --- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject --- @field #Airbase.ID ID Identifier of an airbase. It assigned to an airbase by the Mission Editor automatically. This identifier is used in AI tasks to refer an airbase that exists (spawned and not dead) or not. --- @field #Airbase.Category Category enum contains identifiers of airbase categories. --- @field #Airbase.Desc Desc Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type. - ---- Enum contains identifiers of airbase categories. --- @type Airbase.Category --- @field AIRDROME --- @field HELIPAD --- @field SHIP - ---- Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type. --- @type Airbase.Desc --- @extends #Desc --- @field #Airbase.Category category Category of the airbase type. - ---- Returns airbase by its name. If no airbase found the function will return nil. --- @function [parent=#Airbase] getByName --- @param #string name --- @return #Airbase - ---- Returns airbase descriptor by type name. If no descriptor is found the function will return nil. --- @function [parent=#Airbase] getDescByName --- @param #TypeName typeName Airbase type name. --- @return #Airbase.Desc - ---- Returns Unit that is corresponded to the airbase. Works only for ships. --- @function [parent=#Airbase] getUnit --- @param self --- @return Wrapper.Unit#Unit - ---- Returns identifier of the airbase. --- @function [parent=#Airbase] getID --- @param self --- @return #Airbase.ID - ---- Returns the airbase's callsign - the localized string. --- @function [parent=#Airbase] getCallsign --- @param self --- @return #string - ---- Returns descriptor of the airbase. --- @function [parent=#Airbase] getDesc --- @param self --- @return #Airbase.Desc - - -Airbase = {} --#Airbase diff --git a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua b/Moose Development/Moose/Dcs/DCSCoalitionObject.lua deleted file mode 100644 index b16ca63c2..000000000 --- a/Moose Development/Moose/Dcs/DCSCoalitionObject.lua +++ /dev/null @@ -1,20 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSCoalitionObject - ---- @type CoalitionObject --- @extends Dcs.DCSWrapper.Object#Object - - - ---- Returns coalition of the object. --- @function [parent=#CoalitionObject] getCoalition --- @param #CoalitionObject self --- @return Dcs.DCSTypes#coalition.side - ---- Returns object country. --- @function [parent=#CoalitionObject] getCountry --- @param #CoalitionObject self --- @return #country.id - - -CoalitionObject = {} --#CoalitionObject diff --git a/Moose Development/Moose/Dcs/DCSCommand.lua b/Moose Development/Moose/Dcs/DCSCommand.lua deleted file mode 100644 index 89b2b6f9e..000000000 --- a/Moose Development/Moose/Dcs/DCSCommand.lua +++ /dev/null @@ -1,10 +0,0 @@ ---- @module DCS.DCSCommand - - ---- @type Command --- @field #string id --- @field #Command.params params - ---- @type Command.params - -env.info( "Command defined" ) \ No newline at end of file diff --git a/Moose Development/Moose/Dcs/DCSController.lua b/Moose Development/Moose/Dcs/DCSController.lua deleted file mode 100644 index 99666ef97..000000000 --- a/Moose Development/Moose/Dcs/DCSController.lua +++ /dev/null @@ -1,115 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSController - ---- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C. --- --- This class has 2 types of functions: --- --- * Tasks --- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics. --- @type Controller --- @field #Controller.Detection Detection Enum contains identifiers of surface types. - ---- Enables and disables the controller. --- Note: Now it works only for ground / naval groups! --- @function [parent=#Controller] setOnOff --- @param self --- @param #boolean value Enable / Disable. - --- Tasks - ---- Resets current task and then sets the task to the controller. Task is a table that contains task identifier and task parameters. --- @function [parent=#Controller] setTask --- @param self --- @param #Task task - ---- Resets current task of the controller. --- @function [parent=#Controller] resetTask --- @param self - ---- Pushes the task to the front of the queue and makes the task active. Further call of function Controller.setTask() function will stop current task, clear the queue and set the new task active. If the task queue is empty the function will work like function Controller.setTask() function. --- @function [parent=#Controller] pushTask --- @param self --- @param #Task task - ---- Pops current (front) task from the queue and makes active next task in the queue (if exists). If no more tasks in the queue the function works like function Controller.resetTask() function. Does nothing if the queue is empty. --- @function [parent=#Controller] popTask --- @param self - ---- Returns true if the controller has a task. --- @function [parent=#Controller] hasTask --- @param self --- @return #boolean - --- Commands - ---TODO: describe #Command structure ---- Sets the command to perform by controller. --- @function [parent=#Controller] setCommand --- @param self --- @param #Command command Table that contains command identifier and command parameters. - - --- Behaviours - ---- Sets the option to the controller. --- Option is a pair of identifier and value. Behavior options are global parameters those affect controller behavior in all tasks it performs. --- Option identifiers and values are stored in table AI.Option in subtables Air, Ground and Naval. --- --- OptionId = @{#AI.Option.Air.id} or @{#AI.Option.Ground.id} or @{#AI.Option.Naval.id} --- OptionValue = AI.Option.Air.val[optionName] or AI.Option.Ground.val[optionName] or AI.Option.Naval.val[optionName] --- --- @function [parent=#Controller] setOption --- @param self --- @param #OptionId optionId Option identifier. --- @param #OptionValue optionValue Value of the option. - - --- Detection - ---- Enum contains identifiers of surface types. --- @type Controller.Detection --- @field VISUAL --- @field OPTIC --- @field RADAR --- @field IRST --- @field RWR --- @field DLINK - ---- Detected target. --- @type DetectedTarget --- @field Wrapper.Object#Object object The target --- @field #boolean visible The target is visible --- @field #boolean type The target type is known --- @field #boolean distance Distance to the target is known - - ---- Checks if the target is detected or not. If one or more detection method is specified the function will return true if the target is detected by at least one of these methods. If no detection methods are specified the function will return true if the target is detected by any method. --- @function [parent=#Controller] isTargetDetected --- @param self --- @param Wrapper.Object#Object target Target to check --- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN --- @return #boolean detected True if the target is detected. --- @return #boolean visible Has effect only if detected is true. True if the target is visible now. --- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen. --- @return #boolean type Has effect only if detected is true. True if the target type is known. --- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known. --- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen. --- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen. - - ---- Returns list of detected targets. If one or more detection method is specified the function will return targets which were detected by at least one of these methods. If no detection methods are specified the function will return targets which were detected by any method. --- @function [parent=#Controller] getDetectedTargets --- @param self --- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN --- @return #list<#DetectedTarget> array of DetectedTarget - ---- Know a target. --- @function [parent=#Controller] knowTarget --- @param self --- @param Wrapper.Object#Object object The target. --- @param #boolean type Target type is known. --- @param #boolean distance Distance to target is known. - - -Controller = {} --#Controller \ No newline at end of file diff --git a/Moose Development/Moose/Dcs/DCSGroup.lua b/Moose Development/Moose/Dcs/DCSGroup.lua deleted file mode 100644 index 0e1798e07..000000000 --- a/Moose Development/Moose/Dcs/DCSGroup.lua +++ /dev/null @@ -1,83 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSGroup - ---- Represents group of Units. --- @type Group --- @field #ID ID Identifier of a group. It is assigned to a group by Mission Editor automatically. --- @field #Group.Category Category Enum contains identifiers of group types. - ---- Enum contains identifiers of group types. --- @type Group.Category --- @field AIRPLANE --- @field HELICOPTER --- @field GROUND --- @field SHIP - --- Static Functions - ---- Returns group by the name assigned to the group in Mission Editor. --- @function [parent=#Group] getByName --- @param #string name --- @return #Group - --- Member Functions - ---- returns true if the group exist or false otherwise. --- @function [parent=#Group] isExist --- @param #Group self --- @return #boolean - ---- Destroys the group and all of its units. --- @function [parent=#Group] destroy --- @param #Group self - ---- Returns category of the group. --- @function [parent=#Group] getCategory --- @param #Group self --- @return #Group.Category - ---TODO check coalition.side - ---- Returns the coalition of the group. --- @function [parent=#Group] getCoalition --- @param #Group self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side - ---- Returns the group's name. This is the same name assigned to the group in Mission Editor. --- @function [parent=#Group] getName --- @param #Group self --- @return #string - ---- Returns the group identifier. --- @function [parent=#Group] getID --- @param #Group self --- @return #ID - ---- Returns the unit with number unitNumber. If the unit is not exists the function will return nil. --- @function [parent=#Group] getUnit --- @param #Group self --- @param #number unitNumber --- @return Dcs.DCSWrapper.Unit#Unit - ---- Returns current size of the group. If some of the units will be destroyed, As units are destroyed the size of the group will be changed. --- @function [parent=#Group] getSize --- @param #Group self --- @return #number - ---- Returns initial size of the group. If some of the units will be destroyed, initial size of the group will not be changed. Initial size limits the unitNumber parameter for Group.getUnit() function. --- @function [parent=#Group] getInitialSize --- @param #Group self --- @return #number - ---- Returns array of the units present in the group now. Destroyed units will not be enlisted at all. --- @function [parent=#Group] getUnits --- @param #Group self --- @return #list array of Units - ---- Returns controller of the group. --- @function [parent=#Group] getController --- @param #Group self --- @return Controller#Controller - -Group = {} --#Group - diff --git a/Moose Development/Moose/Dcs/DCSObject.lua b/Moose Development/Moose/Dcs/DCSObject.lua deleted file mode 100644 index fb09234d4..000000000 --- a/Moose Development/Moose/Dcs/DCSObject.lua +++ /dev/null @@ -1,73 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSObject - ---- @type Object --- @field #Object.Category Category --- @field #Object.Desc Desc - ---- @type Object.Category --- @field UNIT --- @field WEAPON --- @field STATIC --- @field SCENERY --- @field BASE - ---- @type Object.Desc --- @extends #Desc --- @field #number life initial life level --- @field #Box3 box bounding box of collision geometry - ---- @function [parent=#Object] isExist --- @param #Object self --- @return #boolean - ---- @function [parent=#Object] destroy --- @param #Object self - ---- @function [parent=#Object] getCategory --- @param #Object self --- @return #Object.Category - ---- Returns type name of the Object. --- @function [parent=#Object] getTypeName --- @param #Object self --- @return #string - ---- Returns object descriptor. --- @function [parent=#Object] getDesc --- @param #Object self --- @return #Object.Desc - ---- Returns true if the object belongs to the category. --- @function [parent=#Object] hasAttribute --- @param #Object self --- @param #AttributeName attributeName Attribute name to check. --- @return #boolean - ---- Returns name of the object. This is the name that is assigned to the object in the Mission Editor. --- @function [parent=#Object] getName --- @param #Object self --- @return #string - ---- Returns object coordinates for current time. --- @function [parent=#Object] getPoint --- @param #Object self --- @return #Vec3 - ---- Returns object position for current time. --- @function [parent=#Object] getPosition --- @param #Object self --- @return #Position3 - ---- Returns the unit's velocity vector. --- @function [parent=#Object] getVelocity --- @param #Object self --- @return #Vec3 - ---- Returns true if the unit is in air. --- @function [parent=#Object] inAir --- @param #Object self --- @return #boolean - -Object = {} --#Object - diff --git a/Moose Development/Moose/Dcs/DCSStaticObject.lua b/Moose Development/Moose/Dcs/DCSStaticObject.lua deleted file mode 100644 index e01f017da..000000000 --- a/Moose Development/Moose/Dcs/DCSStaticObject.lua +++ /dev/null @@ -1,34 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSStaticObject - - -------------------------------------------------------------------------------- --- @module StaticObject --- @extends CoalitionWrapper.Object#CoalitionObject - ---- Represents static object added in the Mission Editor. --- @type StaticObject --- @field #StaticObject.ID ID Identifier of a StaticObject. It assigned to an StaticObject by the Mission Editor automatically. --- @field #StaticObject.Desc Desc Descriptor of StaticObject and Unit are equal. StaticObject is just a passive variant of Unit. - ---- StaticObject descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type. --- @type StaticObject.Desc --- @extends Wrapper.Unit#Unit.Desc - ---- Returns static object by its name. If no static object found nil will be returned. --- @function [parent=#StaticObject] getByName --- @param #string name Name of static object to find. --- @return #StaticObject - ---- returns identifier of the static object. --- @function [parent=#StaticObject] getID --- @param #StaticObject self --- @return #StaticObject.ID - ---- Returns descriptor of the StaticObject. --- @function [parent=#StaticObject] getDesc --- @param #StaticObject self --- @return #StaticObject.Desc - - -StaticObject = {} --#StaticObject diff --git a/Moose Development/Moose/Dcs/DCSTask.lua b/Moose Development/Moose/Dcs/DCSTask.lua deleted file mode 100644 index 825b9f0bc..000000000 --- a/Moose Development/Moose/Dcs/DCSTask.lua +++ /dev/null @@ -1,15 +0,0 @@ ---- @module DCS.DCSTask - - ---- A task descriptor (internal structure for DCS World) --- @type Task --- @field #string id --- @field #Task.param param - ---- @type Task.param - ---- List of @{#Task} --- @type TaskArray --- @list <#Task> - -env.info( "Task defined" ) diff --git a/Moose Development/Moose/Dcs/DCSTime.lua b/Moose Development/Moose/Dcs/DCSTime.lua deleted file mode 100644 index 766f53317..000000000 --- a/Moose Development/Moose/Dcs/DCSTime.lua +++ /dev/null @@ -1,8 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSTime - ---- @type ModelTime --- @extends #number - ---- @type Time --- @extends #number \ No newline at end of file diff --git a/Moose Development/Moose/Dcs/DCSTypes.lua b/Moose Development/Moose/Dcs/DCSTypes.lua deleted file mode 100644 index bb00369e4..000000000 --- a/Moose Development/Moose/Dcs/DCSTypes.lua +++ /dev/null @@ -1,246 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSTypes - - - ---- Time is given in seconds. --- @type Time --- @extends #number - ---- Model time is the time that drives the simulation. Model time may be stopped, accelerated and decelerated relative real time. --- @type ModelTime --- @extends #number - ---- Mission time is a model time plus time of the mission start. --- @type MissionTime --- @extends #number - - ---- Distance is given in meters. --- @type Distance --- @extends #number - ---- Angle is given in radians. --- @type Angle --- @extends #number - ---- Azimuth is an angle of rotation around world axis y counter-clockwise. --- @type Azimuth --- @extends #number - ---- Mass is given in kilograms. --- @type Mass --- @extends #number - ---- Vec3 type is a 3D-vector. --- DCS world has 3-dimensional coordinate system. DCS ground is an infinite plain. --- @type Vec3 --- @field #Distance x is directed to the north --- @field #Distance z is directed to the east --- @field #Distance y is directed up - ---- Vec2 is a 2D-vector for the ground plane as a reference plane. --- @type Vec2 --- @field #Distance x Vec2.x = Vec3.x --- @field #Distance y Vec2.y = Vec3.z - ---- Position is a composite structure. It consists of both coordinate vector and orientation matrix. Position3 (also known as "Pos3" for short) is a table that has following format: --- @type Position3 --- @field #Vec3 p --- @field #Vec3 x --- @field #Vec3 y --- @field #Vec3 z - ---- 3-dimensional box. --- @type Box3 --- @field #Vec3 min --- @field #Vec3 max - ---- Each object belongs to a type. Object type is a named couple of properties those independent of mission and common for all units of the same type. Name of unit type is a string. Samples of unit type: "Su-27", "KAMAZ" and "M2 Bradley". --- @type TypeName --- @extends #string - ---- AttributeName = string --- Each object type may have attributes. --- Attributes are enlisted in ./Scripts/Database/db_attributes.Lua. --- To know what attributes the object type has, look for the unit type script in sub-directories planes/, helicopter/s, vehicles, navy/ of ./Scripts/Database/ directory. --- @type AttributeName --- @extends #string - ---- List of @{#AttributeName} --- @type AttributeNameArray --- @list <#AttributeName> - ---- @type AI --- @field #AI.Skill Skill --- @field #AI.Task Task --- @field #AI.Option Option - ---- @type AI.Skill --- @field AVERAGE --- @field GOOD --- @field HIGH --- @field EXCELLENT --- @field PLAYER --- @field CLIENT - ---- @type AI.Task --- @field #AI.Task.WeaponExpend WeaponExpend --- @field #AI.Task.OrbitPattern OrbitPattern --- @field #AI.Task.Designation Designation --- @field #AI.Task.WaypointType WaypointType --- @field #AI.Task.TurnMethod TurnMethod --- @field #AI.Task.AltitudeType AltitudeType --- @field #AI.Task.VehicleFormation VehicleFormation - ---- @type AI.Task.WeaponExpend --- @field ONE --- @field TWO --- @field FOUR --- @field QUARTER --- @field HALF --- @field ALL - ---- @type AI.Task.OrbitPattern --- @field CIRCLE --- @field RACE_TRACK - ---- @type AI.Task.Designation --- @field NO --- @field AUTO --- @field WP --- @field IR_POINTER --- @field LASER - ---- @type AI.Task.WaypointType --- @field TAKEOFF --- @field TAKEOFF_PARKING --- @field TURNING_POINT --- @field LAND - ---- @type AI.Task.TurnMethod --- @field FLY_OVER_POINT --- @field FIN_POINT - ---- @type AI.Task.AltitudeType --- @field BARO --- @field RADIO - ---- @type AI.Task.VehicleFormation --- @field OFF_ROAD --- @field ON_ROAD --- @field RANK --- @field CONE --- @field DIAMOND --- @field VEE --- @field ECHELON_LEFT --- @field ECHELON_RIGHT - ---- @type AI.Option --- @field #AI.Option.Air Air --- @field #AI.Option.Ground Ground --- @field #AI.Option.Naval Naval - ---- @type AI.Option.Air --- @field #AI.Option.Air.id id --- @field #AI.Option.Air.val val - ---- @type AI.Option.Ground --- @field #AI.Option.Ground.id id --- @field #AI.Option.Ground.val val - ---- @type AI.Option.Naval --- @field #AI.Option.Naval.id id --- @field #AI.Option.Naval.val val - ---TODO: work on formation ---- @type AI.Option.Air.id --- @field NO_OPTION --- @field ROE --- @field REACTION_ON_THREAT --- @field RADAR_USING --- @field FLARE_USING --- @field FORMATION --- @field RTB_ON_BINGO --- @field SILENCE - ---- @type AI.Option.Air.val --- @field #AI.Option.Air.val.ROE ROE --- @field #AI.Option.Air.val.REACTION_ON_THREAT REACTION_ON_THREAT --- @field #AI.Option.Air.val.RADAR_USING RADAR_USING --- @field #AI.Option.Air.val.FLARE_USING FLARE_USING - ---- @type AI.Option.Air.val.ROE --- @field WEAPON_FREE --- @field OPEN_FIRE_WEAPON_FREE --- @field OPEN_FIRE --- @field RETURN_FIRE --- @field WEAPON_HOLD - ---- @type AI.Option.Air.val.REACTION_ON_THREAT --- @field NO_REACTION --- @field PASSIVE_DEFENCE --- @field EVADE_FIRE --- @field BYPASS_AND_ESCAPE --- @field ALLOW_ABORT_MISSION - ---- @type AI.Option.Air.val.RADAR_USING --- @field NEVER --- @field FOR_ATTACK_ONLY --- @field FOR_SEARCH_IF_REQUIRED --- @field FOR_CONTINUOUS_SEARCH - ---- @type AI.Option.Air.val.FLARE_USING --- @field NEVER --- @field AGAINST_FIRED_MISSILE --- @field WHEN_FLYING_IN_SAM_WEZ --- @field WHEN_FLYING_NEAR_ENEMIES - ---- @type AI.Option.Ground.id --- @field NO_OPTION --- @field ROE @{#AI.Option.Ground.val.ROE} --- @field DISPERSE_ON_ATTACK true or false --- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE} - ---- @type AI.Option.Ground.val --- @field #AI.Option.Ground.val.ROE ROE --- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE - ---- @type AI.Option.Ground.val.ROE --- @field OPEN_FIRE --- @field RETURN_FIRE --- @field WEAPON_HOLD - ---- @type AI.Option.Ground.val.ALARM_STATE --- @field AUTO --- @field GREEN --- @field RED - ---- @type AI.Option.Naval.id --- @field NO_OPTION --- @field ROE - ---- @type AI.Option.Naval.val --- @field #AI.Option.Naval.val.ROE ROE - ---- @type AI.Option.Naval.val.ROE --- @field OPEN_FIRE --- @field RETURN_FIRE --- @field WEAPON_HOLD - -AI = {} --#AI - - ---- @type Desc --- @field #TypeName typeName type name --- @field #string displayName localized display name --- @field #table attributes object type attributes - ---- A distance type --- @type Distance - ---- An angle type --- @type Angle - -env.info( 'AI types created' ) - diff --git a/Moose Development/Moose/Dcs/DCSUnit.lua b/Moose Development/Moose/Dcs/DCSUnit.lua deleted file mode 100644 index 723b653d1..000000000 --- a/Moose Development/Moose/Dcs/DCSUnit.lua +++ /dev/null @@ -1,241 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSUnit - ---- @type Unit --- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject --- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically. --- @field #Unit.Category Category --- @field #Unit.RefuelingSystem RefuelingSystem --- @field #Unit.SensorType SensorType --- @field #Unit.OpticType OpticType --- @field #Unit.RadarType RadarType --- @field #Unit.Desc Desc --- @field #Unit.DescAircraft DescAircraft --- @field #Unit.DescAirplane DescAirplane --- @field #Unit.DescHelicopter DescHelicopter --- @field #Unit.DescVehicle DescVehicle --- @field #Unit.DescShip DescShip --- @field #Unit.AmmoItem AmmoItem --- @field #list<#Unit.AmmoItem> Ammo --- @field #Unit.Sensor Sensor --- @field #Unit.Optic Optic --- @field #Unit.Radar Radar --- @field #Unit.IRST IRST - - ---- Enum that stores unit categories. --- @type Unit.Category --- @field AIRPLANE --- @field HELICOPTER --- @field GROUND_UNIT --- @field SHIP --- @field STRUCTURE - ---- Enum that stores aircraft refueling system types. --- @type Unit.RefuelingSystem --- @field BOOM_AND_RECEPTACLE --- @field PROBE_AND_DROGUE - ---- Enum that stores sensor types. --- @type Unit.SensorType --- @field OPTIC --- @field RADAR --- @field IRST --- @field RWR - ---- Enum that stores types of optic sensors. --- @type Unit.OpticType --- @field TV TV-sensor --- @field LLTV Low-level TV-sensor --- @field IR Infra-Red optic sensor - ---- Enum that stores radar types. --- @type Unit.RadarType --- @field AS air search radar --- @field SS surface/land search radar - - ---- A unit descriptor. --- @type Unit.Desc --- @extends Wrapper.Object#Object.Desc --- @field #Unit.Category category Unit Category --- @field #Mass massEmpty mass of empty unit --- @field #number speedMax istance / Time, --maximal velocity - ---- An aircraft descriptor. --- @type Unit.DescAircraft --- @extends Wrapper.Unit#Unit.Desc --- @field #Mass fuelMassMax maximal inner fuel mass --- @field #Distance range Operational range --- @field #Distance Hmax Ceiling --- @field #number VyMax #Distance / #Time, --maximal climb rate --- @field #number NyMin minimal safe acceleration --- @field #number NyMax maximal safe acceleration --- @field #Unit.RefuelingSystem tankerType refueling system type - ---- An airplane descriptor. --- @type Unit.DescAirplane --- @extends Wrapper.Unit#Unit.DescAircraft --- @field #number speedMax0 Distance / Time maximal TAS at ground level --- @field #number speedMax10K Distance / Time maximal TAS at altitude of 10 km - ---- A helicopter descriptor. --- @type Unit.DescHelicopter --- @extends Wrapper.Unit#Unit.DescAircraft --- @field #Distance HmaxStat static ceiling - ---- A vehicle descriptor. --- @type Unit.DescVehicle --- @extends Wrapper.Unit#Unit.Desc --- @field #Angle maxSlopeAngle maximal slope angle --- @field #boolean riverCrossing can the vehicle cross a rivers - ---- A ship descriptor. --- @type Unit.DescShip --- @extends #Unit.Desc - ---- ammunition item: "type-count" pair. --- @type Unit.AmmoItem --- @field #Weapon.Desc desc ammunition descriptor --- @field #number count ammunition count - ---- A unit sensor. --- @type Unit.Sensor --- @field #TypeName typeName --- @field #Unit.SensorType type - ---- An optic sensor. --- @type Unit.Optic --- @extends Wrapper.Unit#Unit.Sensor --- @field #Unit.OpticType opticType - ---- A radar. --- @type Unit.Radar --- @extends Wrapper.Unit#Unit.Sensor --- @field #Distance detectionDistanceRBM detection distance for RCS=1m^2 in real-beam mapping mode, nil if radar doesn't support surface/land search --- @field #Distance detectionDistanceHRM detection distance for RCS=1m^2 in high-resolution mapping mode, nil if radar has no HRM --- @field #Unit.Radar.detectionDistanceAir detectionDistanceAir detection distance for RCS=1m^2 airborne target, nil if radar doesn't support air search - ---- @type Unit.Radar.detectionDistanceAir --- @field #Unit.Radar.detectionDistanceAir.upperHemisphere upperHemisphere --- @field #Unit.Radar.detectionDistanceAir.lowerHemisphere lowerHemisphere - ---- @type Unit.Radar.detectionDistanceAir.upperHemisphere --- @field #Distance headOn --- @field #Distance tailOn - ---- @type Unit.Radar.detectionDistanceAir.lowerHemisphere --- @field #Distance headOn --- @field #Distance tailOn - ---- An IRST. --- @type Wrapper.Unit#Unit.IRST --- @extends Unit.Sensor --- @field #Distance detectionDistanceIdle detection of tail-on target with heat signature = 1 in upper hemisphere, engines are in idle --- @field #Distance detectionDistanceMaximal ..., engines are in maximal mode --- @field #Distance detectionDistanceAfterburner ..., engines are in afterburner mode - ---- An RWR. --- @type Unit.RWR --- @extends Wrapper.Unit#Unit.Sensor - ---- table that stores all unit sensors. --- TODO @type Sensors --- - - ---- Returns unit object by the name assigned to the unit in Mission Editor. If there is unit with such name or the unit is destroyed the function will return nil. The function provides access to non-activated units too. --- @function [parent=#Unit] getByName --- @param #string name --- @return #Unit - ---- Returns if the unit is activated. --- @function [parent=#Unit] isActive --- @param #Unit self --- @return #boolean - ---- Returns name of the player that control the unit or nil if the unit is controlled by A.I. --- @function [parent=#Unit] getPlayerName --- @param #Unit self --- @return #string - ---- returns the unit's unique identifier. --- @function [parent=#Unit] getID --- @param #Unit self --- @return #Unit.ID - - ---- Returns the unit's number in the group. The number is the same number the unit has in ME. It may not be changed during the mission. If any unit in the group is destroyed, the numbers of another units will not be changed. --- @function [parent=#Unit] getNumber --- @param #Unit self --- @return #number - ---- Returns controller of the unit if it exist and nil otherwise --- @function [parent=#Unit] getController --- @param #Unit self --- @return #Controller - ---- Returns the unit's group if it exist and nil otherwise --- @function [parent=#Unit] getGroup --- @param #Unit self --- @return Dcs.DCSWrapper.Group#Group - ---- Returns the unit's callsign - the localized string. --- @function [parent=#Unit] getCallsign --- @param #Unit self --- @return #string - ---- Returns the unit's health. Dead units has health <= 1.0 --- @function [parent=#Unit] getLife --- @param #Unit self --- @return #number - ---- returns the unit's initial health. --- @function [parent=#Unit] getLife0 --- @param #Unit self --- @return #number - ---- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0. --- @function [parent=#Unit] getFuel --- @param #Unit self --- @return #number - ---- Returns the unit ammunition. --- @function [parent=#Unit] getAmmo --- @param #Unit self --- @return #Unit.Ammo - ---- Returns the unit sensors. --- @function [parent=#Unit] getSensors --- @param #Unit self --- @return #Unit.Sensors - ---- Returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors. --- @function [parent=#Unit] hasSensors --- @param #Unit self --- @param #Unit.SensorType sensorType (= nil) Sensor type. --- @param ... Additional parameters. --- @return #boolean --- @usage --- If sensorType is Unit.SensorType.OPTIC, additional parameters are optic sensor types. Following example checks if the unit has LLTV or IR optics: --- unit:hasSensors(Unit.SensorType.OPTIC, Unit.OpticType.LLTV, Unit.OpticType.IR) --- If sensorType is Unit.SensorType.RADAR, additional parameters are radar types. Following example checks if the unit has air search radars: --- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS) --- If no additional parameters are specified the function returns true if the unit has at least one sensor of specified type. --- If sensor type is not specified the function returns true if the unit has at least one sensor of any type. --- - ---- returns two values: --- First value indicates if at least one of the unit's radar(s) is on. --- Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. --- @function [parent=#Unit] getRadar --- @param #Unit self --- @return #boolean, Wrapper.Object#Object - ---- Returns unit descriptor. Descriptor type depends on unit category. --- @function [parent=#Unit] getDesc --- @param #Unit self --- @return #Unit.Desc - - -Unit = {} --#Unit diff --git a/Moose Development/Moose/Dcs/DCSVec3.lua b/Moose Development/Moose/Dcs/DCSVec3.lua deleted file mode 100644 index 0128e1a7a..000000000 --- a/Moose Development/Moose/Dcs/DCSVec3.lua +++ /dev/null @@ -1,11 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSVec3 - - - ---- --- @type Vec3 --- @field #number x --- @field #number y --- @field #number z -Vec3 = {} \ No newline at end of file diff --git a/Moose Development/Moose/Dcs/DCSZone.lua b/Moose Development/Moose/Dcs/DCSZone.lua deleted file mode 100644 index 6070d8cc9..000000000 --- a/Moose Development/Moose/Dcs/DCSZone.lua +++ /dev/null @@ -1,10 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSZone - - - ---- --- @type Zone --- @field DCSVec3#Vec3 point --- @field #number radius -Zone = {} diff --git a/Moose Development/Moose/Dcs/DCScoalition.lua b/Moose Development/Moose/Dcs/DCScoalition.lua deleted file mode 100644 index 309492fd0..000000000 --- a/Moose Development/Moose/Dcs/DCScoalition.lua +++ /dev/null @@ -1,16 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCScoalition - ---- @type coalition --- @field #coalition.side side - ---- @type coalition.side --- @field NEUTRAL --- @field RED --- @field BLUE - ---- @function [parent=#coalition] getCountryCoalition --- @param #number countryId --- @return #number coalitionId - -coalition = coalition -- #coalition diff --git a/Moose Development/Moose/Dcs/DCScountry.lua b/Moose Development/Moose/Dcs/DCScountry.lua deleted file mode 100644 index 32ff4c34e..000000000 --- a/Moose Development/Moose/Dcs/DCScountry.lua +++ /dev/null @@ -1,27 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCScountry - ---- @type country --- @field #country.id id -country = country -- #country - ---- @type country.id --- @field RUSSIA --- @field UKRAINE --- @field USA --- @field TURKEY --- @field UK --- @field FRANCE --- @field GERMANY --- @field CANADA --- @field SPAIN --- @field THE_NETHERLANDS --- @field BELGIUM --- @field NORWAY --- @field DENMARK --- @field ISRAEL --- @field GEORGIA --- @field INSURGENTS --- @field ABKHAZIA --- @field SOUTH_OSETIA --- @field ITALY diff --git a/Moose Development/Moose/Dcs/DCSenv.lua b/Moose Development/Moose/Dcs/DCSenv.lua deleted file mode 100644 index 8b71f0f9e..000000000 --- a/Moose Development/Moose/Dcs/DCSenv.lua +++ /dev/null @@ -1,27 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSenv - ---- @type env - ---- Add message to simulator log with caption "INFO". Message box is optional. --- @function [parent=#env] info --- @field #string message message string to add to log. --- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional. - ---- Add message to simulator log with caption "WARNING". Message box is optional. --- @function [parent=#env] warning --- @field #string message message string to add to log. --- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional. - ---- Add message to simulator log with caption "ERROR". Message box is optional. --- @function [parent=#env] error --- @field #string message message string to add to log. --- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional. - ---- Enables/disables appearance of message box each time lua error occurs. --- @function [parent=#env] setErrorMessageBoxEnabled --- @field #boolean on if true message box appearance is enabled. - - - -env = {} --#env diff --git a/Moose Development/Moose/Dcs/DCSland.lua b/Moose Development/Moose/Dcs/DCSland.lua deleted file mode 100644 index 5e4d2c77c..000000000 --- a/Moose Development/Moose/Dcs/DCSland.lua +++ /dev/null @@ -1,26 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.land - ---- @type land --- @field #land.SurfaceType SurfaceType - - ---- @type land.SurfaceType --- @field LAND --- @field SHALLOW_WATER --- @field WATER --- @field ROAD --- @field RUNWAY - ---- Returns altitude MSL of the point. --- @function [parent=#land] getHeight --- @param #Vec2 point point on the ground. --- @return Dcs.DCSTypes#Distance - ---- returns surface type at the given point. --- @function [parent=#land] getSurfaceType --- @param #Vec2 point Point on the land. --- @return #land.SurfaceType - - -land = {} --#land \ No newline at end of file diff --git a/Moose Development/Moose/Dcs/DCStimer.lua b/Moose Development/Moose/Dcs/DCStimer.lua deleted file mode 100644 index 91fb3b93d..000000000 --- a/Moose Development/Moose/Dcs/DCStimer.lua +++ /dev/null @@ -1,45 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCStimer - ---- @type timer - - ---- Returns model time in seconds. --- @function [parent=#timer] getTime --- @return #Time - ---- Returns mission time in seconds. --- @function [parent=#timer] getAbsTime --- @return #Time - ---- Returns mission start time in seconds. --- @function [parent=#timer] getTime0 --- @return #Time - ---- Schedules function to call at desired model time. --- Time function FunctionToCall(any argument, Time time) --- --- ... --- --- return ... --- --- end --- --- Must return model time of next call or nil. Note that the DCS scheduler calls the function in protected mode and any Lua errors in the called function will be trapped and not reported. If the function triggers a Lua error then it will be terminated and not scheduled to run again. --- @function [parent=#timer] scheduleFunction --- @param #FunctionToCall functionToCall Lua-function to call. Must have prototype of FunctionToCall. --- @param functionArgument Function argument of any type to pass to functionToCall. --- @param #Time time Model time of the function call. --- @return functionId - ---- Re-schedules function to call at another model time. --- @function [parent=#timer] setFunctionTime --- @param functionId Lua-function to call. Must have prototype of FunctionToCall. --- @param #Time time Model time of the function call. - - ---- Removes the function from schedule. --- @function [parent=#timer] removeFunction --- @param functionId Function identifier to remove from schedule - -timer = {} --#timer diff --git a/Moose Development/Moose/Dcs/DCStrigger.lua b/Moose Development/Moose/Dcs/DCStrigger.lua deleted file mode 100644 index c1638c5bb..000000000 --- a/Moose Development/Moose/Dcs/DCStrigger.lua +++ /dev/null @@ -1,8 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCStrigger - - -trigger = {} --#timer - - - \ No newline at end of file diff --git a/Moose Development/Moose/Dcs/DCSworld.lua b/Moose Development/Moose/Dcs/DCSworld.lua deleted file mode 100644 index 80fed64a2..000000000 --- a/Moose Development/Moose/Dcs/DCSworld.lua +++ /dev/null @@ -1,35 +0,0 @@ -------------------------------------------------------------------------------- --- @module DCS.DCSWorld - ---- @type world --- @field #world.event event - - ---- @type world.event --- @field S_EVENT_INVALID --- @field S_EVENT_SHOT --- @field S_EVENT_HIT --- @field S_EVENT_TAKEOFF --- @field S_EVENT_LAND --- @field S_EVENT_CRASH --- @field S_EVENT_EJECTION --- @field S_EVENT_REFUELING --- @field S_EVENT_DEAD --- @field S_EVENT_PILOT_DEAD --- @field S_EVENT_BASE_CAPTURED --- @field S_EVENT_MISSION_START --- @field S_EVENT_MISSION_END --- @field S_EVENT_TOOK_CONTROL --- @field S_EVENT_REFUELING_STOP --- @field S_EVENT_BIRTH --- @field S_EVENT_HUMAN_FAILURE --- @field S_EVENT_ENGINE_STARTUP --- @field S_EVENT_ENGINE_SHUTDOWN --- @field S_EVENT_PLAYER_ENTER_UNIT --- @field S_EVENT_PLAYER_LEAVE_UNIT --- @field S_EVENT_PLAYER_COMMENT --- @field S_EVENT_SHOOTING_START --- @field S_EVENT_SHOOTING_END --- @field S_EVENT_MAX - -world = {} --#world \ No newline at end of file diff --git a/Moose Development/Moose/Functional/ATC_Ground.lua b/Moose Development/Moose/Functional/ATC_Ground.lua index 707a8ff24..af4ac91bf 100644 --- a/Moose Development/Moose/Functional/ATC_Ground.lua +++ b/Moose Development/Moose/Functional/ATC_Ground.lua @@ -12,7 +12,7 @@ -- === -- -- @module Functional.ATC_Ground - +-- @image Air_Traffic_Control_Ground_Operations.JPG --- @type ATC_GROUND -- @field Core.Set#SET_CLIENT SetClient diff --git a/Moose Development/Moose/Functional/CleanUp.lua b/Moose Development/Moose/Functional/CleanUp.lua index 04f4be5b6..63bda13d6 100644 --- a/Moose Development/Moose/Functional/CleanUp.lua +++ b/Moose Development/Moose/Functional/CleanUp.lua @@ -198,7 +198,7 @@ end --- Destroys a missile from the simulator, but checks first if it is still existing! -- @param #CLEANUP_AIRBASE self --- @param Dcs.DCSTypes#Weapon MissileObject +-- @param DCS#Weapon MissileObject function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject ) self:F( { MissileObject } ) @@ -288,9 +288,9 @@ function CLEANUP_AIRBASE.__:OnEventHit( Event ) end end ---- Add the @{DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp. +--- Add the @{DCS#Unit} to the CleanUpList for CleanUp. -- @param #CLEANUP_AIRBASE self --- @param Wrapper.Unit#UNIT CleanUpUnit +-- @param DCS#UNIT CleanUpUnit -- @oaram #string CleanUpUnitName function CLEANUP_AIRBASE.__:AddForCleanUp( CleanUpUnit, CleanUpUnitName ) self:F( { CleanUpUnit, CleanUpUnitName } ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 30de4a170..9e38a5b45 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -37,7 +37,7 @@ do -- DETECTION_BASE --- @type DETECTION_BASE -- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. - -- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. + -- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected. -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. -- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. -- @field #number DetectionRun @@ -553,7 +553,7 @@ do -- DETECTION_BASE --self:F( DetectedTargets ) for DetectionObjectID, Detection in pairs( DetectedTargets ) do - local DetectedObject = Detection.object -- Dcs.DCSWrapper.Object#Object + local DetectedObject = Detection.object -- DCS#Object if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then -- and ( DetectedObject:getCategory() == Object.Category.UNIT or DetectedObject:getCategory() == Object.Category.STATIC ) then @@ -891,7 +891,7 @@ do -- DETECTION_BASE -- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) -- -- @param #DETECTION_BASE self - -- @param #list FilterCategories The Categories entries + -- @param #list FilterCategories The Categories entries -- @return #DETECTION_BASE self function DETECTION_BASE:FilterCategories( FilterCategories ) self:F2() @@ -1165,7 +1165,7 @@ do -- DETECTION_BASE --- Returns if there are friendlies nearby the FAC units ... -- @param #DETECTION_BASE self -- @param DetectedItem - -- @param Dcs.DCSUnit#Unit.Category Category The category of the unit. + -- @param DCS#Unit.Category Category The category of the unit. -- @return #boolean true if there are friendlies nearby function DETECTION_BASE:IsFriendliesNearBy( DetectedItem, Category ) --self:F( { "FriendliesNearBy Test", DetectedItem.FriendliesNearBy } ) @@ -1175,7 +1175,7 @@ do -- DETECTION_BASE --- Returns friendly units nearby the FAC units ... -- @param #DETECTION_BASE self -- @param DetectedItem - -- @param Dcs.DCSUnit#Unit.Category Category The category of the unit. + -- @param DCS#Unit.Category Category The category of the unit. -- @return #map<#string,Wrapper.Unit#UNIT> The map of Friendly UNITs. function DETECTION_BASE:GetFriendliesNearBy( DetectedItem, Category ) @@ -1248,7 +1248,7 @@ do -- DETECTION_BASE } - --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit + --- @param DCS#Unit FoundDCSUnit -- @param Wrapper.Group#GROUP ReportGroup -- @param Core.Set#SET_GROUP ReportSetGroup local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) @@ -1809,7 +1809,7 @@ do -- DETECTION_UNITS -- Beware that when the amount of units detected is large, the DetectedItems list will be large also. -- -- @type DETECTION_UNITS - -- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are detected. + -- @field DCS#Distance DetectionRange The range till which targets are detected. -- @extends #DETECTION_BASE DETECTION_UNITS = { ClassName = "DETECTION_UNITS", @@ -2294,7 +2294,7 @@ do -- DETECTION_AREAS -- the detected zones when a new detection has taken place. -- -- @type DETECTION_AREAS - -- @field Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. + -- @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, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. -- @extends #DETECTION_BASE DETECTION_AREAS = { @@ -2306,7 +2306,7 @@ do -- DETECTION_AREAS --- DETECTION_AREAS constructor. -- @param #DETECTION_AREAS self -- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. - -- @param Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. + -- @param DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. -- @return #DETECTION_AREAS function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange ) diff --git a/Moose Development/Moose/Functional/Escort.lua b/Moose Development/Moose/Functional/Escort.lua index b2c27bdc9..c76742736 100644 --- a/Moose Development/Moose/Functional/Escort.lua +++ b/Moose Development/Moose/Functional/Escort.lua @@ -126,8 +126,8 @@ -- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. -- @field #number FollowDistance The current follow distance. -- @field #boolean ReportTargets If true, nearby targets are reported. --- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. --- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. +-- @Field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. +-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. -- @field FunctionalMENU_GROUPDETECTION_BASE Detection ESCORT = { ClassName = "ESCORT", @@ -294,7 +294,7 @@ end --- Defines a menu slot to let the escort Join and Follow you at a certain distance. -- This menu will appear under **Navigation**. -- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client. +-- @param DCS#Distance Distance The distance in meters that the escort needs to follow the client. -- @return #ESCORT function ESCORT:MenuFollowAt( Distance ) self:F(Distance) @@ -319,8 +319,8 @@ end --- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. -- This menu will appear under **Hold position**. -- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. -- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. -- @return #ESCORT -- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. @@ -380,8 +380,8 @@ end --- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds. -- This menu will appear under **Navigation**. -- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. -- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. -- @return #ESCORT -- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. @@ -441,8 +441,8 @@ end --- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds. -- This menu will appear under **Scan targets**. -- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. -- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. -- @return #ESCORT function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) @@ -566,7 +566,7 @@ end -- This menu will appear under **Report targets**. -- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed. -- @param #ESCORT self --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. +-- @param DCS#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. -- @return #ESCORT function ESCORT:MenuReportTargets( Seconds ) self:F( { Seconds } ) @@ -736,7 +736,7 @@ end -- @param Functional.Escort#ESCORT self -- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Client#CLIENT EscortClient --- @param Dcs.DCSTypes#Distance Distance +-- @param DCS#Distance Distance function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance ) self:F( { EscortGroup, EscortClient, Distance } ) diff --git a/Moose Development/Moose/Functional/Movement.lua b/Moose Development/Moose/Functional/Movement.lua index 8aabf0130..f01dad139 100644 --- a/Moose Development/Moose/Functional/Movement.lua +++ b/Moose Development/Moose/Functional/Movement.lua @@ -8,6 +8,7 @@ -- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units -- on defined intervals (currently every minute). -- @module Functional.Movement +-- @image MOOSE.JPG --- the MOVEMENT class -- @type MOVEMENT diff --git a/Moose Development/Moose/Functional/Protect.lua b/Moose Development/Moose/Functional/Protect.lua deleted file mode 100644 index 00645edbe..000000000 --- a/Moose Development/Moose/Functional/Protect.lua +++ /dev/null @@ -1,305 +0,0 @@ ---- **Functional** -- The PROTECT class handles the protection of objects, which can be zones, units, scenery. --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: **MillerTime** --- --- === --- --- @module Functional.Protect - ---- @type PROTECT.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-) --- @extends Core.Fsm#FSM - ---- @type PROTECT --- @extends #PROTECT.__ - ---- # PROTECT, extends @{Core.Base#BASE} --- --- @field #PROTECT -PROTECT = { - ClassName = "PROTECT", -} - ---- Get the ProtectZone --- @param #PROTECT self --- @return Core.Zone#ZONE_BASE -function PROTECT:GetProtectZone() - return self.ProtectZone -end - - ---- Get the name of the ProtectZone --- @param #PROTECT self --- @return #string -function PROTECT:GetProtectZoneName() - return self.ProtectZone:GetName() -end - - ---- Set the owning coalition of the zone. --- @param #PROTECT self --- @param DCSCoalition.DCSCoalition#coalition Coalition -function PROTECT:SetCoalition( Coalition ) - self.Coalition = Coalition -end - - ---- Get the owning coalition of the zone. --- @param #PROTECT self --- @return DCSCoalition.DCSCoalition#coalition Coalition. -function PROTECT:GetCoalition() - return self.Coalition -end - - ---- Get the owning coalition name of the zone. --- @param #PROTECT self --- @return #string Coalition name. -function PROTECT:GetCoalitionName() - - if self.Coalition == coalition.side.BLUE then - return "Blue" - end - - if self.Coalition == coalition.side.RED then - return "Red" - end - - if self.Coalition == coalition.side.NEUTRAL then - return "Neutral" - end - - return "" -end - - -function PROTECT:IsGuarded() - - local IsGuarded = self.ProtectZone:IsAllInZoneOfCoalition( self.Coalition ) - self:F( { IsGuarded = IsGuarded } ) - return IsGuarded -end - -function PROTECT:IsCaptured() - - local IsCaptured = self.ProtectZone:IsAllInZoneOfOtherCoalition( self.Coalition ) - self:F( { IsCaptured = IsCaptured } ) - return IsCaptured -end - - -function PROTECT:IsAttacked() - - local IsAttacked = self.ProtectZone:IsSomeInZoneOfCoalition( self.Coalition ) - self:F( { IsAttacked = IsAttacked } ) - return IsAttacked -end - - -function PROTECT:IsEmpty() - - local IsEmpty = self.ProtectZone:IsNoneInZone() - self:F( { IsEmpty = IsEmpty } ) - return IsEmpty -end - - ---- Check if the units are still alive. --- @param #PROTECT self -function PROTECT:AreProtectUnitsAlive() - - local IsAlive = false - - local UnitSet = self.ProtectUnitSet - UnitSet:Flush( self ) - local UnitList = UnitSet:GetSet() - - for UnitID, ProtectUnit in pairs( UnitList ) do - local IsUnitAlive = ProtectUnit:IsAlive() - if IsUnitAlive == true then - IsAlive = true - break - end - end - - return IsAlive -end - ---- Check if the statics are still alive. --- @param #PROTECT self -function PROTECT:AreProtectStaticsAlive() - - local IsAlive = false - - local StaticSet = self.ProtectStaticSet - StaticSet:Flush( self ) - local StaticList = StaticSet:GetSet() - - for UnitID, ProtectStatic in pairs( StaticList ) do - local IsStaticAlive = ProtectStatic:IsAlive() - if IsStaticAlive == true then - IsAlive = true - break - end - end - - return IsAlive -end - - ---- Check if there is a capture unit in the zone. --- @param #PROTECT self -function PROTECT:IsCaptureUnitInZone() - - local CaptureUnitSet = self.CaptureUnitSet - CaptureUnitSet:Flush( self ) - - local IsInZone = self.CaptureUnitSet:IsPartiallyInZone( self.ProtectZone ) - - self:F({IsInZone = IsInZone}) - - return IsInZone -end - ---- Smoke. --- @param #PROTECT self --- @param #SMOKECOLOR.Color SmokeColor -function PROTECT:Smoke( SmokeColor ) - - self.SmokeColor = SmokeColor -end - - ---- Flare. --- @param #PROTECT self --- @param #SMOKECOLOR.Color FlareColor -function PROTECT:Flare( FlareColor ) - self.ProtectZone:FlareZone( FlareColor, math.random( 1, 360 ) ) -end - - ---- Mark. --- @param #PROTECT self -function PROTECT:Mark() - - local Coord = self.ProtectZone:GetCoordinate() - local ZoneName = self:GetProtectZoneName() - local State = self:GetState() - - if self.MarkRed and self.MarkBlue then - self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } ) - Coord:RemoveMark( self.MarkRed ) - Coord:RemoveMark( self.MarkBlue ) - end - - if self.Coalition == coalition.side.BLUE then - self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State ) - self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State ) - else - self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State ) - self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State ) - end -end - - ---- Bound. --- @param #PROTECT self -function PROTECT:onafterStart() - - self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusCoalition, self ) - self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusZone, self ) - self:ScheduleRepeat( 10, 15, 0, nil, self.StatusSmoke, self ) -end - ---- Bound. --- @param #PROTECT self -function PROTECT:onenterGuarded() - - - if self.Coalition == coalition.side.BLUE then - --elf.ProtectZone:BoundZone( 12, country.id.USA ) - else - --self.ProtectZone:BoundZone( 12, country.id.RUSSIA ) - end - - self:Mark() - -end - -function PROTECT:onenterCaptured() - - local NewCoalition = self.ProtectZone:GetCoalition() - self:F( { NewCoalition = NewCoalition } ) - self:SetCoalition( NewCoalition ) - - self:Mark() -end - - -function PROTECT:onenterEmpty() - - self:Mark() -end - - -function PROTECT:onenterAttacked() - - self:Mark() -end - - ---- Check status Coalition ownership. --- @param #PROTECT self -function PROTECT:StatusCoalition() - - self:F( { State = self:GetState() } ) - - self.ProtectZone:Scan() - - if self:IsGuarded() then - self:Guard() - else - if self:IsCaptured() then - self:Capture() - end - end -end - ---- Check status Zone. --- @param #PROTECT self -function PROTECT:StatusZone() - - self:F( { State = self:GetState() } ) - - self.ProtectZone:Scan() - - if self:IsAttacked() then - self:Attack() - else - if self:IsEmpty() then - self:Empty() - end - end -end - ---- Check status Smoke. --- @param #PROTECT self -function PROTECT:StatusSmoke() - - local CurrentTime = timer.getTime() - - if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then - if self.SmokeColor then - self.ProtectZone:GetCoordinate():Smoke( self.SmokeColor ) - --self.SmokeColor = nil - self.SmokeTime = CurrentTime - end - end -end - - - - - diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 9e192a795..610c67b17 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -55,7 +55,7 @@ -- -- === -- @module Functional.Rat --- @module RAT.JPG +-- @image RAT.JPG ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- RAT class @@ -1663,7 +1663,7 @@ end --- Initialize basic parameters of the aircraft based on its (template) group in the mission editor. -- @param #RAT self --- @param Dcs.DCSWrapper.Group#Group DCSgroup Group of the aircraft in the mission editor. +-- @param DCS#Group DCSgroup Group of the aircraft in the mission editor. function RAT:_InitAircraft(DCSgroup) self:F2(DCSgroup) @@ -3762,11 +3762,11 @@ end function RAT:_Destroy(group) self:F2(group) - local DCSGroup = group:GetDCSObject() -- Dcs.DCSGroup#Group + local DCSGroup = group:GetDCSObject() -- DCS#Group if DCSGroup and DCSGroup:isExist() then - --local DCSUnit = DCSGroup:getUnit(1) -- Dcs.DCSUnit#Unit + --local DCSUnit = DCSGroup:getUnit(1) -- DCS#Unit --if DCSUnit then -- self:_CreateEventDead(timer.getTime(), DCSUnit) --end @@ -3797,8 +3797,8 @@ end --- Create a Dead event. -- @param #RAT self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. function RAT:_CreateEventDead(EventTime, Initiator) self:F( { EventTime, Initiator } ) @@ -4030,11 +4030,11 @@ end --- Orbit at a specified position at a specified alititude with a specified speed. -- @param #RAT self --- @param Dcs.DCSTypes#Vec2 P1 The point to hold the position. +-- @param DCS#Vec2 P1 The point to hold the position. -- @param #number Altitude The altitude ASL at which to hold the position. -- @param #number Speed The speed flying when holding the position in m/s. -- @param #number Duration Duration of holding pattern in seconds. --- @return Dcs.DCSTasking.Task#Task DCSTask +-- @return DCS#Task DCSTask function RAT:_TaskHolding(P1, Altitude, Speed, Duration) --local LandHeight = land.getHeight(P1) diff --git a/Moose Development/Moose/Functional/ZoneGoal.lua b/Moose Development/Moose/Functional/ZoneGoal.lua index 60c2f6d25..fb610e7d9 100644 --- a/Moose Development/Moose/Functional/ZoneGoal.lua +++ b/Moose Development/Moose/Functional/ZoneGoal.lua @@ -12,6 +12,7 @@ -- === -- -- @module Functional.ZoneGoal +-- @image MOOSE.JPG do -- Zone diff --git a/Moose Development/Moose/Functional/ZoneGoalCargo.lua b/Moose Development/Moose/Functional/ZoneGoalCargo.lua index 5fc27acc6..48b492aaa 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCargo.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCargo.lua @@ -12,6 +12,7 @@ -- === -- -- @module Functional.ZoneGoalCargo +-- @image MOOSE.JPG do -- ZoneGoal diff --git a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua index b0b737518..cb66ad3bc 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua @@ -12,6 +12,7 @@ -- === -- -- @module Functional.ZoneGoalCoalition +-- @image MOOSE.JPG do -- ZoneGoal diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 74d50dfb6..131e8e4b9 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -13,13 +13,10 @@ -- @image Task_Command_Center.JPG - - - --- The COMMANDCENTER class -- @type COMMANDCENTER -- @field Wrapper.Group#GROUP HQ --- @field Dcs.DCSCoalitionWrapper.Object#coalition CommandCenterCoalition +-- @field DCS#coalition CommandCenterCoalition -- @list Missions -- @extends Core.Base#BASE diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 9dd3da5bb..962770e14 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.Task +-- @image MOOSE.JPG --- @type TASK -- @field Core.Scheduler#SCHEDULER TaskScheduler diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 349d090c1..2822615d5 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.TaskInfo +-- @image MOOSE.JPG --- @type TASKINFO -- @extends Core.Base#BASE diff --git a/Moose Development/Moose/Tasking/TaskZoneCapture.lua b/Moose Development/Moose/Tasking/TaskZoneCapture.lua index ad563c1d5..e32ea58bf 100644 --- a/Moose Development/Moose/Tasking/TaskZoneCapture.lua +++ b/Moose Development/Moose/Tasking/TaskZoneCapture.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.TaskZoneCapture +-- @image MOOSE.JPG do -- TASK_ZONE_GOAL diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index 122356bd5..e3d3ed793 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.Tasking.Task_A2A +-- @image MOOSE.JPG do -- TASK_A2A diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 1c6fa1276..319a30fb2 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.Task_A2G +-- @image MOOSE.JPG do -- TASK_A2G diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 7cf6bd9c1..200877922 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -24,6 +24,7 @@ -- === -- -- @module Tasking.Task_Cargo +-- @image MOOSE.JPG do -- TASK_CARGO diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 16dc70cf0..1fd738087 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -9,6 +9,7 @@ -- === -- -- @module Tasking.Task_Cargo_Dispatcher +-- @image MOOSE.JPG do -- TASK_CARGO_DISPATCHER diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index c82fa505e..dc7f31c62 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -30,6 +30,7 @@ -- ### Author: FlightControl - Framework Design & Programming -- -- @module Tasking.Task_Manager +-- @image MOOSE.JPG do -- TASK_MANAGER diff --git a/Moose Development/Moose/Utilities/Routines.lua b/Moose Development/Moose/Utilities/Routines.lua index 508a35ed5..285f270d7 100644 --- a/Moose Development/Moose/Utilities/Routines.lua +++ b/Moose Development/Moose/Utilities/Routines.lua @@ -1,6 +1,6 @@ --- Various routines -- @module routines --- @author Flightcontrol +-- @image MOOSE.JPG env.setErrorMessageBoxEnabled(false) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 7ffb6dd44..5dab11d52 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -10,6 +10,7 @@ -- * FlightControl : Rework to OO framework -- -- @module Utils +-- @image MOOSE.JPG --- @type SMOKECOLOR diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 50c331293..0a062eb1e 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -238,7 +238,7 @@ end --- Finds a AIRBASE from the _DATABASE using a DCSAirbase object. -- @param #AIRBASE self --- @param Dcs.DCSWrapper.Airbase#Airbase DCSAirbase An existing DCS Airbase object reference. +-- @param DCS#Airbase DCSAirbase An existing DCS Airbase object reference. -- @return Wrapper.Airbase#AIRBASE self function AIRBASE:Find( DCSAirbase ) diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 0c1eefdaf..09b082339 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -273,7 +273,7 @@ end --- Return the DCSGroup of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 -- @param #CLIENT self --- @return Dcs.DCSWrapper.Group#Group +-- @return DCS#Group The group of the Client. function CLIENT:GetDCSGroup() self:F3() @@ -347,10 +347,10 @@ function CLIENT:GetDCSGroup() end --- TODO: Check Dcs.DCSTypes#Group.ID +-- TODO: Check DCS#Group.ID --- Get the group ID of the client. -- @param #CLIENT self --- @return Dcs.DCSTypes#Group.ID +-- @return DCS#Group.ID function CLIENT:GetClientGroupID() local ClientGroup = self:GetDCSGroup() @@ -389,7 +389,7 @@ end --- Returns the DCSUnit of the CLIENT. -- @param #CLIENT self --- @return Dcs.DCSTypes#Unit +-- @return DCS#Unit function CLIENT:GetClientGroupDCSUnit() self:F2() diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 5e7a15ef9..1665f1b44 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -14,7 +14,7 @@ --- @type CONTROLLABLE -- @extends Wrapper.Positionable#POSITIONABLE --- @field Dcs.DCSWrapper.Controllable#Controllable DCSControllable The DCS controllable class. +-- @field DCS#Controllable DCSControllable The DCS controllable class. -- @field #string ControllableName The name of the controllable. @@ -171,7 +171,7 @@ CONTROLLABLE = { --- Create a new CONTROLLABLE from a DCSControllable -- @param #CONTROLLABLE self --- @param Dcs.DCSWrapper.Controllable#Controllable ControllableName The DCS Controllable name +-- @param #string ControllableName The DCS Controllable name -- @return #CONTROLLABLE self function CONTROLLABLE:New( ControllableName ) local self = BASE:Inherit( self, POSITIONABLE:New( ControllableName ) ) -- #CONTROLLABLE @@ -186,7 +186,7 @@ end --- Get the controller for the CONTROLLABLE. -- @param #CONTROLLABLE self --- @return Dcs.DCSController#Controller +-- @return DCS#Controller function CONTROLLABLE:_GetController() local DCSControllable = self:GetDCSObject() @@ -396,13 +396,13 @@ end --- Return a condition section for a controlled task. -- @param #CONTROLLABLE self --- @param Dcs.DCSTime#Time time +-- @param DCS#Time time -- @param #string userFlag -- @param #boolean userFlagValue -- @param #string condition --- @param Dcs.DCSTime#Time duration +-- @param DCS#Time duration -- @param #number lastWayPoint --- return Dcs.DCSTasking.Task#Task +-- return DCS#Task function CONTROLLABLE:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint ) self:F2( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } ) @@ -420,9 +420,9 @@ end --- Return a Controlled Task taking a Task and a TaskCondition. -- @param #CONTROLLABLE self --- @param Dcs.DCSTasking.Task#Task DCSTask +-- @param DCS#Task DCSTask -- @param #DCSStopCondition DCSStopCondition --- @return Dcs.DCSTasking.Task#Task +-- @return DCS#Task function CONTROLLABLE:TaskControlled( DCSTask, DCSStopCondition ) self:F2( { DCSTask, DCSStopCondition } ) @@ -442,8 +442,8 @@ end --- Return a Combo Task taking an array of Tasks. -- @param #CONTROLLABLE self --- @param Dcs.DCSTasking.Task#TaskArray DCSTasks Array of @{DCSTasking.Task#Task} --- @return Dcs.DCSTasking.Task#Task +-- @param DCS#TaskArray DCSTasks Array of @{DCSTasking.Task#Task} +-- @return DCS#Task function CONTROLLABLE:TaskCombo( DCSTasks ) self:F2( { DCSTasks } ) @@ -466,8 +466,8 @@ end --- Return a WrappedAction Task taking a Command. -- @param #CONTROLLABLE self --- @param Dcs.DCSCommand#Command DCSCommand --- @return Dcs.DCSTasking.Task#Task +-- @param DCS#Command DCSCommand +-- @return DCS#Task function CONTROLLABLE:TaskWrappedAction( DCSCommand, Index ) self:F2( { DCSCommand } ) @@ -490,8 +490,8 @@ end --- Set a Task at a Waypoint using a Route list. -- @param #CONTROLLABLE self -- @param #table Waypoint The Waypoint! --- @param Dcs.DCSTasking.Task#Task Task The Task structure to be executed! --- @return Dcs.DCSTasking.Task#Task +-- @param DCS#Task Task The Task structure to be executed! +-- @return DCS#Task function CONTROLLABLE:SetTaskWaypoint( Waypoint, Task ) Waypoint.task = self:TaskCombo( { Task } ) @@ -505,7 +505,7 @@ end --- Executes a command action -- @param #CONTROLLABLE self --- @param Dcs.DCSCommand#Command DCSCommand +-- @param DCS#Command DCSCommand -- @return #CONTROLLABLE self function CONTROLLABLE:SetCommand( DCSCommand ) self:F2( DCSCommand ) @@ -525,7 +525,7 @@ end -- @param #CONTROLLABLE self -- @param #number FromWayPoint -- @param #number ToWayPoint --- @return Dcs.DCSTasking.Task#Task +-- @return DCS#Task -- @usage -- --- This test demonstrates the use(s) of the SwitchWayPoint method of the GROUP class. -- HeliGroup = GROUP:FindByName( "Helicopter" ) @@ -564,7 +564,7 @@ end -- -- @param #CONTROLLABLE self -- @param #boolean StopRoute true if the ground unit needs to stop, false if it needs to continue to move. --- @return Dcs.DCSTasking.Task#Task +-- @return DCS#Task function CONTROLLABLE:CommandStopRoute( StopRoute ) self:F2( { StopRoute } ) @@ -587,12 +587,12 @@ end -- @param #CONTROLLABLE self -- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. -- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. -- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) self:F2( { self.ControllableName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) @@ -644,13 +644,13 @@ end -- @param #CONTROLLABLE self -- @param Wrapper.Unit#UNIT AttackUnit The UNIT. -- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. -- @param #number Altitude (optional) The altitude from where to attack. -- @param #boolean Visible (optional) not a clue. -- @param #number WeaponType (optional) The WeaponType. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskAttackUnit( AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, WeaponType ) self:F2( { self.ControllableName, AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, WeaponType } ) @@ -680,14 +680,14 @@ end --- (AIR) Delivering weapon at the point on the ground. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. +-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. -- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. -- @param #number Altitude (optional) The altitude from where to attack. -- @param #number WeaponType (optional) The WeaponType. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskBombing( Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType ) self:F2( { self.ControllableName, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType } ) @@ -714,14 +714,14 @@ end --- (AIR) Attacking the map object (building, structure, e.t.c). -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. +-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. -- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. -- @param #number Altitude (optional) The altitude from where to attack. -- @param #number WeaponType (optional) The WeaponType. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskAttackMapObject( Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType ) self:F2( { self.ControllableName, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType } ) @@ -749,7 +749,7 @@ end --- (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point to hold the position. +-- @param DCS#Vec2 Point The point to hold the position. -- @param #number Altitude The altitude [m] to hold the position. -- @param #number Speed The speed [m/s] flying when holding the position. -- @return #CONTROLLABLE self @@ -832,11 +832,11 @@ end -- @param #CONTROLLABLE self -- @param Wrapper.Airbase#AIRBASE Airbase Airbase to attack. -- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. -- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) self:F2( { self.ControllableName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) @@ -871,7 +871,7 @@ end --- (AIR) Refueling from the nearest tanker. No parameters. -- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskRefueling() self:F2( { self.ControllableName } ) @@ -893,7 +893,7 @@ end --- (AIR HELICOPTER) Landing at the ground. For helicopters only. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to land. +-- @param DCS#Vec2 Point The point where to land. -- @param #number Duration The duration in seconds to stay on the ground. -- @return #CONTROLLABLE self function CONTROLLABLE:TaskLandAtVec2( Point, Duration ) @@ -958,9 +958,9 @@ end -- If another controllable is on land the unit / controllable will orbit around. -- @param #CONTROLLABLE self -- @param Wrapper.Controllable#CONTROLLABLE FollowControllable The controllable to be followed. --- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. +-- @param DCS#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. -- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskFollow( FollowControllable, Vec3, LastWaypointIndex ) self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex } ) @@ -1000,11 +1000,11 @@ end -- The unit / controllable will also protect that controllable from threats of specified types. -- @param #CONTROLLABLE self -- @param Wrapper.Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. --- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. +-- @param DCS#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. -- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. -- @param #number EngagementDistanceMax Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @param DCS#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes ) self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) @@ -1046,11 +1046,11 @@ end --- (GROUND) Fire at a VEC2 point until ammunition is finished. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 The point to fire at. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone to deploy the fire at. +-- @param DCS#Vec2 Vec2 The point to fire at. +-- @param DCS#Distance Radius The radius of the zone to deploy the fire at. -- @param #number AmmoCount (optional) Quantity of ammunition to expand (omit to fire until ammunition is depleted). -- @param #number WeaponType (optional) Enum for weapon type ID. This value is only required if you want the group firing to use a specific weapon, for instance using the task on a ship to force it to fire guided missiles at targets within cannon range. See http://wiki.hoggit.us/view/DCS_enum_weapon_flag --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType ) self:F2( { self.ControllableName, Vec2, Radius, AmmoCount, WeaponType } ) @@ -1089,7 +1089,7 @@ end --- (GROUND) Hold ground controllable from moving. -- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskHold() self:F2( { self.ControllableName } ) @@ -1118,9 +1118,9 @@ end -- @param #CONTROLLABLE self -- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. -- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. +-- @param DCS#AI.Task.Designation Designation (optional) Designation type. -- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) self:F2( { self.ControllableName, AttackGroup, WeaponType, Designation, Datalink } ) @@ -1152,10 +1152,10 @@ end --- (AIR) Engaging targets of defined types. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. +-- @param DCS#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored. +-- @param DCS#AttributeNameArray TargetTypes Array of target categories allowed to engage. -- @param #number Priority All enroute tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) self:F2( { self.ControllableName, Distance, TargetTypes, Priority } ) @@ -1185,11 +1185,11 @@ end --- (AIR) Engaging a targets of defined types at circle-shaped zone. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the zone. --- @param Dcs.DCSTypes#Distance Radius Radius of the zone. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. +-- @param DCS#Vec2 Vec2 2D-coordinates of the zone. +-- @param DCS#Distance Radius Radius of the zone. +-- @param DCS#AttributeNameArray TargetTypes Array of target categories allowed to engage. -- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskEngageTargetsInZone( Vec2, Radius, TargetTypes, Priority ) self:F2( { self.ControllableName, Vec2, Radius, TargetTypes, Priority } ) @@ -1223,12 +1223,12 @@ end -- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. -- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. -- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. -- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) self:F2( { self.ControllableName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) @@ -1284,13 +1284,13 @@ end -- @param Wrapper.Unit#UNIT EngageUnit The UNIT. -- @param #number Priority (optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. -- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired altitude to perform the unit engagement. +-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param DCS#Distance Altitude (optional) Desired altitude to perform the unit engagement. -- @param #boolean Visible (optional) Unit must be visible. -- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskEngageUnit( EngageUnit, Priority, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, ControllableAttack ) self:F2( { self.ControllableName, EngageUnit, Priority, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, ControllableAttack } ) @@ -1334,7 +1334,7 @@ end --- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. -- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskAWACS( ) self:F2( { self.ControllableName } ) @@ -1357,7 +1357,7 @@ end --- (AIR) Aircraft will act as a tanker for friendly units. No parameters. -- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskTanker( ) self:F2( { self.ControllableName } ) @@ -1382,7 +1382,7 @@ end --- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. -- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskEWR( ) self:F2( { self.ControllableName } ) @@ -1412,9 +1412,9 @@ end -- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. -- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. -- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. +-- @param DCS#AI.Task.Designation Designation (optional) Designation type. -- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) self:F2( { self.ControllableName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) @@ -1449,9 +1449,9 @@ end -- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. -- If the task is assigned to the controllable lead unit will be a FAC. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Distance Radius The maximal distance from the FAC to a target. +-- @param DCS#Distance Radius The maximal distance from the FAC to a target. -- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:EnRouteTaskFAC( Radius, Priority ) self:F2( { self.ControllableName, Radius, Priority } ) @@ -1480,10 +1480,10 @@ end --- (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to wait. +-- @param DCS#Vec2 Point The point where to wait. -- @param #number Duration The duration in seconds to wait. -- @param #CONTROLLABLE EmbarkingControllable The controllable to be embarked. --- @return Dcs.DCSTasking.Task#Task The DCS task structure +-- @return DCS#Task The DCS task structure function CONTROLLABLE:TaskEmbarking( Point, Duration, EmbarkingControllable ) self:F2( { self.ControllableName, Point, Duration, EmbarkingControllable.DCSControllable } ) @@ -1507,13 +1507,13 @@ end --- Move to a defined Vec2 Point, and embark to a controllable when arrived within a defined Radius. -- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to wait. +-- @param DCS#Vec2 Point The point where to wait. -- @param #number Radius The radius of the embarking zone around the Point. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. +-- @return DCS#Task The DCS task structure. function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) self:F2( { self.ControllableName, Point, Radius } ) - local DCSTask --Dcs.DCSTasking.Task#Task + local DCSTask --DCS#Task DCSTask = { id = 'EmbarkToTransport', params = { x = Point.x, y = Point.y, @@ -1608,7 +1608,7 @@ end --- (AIR + GROUND) Return a mission task from a mission template. -- @param #CONTROLLABLE self -- @param #table TaskMission A table containing the mission task. --- @return Dcs.DCSTasking.Task#Task +-- @return DCS#Task function CONTROLLABLE:TaskMission( TaskMission ) self:F2( Points ) @@ -1762,7 +1762,7 @@ end --- Return a Misson task to follow a given route defined by Points. -- @param #CONTROLLABLE self -- @param #table Points A table of route points. --- @return Dcs.DCSTasking.Task#Task +-- @return DCS#Task function CONTROLLABLE:TaskRoute( Points ) self:F2( Points ) @@ -1777,7 +1777,7 @@ do -- Route methods --- (AIR + GROUND) Make the Controllable move to fly to a given point. -- @param #CONTROLLABLE self - -- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. + -- @param DCS#Vec3 Point The destination point in Vec3 format. -- @param #number Speed The speed [m/s] to travel. -- @return #CONTROLLABLE self function CONTROLLABLE:RouteToVec2( Point, Speed ) @@ -1828,7 +1828,7 @@ do -- Route methods --- (AIR + GROUND) Make the Controllable move to a given point. -- @param #CONTROLLABLE self - -- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. + -- @param DCS#Vec3 Point The destination point in Vec3 format. -- @param #number Speed The speed [m/s] to travel. -- @return #CONTROLLABLE self function CONTROLLABLE:RouteToVec3( Point, Speed ) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index fe4d5e20b..dc8157cde 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -113,9 +113,9 @@ GROUPTEMPLATE.Takeoff = { -- It is merely added to the @{Core.Database}. -- @param #GROUP self -- @param #table GroupTemplate The GroupTemplate Structure exactly as defined within the mission editor. --- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the group. --- @param Dcs.DCSGroup#Group.Category CategoryID The Group.Category of the group. --- @param Dcs.DCScountry#country.id CountryID the country.id of the group. +-- @param DCS#coalition.side CoalitionSide The coalition.side of the group. +-- @param DCS#Group.Category CategoryID The Group.Category of the group. +-- @param DCS#country.id CountryID the country.id of the group. -- @return #GROUP self function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID ) local GroupName = GroupTemplate.name @@ -149,7 +149,7 @@ end --- Find the GROUP wrapper class instance using the DCS Group. -- @param #GROUP self --- @param Dcs.DCSWrapper.Group#Group DCSGroup The DCS Group. +-- @param DCS#Group DCSGroup The DCS Group. -- @return #GROUP The GROUP. function GROUP:Find( DCSGroup ) @@ -172,7 +172,7 @@ end --- Returns the DCS Group. -- @param #GROUP self --- @return Dcs.DCSWrapper.Group#Group The DCS Group. +-- @return DCS#Group The DCS Group. function GROUP:GetDCSObject() local DCSGroup = Group.getByName( self.GroupName ) @@ -185,7 +185,7 @@ end --- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Position The 3D position vectors of the POSITIONABLE. +-- @return DCS#Position The 3D position vectors of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3() self:F2( self.PositionableName ) @@ -217,11 +217,11 @@ end function GROUP:IsAlive() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSObject() -- Dcs.DCSGroup#Group + local DCSGroup = self:GetDCSObject() -- DCS#Group if DCSGroup then if DCSGroup:isExist() then - local DCSUnit = DCSGroup:getUnit(1) -- Dcs.DCSUnit#Unit + local DCSUnit = DCSGroup:getUnit(1) -- DCS#Unit if DCSUnit then local GroupIsAlive = DCSUnit:isActive() self:T3( GroupIsAlive ) @@ -277,7 +277,7 @@ end --- Returns category of the DCS Group. -- @param #GROUP self --- @return Dcs.DCSWrapper.Group#Group.Category The category ID +-- @return DCS#Group.Category The category ID function GROUP:GetCategory() self:F2( self.GroupName ) @@ -317,7 +317,7 @@ end --- Returns the coalition of the DCS Group. -- @param #GROUP self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The coalition side of the DCS Group. +-- @return DCS#coalition.side The coalition side of the DCS Group. function GROUP:GetCoalition() self:F2( self.GroupName ) @@ -333,7 +333,7 @@ end --- Returns the country of the DCS Group. -- @param #GROUP self --- @return Dcs.DCScountry#country.id The country identifier. +-- @return DCS#country.id The country identifier. -- @return #nil The DCS Group is not existing or alive. function GROUP:GetCountry() self:F2( self.GroupName ) @@ -448,7 +448,7 @@ end -- If the underlying DCS Unit does not exist, the method will return nil. . -- @param #GROUP self -- @param #number UnitNumber The number of the DCS Unit to be returned. --- @return Dcs.DCSWrapper.Unit#Unit The DCS Unit. +-- @return DCS#Unit The DCS Unit. function GROUP:GetDCSUnit( UnitNumber ) self:F3( { self.GroupName, UnitNumber } ) @@ -488,7 +488,7 @@ end --- Returns the average velocity Vec3 vector. -- @param Wrapper.Group#GROUP self --- @return Dcs.DCSTypes#Vec3 The velocity Vec3 vector +-- @return DCS#Vec3 The velocity Vec3 vector -- @return #nil The GROUP is not existing or alive. function GROUP:GetVelocityVec3() self:F2( self.GroupName ) @@ -524,7 +524,7 @@ end --- Returns the average group height in meters. -- @param Wrapper.Group#GROUP self -- @param #boolean FromGround Measure from the ground or from sea level. Provide **true** for measuring from the ground. **false** or **nil** if you measure from sea level. --- @return Dcs.DCSTypes#Vec3 The height of the group. +-- @return DCS#Vec3 The height of the group. -- @return #nil The GROUP is not existing or alive. function GROUP:GetHeight( FromGround ) self:F2( self.GroupName ) @@ -658,7 +658,7 @@ end --- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. -- @param #GROUP self --- @return Dcs.DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. +-- @return DCS#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. function GROUP:GetVec2() self:F2( self.GroupName ) @@ -671,7 +671,7 @@ end --- Returns the current Vec3 vector of the first DCS Unit in the GROUP. -- @param #GROUP self --- @return Dcs.DCSTypes#Vec3 Current Vec3 of the first DCS Unit of the GROUP. +-- @return DCS#Vec3 Current Vec3 of the first DCS Unit of the GROUP. function GROUP:GetVec3() self:F2( self.GroupName ) @@ -723,10 +723,10 @@ end --- Returns a random @{DCSTypes#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP. -- @param #GROUP self -- @param #number Radius --- @return Dcs.DCSTypes#Vec3 The random 3D point vector around the first UNIT of the GROUP. +-- @return DCS#Vec3 The random 3D point vector around the first UNIT of the GROUP. -- @return #nil The GROUP is invalid or empty -- @usage --- -- If Radius is ignored, returns the Dcs.DCSTypes#Vec3 of first UNIT of the GROUP +-- -- If Radius is ignored, returns the DCS#Vec3 of first UNIT of the GROUP function GROUP:GetRandomVec3(Radius) self:F2(self.GroupName) @@ -1004,10 +1004,10 @@ do -- AI methods -- @return #GROUP The GROUP. function GROUP:SetAIOnOff( AIOnOff ) - local DCSGroup = self:GetDCSObject() -- Dcs.DCSGroup#Group + local DCSGroup = self:GetDCSObject() -- DCS#Group if DCSGroup then - local DCSController = DCSGroup:getController() -- Dcs.DCSController#Controller + local DCSController = DCSGroup:getController() -- DCS#Controller if DCSController then DCSController:setOnOff( AIOnOff ) return self @@ -1114,7 +1114,7 @@ end --- Sets the CountryID of the group in a Template. -- @param #GROUP self --- @param Dcs.DCScountry#country.id CountryID The country ID. +-- @param DCS#country.id CountryID The country ID. -- @return #table function GROUP:SetTemplateCountry( Template, CountryID ) Template.CountryID = CountryID @@ -1123,7 +1123,7 @@ end --- Sets the CoalitionID of the group in a Template. -- @param #GROUP self --- @param Dcs.DCSCoalitionWrapper.Object#coalition.side CoalitionID The coalition ID. +-- @param DCS#coalition.side CoalitionID The coalition ID. -- @return #table function GROUP:SetTemplateCoalition( Template, CoalitionID ) Template.CoalitionID = CoalitionID diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index 94d946f3c..671577882 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -9,6 +9,7 @@ -- === -- -- @module Wrapper.Identifiable +-- @image MOOSE.JPG --- @type IDENTIFIABLE -- @extends Wrapper.Object#OBJECT @@ -42,7 +43,7 @@ local _CategoryName = { --- Create a new IDENTIFIABLE from a DCSIdentifiable -- @param #IDENTIFIABLE self --- @param Dcs.DCSWrapper.Identifiable#Identifiable IdentifiableName The DCS Identifiable name +-- @param #string IdentifiableName The DCS Identifiable name -- @return #IDENTIFIABLE self function IDENTIFIABLE:New( IdentifiableName ) local self = BASE:Inherit( self, OBJECT:New( IdentifiableName ) ) @@ -60,7 +61,7 @@ end function IDENTIFIABLE:IsAlive() self:F3( self.IdentifiableName ) - local DCSIdentifiable = self:GetDCSObject() -- Dcs.DCSObject#Object + local DCSIdentifiable = self:GetDCSObject() -- DCS#Object if DCSIdentifiable then local IdentifiableIsAlive = DCSIdentifiable:isExist() @@ -108,7 +109,7 @@ end --- Returns category of the DCS Identifiable. -- @param #IDENTIFIABLE self --- @return Dcs.DCSWrapper.Object#Object.Category The category ID +-- @return DCS#Object.Category The category ID function IDENTIFIABLE:GetCategory() self:F2( self.ObjectName ) @@ -140,7 +141,7 @@ end --- Returns coalition of the Identifiable. -- @param #IDENTIFIABLE self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The side of the coalition. +-- @return DCS#coalition.side The side of the coalition. -- @return #nil The DCS Identifiable is not existing or alive. function IDENTIFIABLE:GetCoalition() self:F2( self.IdentifiableName ) @@ -189,7 +190,7 @@ end --- Returns country of the Identifiable. -- @param #IDENTIFIABLE self --- @return Dcs.DCScountry#country.id The country identifier. +-- @return DCS#country.id The country identifier. -- @return #nil The DCS Identifiable is not existing or alive. function IDENTIFIABLE:GetCountry() self:F2( self.IdentifiableName ) @@ -210,7 +211,7 @@ end --- Returns Identifiable descriptor. Descriptor type depends on Identifiable category. -- @param #IDENTIFIABLE self --- @return Dcs.DCSWrapper.Identifiable#Identifiable.Desc The Identifiable descriptor. +-- @return DCS#Object.Desc The Identifiable descriptor. -- @return #nil The DCS Identifiable is not existing or alive. function IDENTIFIABLE:GetDesc() self:F2( self.IdentifiableName ) diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index b2b034a30..c218bf4c1 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -9,6 +9,7 @@ -- === -- -- @module Wrapper.Object +-- @image MOOSE.JPG --- @type OBJECT @@ -40,7 +41,7 @@ OBJECT = { --- Create a new OBJECT from a DCSObject -- @param #OBJECT self --- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name +-- @param DCS#Object ObjectName The Object name -- @return #OBJECT self function OBJECT:New( ObjectName, Test ) local self = BASE:Inherit( self, BASE:New() ) @@ -53,7 +54,7 @@ end --- Returns the unit's unique identifier. -- @param Wrapper.Object#OBJECT self --- @return Dcs.DCSWrapper.Object#Object.ID ObjectID +-- @return DCS#Object.ID ObjectID -- @return #nil The DCS Object is not existing or alive. function OBJECT:GetID() diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 296cc0119..912467d20 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -60,7 +60,7 @@ POSITIONABLE.__.Cargo = {} --- Create a new POSITIONABLE from a DCSPositionable -- @param #POSITIONABLE self --- @param Dcs.DCSWrapper.Positionable#Positionable PositionableName The POSITIONABLE name +-- @param #string PositionableName The POSITIONABLE name -- @return #POSITIONABLE self function POSITIONABLE:New( PositionableName ) local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) @@ -71,7 +71,7 @@ end --- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Position The 3D position vectors of the POSITIONABLE. +-- @return DCS#Position The 3D position vectors of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetPositionVec3() self:F2( self.PositionableName ) @@ -91,7 +91,7 @@ end --- Returns the @{DCSTypes#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec2 The 2D point vector of the POSITIONABLE. +-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetVec2() self:F2( self.PositionableName ) @@ -188,10 +188,10 @@ end --- Returns a random @{DCSTypes#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @param #number Radius --- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. +-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. -- @usage --- -- If Radius is ignored, returns the Dcs.DCSTypes#Vec3 of first UNIT of the GROUP +-- -- If Radius is ignored, returns the DCS#Vec3 of first UNIT of the GROUP function POSITIONABLE:GetRandomVec3( Radius ) self:F2( self.PositionableName ) @@ -222,7 +222,7 @@ end --- Returns the @{DCSTypes#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. +-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetVec3() self:F2( self.PositionableName ) @@ -243,7 +243,7 @@ end --- Get the bounding box of the underlying POSITIONABLE DCS Object. -- @param #POSITIONABLE self --- @return Dcs.DCSTypes#Distance The bounding box of the POSITIONABLE. +-- @return DCS#Distance The bounding box of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetBoundingBox() --R2.1 self:F2() @@ -251,7 +251,7 @@ function POSITIONABLE:GetBoundingBox() --R2.1 local DCSPositionable = self:GetDCSObject() if DCSPositionable then - local PositionableDesc = DCSPositionable:getDesc() --Dcs.DCSTypes#Desc + local PositionableDesc = DCSPositionable:getDesc() --DCS#Desc if PositionableDesc then local PositionableBox = PositionableDesc.box return PositionableBox @@ -266,7 +266,7 @@ end --- Returns the altitude of the POSITIONABLE. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Distance The altitude of the POSITIONABLE. +-- @return DCS#Distance The altitude of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetAltitude() self:F2() @@ -274,7 +274,7 @@ function POSITIONABLE:GetAltitude() local DCSPositionable = self:GetDCSObject() if DCSPositionable then - local PositionablePointVec3 = DCSPositionable:getPoint() --Dcs.DCSTypes#Vec3 + local PositionablePointVec3 = DCSPositionable:getPoint() --DCS#Vec3 return PositionablePointVec3.y end @@ -383,7 +383,7 @@ end --- Returns the POSITIONABLE velocity Vec3 vector. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The velocity Vec3 vector +-- @return DCS#Vec3 The velocity Vec3 vector -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetVelocityVec3() self:F2( self.PositionableName ) @@ -404,7 +404,7 @@ end --- Returns the POSITIONABLE height in meters. -- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The height of the positionable. +-- @return DCS#Vec3 The height of the positionable. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetHeight() --R2.1 self:F2( self.PositionableName ) @@ -483,7 +483,7 @@ end --- Returns a message with the callsign embedded (if there is one). -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -- @return Core.Message#MESSAGE function POSITIONABLE:GetMessage( Message, Duration, Name ) --R2.1 changed callsign and name and using GetMessageText @@ -518,7 +518,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToAll( Message, Duration, Name ) self:F2( { Message, Duration } ) @@ -535,8 +535,8 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTYpes#Duration Duration The duration of the message. --- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message. +-- @param DCS#Duration Duration The duration of the message. +-- @param DCS#coalition MessageCoalition The Coalition receiving the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, Name ) self:F2( { Message, Duration } ) @@ -557,7 +557,7 @@ end -- @param #POSITIONABLE self -- @param #string Message The message text -- @param Core.Message#MESSAGE.Type MessageType The message type that determines the duration. --- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message. +-- @param DCS#coalition MessageCoalition The Coalition receiving the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageTypeToCoalition( Message, MessageType, MessageCoalition, Name ) self:F2( { Message, MessageType } ) @@ -577,7 +577,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTYpes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToRed( Message, Duration, Name ) self:F2( { Message, Duration } ) @@ -594,7 +594,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToBlue( Message, Duration, Name ) self:F2( { Message, Duration } ) @@ -611,7 +611,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param Wrapper.Client#CLIENT Client The client object receiving the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToClient( Message, Duration, Client, Name ) @@ -629,7 +629,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param Wrapper.Group#GROUP MessageGroup The GROUP object receiving the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name ) @@ -676,7 +676,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param Core.Set#SET_GROUP MessageSetGroup The SET_GROUP collection receiving the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Name ) --R2.1 @@ -700,7 +700,7 @@ end -- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. -- @param #POSITIONABLE self -- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param DCS#Duration Duration The duration of the message. -- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. function POSITIONABLE:Message( Message, Duration, Name ) self:F2( { Message, Duration } ) diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 7ca5699b3..a62aa11c1 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -56,7 +56,7 @@ end --- Finds a STATIC from the _DATABASE using a DCSStatic object. -- @param #STATIC self --- @param Dcs.DCSWrapper.Static#Static DCSStatic An existing DCS Static object reference. +-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference. -- @return #STATIC self function STATIC:Find( DCSStatic ) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 03278f9c7..753b842f4 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -45,7 +45,7 @@ -- -- The DCS Unit APIs are used extensively within MOOSE. The UNIT class has for each DCS Unit API a corresponding method. -- To be able to distinguish easily in your code the difference between a UNIT API call and a DCS Unit API call, --- the first letter of the method is also capitalized. So, by example, the DCS Unit method @{DCSWrapper.Unit#Unit.getName}() +-- the first letter of the method is also capitalized. So, by example, the DCS Unit method @{DCS#Unit.getName}() -- is implemented in the UNIT class as @{#UNIT.GetName}(). -- -- ## Smoke, Flare Units @@ -116,7 +116,7 @@ end --- Finds a UNIT from the _DATABASE using a DCSUnit object. -- @param #UNIT self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit An existing DCS Unit object reference. +-- @param DCS#Unit DCSUnit An existing DCS Unit object reference. -- @return #UNIT self function UNIT:Find( DCSUnit ) @@ -145,7 +145,7 @@ end --- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit +-- @return DCS#Unit function UNIT:GetDCSObject() local DCSUnit = Unit.getByName( self.UnitName ) @@ -311,7 +311,7 @@ end function UNIT:IsAlive() self:F3( self.UnitName ) - local DCSUnit = self:GetDCSObject() -- Dcs.DCSUnit#Unit + local DCSUnit = self:GetDCSObject() -- DCS#Unit if DCSUnit then local UnitIsAlive = DCSUnit:isExist() and DCSUnit:isActive() @@ -352,7 +352,7 @@ end function UNIT:GetPlayerName() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSObject() -- Dcs.DCSUnit#Unit + local DCSUnit = self:GetDCSObject() -- DCS#Unit if DCSUnit then @@ -458,7 +458,7 @@ end --- Returns the Unit's ammunition. -- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit.Ammo +-- @return DCS#Unit.Ammo -- @return #nil The DCS Unit is not existing or alive. function UNIT:GetAmmo() self:F2( self.UnitName ) @@ -475,7 +475,7 @@ end --- Returns the unit sensors. -- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit.Sensors +-- @return DCS#Unit.Sensors -- @return #nil The DCS Unit is not existing or alive. function UNIT:GetSensors() self:F2( self.UnitName ) @@ -539,7 +539,7 @@ end -- * Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. -- @param #UNIT self -- @return #boolean Indicates if at least one of the unit's radar(s) is on. --- @return Dcs.DCSWrapper.Object#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. +-- @return DCS#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. -- @return #nil The DCS Unit is not existing or alive. function UNIT:GetRadar() self:F2( self.UnitName ) From 18098d402b284e67652e0189b99ab2dea9eb3c80 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 1 Jun 2018 10:59:53 +0200 Subject: [PATCH 146/170] Documentation updates --- .../Moose/AI/AI_A2A_Dispatcher.lua | 30 ++++++------ .../Moose/Functional/Detection.lua | 46 +++++++++---------- .../Moose/Tasking/DetectionManager.lua | 4 +- .../Moose/Tasking/Task_A2A_Dispatcher.lua | 4 +- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 2 +- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 6f0c7045d..92ecfce9b 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1267,7 +1267,7 @@ do -- AI_A2A_DISPATCHER --- Calculates which AI friendlies are nearby the area -- @param #AI_A2A_DISPATCHER self -- @param DetectedItem - -- @return #number, Core.CommandCenter#REPORT + -- @return #table A list of the friendlies nearby. function AI_A2A_DISPATCHER:GetAIFriendliesNearBy( DetectedItem ) local FriendliesNearBy = self.Detection:GetFriendliesDistance( DetectedItem ) @@ -2881,7 +2881,7 @@ do -- AI_A2A_DISPATCHER --- Creates an ENGAGE task when there are human friendlies airborne near the targets. -- @param #AI_A2A_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem + -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem The detected item. -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function AI_A2A_DISPATCHER:EvaluateENGAGE( DetectedItem ) @@ -2908,7 +2908,7 @@ do -- AI_A2A_DISPATCHER --- Creates an GCI task when there are targets for it. -- @param #AI_A2A_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem + -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem The detected item. -- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units. -- @return #nil If there are no targets to be set. function AI_A2A_DISPATCHER:EvaluateGCI( DetectedItem ) @@ -2935,7 +2935,7 @@ do -- AI_A2A_DISPATCHER --- Assigns A2A AI Tasks in relation to the detected items. -- @param #AI_A2A_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. function AI_A2A_DISPATCHER:ProcessDetected( Detection ) @@ -3060,10 +3060,10 @@ end do - --- Calculates which HUMAN friendlies are nearby the area + --- Calculates which HUMAN friendlies are nearby the area. -- @param #AI_A2A_DISPATCHER self - -- @param DetectedItem - -- @return #number, Core.CommandCenter#REPORT + -- @param DetectedItem The detected item. + -- @return #number, Core.Report#REPORT The amount of friendlies and a text string explaining which friendlies of which type. function AI_A2A_DISPATCHER:GetPlayerFriendliesNearBy( DetectedItem ) local DetectedSet = DetectedItem.Set @@ -3106,14 +3106,14 @@ do return PlayersCount, PlayerTypesReport end - --- Calculates which friendlies are nearby the area + --- Calculates which friendlies are nearby the area. -- @param #AI_A2A_DISPATCHER self - -- @param DetectedItem - -- @return #number, Core.CommandCenter#REPORT - function AI_A2A_DISPATCHER:GetFriendliesNearBy( Target ) + -- @param DetectedItem The detected item. + -- @return #number, Core.Report#REPORT The amount of friendlies and a text string explaining which friendlies of which type. + function AI_A2A_DISPATCHER:GetFriendliesNearBy( DetectedItem ) - local DetectedSet = Target.Set - local FriendlyUnitsNearBy = self.Detection:GetFriendliesNearBy( Target ) + local DetectedSet = DetectedItem.Set + local FriendlyUnitsNearBy = self.Detection:GetFriendliesNearBy( DetectedItem ) local FriendlyTypes = {} local FriendliesCount = 0 @@ -3150,8 +3150,8 @@ do return FriendliesCount, FriendlyTypesReport end - --- - -- @param AI_A2A_DISPATCHER + --- Schedules a new CAP for the given SquadronName. + -- @param #AI_A2A_DISPATCHER self -- @param #string SquadronName The squadron name. function AI_A2A_DISPATCHER:SchedulerCAP( SquadronName ) self:CAP( SquadronName ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 9e38a5b45..f8cfbf327 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -100,11 +100,11 @@ do -- DETECTION_BASE -- -- Various methods exist how to retrieve the grouped items from a DETECTION_BASE derived class: -- - -- * The method @{Detection#DETECTION_BASE.GetDetectedItems}() retrieves the DetectedItems[] list. - -- * A DetectedItem from the DetectedItems[] list can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedItem}( DetectedItemIndex ). + -- * The method @{Functional.Detection#DETECTION_BASE.GetDetectedItems}() retrieves the DetectedItems[] list. + -- * A DetectedItem from the DetectedItems[] list can be retrieved using the method @{Functional.Detection#DETECTION_BASE.GetDetectedItem}( DetectedItemIndex ). -- Note that this method returns a DetectedItem element from the list, that contains a Set variable and further information -- about the DetectedItem that is set by the DETECTION_BASE derived classes, used to group the DetectedItem. - -- * A DetectedSet from the DetectedItems[] list can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedSet}( DetectedItemIndex ). + -- * A DetectedSet from the DetectedItems[] list can be retrieved using the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}( DetectedItemIndex ). -- This method retrieves the Set from a DetectedItem element from the DetectedItem list (DetectedItems[ DetectedItemIndex ].Set ). -- -- ## **Visual filters** to fine-tune the probability of the detected objects @@ -141,7 +141,7 @@ do -- DETECTION_BASE -- -- Note that based on this probability factor, not only the detection but also the **type** of the unit will be applied! -- - -- Use the method @{Detection#DETECTION_BASE.SetDistanceProbability}() to set the probability factor upon a 10 km distance. + -- Use the method @{Functional.Detection#DETECTION_BASE.SetDistanceProbability}() to set the probability factor upon a 10 km distance. -- -- ### Alpha Angle visual detection probability -- @@ -153,7 +153,7 @@ do -- DETECTION_BASE -- For example, if a alpha angle probability factor of 0.7 is given, the extrapolated probabilities of the different angles would look like: -- 0°: 70%, 10°: 75,21%, 20°: 80,26%, 30°: 85%, 40°: 89,28%, 50°: 92,98%, 60°: 95,98%, 70°: 98,19%, 80°: 99,54%, 90°: 100% -- - -- Use the method @{Detection#DETECTION_BASE.SetAlphaAngleProbability}() to set the probability factor if 0°. + -- Use the method @{Functional.Detection#DETECTION_BASE.SetAlphaAngleProbability}() to set the probability factor if 0°. -- -- ### Cloudy Zones detection probability -- @@ -161,7 +161,7 @@ do -- DETECTION_BASE -- The Cloudy Zones work with the ZONE_BASE derived classes. The mission designer can define within the mission -- zones that reflect cloudy areas where detected units may not be so easily visually detected. -- - -- Use the method @{Detection#DETECTION_BASE.SetZoneProbability}() to set for a defined number of zones, the probability factors. + -- Use the method @{Functional.Detection#DETECTION_BASE.SetZoneProbability}() to set for a defined number of zones, the probability factors. -- -- Note however, that the more zones are defined to be "cloudy" within a detection, the more performance it will take -- from the DETECTION_BASE to calculate the presence of the detected unit within each zone. @@ -178,7 +178,7 @@ do -- DETECTION_BASE -- ### Detection acceptance of within range limit -- -- A range can be set that will limit a successful detection for a unit. - -- Use the method @{Detection#DETECTION_BASE.SetAcceptRange}() to apply a range in meters till where detected units will be accepted. + -- Use the method @{Functional.Detection#DETECTION_BASE.SetAcceptRange}() to apply a range in meters till where detected units will be accepted. -- -- local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers. -- @@ -195,7 +195,7 @@ do -- DETECTION_BASE -- ### Detection acceptance if within zone(s). -- -- Specific ZONE_BASE object(s) can be given as a parameter, which will only accept a detection if the unit is within the specified ZONE_BASE object(s). - -- Use the method @{Detection#DETECTION_BASE.SetAcceptZones}() will accept detected units if they are within the specified zones. + -- Use the method @{Functional.Detection#DETECTION_BASE.SetAcceptZones}() will accept detected units if they are within the specified zones. -- -- local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers. -- @@ -215,7 +215,7 @@ do -- DETECTION_BASE -- ### Detection rejectance if within zone(s). -- -- Specific ZONE_BASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONE_BASE object(s). - -- Use the method @{Detection#DETECTION_BASE.SetRejectZones}() will reject detected units if they are within the specified zones. + -- Use the method @{Functional.Detection#DETECTION_BASE.SetRejectZones}() will reject detected units if they are within the specified zones. -- An example of how to use the method is shown below. -- -- local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers. @@ -235,7 +235,7 @@ do -- DETECTION_BASE -- -- ## Detection of Friendlies Nearby -- - -- Use the method @{Detection#DETECTION_BASE.SetFriendliesRange}() to set the range what will indicate when friendlies are nearby + -- Use the method @{Functional.Detection#DETECTION_BASE.SetFriendliesRange}() to set the range what will indicate when friendlies are nearby -- a DetectedItem. The default range is 6000 meters. For air detections, it is advisory to use about 30.000 meters. -- -- ## DETECTION_BASE is a Finite State Machine @@ -1802,7 +1802,7 @@ end do -- DETECTION_UNITS - --- # DETECTION_UNITS class, extends @{Detection#DETECTION_BASE} + --- # DETECTION_UNITS class, extends @{Functional.Detection#DETECTION_BASE} -- -- The DETECTION_UNITS class will detect units within the battle zone. -- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference. @@ -2052,7 +2052,7 @@ end do -- DETECTION_TYPES - --- # 3) DETECTION_TYPES class, extends @{Detection#DETECTION_BASE} + --- # 3) DETECTION_TYPES class, extends @{Functional.Detection#DETECTION_BASE} -- -- The DETECTION_TYPES class will detect units within the battle zone. -- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected. @@ -2261,7 +2261,7 @@ end do -- DETECTION_AREAS - --- # 4) DETECTION_AREAS class, extends @{Detection#DETECTION_BASE} + --- # 4) DETECTION_AREAS class, extends @{Functional.Detection#DETECTION_BASE} -- -- The DETECTION_AREAS class will detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s), -- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Unit#UNIT}s detected. @@ -2270,26 +2270,26 @@ do -- DETECTION_AREAS -- -- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones -- - -- The methods to manage the DetectedItems[].Set(s) are implemented in @{Detection#DECTECTION_BASE} and - -- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Detection#DETECTION_AREAS}. + -- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DECTECTION_BASE} and + -- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Functional.Detection#DETECTION_AREAS}. -- - -- Retrieve the DetectedItems[].Set with the method @{Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned. + -- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned. -- - -- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Detection#DETECTION_BASE.GetDetectionZones}(). - -- To understand the amount of zones created, use the method @{Detection#DETECTION_BASE.GetDetectionZoneCount}(). - -- If you want to obtain a specific zone from the DetectedZones, use the method @{Detection#DETECTION_BASE.GetDetectionZone}() with a given index. + -- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}(). + -- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}(). + -- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index. -- -- ## 4.4) Flare or Smoke detected units -- - -- Use the methods @{Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place. + -- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place. -- -- ## 4.5) Flare or Smoke or Bound detected zones -- -- Use the methods: -- - -- * @{Detection#DETECTION_AREAS.FlareDetectedZones}() to flare in a color - -- * @{Detection#DETECTION_AREAS.SmokeDetectedZones}() to smoke in a color - -- * @{Detection#DETECTION_AREAS.SmokeDetectedZones}() to bound with a tire with a white flag + -- * @{Functional.Detection#DETECTION_AREAS.FlareDetectedZones}() to flare in a color + -- * @{Functional.Detection#DETECTION_AREAS.SmokeDetectedZones}() to smoke in a color + -- * @{Functional.Detection#DETECTION_AREAS.SmokeDetectedZones}() to bound with a tire with a white flag -- -- the detected zones when a new detection has taken place. -- diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index a716c11ff..0c76973dd 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -256,7 +256,7 @@ do -- DETECTION_REPORTING --- Creates a string of the detected items in a @{Detection}. -- @param #DETECTION_MANAGER self - -- @param Core.Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object. + -- @param Core.Set#SET_UNIT DetectedSet The detected Set created by the @{Functional.Detection#DETECTION_BASE} object. -- @return #DETECTION_MANAGER self function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet ) self:F2() @@ -289,7 +289,7 @@ do -- DETECTION_REPORTING --- Reports the detected items to the @{Core.Set#SET_GROUP}. -- @param #DETECTION_REPORTING self -- @param Wrapper.Group#GROUP Group The @{Wrapper.Group} object to where the report needs to go. - -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Detection#DETECTION_BASE} object. + -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Functional.Detection#DETECTION_BASE} object. -- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. function DETECTION_REPORTING:ProcessDetected( Group, Detection ) self:F2( Group ) diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 204eb87a3..9b68fd38a 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -334,7 +334,7 @@ do -- TASK_A2A_DISPATCHER -- @param #TASK_A2A_DISPATCHER self -- @param Tasking.Mission#MISSION Mission -- @param Tasking.Task#TASK Task - -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. -- @param #boolean DetectedItemID -- @param #boolean DetectedItemChange -- @return Tasking.Task#TASK @@ -484,7 +484,7 @@ do -- TASK_A2A_DISPATCHER --- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}. -- @param #TASK_A2A_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. function TASK_A2A_DISPATCHER:ProcessDetected( Detection ) self:F() diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index 27493d738..d9dae1ab4 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -582,7 +582,7 @@ do -- TASK_A2G_DISPATCHER --- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}. -- @param #TASK_A2G_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. function TASK_A2G_DISPATCHER:ProcessDetected( Detection ) self:F() From 43a4052dc8ead23784027fe8a89c6044e0e2330f Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 1 Jun 2018 16:00:42 +0200 Subject: [PATCH 147/170] Documentation cleanup --- Moose Development/Moose/AI/AI_A2A_Gci.lua | 4 +-- Moose Development/Moose/AI/AI_A2A_Patrol.lua | 4 +-- Moose Development/Moose/AI/AI_BAI.lua | 5 ++- Moose Development/Moose/AI/AI_Balancer.lua | 6 ++-- Moose Development/Moose/AI/AI_CAP.lua | 4 +-- Moose Development/Moose/AI/AI_CAS.lua | 6 +--- Moose Development/Moose/AI/AI_Cargo_APC.lua | 6 +--- .../Moose/AI/AI_Cargo_Airplane.lua | 4 +-- .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 6 +--- Moose Development/Moose/AI/AI_Formation.lua | 6 ++-- Moose Development/Moose/AI/AI_Patrol.lua | 10 +++--- Moose Development/Moose/Cargo/Cargo.lua | 3 +- Moose Development/Moose/Cargo/CargoCrate.lua | 4 +-- Moose Development/Moose/Cargo/CargoGroup.lua | 4 +-- .../Moose/Cargo/CargoSlingload.lua | 4 +-- Moose Development/Moose/Cargo/CargoUnit.lua | 4 +-- Moose Development/Moose/Core/Database.lua | 4 ++- Moose Development/Moose/Core/Event.lua | 5 +-- Moose Development/Moose/Core/Fsm.lua | 4 +-- Moose Development/Moose/Core/Goal.lua | 2 +- Moose Development/Moose/Core/Menu.lua | 36 +++++++++++-------- Moose Development/Moose/Core/Point.lua | 6 ++-- Moose Development/Moose/Core/Radio.lua | 18 +++++----- Moose Development/Moose/Core/Scheduler.lua | 2 +- Moose Development/Moose/Core/Settings.lua | 2 +- Moose Development/Moose/Core/Spawn.lua | 3 +- Moose Development/Moose/Core/SpawnStatic.lua | 2 +- Moose Development/Moose/Core/Spot.lua | 2 +- Moose Development/Moose/Core/Velocity.lua | 2 +- Moose Development/Moose/Core/Zone.lua | 8 ++--- .../Moose/Functional/Detection.lua | 13 +++---- .../Moose/Functional/PseudoATC.lua | 4 +-- Moose Development/Moose/Functional/RAT.lua | 3 +- Moose Development/Moose/Functional/Range.lua | 2 +- .../Moose/Functional/ZoneCaptureCoalition.lua | 4 +-- .../Moose/Functional/ZoneGoal.lua | 4 +-- .../Moose/Functional/ZoneGoalCargo.lua | 4 +-- .../Moose/Functional/ZoneGoalCoalition.lua | 4 +-- Moose Development/Moose/Wrapper/Airbase.lua | 2 +- Moose Development/Moose/Wrapper/Client.lua | 3 +- .../Moose/Wrapper/Controllable.lua | 8 ++--- Moose Development/Moose/Wrapper/Group.lua | 4 ++- .../Moose/Wrapper/Identifiable.lua | 2 +- Moose Development/Moose/Wrapper/Object.lua | 2 +- .../Moose/Wrapper/Positionable.lua | 6 ++-- Moose Development/Moose/Wrapper/Scenery.lua | 3 +- Moose Development/Moose/Wrapper/Static.lua | 9 ++--- 47 files changed, 108 insertions(+), 145 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index e968c7320..c1acb6df7 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -17,9 +17,7 @@ -- @extends AI.AI_A2A#AI_A2A ---- # AI_A2A_GCI class, extends @{AI.AI_A2A#AI_A2A} --- --- The AI_A2A_GCI class implements the core functions to intercept intruders. The Engage function will intercept intruders. +--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. -- -- ![Process](..\Presentations\AI_GCI\Dia3.JPG) -- diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index e9ea266db..3ff3cfa69 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -13,9 +13,7 @@ --- @type AI_A2A_PATROL -- @extends AI.AI_A2A#AI_A2A ---- # AI_A2A_PATROL class, extends @{AI.AI_A2A#AI_A2A} --- --- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}. +--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}. -- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index d68e5b006..fa66d3993 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -27,9 +27,8 @@ -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- AI_BAI_ZONE derives from the @{AI.AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. --- --- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. +--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. +-- -- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_BAI\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 9b704e8a1..f82631dab 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -27,10 +27,8 @@ -- @extends Core.Fsm#FSM_SET ---- # AI_BALANCER class, extends @{Core.Fsm#FSM_SET} --- --- The AI_BALANCER class monitors and manages as many replacement AI groups as there are --- CLIENTS in a SET_CLIENT collection, which are not occupied by human players. +--- Monitors and manages as many replacement AI groups as there are +-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players. -- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. -- -- The parent class @{Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM). diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index 19d51ca81..f6b42f37b 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -31,9 +31,7 @@ -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_CAP_ZONE class, extends @{AI.AI_Patrol#AI_PATROL_ZONE} --- --- The AI_CAP_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} +-- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index bb70b61df..2ef978853 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -28,11 +28,7 @@ -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_CAS_ZONE class, extends @{AI.AI_Patrol#AI_PATROL_ZONE} --- --- AI_CAS_ZONE derives from the @{AI.AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. --- --- The AI_CAS_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. +--- Implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. -- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_CAS\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index c4863e159..a2d086683 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -13,11 +13,7 @@ -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_APC class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- --- === --- --- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups. +--- Brings a dynamic cargo handling capability for AI groups. -- -- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI\_CARGO\APC module uses the @{Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index ed10d2e5d..343823d2f 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -13,9 +13,7 @@ -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_AIRPLANE class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- --- === +--- Implements the transportation of cargo by airplanes. -- -- @field #AI_CARGO_AIRPLANE AI_CARGO_AIRPLANE = { diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index 409699733..c208bab9a 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -13,11 +13,7 @@ -- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER ---- # AI\_CARGO\_DISPATCHER\_AIRPLANE class, extends @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} --- --- === --- --- AI\_CARGO\_DISPATCHER\_AIRPLANE brings a dynamic cargo handling capability for AI groups. +--- Brings a dynamic cargo handling capability for AI groups. -- -- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI\_CARGO\_DISPATCHER\_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index ebc5d2b6f..be8abc9e9 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -58,9 +58,7 @@ -- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup. ---- # AI_FORMATION class, extends @{Core.Fsm#FSM_SET} --- --- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader. +--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader. -- -- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions. -- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! @@ -86,7 +84,7 @@ -- -- Create a new SPAWN object with the @{#AI_FORMATION.New} method: -- --- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text. +-- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Wrapper.Unit#UNIT}, with an optional briefing text. -- -- ## Formation methods -- diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 1553be007..c89ab36e0 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -40,9 +40,7 @@ -- @field Core.Spawn#SPAWN CoordTest -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI_PATROL_ZONE class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- --- The AI_PATROL_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}. +--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}. -- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- @@ -558,18 +556,18 @@ function AI_PATROL_ZONE:SetDetectionZone( DetectionZone ) end end ---- Gets a list of @{Unit#UNIT}s that were detected by the AI. +--- Gets a list of @{Wrapper.Unit#UNIT}s that were detected by the AI. -- No filtering is applied, so, ANY detected UNIT can be in this list. -- It is up to the mission designer to use the @{Wrapper.Unit} class and methods to filter the targets. -- @param #AI_PATROL_ZONE self --- @return #table The list of @{Unit#UNIT}s +-- @return #table The list of @{Wrapper.Unit#UNIT}s function AI_PATROL_ZONE:GetDetectedUnits() self:F2() return self.DetectedUnits end ---- Clears the list of @{Unit#UNIT}s that were detected by the AI. +--- Clears the list of @{Wrapper.Unit#UNIT}s that were detected by the AI. -- @param #AI_PATROL_ZONE self function AI_PATROL_ZONE:ClearDetectedUnits() self:F2() diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 31fa1644e..f5570dd18 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -144,9 +144,8 @@ do -- CARGO -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - --- # (R2.4) CARGO class, extends @{Core.Fsm#FSM_PROCESS} + --- Defines the core functions that defines a cargo object within MOOSE. -- - -- The CARGO class defines the core functions that defines a cargo object within MOOSE. -- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation. -- -- CARGO is not meant to be used directly by mission designers, but provides a base class for **concrete cargo implementation classes** to handle: diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index c3e12ddea..399c29ffb 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -22,9 +22,7 @@ do -- CARGO_CRATE -- @type CARGO_CRATE -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - --- # CARGO\_CRATE class, extends @{Cargo.Cargo#CARGO_REPRESENTABLE} - -- - -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. -- -- === diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 98435b25c..de8b08e6d 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -28,9 +28,7 @@ do -- CARGO_GROUP -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. -- @field #string GroupName The name of the CargoGroup. - --- # CARGO\_GROUP class, extends @{Cargo.Cargo#CARGO_REPORTABLE} - -- - -- The CARGO\_GROUP class defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. + --- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. -- -- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo: diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 617cc4770..ff948d4e6 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -23,9 +23,7 @@ do -- CARGO_SLINGLOAD -- @type CARGO_SLINGLOAD -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - --- # CARGO\_CRATE class, extends @{Cargo.Cargo#CARGO_REPRESENTABLE} - -- - -- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- -- === -- diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 09fd9f0ce..2a5f009ac 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -22,9 +22,7 @@ do -- CARGO_UNIT -- @type CARGO_UNIT -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - --- # CARGO\_UNIT class, extends @{Cargo.Cargo#CARGO_REPRESENTABLEE} - -- - -- The CARGO\_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. + --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_UNIT objects to and from carriers. -- -- === diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 37e792279..82e195f82 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -14,7 +14,9 @@ --- @type DATABASE -- @extends Core.Base#BASE ---- Mission designers can use the DATABASE class to refer to: +--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator. +-- +-- Mission designers can use the DATABASE class to refer to: -- -- * STATICS -- * UNITS diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 3f1b1cd57..f61e0ca40 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -167,6 +167,7 @@ --- The EVENT structure +-- -- @type EVENT -- @field #EVENT.Events Events -- @extends Core.Base#BASE @@ -230,7 +231,7 @@ EVENTS = { -- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). -- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCSStaticObject#StaticObject}. -- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name. --- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Unit#UNIT} of the initiator Unit object. +-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Wrapper.Unit#UNIT} of the initiator Unit object. -- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName). -- @field DCS#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}. -- @field #string IniDCSGroupName (UNIT) The initiating Group name. @@ -245,7 +246,7 @@ EVENTS = { -- @field DCS#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). -- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCSStaticObject#StaticObject}. -- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name. --- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Unit#UNIT} of the target Unit object. +-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Wrapper.Unit#UNIT} of the target Unit object. -- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName). -- @field DCS#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}. -- @field #string TgtDCSGroupName (UNIT) The target Group name. diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index b92beb1c1..a4a833da2 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -801,7 +801,7 @@ do -- FSM_CONTROLLABLE -- @field Wrapper.Controllable#CONTROLLABLE Controllable -- @extends Core.Fsm#FSM - --- FSM_CONTROLLABLE class models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s. + --- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s. -- -- === -- @@ -1177,7 +1177,7 @@ do -- FSM_TASK -- @field Tasking.Task#TASK Task -- @extends #FSM - --- FSM_TASK class models Finite State Machines for @{Task}s. + --- Models Finite State Machines for @{Tasking.Task}s. -- -- === -- diff --git a/Moose Development/Moose/Core/Goal.lua b/Moose Development/Moose/Core/Goal.lua index 608c4ecc0..926e8eca1 100644 --- a/Moose Development/Moose/Core/Goal.lua +++ b/Moose Development/Moose/Core/Goal.lua @@ -19,7 +19,7 @@ do -- Goal -- @extends Core.Fsm#FSM - --- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized. + --- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized. -- -- ## 1. GOAL constructor -- diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 03d95c47f..fd677b5c5 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -13,15 +13,15 @@ -- -- ### To manage **main menus**, the classes begin with **MENU_**: -- --- * @{Menu#MENU_MISSION}: Manages main menus for whole mission file. --- * @{Menu#MENU_COALITION}: Manages main menus for whole coalition. --- * @{Menu#MENU_GROUP}: Manages main menus for GROUPs. +-- * @{Core.Menu#MENU_MISSION}: Manages main menus for whole mission file. +-- * @{Core.Menu#MENU_COALITION}: Manages main menus for whole coalition. +-- * @{Core.Menu#MENU_GROUP}: Manages main menus for GROUPs. -- -- ### To manage **command menus**, which are menus that allow the player to issue **functions**, the classes begin with **MENU_COMMAND_**: -- --- * @{Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file. --- * @{Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition. --- * @{Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs. +-- * @{Core.Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file. +-- * @{Core.Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition. +-- * @{Core.Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs. -- -- === --- @@ -183,7 +183,7 @@ do -- MENU_BASE --- @type MENU_BASE -- @extends Base#BASE - --- The MENU_BASE class defines the main MENU class where other MENU classes are derived from. + --- Defines the main MENU class where other MENU classes are derived from. -- This is an abstract class, so don't use it. -- @field #MENU_BASE MENU_BASE = { @@ -286,7 +286,7 @@ do -- MENU_COMMAND_BASE -- @field #function MenuCallHandler -- @extends Core.Menu#MENU_BASE - --- The MENU_COMMAND_BASE class defines the main MENU class where other MENU COMMAND_ + --- Defines the main MENU class where other MENU COMMAND_ -- classes are derived from, in order to set commands. -- -- @field #MENU_COMMAND_BASE @@ -356,7 +356,8 @@ do -- MENU_MISSION --- @type MENU_MISSION -- @extends Core.Menu#MENU_BASE - --- The MENU_MISSION class manages the main menus for a complete mission. + --- Manages the main menus for a complete mission. + -- -- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. -- @field #MENU_MISSION @@ -451,7 +452,8 @@ do -- MENU_MISSION_COMMAND --- @type MENU_MISSION_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - --- The MENU_MISSION_COMMAND class manages the command menus for a complete mission, which allow players to execute functions during mission execution. + --- Manages the command menus for a complete mission, which allow players to execute functions during mission execution. + -- -- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}. -- @@ -536,7 +538,8 @@ do -- MENU_COALITION --- @type MENU_COALITION -- @extends Core.Menu#MENU_BASE - --- The @{Menu#MENU_COALITION} class manages the main menus for coalitions. + --- Manages the main menus for @{DCS.coalition}s. + -- -- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}. -- @@ -672,7 +675,8 @@ do -- MENU_COALITION_COMMAND --- @type MENU_COALITION_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - --- The MENU_COALITION_COMMAND class manages the command menus for coalitions, which allow players to execute functions during mission execution. + --- Manages the command menus for coalitions, which allow players to execute functions during mission execution. + -- -- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}. -- @@ -770,7 +774,8 @@ do -- @extends Core.Menu#MENU_BASE - --- The MENU_GROUP class manages the main menus for coalitions. + --- Manages the main menus for @{Wrapper.Group}s. + -- -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. -- @@ -926,7 +931,7 @@ do --- @type MENU_GROUP_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - --- The @{Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. + --- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. -- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND.Remove}. -- @@ -1155,7 +1160,8 @@ do --- @type MENU_GROUP_COMMAND_DELAYED -- @extends Core.Menu#MENU_COMMAND_BASE - --- The @{Menu#MENU_GROUP_COMMAND_DELAYED} class manages the command menus for coalitions, which allow players to execute functions during mission execution. + --- Manages the command menus for coalitions, which allow players to execute functions during mission execution. + -- -- You can add menus with the @{#MENU_GROUP_COMMAND_DELAYED.New} method, which constructs a MENU_GROUP_COMMAND_DELAYED object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND_DELAYED.Remove}. -- diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index be99b5d75..632c1007c 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -36,7 +36,7 @@ do -- COORDINATE -- @extends Core.Base#BASE - --- COORDINATE defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. + --- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- ## COORDINATE constructor -- @@ -1597,7 +1597,7 @@ do -- POINT_VEC3 -- @extends Core.Point#COORDINATE - --- POINT_VEC3 defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. + --- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space. -- -- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. -- In order to keep the credibility of the the author, @@ -1808,7 +1808,7 @@ do -- POINT_VEC2 -- @field DCS#Distance y the y coordinate in meters. -- @extends Core.Point#COORDINATE - --- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. + --- Defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. -- -- ## POINT_VEC2 constructor -- diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index 1e1d96aaf..85dc9162a 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -16,9 +16,9 @@ -- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file), -- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission. -- --- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Positionable#POSITIONABLE} +-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Positionable#POSITIONABLE} -- --- * If the transmitter is a @{Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically, +-- * If the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically, -- * If the transmitter is any other @{Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped. -- -- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft, @@ -34,7 +34,7 @@ -- @image Core_Radio.JPG ---- # RADIO class, extends @{Core.Base#BASE} +--- Models the radio capabilty. -- -- ## RADIO usage -- @@ -44,14 +44,14 @@ -- * Then, you will **set the relevant parameters** to the transmission (see below), -- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function. -- --- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Positionable#POSITIONABLE} +-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Positionable#POSITIONABLE} -- -- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"), -- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission. -- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission. -- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead... -- --- Additional Methods to set relevant parameters if the transmiter is a @{Unit#UNIT} or a @{Wrapper.Group#GROUP} +-- Additional Methods to set relevant parameters if the transmiter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} -- -- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration, -- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call @@ -63,7 +63,7 @@ -- -- What is this power thing ? -- --- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna, +-- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna, -- * Otherwise, DCS sets it automatically, depending on what's available on your Unit, -- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**, -- * This an automated DCS calculation you have no say on, @@ -338,16 +338,14 @@ function RADIO:StopBroadcast() end ---- # BEACON class, extends @{Core.Base#BASE} --- --- After attaching a @{#BEACON} to your @{Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want. +--- After attaching a @{#BEACON} to your @{Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want. -- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon. -- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is -- attach to a cargo crate, for exemple. -- -- ## AA TACAN Beacon usage -- --- This beacon only works with airborne @{Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon. +-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon. -- Use @#BEACON:StopAATACAN}() to stop it. -- -- ## General Purpose Radio Beacon usage diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index 734c31c01..b8a75c5b8 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -46,7 +46,7 @@ -- @extends Core.Base#BASE ---- The SCHEDULER class creates schedule. +--- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization. -- -- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**. -- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called. diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index 77de7dac2..819690607 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -21,7 +21,7 @@ --- @type SETTINGS -- @extends Core.Base#BASE ---- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. +--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. -- -- === -- diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 94c3b5564..7cf879f08 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -36,7 +36,8 @@ -- @extends Core.Base#BASE ---- The SPAWN class allows to spawn dynamically new groups. +--- Allows to spawn dynamically new @{Core.Group}s. +-- -- Each SPAWN object needs to be have related **template groups** setup in the Mission Editor (ME), -- which is a normal group with the **Late Activation** flag set. -- This template group will never be activated in your mission. diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua index 52df548da..334201e4c 100644 --- a/Moose Development/Moose/Core/SpawnStatic.lua +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -36,7 +36,7 @@ -- @extends Core.Base#BASE ---- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s. +--- Allows to spawn dynamically new @{Static}s. -- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), -- SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy" -- these properties to create a new static object and place it at the desired coordinate. diff --git a/Moose Development/Moose/Core/Spot.lua b/Moose Development/Moose/Core/Spot.lua index 0af7a7b02..4e17118f5 100644 --- a/Moose Development/Moose/Core/Spot.lua +++ b/Moose Development/Moose/Core/Spot.lua @@ -46,7 +46,7 @@ do -- @extends Core.Fsm#FSM - --- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to: + --- Implements the target spotting or marking functionality, but adds additional luxury to be able to: -- -- * Mark targets for a defined duration. -- * wiggle the spot at the target. diff --git a/Moose Development/Moose/Core/Velocity.lua b/Moose Development/Moose/Core/Velocity.lua index 04e4675bb..7e7a368f3 100644 --- a/Moose Development/Moose/Core/Velocity.lua +++ b/Moose Development/Moose/Core/Velocity.lua @@ -16,7 +16,7 @@ do -- Velocity -- @extends Core.Base#BASE - -- VELOCITY models a speed, which can be expressed in various formats according the Settings. + --- VELOCITY models a speed, which can be expressed in various formats according the Settings. -- -- ## VELOCITY constructor -- diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 3697c6de2..55a1a0412 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -21,7 +21,7 @@ -- * @{#ZONE_BASE}: The ZONE_BASE class defining the base for all other zone classes. -- * @{#ZONE_RADIUS}: The ZONE_RADIUS class defined by a zone name, a location and a radius. -- * @{#ZONE}: The ZONE class, defined by the zone name as defined within the Mission Editor. --- * @{#ZONE_UNIT}: The ZONE_UNIT class defines by a zone around a @{Unit#UNIT} with a radius. +-- * @{#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. -- @@ -1017,7 +1017,7 @@ end -- @field Wrapper.Unit#UNIT ZoneUNIT -- @extends Core.Zone#ZONE_RADIUS ---- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. +--- The ZONE_UNIT class defined by a zone around a @{Wrapper.Unit#UNIT} with a radius. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. -- -- @field #ZONE_UNIT @@ -1045,9 +1045,9 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius ) end ---- Returns the current location of the @{Unit#UNIT}. +--- Returns the current location of the @{Wrapper.Unit#UNIT}. -- @param #ZONE_UNIT self --- @return DCS#Vec2 The location of the zone based on the @{Unit#UNIT}location. +-- @return DCS#Vec2 The location of the zone based on the @{Wrapper.Unit#UNIT}location. function ZONE_UNIT:GetVec2() self:F2( self.ZoneName ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index f8cfbf327..33b4c9331 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1802,9 +1802,8 @@ end do -- DETECTION_UNITS - --- # DETECTION_UNITS class, extends @{Functional.Detection#DETECTION_BASE} + --- Will detect units within the battle zone. -- - -- The DETECTION_UNITS class will detect units within the battle zone. -- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference. -- Beware that when the amount of units detected is large, the DetectedItems list will be large also. -- @@ -2052,9 +2051,7 @@ end do -- DETECTION_TYPES - --- # 3) DETECTION_TYPES class, extends @{Functional.Detection#DETECTION_BASE} - -- - -- The DETECTION_TYPES class will detect units within the battle zone. + --- Will detect units within the battle zone. -- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected. -- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference. -- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also. @@ -2261,10 +2258,8 @@ end do -- DETECTION_AREAS - --- # 4) DETECTION_AREAS class, extends @{Functional.Detection#DETECTION_BASE} - -- - -- The DETECTION_AREAS class will detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s), - -- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Unit#UNIT}s detected. + --- Detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s), + -- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Wrapper.Unit#UNIT}s detected. -- The class is group the detected units within zones given a DetectedZoneRange parameter. -- A set with multiple detected zones will be created as there are groups of units detected. -- diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index b8a9f2cd0..a6b42d68f 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -53,7 +53,7 @@ -- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. -- @extends Core.Base#BASE ---- The PSEUDOATC class adds some rudimentary ATC functionality via the radio menu. +--- Adds some rudimentary ATC functionality via the radio menu. -- -- Local weather reports can be requested for nearby airports and player's mission waypoints. -- The weather report includes @@ -986,7 +986,7 @@ function PSEUDOATC:_DisplayMessageToGroup(_unit, _text, _time, _clear) end --- Returns a string which consits of this callsign and the player name. --- @param #RANGE self +-- @param #PSEUDOATC self -- @param #string unitname Name of the player unit. function PSEUDOATC:_myname(unitname) self:F2(unitname) diff --git a/Moose Development/Moose/Functional/RAT.lua b/Moose Development/Moose/Functional/RAT.lua index 610c67b17..53b4d67f6 100644 --- a/Moose Development/Moose/Functional/RAT.lua +++ b/Moose Development/Moose/Functional/RAT.lua @@ -148,8 +148,7 @@ -- @field #boolean useparkingdb Parking spots are added to data base once an aircraft has used it. These spots can later be used by other aircraft. Default is true. -- @extends Core.Spawn#SPAWN ---- The RAT class implements an easy to use way to randomly fill your map with AI aircraft. --- +--- Implements an easy to use way to randomly fill your map with AI aircraft. -- -- ## Airport Selection -- diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index a7448cecd..1e39d0735 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -83,7 +83,7 @@ -- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated. -- @extends Core.Base#BASE ---- The RANGE class enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. +--- Enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. -- The parameter "rangename" defindes the name of the range. It has to be unique since this is also the name displayed in the radio menu. -- -- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated. diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index b4551e87f..767f2e634 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -26,9 +26,7 @@ do -- ZONE_CAPTURE_COALITION -- @extends Functional.ZoneGoalCoalition#ZONE_GOAL_COALITION - --- # ZONE\_CAPTURE\_COALITION class, extends @{ZoneGoalCoalition#ZONE_GOAL_COALITION} - -- - -- Models the process to capture a Zone for a Coalition, which is guarded by another Coalition. + --- Models the process to capture a Zone for a Coalition, which is guarded by another Coalition. -- This is a powerful concept that allows to create very dynamic missions based on the different state transitions of various zones. -- -- --- diff --git a/Moose Development/Moose/Functional/ZoneGoal.lua b/Moose Development/Moose/Functional/ZoneGoal.lua index fb610e7d9..0caabc8a3 100644 --- a/Moose Development/Moose/Functional/ZoneGoal.lua +++ b/Moose Development/Moose/Functional/ZoneGoal.lua @@ -20,9 +20,7 @@ do -- Zone -- @extends Core.Fsm#FSM - --- # ZONE_GOAL class, extends @{Fsm#FSM} - -- - -- ZONE_GOAL models processes that have a Goal with a defined achievement involving a Zone. + -- Models processes that have a Goal with a defined achievement involving a Zone. -- Derived classes implement the ways how the achievements can be realized. -- -- ## 1. ZONE_GOAL constructor diff --git a/Moose Development/Moose/Functional/ZoneGoalCargo.lua b/Moose Development/Moose/Functional/ZoneGoalCargo.lua index 48b492aaa..9ae8ae613 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCargo.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCargo.lua @@ -20,9 +20,7 @@ do -- ZoneGoal -- @extends Functional.ZoneGoal#ZONE_GOAL - --- # ZONE_GOAL_CARGO class, extends @{ZoneGoal#ZONE_GOAL} - -- - -- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo. + --- Models processes that have a Goal with a defined achievement involving a Zone and Cargo. -- Derived classes implement the ways how the achievements can be realized. -- -- ## 1. ZONE_GOAL_CARGO constructor diff --git a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua index cb66ad3bc..ba86ffe95 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua @@ -20,9 +20,7 @@ do -- ZoneGoal -- @extends Functional.ZoneGoal#ZONE_GOAL - --- # ZONE_GOAL_COALITION class, extends @{ZoneGoal#ZONE_GOAL} - -- - -- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition. + --- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition. -- Derived classes implement the ways how the achievements can be realized. -- -- ## 1. ZONE_GOAL_COALITION constructor diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 0a062eb1e..d31779479 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -15,7 +15,7 @@ --- @type AIRBASE -- @extends Wrapper.Positionable#POSITIONABLE ---- AIRBASE is a wrapper class to handle the DCS Airbase objects: +--- Wrapper class to handle the DCS Airbase objects: -- -- * Support all DCS Airbase APIs. -- * Enhance with Airbase specific APIs not in the DCS Airbase API set. diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 09b082339..7352537f7 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -17,7 +17,8 @@ -- @extends Wrapper.Unit#UNIT ---- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. +--- Wrapper class of those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. +-- -- Note that clients are NOT the same as Units, they are NOT necessarily alive. -- The CLIENT class is a wrapper class to handle the DCS Unit objects that have the skillset defined as __Client__ or __Player__: -- diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 1665f1b44..9e29ab41d 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -19,7 +19,7 @@ ---- CONTROLLABLE is a wrapper class to handle the "DCS Controllable objects", which are Groups and Units: +--- Wrapper class to handle the "DCS Controllable objects", which are Groups and Units: -- -- * Support all DCS Controllable APIs. -- * Enhance with Controllable specific APIs not in the DCS Controllable API set. @@ -421,7 +421,7 @@ end --- Return a Controlled Task taking a Task and a TaskCondition. -- @param #CONTROLLABLE self -- @param DCS#Task DCSTask --- @param #DCSStopCondition DCSStopCondition +-- @param DCS#DCSStopCondition DCSStopCondition -- @return DCS#Task function CONTROLLABLE:TaskControlled( DCSTask, DCSStopCondition ) self:F2( { DCSTask, DCSStopCondition } ) @@ -2096,7 +2096,7 @@ do -- Route methods -- A speed can be given in km/h. -- A given formation can be given. -- @param #CONTROLLABLE self - -- @param #Vec2 Vec2 The Vec2 where to route to. + -- @param DCS#Vec2 Vec2 The Vec2 where to route to. -- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h. -- @param Base#FORMATION Formation The formation string. function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) @@ -2152,7 +2152,7 @@ end -- Route methods --- Do Script command -- @param #CONTROLLABLE self -- @param #string DoScript --- @return #DCSCommand +-- @return DCS#DCSCommand function CONTROLLABLE:CommandDoScript( DoScript ) local DCSDoScript = { diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index dc8157cde..dd570df5e 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -32,7 +32,9 @@ -- @field #string GroupName The name of the group. ---- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. +--- Wrapper class of the DCS world Group object. +-- +-- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. -- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Group objects are spawned (using the @{SPAWN} class). -- -- The GROUP class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index 671577882..6e226a466 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -15,7 +15,7 @@ -- @extends Wrapper.Object#OBJECT -- @field #string IdentifiableName The name of the identifiable. ---- The IDENTIFIABLE class is a wrapper class to handle the DCS Identifiable objects: +--- Wrapper class to handle the DCS Identifiable objects. -- -- * Support all DCS Identifiable APIs. -- * Enhance with Identifiable specific APIs not in the DCS Identifiable API set. diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index c218bf4c1..1b9b46995 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -17,7 +17,7 @@ -- @field #string ObjectName The name of the Object. ---- OBJECT handles the DCS Object objects: +--- Wrapper class to hendle the DCS Object objects. -- -- * Support all DCS Object APIs. -- * Enhance with Object specific APIs not in the DCS Object API set. diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 912467d20..b60ee07be 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -18,7 +18,7 @@ -- @extends Wrapper.Identifiable#IDENTIFIABLE ---- The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects: +--- Wrapper class to handle the POSITIONABLE objects. -- -- * Support all DCS APIs. -- * Enhance with POSITIONABLE specific APIs not in the DCS API set. @@ -716,7 +716,7 @@ end --- Create a @{Radio#RADIO}, to allow radio transmission for this POSITIONABLE. -- Set parameters with the methods provided, then use RADIO:Broadcast() to actually broadcast the message -- @param #POSITIONABLE self --- @return #RADIO Radio +-- @return Core.Radio#RADIO Radio function POSITIONABLE:GetRadio() --R2.1 self:F2(self) return RADIO:New(self) @@ -724,7 +724,7 @@ end --- Create a @{Radio#BEACON}, to allow this POSITIONABLE to broadcast beacon signals -- @param #POSITIONABLE self --- @return #RADIO Radio +-- @return Core.Radio#RADIO Radio function POSITIONABLE:GetBeacon() --R2.1 self:F2(self) return BEACON:New(self) diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 31bfbf05a..9a9cb9ff2 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -17,7 +17,8 @@ -- @extends Wrapper.Positionable#POSITIONABLE ---- Scenery objects are defined on the map. +--- Wrapper class to handle Scenery objects that are defined on the map. +-- -- The @{Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: -- -- * Wraps the DCS Scenery objects. diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index a62aa11c1..27800cff0 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -15,7 +15,8 @@ --- @type STATIC -- @extends Wrapper.Positionable#POSITIONABLE ---- Statics are **Static Units** defined within the Mission Editor. +--- Wrapper class to handle Static objects. +-- -- Note that Statics are almost the same as Units, but they don't have a controller. -- The @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: -- @@ -126,7 +127,7 @@ function STATIC:GetThreatLevel() end --- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group. --- @param #UNIT self +-- @param #STATIC self -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param #number Heading The heading of the unit respawn. function STATIC:SpawnAt( Coordinate, Heading ) @@ -139,7 +140,7 @@ end --- Respawn the @{Wrapper.Unit} at the same location with the same properties. -- This is useful to respawn a cargo after it has been destroyed. --- @param #UNIT self +-- @param #STATIC self function STATIC:ReSpawn() local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName ) @@ -149,7 +150,7 @@ end --- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading. --- @param #UNIT self +-- @param #STATIC self -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param #number Heading The heading of the unit respawn. function STATIC:ReSpawnAt( Coordinate, Heading ) From 0b959306743e1b86580111bfa1f28bfb366d9edc Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 1 Jun 2018 23:51:53 +0200 Subject: [PATCH 148/170] ARTY v0.9.8 Improved maker targets and moves assignments. Removed env.info() --- Moose Development/Moose/Core/Point.lua | 42 +- .../Moose/Functional/Artillery.lua | 437 ++++++++++++------ 2 files changed, 325 insertions(+), 154 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0a90f6440..23dfae5ad 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1153,13 +1153,19 @@ do -- COORDINATE --- Mark to All -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToAll( "This is a target for all players" ) - function COORDINATE:MarkToAll( MarkText ) + function COORDINATE:MarkToAll( MarkText, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - trigger.action.markToAll( MarkID, MarkText, self:GetVec3(), false, "" ) + if ReadOnly==nil then + ReadOnly=false + end + local text=Text or "" + trigger.action.markToAll( MarkID, MarkText, self:GetVec3(), ReadOnly, text) return MarkID end @@ -1167,50 +1173,66 @@ do -- COORDINATE -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param Coalition + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToCoalition( "This is a target for the red coalition", coalition.side.RED ) - function COORDINATE:MarkToCoalition( MarkText, Coalition ) + function COORDINATE:MarkToCoalition( MarkText, Coalition, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - trigger.action.markToCoalition( MarkID, MarkText, self:GetVec3(), Coalition, false, "" ) + if ReadOnly==nil then + ReadOnly=false + end + local text=Text or "" + trigger.action.markToCoalition( MarkID, MarkText, self:GetVec3(), Coalition, ReadOnly, text ) return MarkID end --- Mark to Red Coalition -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToCoalitionRed( "This is a target for the red coalition" ) - function COORDINATE:MarkToCoalitionRed( MarkText ) - return self:MarkToCoalition( MarkText, coalition.side.RED ) + function COORDINATE:MarkToCoalitionRed( MarkText, ReadOnly, Text ) + return self:MarkToCoalition( MarkText, coalition.side.RED, ReadOnly, Text ) end --- Mark to Blue Coalition -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkID = TargetCoord:MarkToCoalitionBlue( "This is a target for the blue coalition" ) - function COORDINATE:MarkToCoalitionBlue( MarkText ) - return self:MarkToCoalition( MarkText, coalition.side.BLUE ) + function COORDINATE:MarkToCoalitionBlue( MarkText, ReadOnly, Text ) + return self:MarkToCoalition( MarkText, coalition.side.BLUE, ReadOnly, Text ) end --- Mark to Group -- @param #COORDINATE self -- @param #string MarkText Free format text that shows the marking clarification. -- @param Wrapper.Group#GROUP MarkGroup The @{Wrapper.Group} that receives the mark. + -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. + -- @param #string Text (Optional) Text displayed when mark is added. Default none. -- @return #number The resulting Mark ID which is a number. -- @usage -- local TargetCoord = TargetGroup:GetCoordinate() -- local MarkGroup = GROUP:FindByName( "AttackGroup" ) -- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup ) - function COORDINATE:MarkToGroup( MarkText, MarkGroup ) + function COORDINATE:MarkToGroup( MarkText, MarkGroup, ReadOnly, Text ) local MarkID = UTILS.GetMarkID() - trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), MarkGroup:GetID(), false, "" ) + if ReadOnly==nil then + ReadOnly=false + end + local text=Text or "" + trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), MarkGroup:GetID(), ReadOnly, text ) return MarkID end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 0cbc4474d..2857d755a 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -75,7 +75,7 @@ -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. -- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. -- @field #number Nshots Number of shots fired on current target. --- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0.5 km. +-- @field #number minrange Minimum firing range in kilometers. Targets closer than this distance are not engaged. Default 0.1 km. -- @field #number maxrange Maximum firing range in kilometers. Targets further away than this distance are not engaged. Default 10000 km. -- @field #number nukewarhead Explosion strength of tactical nuclear warhead in kg TNT. Default 75000. -- @field #number Nukes Number of nuclear shells, the group has available. Default is same number as normal shells. Note that if normal shells are empty, firing nukes is also not possible any more. @@ -86,7 +86,8 @@ -- @field #number relocateRmin Minimum distance in meters the group will look for places to relocate. -- @field #number relocateRmax Maximum distance in meters the group will look for places to relocate. -- @field #boolean markallow If true, Players are allowed to assign targets and moves for ARTY group by placing markers on the F10 map. Default is false. --- @field #number markkey Authorization key. Only player who know this key can assign targets and moves via markers on the F10 map. Default no authorization required. +-- @field #number markkey Authorization key. Only player who know this key can assign targets and moves via markers on the F10 map. Default no authorization required. +-- @field #boolean markreadonly Marks for targets are readonly and cannot be removed by players. Default is false. -- @extends Core.Fsm#FSM_CONTROLLABLE --- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can @@ -424,7 +425,7 @@ ARTY={ ammorockets={}, ammomissiles={}, Nshots=0, - minrange=500, + minrange=100, maxrange=1000000, nukewarhead=75000, Nukes=nil, @@ -436,6 +437,7 @@ ARTY={ relocateRmax=800, markallow=false, markkey=nil, + markreadonly=false, } --- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag @@ -457,7 +459,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.7" +ARTY.version="0.9.8" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -665,7 +667,7 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w table.insert(self.targets, _target) -- Trigger new target event. - self:NewTarget(_target) + self:__NewTarget(1, _target) return _name end @@ -732,21 +734,18 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) -- Prepare move array. local _move={name=_name, coord=coord, time=_time, speed=speed, onroad=onroad, cancel=cancel} - if self.Debug then - coord:MarkToAll(string.format("Battery %s move position.", self.Controllable:GetName())) - end - -- Add to table. table.insert(self.moves, _move) + return _name end --- Set minimum firing range. Targets closer than this distance are not engaged. -- @param #ARTY self --- @param #number range Min range in kilometers. Default is 0.5 km. +-- @param #number range Min range in kilometers. Default is 0.1 km. function ARTY:SetMinFiringRange(range) self:F({range=range}) - self.minrange=range*1000 or 500 + self.minrange=range*1000 or 100 end --- Set maximum firing range. Targets further away than this distance are not engaged. @@ -864,7 +863,7 @@ function ARTY:RemoveTarget(name) self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) if self.currentTarget then if self.currentTarget.name==name then - self:T(ARTY.id..string.format("Group %s: Cancelling current target %s (id=%d).", self.Controllable:GetName(), name, id)) + self:T(ARTY.id..string.format("Group %s: Cancelling current target %s.", self.Controllable:GetName(), name)) self:CeaseFire(self.currentTarget) end end @@ -881,6 +880,12 @@ function ARTY:RemoveMove(name) table.remove(self.moves, id) end self:T(ARTY.id..string.format("Group %s: Number of moves = %d.", self.Controllable:GetName(), #self.moves)) + if self.currentMove then + if self.currentMove.name==name then + self:T(ARTY.id..string.format("Group %s: Cancelling current move %s.", self.Controllable:GetName(), name)) + self:Arrived() + end + end end --- Delete ALL targets from current target list. @@ -973,9 +978,13 @@ end --- Enable assigning targets and moves by placing markers on the F10 map. -- @param #ARTY self -- @param #number key (Optional) Authorization key. Only players knowing this key can assign targets. Default is no authorization required. -function ARTY:SetMarkAssignmentsOn(key) +-- @param #boolean readonly (Optional) Marks are readonly and cannot be removed by players. This also means that targets cannot be cancelled by removing the mark. Default false. +function ARTY:SetMarkAssignmentsOn(key, readonly) self.markkey=key self.markallow=true + if readonly==nil then + self.markreadonly=false + end end --- Disable assigning targets by placing markers on the F10 map. @@ -1055,6 +1064,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Relocate max dist. = %d m\n", self.relocateRmax) text=text..string.format("Marker assignments = %s\n", tostring(self.markallow)) text=text..string.format("Marker auth. key = %s\n", tostring(self.markkey)) + text=text..string.format("Marker readonly = %s\n", tostring(self.markreadonly)) text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do @@ -1112,6 +1122,7 @@ function ARTY:_Markertext(text) assignment.battery={} assignment.move=false assignment.engage=false + assignment.readonly=false assignment.time=nil assignment.nshells=nil assignment.prio=nil @@ -1136,7 +1147,6 @@ function ARTY:_Markertext(text) local keywords=self:_split(text, ",") for _,key in pairs(keywords) do - --env.info("key="..key) local s=self:_split(key, " ") local val=s[2] @@ -1148,7 +1158,7 @@ function ARTY:_Markertext(text) for i=2,#v,2 do table.insert(assignment.battery, v[i]) - env.info(string.format("FF: Battery=%s.", v[i])) + self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) end elseif key:lower():find("time") then @@ -1158,27 +1168,27 @@ function ARTY:_Markertext(text) else assignment.time=val end - env.info(string.format("FF: Time=%s.", val)) + self:T2(ARTY.id..string.format("Key Time=%s.", val)) elseif key:lower():find("shots") then assignment.nshells=tonumber(s[2]) - env.info(string.format("FF: Shots=%s.", val)) + self:T(ARTY.id..string.format("Key Shots=%s.", val)) elseif key:lower():find("prio") then assignment.prio=tonumber(val) - env.info(string.format("FF: Prio=%s.", val)) + self:T2(string.format("Key Prio=%s.", val)) elseif key:lower():find("maxengage") then assignment.maxengage=tonumber(val) - env.info(string.format("FF: Maxengage=%s.", val)) + self:T2(ARTY.id..string.format("Key Maxengage=%s.", val)) elseif key:lower():find("radius") then assignment.radius=tonumber(val) - env.info(string.format("FF: Radius=%s.", val)) + self:T2(ARTY.id..string.format("Key Radius=%s.", val)) elseif key:lower():find("weapon") then @@ -1193,28 +1203,31 @@ function ARTY:_Markertext(text) else assignment.weapontype=ARTY.WeaponType.Auto end - env.info(string.format("FF: Weapon=%s.", val)) + self:T2(ARTY.id..string.format("Key Weapon=%s.", val)) elseif key:lower():find("speed") then assignment.speed=tonumber(val) - env.info(string.format("FF: Speed=%s.", val)) + self:T2(ARTY.id..string.format("Key Speed=%s.", val)) elseif key:lower():find("road") then assignment.onroad=true - env.info(string.format("FF: Onroad=true.")) + self:T2(ARTY.id..string.format("Key Onroad=true.")) elseif key:lower():find("key") then assignment.key=tonumber(val) - env.info(string.format("FF: Key=%s.", val)) + self:T(ARTY.id..string.format("Key Key=%s.", val)) + elseif key:lower():find("irrevocable") then + assignment.readonly=true + self:T2(ARTY.id..string.format("Key Readonly=true.")) end end else - env.info("FF: This is NO arty command!") + self:T2(ARTY.id..string.format("This is NO arty command:\n%s", tostring(text))) end return assignment @@ -1230,143 +1243,275 @@ function ARTY:onEvent(Event) return true end + -- Set battery and coalition. local batteryname=self.Controllable:GetName() local batterycoalition=self.Controllable:GetCoalition() - env.info(string.format("Event captured = %s", tostring(batteryname))) - env.info(string.format("Event id = %s", tostring(Event.id))) - env.info(string.format("Event time = %s", tostring(Event.time))) - env.info(string.format("Event idx = %s", tostring(Event.idx))) - env.info(string.format("Event coalition = %s", tostring(Event.coalition))) - env.info(string.format("Event group id = %s", tostring(Event.groupID))) - env.info(string.format("Event text = %s", tostring(Event.text))) + self:T(string.format("Event captured = %s", tostring(batteryname))) + self:T(string.format("Event id = %s", tostring(Event.id))) + self:T(string.format("Event time = %s", tostring(Event.time))) + self:T(string.format("Event idx = %s", tostring(Event.idx))) + self:T(string.format("Event coalition = %s", tostring(Event.coalition))) + self:T(string.format("Event group id = %s", tostring(Event.groupID))) + self:T(string.format("Event text = %s", tostring(Event.text))) self:E({eventid=Event.id, vec3=Event.pos}) if Event.initiator~=nil then local _unitname=Event.initiator:getName() - env.info(string.format("Event ini unit name = %s", tostring(_unitname))) + self:T(string.format("Event ini unit name = %s", tostring(_unitname))) end - if Event.id==world.event.S_EVENT_MARK_ADDED then - self:E({event="S_EVENT_MARK_ADDED", vec3=Event.pos}) + self:E({event="S_EVENT_MARK_ADDED", battery=batteryname, vec3=Event.pos}) elseif Event.id==world.event.S_EVENT_MARK_CHANGE then - self:E({event="S_EVENT_MARK_CHANGE", vec3=Event.pos}) + self:E({event="S_EVENT_MARK_CHANGE", battery=batteryname, vec3=Event.pos}) - -- Check if marker has a text and the "arty" keyword. - if Event.text~=nil and Event.text:lower():find("arty") then - - -- Check if the coalition is the same or an authorization key has been defined. - if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then - - -- Evaluate marker text and extract parameters. - local _assign=self:_Markertext(Event.text) - - -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. - local _assigned=true - if #_assign.battery>0 then - _assigned=false - for _,bat in pairs(_assign.battery) do - env.info(string.format("FF: compare %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) - if batteryname==bat then - _assigned=true - end - end - end - - -- Check if the authorization key is required and if it is valid. - local _validkey=true - if self.markkey~=nil then - _validkey=false - if _assign.key~=nil then - _validkey=self.markkey==_assign.key - end - self:T(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(_assign.key), tostring(_validkey))) - local text="" - if _assign.key==nil then - text=string.format("%s, authorization required but did not receive a key!", batteryname) - elseif _validkey==false then - text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(_assign.key)) - elseif _validkey==true then - text=string.format("%s, authorization successful!", batteryname) - end - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) - end - - -- We are meant. - if _assigned and _validkey then - - -- Convert (wrong x-->z, z-->x) vec3 - local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} - -- Get coordinate from vec3. - local _coord=COORDINATE:NewFromVec3(vec3) - - if _assign.move then - - local text=string.format("%s, received new relocation assignment.", batteryname) - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) - - -- Create a new name. - local _name=string.format("Marked Move ID=%d for battery %s", Event.idx, batteryname) - self:E(ARTY.id.._name) - - -- Assign a relocation of the arty group. - self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) - - else - - local text=string.format("%s, received new target assignment.", batteryname) - if _assign.time then - text=text..string.format("\nTime %s",_assign.time) - end - if _assign.prio then - text=text..string.format("\nPrio %d",_assign.prio) - end - if _assign.nshells then - text=text..string.format("\nShots %d",_assign.nshells) - end - if _assign.maxengage then - text=text..string.format("\nEngagements %d",_assign.maxengage) - end - if _assign.weapontype then - text=text..string.format("\nWeapon %s",self:_WeaponTypeName(_assign.weapontype)) - end - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) - - -- Create a new name. - local _name=string.format("Marked Target ID=%d for battery %s", Event.idx, batteryname) - self:E(ARTY.id.._name) - - -- Assign a new firing engagement. - self:AssignTargetCoord(_coord,_assign.prio,_assign.radius,_assign.nshells,_assign.maxengage,_assign.time,_assign.weapontype, _name, true) - - end - end - - end - end + -- Handle event. + self:_OnEventMarkChange(Event) elseif Event.id==world.event.S_EVENT_MARK_REMOVED then - self:E({event="S_EVENT_MARK_REMOVED", vec3=Event.pos}) - - -- Check if we have the right coalition. - if batterycoalition==Event.coalition and Event.text:lower():find("arty") then - - -- This should be the unique name of the target or move. - - if Event.text:lower():find("move") then - local _name=string.format("Marked Move ID=%d for battery %s", Event.idx, batteryname) - self:RemoveMove(_name) - else - local _name=string.format("Marked Target ID=%d for battery %s", Event.idx, batteryname) - self:RemoveTarget(_name) - end - end + self:E({event="S_EVENT_MARK_REMOVED", battery=batteryname, vec3=Event.pos}) + -- Hande event. + self:_OnEventMarkRemove(Event) end end +--- Function called when a F10 map mark was removed. +-- @param #ARTY self +-- @param #table Event Event data. +function ARTY:_OnEventMarkRemove(Event) + + -- Get battery coalition and name. + local batterycoalition=self.Controllable:GetCoalition() + local batteryname=self.Controllable:GetName() + + if Event.text~=nil and Event.text:find("BATTERY") then + + local _cancelmove=false + local _canceltarget=false + local _name="" + local _id=nil + if Event.text:find("Marked Relocation") then + _cancelmove=true + _name=string.format("BATTERY %s Marked Relocation ID=%d", batteryname, Event.idx) + _id=self:_GetMoveIndexByName(_name) + elseif Event.text:find("Marked Target") then + _canceltarget=true + _name=string.format("BATTERY %s Marked Target ID=%d", batteryname, Event.idx) + _id=self:_GetTargetIndexByName(_name) + else + return + end + + if _id==nil then + return + end + + -- Check if the coalition is the same or an authorization key has been defined. + if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then + + -- Get assignment. + local mykey=nil + if self.markkey~=nil then + -- keywords are split by "," + local keywords=self:_split(Event.text, ",") + for _,key in pairs(keywords) do + local s=self:_split(key, " ") + local val=s[2] + if key:lower():find("key") then + mykey=tonumber(val) + self:T(ARTY.id..string.format("Key Key=%s.", val)) + end + end + end + + -- Check if the authorization key is required and if it is valid. + local _validkey=true + if self.markkey~=nil then + _validkey=false + if mykey~=nil then + _validkey=self.markkey==mykey + end + self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) + local text="" + if mykey==nil then + text=string.format("%s, authorization required but did not receive a key!", batteryname) + elseif _validkey==false then + text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(mykey)) + elseif _validkey==true then + text=string.format("%s, authentification successful!", batteryname) + end + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + end + + -- Check if we have the right coalition. + if _validkey then + + -- This should be the unique name of the target or move. + if _cancelmove then + self:RemoveMove(_name) + elseif _canceltarget then + self:RemoveTarget(_name) + end + + end + + end + + end +end + +--- Function called when a F10 map mark was changed. +-- @param #ARTY self +-- @param #table Event Event data. +function ARTY:_OnEventMarkChange(Event) + + -- Check if marker has a text and the "arty" keyword. + if Event.text~=nil and Event.text:lower():find("arty") then + + -- Get battery coalition and name. + local batterycoalition=self.Controllable:GetCoalition() + local batteryname=self.Controllable:GetName() + + -- Check if the coalition is the same or an authorization key has been defined. + if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then + + -- Evaluate marker text and extract parameters. + local _assign=self:_Markertext(Event.text) + + -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. + local _assigned=true + if #_assign.battery>0 then + _assigned=false + for _,bat in pairs(_assign.battery) do + self:T2(ARTY.id..string.format("Compare battery names %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) + if batteryname==bat then + _assigned=true + end + end + end + + -- Check if ENGAGE or MOVE keywords were found. + if not (_assign.engage or _assign.move) or (not _assigned) then + return + end + + -- Check if the authorization key is required and if it is valid. + local _validkey=true + if self.markkey~=nil then + _validkey=false + if _assign.key~=nil then + _validkey=self.markkey==_assign.key + end + self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(_assign.key), tostring(_validkey))) + local text="" + if _assign.key==nil then + text=string.format("%s, authorization required but did not receive a key!", batteryname) + elseif _validkey==false then + text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(_assign.key)) + elseif _validkey==true then + text=string.format("%s, authentification successful!", batteryname) + end + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + end + + -- We are meant. + if _validkey then + + -- Convert (wrong x-->z, z-->x) vec3 + local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} + + -- Get coordinate from vec3. + local _coord=COORDINATE:NewFromVec3(vec3) + + -- Remove old mark because it might contain confidential data such as the key. + -- Also I don't know who can see the mark which was created. + _coord:RemoveMark(Event.idx) + + local _id=UTILS._MarkID+1 + + if _assign.move then + + -- Create a new name. This determins the string we search when deleting a move! + local _name=string.format("BATTERY %s Marked Relocation ID=%d", batteryname, _id) + self:E(ARTY.id.._name) + + local text=string.format("%s, received new relocation assignment.", batteryname) + text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + + -- Assign a relocation of the arty group. + local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) + + if _movename~=nil then + local _mid=self:_GetMoveIndexByName(_movename) + local _move=self.moves[_mid] + + -- Create new target name. + local clock=tostring(self:_SecondsToClock(_move.time)) + local _road="Off Road" + if _move.onroad==true then + _road="On Road" + end + local _markertext=_movename..string.format(", Time %s, Speed %d km/h, %s.", clock, _move.speed, _road) + + -- Create a new mark. This will trigger the mark added event. + local _randomcoord=_coord:GetRandomCoordinateInRadius(100) + _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) + end + + else + + -- Create a new name. + local _name=string.format("BATTERY %s Marked Target ID=%d", batteryname, _id) + self:E(ARTY.id.._name) + + local text=string.format("%s, received new target assignment.", batteryname) + text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) + if _assign.time then + text=text..string.format("\nTime %s",_assign.time) + end + if _assign.prio then + text=text..string.format("\nPrio %d",_assign.prio) + end + if _assign.nshells then + text=text..string.format("\nShots %d",_assign.nshells) + end + if _assign.maxengage then + text=text..string.format("\nEngagements %d",_assign.maxengage) + end + if _assign.weapontype then + text=text..string.format("\nWeapon %s",self:_WeaponTypeName(_assign.weapontype)) + end + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + + -- Assign a new firing engagement. + -- Note, we set unique=true so this target gets only added once. + local _targetname=self:AssignTargetCoord(_coord,_assign.prio,_assign.radius,_assign.nshells,_assign.maxengage,_assign.time,_assign.weapontype, _name, true) + + if _targetname~=nil then + local _tid=self:_GetTargetIndexByName(_targetname) + local _target=self.targets[_tid] + + -- Create new target name. + local clock=tostring(self:_SecondsToClock(_target.time)) + local weapon=self:_WeaponTypeName(_target.weapontype) + local _markertext=_targetname..string.format(", Priority %d, Radius=%d m, Shots %d, Engagements=%d, Weapon %s, Time %s", _target.prio, _target.radius, _target.nshells, _target.maxengage, weapon, clock) + + -- Create a new mark. This will trigger the mark added event. + local _randomcoord=_coord:GetRandomCoordinateInRadius(250) + _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) + end + end + end + + end + end + +end + --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self function ARTY:_StatusReport() @@ -2298,6 +2443,9 @@ function ARTY:onafterArrived(Controllable, From, Event, To) -- Set alarm state to auto. self.Controllable:OptionAlarmStateAuto() + -- Clear Tasks + self.Controllable:ClearTasks() + -- Send message local text=string.format("%s, arrived at destination.", Controllable:GetName()) self:T(ARTY.id..text) @@ -2827,8 +2975,9 @@ function ARTY:_GetTargetIndexByName(name) for i=1,#self.targets do local targetname=self.targets[i].name + self:T(ARTY.id..string.format("Have target with name %s. Index = %d", targetname, i)) if targetname==name then - self:T2(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) + self:T(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) return i end end From e9473e917991a8dc659cbd2e16689eeb7732ece3 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 2 Jun 2018 07:25:43 +0200 Subject: [PATCH 149/170] Documentation improvements --- Moose Development/Moose/Tasking/Task_A2A.lua | 12 +++--------- Moose Development/Moose/Tasking/Task_A2G.lua | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index e3d3ed793..0a18e28cc 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -361,9 +361,7 @@ do -- TASK_A2A_INTERCEPT -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2A_INTERCEPT class, extends @{Task_A2A#TASK_A2A} - -- - -- The TASK_A2A_INTERCEPT class defines an intercept task for a human player to be executed. + --- Defines an intercept task for a human player to be executed. -- When enemy planes need to be intercepted by human players, use this task type to urgen the players to get out there! -- -- The TASK_A2A_INTERCEPT is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks @@ -460,9 +458,7 @@ do -- TASK_A2A_SWEEP -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2A_SWEEP class, extends @{Task_A2A#TASK_A2A} - -- - -- The TASK_A2A_SWEEP class defines a sweep task for a human player to be executed. + --- Defines a sweep task for a human player to be executed. -- A sweep task needs to be given when targets were detected but somehow the detection was lost. -- Most likely, these enemy planes are hidden in the mountains or are flying under radar. -- These enemy planes need to be sweeped by human players, and use this task type to urge the players to get out there and find those enemy fighters. @@ -571,9 +567,7 @@ do -- TASK_A2A_ENGAGE -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2A_ENGAGE class, extends @{Task_A2A#TASK_A2A} - -- - -- The TASK_A2A_ENGAGE class defines an engage task for a human player to be executed. + --- Defines an engage task for a human player to be executed. -- When enemy planes are close to human players, use this task type is used urge the players to get out there! -- -- The TASK_A2A_ENGAGE is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create engage tasks diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 319a30fb2..d30eff7aa 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -366,9 +366,7 @@ do -- TASK_A2G_SEAD -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2G_SEAD class, extends @{Task_A2G#TASK_A2G} - -- - -- The TASK_A2G_SEAD class defines an Suppression or Extermination of Air Defenses task for a human player to be executed. + --- Defines an Suppression or Extermination of Air Defenses task for a human player to be executed. -- These tasks are important to be executed as they will help to achieve air superiority at the vicinity. -- -- The TASK_A2G_SEAD is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks @@ -459,9 +457,7 @@ do -- TASK_A2G_BAI -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2G_BAI class, extends @{Task_A2G#TASK_A2G} - -- - -- The TASK_A2G_BAI class defines an Battlefield Air Interdiction task for a human player to be executed. + -- Defines an Battlefield Air Interdiction task for a human player to be executed. -- These tasks are more strategic in nature and are most of the time further away from friendly forces. -- BAI tasks can also be used to express the abscence of friendly forces near the vicinity. -- @@ -555,9 +551,7 @@ do -- TASK_A2G_CAS -- @field Core.Set#SET_UNIT TargetSetUnit -- @extends Tasking.Task#TASK - --- # TASK_A2G_CAS class, extends @{Task_A2G#TASK_A2G} - -- - -- The TASK_A2G_CAS class defines an Close Air Support task for a human player to be executed. + -- Defines an Close Air Support task for a human player to be executed. -- Friendly forces will be in the vicinity within 6km from the enemy. -- -- The TASK_A2G_CAS is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create CAS tasks From d9d53db53f04c71e90648e716ffc31f570cda60d Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 2 Jun 2018 18:23:06 +0200 Subject: [PATCH 150/170] Documentation improvements. --- Moose Development/Moose/AI/AI_A2A_Cap.lua | 14 ++-- .../Moose/AI/AI_A2A_Dispatcher.lua | 8 +-- Moose Development/Moose/AI/AI_A2A_Gci.lua | 14 ++-- Moose Development/Moose/AI/AI_BAI.lua | 14 ++-- Moose Development/Moose/AI/AI_Balancer.lua | 2 +- Moose Development/Moose/AI/AI_CAP.lua | 14 ++-- Moose Development/Moose/AI/AI_CAS.lua | 14 ++-- Moose Development/Moose/AI/AI_Formation.lua | 24 +++---- .../Moose/Actions/Act_Account.lua | 4 +- .../Moose/Actions/Act_Assign.lua | 6 +- .../Moose/Actions/Act_Assist.lua | 2 +- Moose Development/Moose/Actions/Act_Route.lua | 4 +- Moose Development/Moose/Cargo/Cargo.lua | 8 +-- Moose Development/Moose/Core/Base.lua | 2 +- Moose Development/Moose/Core/Event.lua | 10 +-- Moose Development/Moose/Core/Message.lua | 18 ++--- Moose Development/Moose/Core/Point.lua | 10 +-- Moose Development/Moose/Core/Radio.lua | 26 +++---- .../Moose/Core/ScheduleDispatcher.lua | 2 +- Moose Development/Moose/Core/Set.lua | 34 ++++----- Moose Development/Moose/Core/Spawn.lua | 2 +- Moose Development/Moose/Core/Zone.lua | 72 +++++++++---------- .../Moose/Functional/Artillery.lua | 4 +- .../Moose/Functional/Designate.lua | 2 +- .../Moose/Functional/Scoring.lua | 2 +- .../Moose/Tasking/DetectionManager.lua | 22 +++--- Moose Development/Moose/Tasking/Task.lua | 6 +- .../Moose/Tasking/TaskZoneCapture.lua | 8 +-- Moose Development/Moose/Tasking/Task_A2A.lua | 16 ++--- .../Moose/Tasking/Task_A2A_Dispatcher.lua | 2 +- Moose Development/Moose/Tasking/Task_A2G.lua | 10 +-- .../Moose/Tasking/Task_CARGO.lua | 6 +- .../Moose/Tasking/Task_Cargo_Dispatcher.lua | 2 +- .../Moose/Tasking/Task_Manager.lua | 18 ++--- Moose Development/Moose/Wrapper/Client.lua | 6 +- Moose Development/Moose/Wrapper/Group.lua | 4 +- Moose Development/Moose/Wrapper/Object.lua | 2 +- .../Moose/Wrapper/Positionable.lua | 12 ++-- Moose Development/Moose/Wrapper/Scenery.lua | 2 +- Moose Development/Moose/Wrapper/Static.lua | 2 +- 40 files changed, 215 insertions(+), 215 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index e6abde8d9..480bd39ec 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -61,13 +61,13 @@ -- -- ### 2.2 AI_A2A_CAP Events -- --- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. --- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. -- * **@{#AI_A2A_CAP.Engage}**: Let the AI engage the bogeys. -- * **@{#AI_A2A_CAP.Abort}**: Aborts the engagement and return patrolling in the patrol zone. --- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. @@ -80,7 +80,7 @@ -- that will define when the AI will engage with the detected airborne enemy targets. -- The range can be beyond or smaller than the range of the Patrol Zone. -- The range is applied at the position of the AI. --- Use the method @{AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range. +-- Use the method @{AI.AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range. -- -- ## 4. Set the Zone of Engagement -- @@ -88,7 +88,7 @@ -- -- An optional @{Zone} can be set, -- that will define when the AI will engage with the detected airborne enemy targets. --- Use the method @{AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone. +-- Use the method @{AI.AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 92ecfce9b..1dd660b49 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -220,7 +220,7 @@ do -- AI_A2A_DISPATCHER -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. -- It all depends on what the desired effect is. -- - -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the AI\_A2A\_DISPATCHER class. + -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional.Detection#DETECTION_BASE} object that is given as the input parameter of the AI\_A2A\_DISPATCHER class. -- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network, -- increasing or decreasing the radar coverage of the Early Warning System. -- @@ -821,7 +821,7 @@ do -- AI_A2A_DISPATCHER --- AI_A2A_DISPATCHER constructor. -- This is defining the A2A DISPATCHER for one coaliton. - -- The Dispatcher works with a @{Functional#Detection} object that is taking of the detection of targets using the EWR units. + -- The Dispatcher works with a @{Functional.Detection#DETECTION_BASE} object that is taking of the detection of targets using the EWR units. -- The Detection object is polymorphic, depending on the type of detection object choosen, the detection will work differently. -- @param #AI_A2A_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network. @@ -3165,7 +3165,7 @@ do -- @extends #AI_A2A_DISPATCHER --- Create an automatic air defence system for a coalition setting up GCI and CAP air defenses. - -- The class derives from @{AI#AI_A2A_DISPATCHER} and thus, all the methods that are defined in the @{AI#AI_A2A_DISPATCHER} class, can be used also in AI\_A2A\_GCICAP. + -- The class derives from @{#AI_A2A_DISPATCHER} and thus, all the methods that are defined in the @{#AI_A2A_DISPATCHER} class, can be used also in AI\_A2A\_GCICAP. -- -- === -- @@ -3268,7 +3268,7 @@ do -- -- **The place of the helicopter is important, as the airbase closest to the helicopter will be the airbase from where the CAP planes will take off for CAP.** -- - -- ## 2) There are a lot of defaults set, which can be further modified using the methods in @{AI#AI_A2A_DISPATCHER}: + -- ## 2) There are a lot of defaults set, which can be further modified using the methods in @{#AI_A2A_DISPATCHER}: -- -- ### 2.1) Planes are taking off in the air from the airbases. -- diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index c1acb6df7..cc24341c3 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -64,13 +64,13 @@ -- -- ### 2.2 AI_A2A_GCI Events -- --- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. --- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. -- * **@{#AI_A2A_GCI.Engage}**: Let the AI engage the bogeys. -- * **@{#AI_A2A_GCI.Abort}**: Aborts the engagement and return patrolling in the patrol zone. --- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. @@ -83,7 +83,7 @@ -- that will define when the AI will engage with the detected airborne enemy targets. -- The range can be beyond or smaller than the range of the Patrol Zone. -- The range is applied at the position of the AI. --- Use the method @{AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range. +-- Use the method @{AI.AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range. -- -- ## 4. Set the Zone of Engagement -- @@ -91,7 +91,7 @@ -- -- An optional @{Zone} can be set, -- that will define when the AI will engage with the detected airborne enemy targets. --- Use the method @{AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone. +-- Use the method @{AI.AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index fa66d3993..0265e7113 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -99,13 +99,13 @@ -- -- ### 2.2. AI_BAI_ZONE Events -- --- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. --- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. -- * **@{#AI_BAI_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds. -- * **@{#AI_BAI_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. --- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}. -- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task. -- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. @@ -179,7 +179,7 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. - -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. @@ -191,7 +191,7 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. - -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index f82631dab..845826703 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -31,7 +31,7 @@ -- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players. -- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. -- --- The parent class @{Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM). +-- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM). -- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods. -- An explanation about state and event transition methods can be found in the @{FSM} module documentation. -- diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index f6b42f37b..e98f4f135 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -79,13 +79,13 @@ -- -- ### 2.2 AI_CAP_ZONE Events -- --- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. --- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. -- * **@{#AI_CAP_ZONE.Engage}**: Let the AI engage the bogeys. -- * **@{#AI_CAP_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. --- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. @@ -98,7 +98,7 @@ -- that will define when the AI will engage with the detected airborne enemy targets. -- The range can be beyond or smaller than the range of the Patrol Zone. -- The range is applied at the position of the AI. --- Use the method @{AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range. +-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range. -- -- ## 4. Set the Zone of Engagement -- @@ -106,7 +106,7 @@ -- -- An optional @{Zone} can be set, -- that will define when the AI will engage with the detected airborne enemy targets. --- Use the method @{AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone. +-- Use the method @{AI.AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 2ef978853..7ddb55876 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -99,13 +99,13 @@ -- -- ### 2.2. AI_CAS_ZONE Events -- --- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. --- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. -- * **@{#AI_CAS_ZONE.Engage}**: Engage the AI to provide CAS in the Engage Zone, destroying any target it finds. -- * **@{#AI_CAS_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. --- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. --- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}. -- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task. -- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. @@ -166,7 +166,7 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. - -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. @@ -178,7 +178,7 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. -- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. -- If parameter is not defined the unit / controllable will choose expend on its own discretion. - -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. -- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index be8abc9e9..e262a67e4 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -84,25 +84,25 @@ -- -- Create a new SPAWN object with the @{#AI_FORMATION.New} method: -- --- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Wrapper.Unit#UNIT}, with an optional briefing text. +-- * @{#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Wrapper.Unit#UNIT}, with an optional briefing text. -- -- ## Formation methods -- -- The following methods can be used to set or change the formation: -- --- * @{AI_Formation#AI_FORMATION.FormationLine}(): Form a line formation (core formation function). --- * @{AI_Formation#AI_FORMATION.FormationTrail}(): Form a trail formation. --- * @{AI_Formation#AI_FORMATION.FormationLeftLine}(): Form a left line formation. --- * @{AI_Formation#AI_FORMATION.FormationRightLine}(): Form a right line formation. --- * @{AI_Formation#AI_FORMATION.FormationRightWing}(): Form a right wing formation. --- * @{AI_Formation#AI_FORMATION.FormationLeftWing}(): Form a left wing formation. --- * @{AI_Formation#AI_FORMATION.FormationCenterWing}(): Form a center wing formation. --- * @{AI_Formation#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing. --- * @{AI_Formation#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation. +-- * @{#AI_FORMATION.FormationLine}(): Form a line formation (core formation function). +-- * @{#AI_FORMATION.FormationTrail}(): Form a trail formation. +-- * @{#AI_FORMATION.FormationLeftLine}(): Form a left line formation. +-- * @{#AI_FORMATION.FormationRightLine}(): Form a right line formation. +-- * @{#AI_FORMATION.FormationRightWing}(): Form a right wing formation. +-- * @{#AI_FORMATION.FormationLeftWing}(): Form a left wing formation. +-- * @{#AI_FORMATION.FormationCenterWing}(): Form a center wing formation. +-- * @{#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing. +-- * @{#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation. -- -- ## Randomization -- --- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters. +-- Use the method @{AI.AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters. -- -- @usage -- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart() @@ -901,7 +901,7 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS end ---- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation. +--- Use the method @{AI.AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation. -- @param #AI_FORMATION self -- @param #number FlightRandomization The formation flying errors that pilots can make while in formation. Is a range set in meters. -- @return #AI_FORMATION diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 0d057dc24..b0d26c9ea 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -9,7 +9,7 @@ do -- ACT_ACCOUNT - --- # @{#ACT_ACCOUNT} FSM class, extends @{Fsm#FSM_PROCESS} + --- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS} -- -- ## ACT_ACCOUNT state machine: -- @@ -138,7 +138,7 @@ end -- ACT_ACCOUNT do -- ACT_ACCOUNT_DEADS - --- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#ACT_ACCOUNT} + --- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT} -- -- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units. -- The process is given a @{Set} of units that will be tracked upon successful destruction. diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 5e8984b18..969009ab1 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -2,7 +2,7 @@ -- -- === -- --- # @{#ACT_ASSIGN} FSM template class, extends @{Fsm#FSM_PROCESS} +-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS} -- -- ## ACT_ASSIGN state machine: -- @@ -54,7 +54,7 @@ -- -- === -- --- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} +-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN} -- -- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task. -- @@ -64,7 +64,7 @@ -- -- === -- --- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} +-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN} -- -- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option. -- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task. diff --git a/Moose Development/Moose/Actions/Act_Assist.lua b/Moose Development/Moose/Actions/Act_Assist.lua index b5a473fda..f9cd5fc3a 100644 --- a/Moose Development/Moose/Actions/Act_Assist.lua +++ b/Moose Development/Moose/Actions/Act_Assist.lua @@ -48,7 +48,7 @@ -- -- === -- --- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#ACT_ASSIST} +-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#ACT_ASSIST} -- -- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}. -- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour. diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index 87ee9a72e..9f858879f 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -2,7 +2,7 @@ -- -- === -- --- # @{#ACT_ROUTE} FSM class, extends @{Fsm#FSM_PROCESS} +-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS} -- -- ## ACT_ROUTE state machine: -- @@ -60,7 +60,7 @@ -- -- === -- --- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE} +-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE} -- -- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}. -- The player receives on perioding times messages with the coordinates of the route to follow. diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index f5570dd18..8add3c374 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -36,14 +36,14 @@ -- The cargo must be in the **Loaded** state. -- @function [parent=#CARGO] UnBoard -- @param #CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. --- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. -- The cargo must be in the **Loaded** state. -- @function [parent=#CARGO] __UnBoard -- @param #CARGO self -- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. -- Load @@ -68,14 +68,14 @@ -- The cargo must be in the **Loaded** state. -- @function [parent=#CARGO] UnLoad -- @param #CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. --- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. -- The cargo must be in the **Loaded** state. -- @function [parent=#CARGO] __UnLoad -- @param #CARGO self -- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. -- State Transition Functions diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 996376961..83d9cd5a7 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -122,7 +122,7 @@ local _ClassID = 0 -- ### 1.3.2 Event Handling of DCS Events -- -- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called --- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information +-- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information -- about the event that occurred. -- -- Find below an example of the prototype how to write an event handling function for two units: diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index f61e0ca40..4585a965b 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -72,7 +72,7 @@ -- ### 1.3.2 Event Handling of DCS Events -- -- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called --- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information +-- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information -- about the event that occurred. -- -- Find below an example of the prototype how to write an event handling function for two units: @@ -114,7 +114,7 @@ -- -- # 3) EVENTDATA type -- --- The @{Event#EVENTDATA} structure contains all the fields that are populated with event information before +-- The @{Core.Event#EVENTDATA} structure contains all the fields that are populated with event information before -- an Event Handler method is being called by the event dispatcher. -- The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events. -- There are basically 4 main categories of information stored in the EVENTDATA structure: @@ -229,7 +229,7 @@ EVENTS = { -- -- @field DCS#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{DCS#Unit} or @{DCS#StaticObject}. -- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). --- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCSStaticObject#StaticObject}. +-- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCS#StaticObject}. -- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name. -- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Wrapper.Unit#UNIT} of the initiator Unit object. -- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName). @@ -242,9 +242,9 @@ EVENTS = { -- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator. -- @field #string IniTypeName (UNIT) The type name of the initiator. -- --- @field DCS#Unit target (UNIT/STATIC) The target @{DCS#Unit} or @{DCSStaticObject#StaticObject}. +-- @field DCS#Unit target (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}. -- @field DCS#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). --- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCSStaticObject#StaticObject}. +-- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}. -- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name. -- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Wrapper.Unit#UNIT} of the target Unit object. -- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName). diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 926284332..bb58abaac 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -15,26 +15,26 @@ -- -- ## MESSAGE construction -- --- Messages are created with @{Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet. +-- Messages are created with @{#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet. -- To send messages, you need to use the To functions. -- -- ## Send messages to an audience -- -- Messages are sent: -- --- * To a @{Client} using @{Message#MESSAGE.ToClient}(). --- * To a @{Wrapper.Group} using @{Message#MESSAGE.ToGroup}() --- * To a coalition using @{Message#MESSAGE.ToCoalition}(). --- * To the red coalition using @{Message#MESSAGE.ToRed}(). --- * To the blue coalition using @{Message#MESSAGE.ToBlue}(). --- * To all Players using @{Message#MESSAGE.ToAll}(). +-- * To a @{Client} using @{#MESSAGE.ToClient}(). +-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}() +-- * To a coalition using @{#MESSAGE.ToCoalition}(). +-- * To the red coalition using @{#MESSAGE.ToRed}(). +-- * To the blue coalition using @{#MESSAGE.ToBlue}(). +-- * To all Players using @{#MESSAGE.ToAll}(). -- -- ## Send conditionally to an audience -- -- Messages can be sent conditionally to an audience (when a condition is true): -- --- * To all players using @{Message#MESSAGE.ToAllIf}(). --- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}(). +-- * To all players using @{#MESSAGE.ToAllIf}(). +-- * To a coalition using @{#MESSAGE.ToCoalitionIf}(). -- -- === -- diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 632c1007c..faf1a49d6 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -43,8 +43,8 @@ do -- COORDINATE -- A new COORDINATE object can be created with: -- -- * @{#COORDINATE.New}(): a 3D point. - -- * @{#COORDINATE.NewFromVec2}(): a 2D point created from a @{DCSTypes#Vec2}. - -- * @{#COORDINATE.NewFromVec3}(): a 3D point created from a @{DCSTypes#Vec3}. + -- * @{#COORDINATE.NewFromVec2}(): a 2D point created from a @{DCS#Vec2}. + -- * @{#COORDINATE.NewFromVec3}(): a 3D point created from a @{DCS#Vec3}. -- -- ## Create waypoints for routes -- @@ -1610,7 +1610,7 @@ do -- POINT_VEC3 -- A new POINT_VEC3 object can be created with: -- -- * @{#POINT_VEC3.New}(): a 3D point. - -- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCSTypes#Vec3}. + -- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCS#Vec3}. -- -- -- ## Manupulate the X, Y, Z coordinates of the POINT_VEC3 @@ -1814,8 +1814,8 @@ do -- POINT_VEC2 -- -- A new POINT_VEC2 instance can be created with: -- - -- * @{Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. - -- * @{Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCSTypes#Vec2}. + -- * @{Core.Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. + -- * @{Core.Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCS#Vec2}. -- -- ## Manupulate the X, Altitude, Y coordinates of the 2D point -- diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index 85dc9162a..77def8fa6 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -16,10 +16,10 @@ -- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file), -- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission. -- --- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Positionable#POSITIONABLE} +-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE} -- -- * If the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically, --- * If the transmitter is any other @{Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped. +-- * If the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped. -- -- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft, -- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below). @@ -40,11 +40,11 @@ -- -- There are 3 steps to a successful radio transmission. -- --- * First, you need to **"add a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function, +-- * First, you need to **"add a @{#RADIO} object** to your @{Wrapper.Positionable#POSITIONABLE}. This is done using the @{Wrapper.Positionable#POSITIONABLE.GetRadio}() function, -- * Then, you will **set the relevant parameters** to the transmission (see below), -- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function. -- --- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Positionable#POSITIONABLE} +-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Wrapper.Positionable#POSITIONABLE} -- -- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"), -- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission. @@ -56,14 +56,14 @@ -- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration, -- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call -- --- Additional Methods to set relevant parameters if the transmiter is any other @{Positionable#POSITIONABLE} +-- Additional Methods to set relevant parameters if the transmiter is any other @{Wrapper.Positionable#POSITIONABLE} -- -- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts -- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call -- -- What is this power thing ? -- --- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna, +-- * If your transmission is sent by a @{Wrapper.Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna, -- * Otherwise, DCS sets it automatically, depending on what's available on your Unit, -- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**, -- * This an automated DCS calculation you have no say on, @@ -92,7 +92,7 @@ RADIO = { } --- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast --- If you want to create a RADIO, you probably should use @{Positionable#POSITIONABLE.GetRadio}() instead +-- If you want to create a RADIO, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetRadio}() instead -- @param #RADIO self -- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities. -- @return #RADIO Radio @@ -261,7 +261,7 @@ end --- Create a new transmission, that is to say, populate the RADIO with relevant data -- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP, --- but it will work for any @{Positionable#POSITIONABLE}. +-- but it will work for any @{Wrapper.Positionable#POSITIONABLE}. -- Only the RADIO and the Filename are mandatory. -- @param #RADIO self -- @param #string FileName @@ -286,7 +286,7 @@ end --- Actually Broadcast the transmission -- * The Radio has to be populated with the new transmission before broadcasting. --- * Please use RADIO setters or either @{Radio#RADIO.NewGenericTransmission} or @{Radio#RADIO.NewUnitTransmission} +-- * Please use RADIO setters or either @{#RADIO.NewGenericTransmission} or @{#RADIO.NewUnitTransmission} -- * This class is in fact pretty smart, it determines the right DCS function to use depending on the type of POSITIONABLE -- * If the POSITIONABLE is not a UNIT or a GROUP, we use the generic (but limited) trigger.action.radioTransmission() -- * If the POSITIONABLE is a UNIT or a GROUP, we use the "TransmitMessage" Command @@ -338,7 +338,7 @@ function RADIO:StopBroadcast() end ---- After attaching a @{#BEACON} to your @{Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want. +--- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want. -- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon. -- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is -- attach to a cargo crate, for exemple. @@ -350,8 +350,8 @@ end -- -- ## General Purpose Radio Beacon usage -- --- This beacon will work with any @{Positionable#POSITIONABLE}, but **it won't follow the @{Positionable#POSITIONABLE}** ! This means that you should only use it with --- @{Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon. +-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with +-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon. -- Use @{#BEACON:StopRadioBeacon}() to stop it. -- -- @type BEACON @@ -361,7 +361,7 @@ BEACON = { } --- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.AATACAN} or @{#BEACON.Generic} --- If you want to create a BEACON, you probably should use @{Positionable#POSITIONABLE.GetBeacon}() instead. +-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead. -- @param #BEACON self -- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities. -- @return #BEACON Beacon diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index a9d27adbc..8173c85c8 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -22,7 +22,7 @@ -- -- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object. -- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER. --- The SCHEDULER object plans new scheduled functions through the @{Scheduler#SCHEDULER.Schedule}() method. +-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method. -- The Schedule() method returns the CallID that is the reference ID for each planned schedule. -- -- === diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 2209dcad1..78607d83d 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -381,9 +381,9 @@ function SET_BASE:FilterStop() return self end ---- Iterate the SET_BASE while identifying the nearest object from a @{Point#POINT_VEC2}. +--- Iterate the SET_BASE while identifying the nearest object from a @{Core.Point#POINT_VEC2}. -- @param #SET_BASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest object in the set. +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest object in the set. -- @return Core.Base#BASE The closest object. function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ) self:F2( PointVec2 ) @@ -852,9 +852,9 @@ function SET_GROUP:FindGroup( GroupName ) return GroupFound end ---- Iterate the SET_GROUP while identifying the nearest object from a @{Point#POINT_VEC2}. +--- Iterate the SET_GROUP while identifying the nearest object from a @{Core.Point#POINT_VEC2}. -- @param #SET_GROUP self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest object in the set. +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest object in the set. -- @return Wrapper.Group#GROUP The closest group. function SET_GROUP:FindNearestGroupFromPointVec2( PointVec2 ) self:F2( PointVec2 ) @@ -4125,9 +4125,9 @@ function SET_AIRBASE:ForEachAirbase( IteratorFunction, ... ) return self end ---- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Point#POINT_VEC2}. +--- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Core.Point#POINT_VEC2}. -- @param #SET_AIRBASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}. +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}. -- @return Wrapper.Airbase#AIRBASE The closest @{Wrapper.Airbase#AIRBASE}. function SET_AIRBASE:FindNearestAirbaseFromPointVec2( PointVec2 ) self:F2( PointVec2 ) @@ -4440,10 +4440,10 @@ function SET_CARGO:ForEachCargo( IteratorFunction, ... ) --R2.1 return self end ---- (R2.1) Iterate the SET_CARGO while identifying the nearest @{Cargo#CARGO} from a @{Point#POINT_VEC2}. +--- (R2.1) Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#POINT_VEC2}. -- @param #SET_CARGO self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Cargo#CARGO}. --- @return Wrapper.Cargo#CARGO The closest @{Cargo#CARGO}. +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Cargo.Cargo#CARGO}. +-- @return Wrapper.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}. function SET_CARGO:FindNearestCargoFromPointVec2( PointVec2 ) --R2.1 self:F2( PointVec2 ) @@ -4480,36 +4480,36 @@ function SET_CARGO:FirstCargoWithStateAndNotDeployed( State ) end ---- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is UnLoaded. +--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded. -- @param #SET_CARGO self --- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. function SET_CARGO:FirstCargoUnLoaded() local FirstCargo = self:FirstCargoWithState( "UnLoaded" ) return FirstCargo end ---- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is UnLoaded and not Deployed. +--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded and not Deployed. -- @param #SET_CARGO self --- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. function SET_CARGO:FirstCargoUnLoadedAndNotDeployed() local FirstCargo = self:FirstCargoWithStateAndNotDeployed( "UnLoaded" ) return FirstCargo end ---- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is Loaded. +--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Loaded. -- @param #SET_CARGO self --- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. function SET_CARGO:FirstCargoLoaded() local FirstCargo = self:FirstCargoWithState( "Loaded" ) return FirstCargo end ---- Iterate the SET_CARGO while identifying the first @{Cargo#CARGO} that is Deployed. +--- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Deployed. -- @param #SET_CARGO self --- @return Cargo.Cargo#CARGO The first @{Cargo#CARGO}. +-- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. function SET_CARGO:FirstCargoDeployed() local FirstCargo = self:FirstCargoWithState( "Deployed" ) return FirstCargo diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 7cf879f08..b07ea4421 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -184,7 +184,7 @@ -- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. -- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Wrapper.Airbase}, which can be an airdrome, ship or helipad. -- --- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. +-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{Wrapper.Group#GROUP.New} object, that contains a reference to the DCSGroup object. -- You can use the @{GROUP} object to do further actions with the DCSGroup. -- -- ### **Scheduled** spawning methods diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 55a1a0412..211c44306 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -180,14 +180,14 @@ function ZONE_BASE:IsPointVec3InZone( PointVec3 ) end ---- Returns the @{DCSTypes#Vec2} coordinate of the zone. +--- Returns the @{DCS#Vec2} coordinate of the zone. -- @param #ZONE_BASE self -- @return #nil. function ZONE_BASE:GetVec2() return nil end ---- Returns a @{Point#POINT_VEC2} of the zone. +--- Returns a @{Core.Point#POINT_VEC2} of the zone. -- @param #ZONE_BASE self -- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return Core.Point#POINT_VEC2 The PointVec2 of the zone. @@ -204,7 +204,7 @@ function ZONE_BASE:GetPointVec2() end ---- Returns a @{Point#COORDINATE} of the zone. +--- Returns a @{Core.Point#COORDINATE} of the zone. -- @param #ZONE_BASE self -- @return Core.Point#COORDINATE The Coordinate of the zone. function ZONE_BASE:GetCoordinate() @@ -220,7 +220,7 @@ function ZONE_BASE:GetCoordinate() end ---- Returns the @{DCSTypes#Vec3} of the zone. +--- Returns the @{DCS#Vec3} of the zone. -- @param #ZONE_BASE self -- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return DCS#Vec3 The Vec3 of the zone. @@ -238,7 +238,7 @@ function ZONE_BASE:GetVec3( Height ) return Vec3 end ---- Returns a @{Point#POINT_VEC3} of the zone. +--- Returns a @{Core.Point#POINT_VEC3} of the zone. -- @param #ZONE_BASE self -- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return Core.Point#POINT_VEC3 The PointVec3 of the zone. @@ -254,7 +254,7 @@ function ZONE_BASE:GetPointVec3( Height ) return PointVec3 end ---- Returns a @{Point#COORDINATE} of the zone. +--- Returns a @{Core.Point#COORDINATE} of the zone. -- @param #ZONE_BASE self -- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return Core.Point#COORDINATE The Coordinate of the zone. @@ -271,21 +271,21 @@ function ZONE_BASE:GetCoordinate( Height ) --R2.1 end ---- Define a random @{DCSTypes#Vec2} within the zone. +--- Define a random @{DCS#Vec2} within the zone. -- @param #ZONE_BASE self -- @return DCS#Vec2 The Vec2 coordinates. function ZONE_BASE:GetRandomVec2() return nil end ---- Define a random @{Point#POINT_VEC2} within the zone. +--- Define a random @{Core.Point#POINT_VEC2} within the zone. -- @param #ZONE_BASE self -- @return Core.Point#POINT_VEC2 The PointVec2 coordinates. function ZONE_BASE:GetRandomPointVec2() return nil end ---- Define a random @{Point#POINT_VEC3} within the zone. +--- Define a random @{Core.Point#POINT_VEC3} within the zone. -- @param #ZONE_BASE self -- @return Core.Point#POINT_VEC3 The PointVec3 coordinates. function ZONE_BASE:GetRandomPointVec3() @@ -391,17 +391,17 @@ end -- -- ## Manage the location of the zone -- --- * @{#ZONE_RADIUS.SetVec2}(): Sets the @{DCSTypes#Vec2} of the zone. --- * @{#ZONE_RADIUS.GetVec2}(): Returns the @{DCSTypes#Vec2} of the zone. --- * @{#ZONE_RADIUS.GetVec3}(): Returns the @{DCSTypes#Vec3} of the zone, taking an additional height parameter. +-- * @{#ZONE_RADIUS.SetVec2}(): Sets the @{DCS#Vec2} of the zone. +-- * @{#ZONE_RADIUS.GetVec2}(): Returns the @{DCS#Vec2} of the zone. +-- * @{#ZONE_RADIUS.GetVec3}(): Returns the @{DCS#Vec3} of the zone, taking an additional height parameter. -- -- ## Zone point randomization -- -- Various functions exist to find random points within the zone. -- -- * @{#ZONE_RADIUS.GetRandomVec2}(): Gets a random 2D point in the zone. --- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Point#POINT_VEC2} object representing a random 2D point in the zone. --- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight. +-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Core.Point#POINT_VEC2} object representing a random 2D point in the zone. +-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Core.Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight. -- -- @field #ZONE_RADIUS ZONE_RADIUS = { @@ -557,7 +557,7 @@ function ZONE_RADIUS:SetRadius( Radius ) return self.Radius end ---- Returns the @{DCSTypes#Vec2} of the zone. +--- Returns the @{DCS#Vec2} of the zone. -- @param #ZONE_RADIUS self -- @return DCS#Vec2 The location of the zone. function ZONE_RADIUS:GetVec2() @@ -568,7 +568,7 @@ function ZONE_RADIUS:GetVec2() return self.Vec2 end ---- Sets the @{DCSTypes#Vec2} of the zone. +--- Sets the @{DCS#Vec2} of the zone. -- @param #ZONE_RADIUS self -- @param DCS#Vec2 Vec2 The new location of the zone. -- @return DCS#Vec2 The new location of the zone. @@ -582,7 +582,7 @@ function ZONE_RADIUS:SetVec2( Vec2 ) return self.Vec2 end ---- Returns the @{DCSTypes#Vec3} of the ZONE_RADIUS. +--- Returns the @{DCS#Vec3} of the ZONE_RADIUS. -- @param #ZONE_RADIUS self -- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return DCS#Vec3 The point of the zone. @@ -879,11 +879,11 @@ function ZONE_RADIUS:GetRandomVec2( inner, outer ) return Point end ---- Returns a @{Point#POINT_VEC2} object reflecting a random 2D location within the zone. +--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. -- @param #ZONE_RADIUS self -- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. -- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. --- @return Core.Point#POINT_VEC2 The @{Point#POINT_VEC2} object reflecting the random 3D location within the zone. +-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone. function ZONE_RADIUS:GetRandomPointVec2( inner, outer ) self:F( self.ZoneName, inner, outer ) @@ -910,11 +910,11 @@ function ZONE_RADIUS:GetRandomVec3( inner, outer ) end ---- Returns a @{Point#POINT_VEC3} object reflecting a random 3D location within the zone. +--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone. -- @param #ZONE_RADIUS self -- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. -- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. --- @return Core.Point#POINT_VEC3 The @{Point#POINT_VEC3} object reflecting the random 3D location within the zone. +-- @return Core.Point#POINT_VEC3 The @{Core.Point#POINT_VEC3} object reflecting the random 3D location within the zone. function ZONE_RADIUS:GetRandomPointVec3( inner, outer ) self:F( self.ZoneName, inner, outer ) @@ -926,7 +926,7 @@ function ZONE_RADIUS:GetRandomPointVec3( inner, outer ) end ---- Returns a @{Point#COORDINATE} object reflecting a random 3D location within the zone. +--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone. -- @param #ZONE_RADIUS self -- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. -- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. @@ -1086,7 +1086,7 @@ function ZONE_UNIT:GetRandomVec2() return RandomVec2 end ---- Returns the @{DCSTypes#Vec3} of the ZONE_UNIT. +--- Returns the @{DCS#Vec3} of the ZONE_UNIT. -- @param #ZONE_UNIT self -- @param DCS#Distance Height The height to add to the land height where the center of the zone is located. -- @return DCS#Vec3 The point of the zone. @@ -1166,11 +1166,11 @@ function ZONE_GROUP:GetRandomVec2() return Point end ---- Returns a @{Point#POINT_VEC2} object reflecting a random 2D location within the zone. +--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. -- @param #ZONE_GROUP self -- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. -- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. --- @return Core.Point#POINT_VEC2 The @{Point#POINT_VEC2} object reflecting the random 3D location within the zone. +-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone. function ZONE_GROUP:GetRandomPointVec2( inner, outer ) self:F( self.ZoneName, inner, outer ) @@ -1183,7 +1183,7 @@ end --- @type ZONE_POLYGON_BASE --- --@field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}. +-- --@field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}. -- @extends #ZONE_BASE @@ -1196,8 +1196,8 @@ end -- Various functions exist to find random points within the zone. -- -- * @{#ZONE_POLYGON_BASE.GetRandomVec2}(): Gets a random 2D point in the zone. --- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Point#POINT_VEC2} object representing a random 2D point within the zone. --- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. +-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Core.Point#POINT_VEC2} object representing a random 2D point within the zone. +-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. -- -- @field #ZONE_POLYGON_BASE ZONE_POLYGON_BASE = { @@ -1208,11 +1208,11 @@ ZONE_POLYGON_BASE = { -- @type ZONE_POLYGON_BASE.ListVec2 -- @list ---- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{DCSTypes#Vec2}, forming a polygon. +--- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{DCS#Vec2}, forming a polygon. -- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. -- @param #ZONE_POLYGON_BASE self -- @param #string ZoneName Name of the zone. --- @param #ZONE_POLYGON_BASE.ListVec2 PointsArray An array of @{DCSTypes#Vec2}, forming a polygon.. +-- @param #ZONE_POLYGON_BASE.ListVec2 PointsArray An array of @{DCS#Vec2}, forming a polygon.. -- @return #ZONE_POLYGON_BASE self function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) @@ -1368,7 +1368,7 @@ function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 ) return InPolygon end ---- Define a random @{DCSTypes#Vec2} within the zone. +--- Define a random @{DCS#Vec2} within the zone. -- @param #ZONE_POLYGON_BASE self -- @return DCS#Vec2 The Vec2 coordinate. function ZONE_POLYGON_BASE:GetRandomVec2() @@ -1394,9 +1394,9 @@ function ZONE_POLYGON_BASE:GetRandomVec2() return Vec2 end ---- Return a @{Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. +--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. -- @param #ZONE_POLYGON_BASE self --- @return @{Point#POINT_VEC2} +-- @return @{Core.Point#POINT_VEC2} function ZONE_POLYGON_BASE:GetRandomPointVec2() self:F2() @@ -1407,9 +1407,9 @@ function ZONE_POLYGON_BASE:GetRandomPointVec2() return PointVec2 end ---- Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. +--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. -- @param #ZONE_POLYGON_BASE self --- @return @{Point#POINT_VEC3} +-- @return @{Core.Point#POINT_VEC3} function ZONE_POLYGON_BASE:GetRandomPointVec3() self:F2() @@ -1421,7 +1421,7 @@ function ZONE_POLYGON_BASE:GetRandomPointVec3() end ---- Return a @{Point#COORDINATE} object representing a random 3D point at landheight within the zone. +--- Return a @{Core.Point#COORDINATE} object representing a random 3D point at landheight within the zone. -- @param #ZONE_POLYGON_BASE self -- @return Core.Point#COORDINATE function ZONE_POLYGON_BASE:GetRandomCoordinate() diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index acd0811d4..47d63dd8a 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -134,7 +134,7 @@ -- -- ### Parameters: -- --- * *coord*: Coordinates of the target, given as @{Point#COORDINATE} object. +-- * *coord*: Coordinates of the target, given as @{Core.Point#COORDINATE} object. -- * *prio*: Priority of the target. This a number between 1 (high prio) and 100 (low prio). Targets with higher priority are engaged before targets with lower priority. -- * *radius*: Radius in meters which defines the area the ARTY group will attempt to be hitting. Default is 100 meters. -- * *nshells*: Number of shots (shells, rockets, missiles) fired by the group at each engagement of a target. Default is 5. @@ -220,7 +220,7 @@ -- -- ### Parameters -- --- * *coord*: Coordinates where the group should move to given as @{Point#COORDINATE} object. +-- * *coord*: Coordinates where the group should move to given as @{Core.Point#COORDINATE} object. -- * *time*: The time when the move should be executed. This has to be given as a string in the format "hh:mm:ss" (hh=hours, mm=minutes, ss=seconds). -- * *speed*: Speed of the group in km/h. -- * *onroad*: If this parameter is set to true, the group uses mainly roads to get to the commanded coordinates. diff --git a/Moose Development/Moose/Functional/Designate.lua b/Moose Development/Moose/Functional/Designate.lua index c6818c456..f23961e12 100644 --- a/Moose Development/Moose/Functional/Designate.lua +++ b/Moose Development/Moose/Functional/Designate.lua @@ -267,7 +267,7 @@ do -- DESIGNATE -- -- ## 6. Designate Menu Location for a Mission -- - -- You can make DESIGNATE work for a @{Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission. + -- You can make DESIGNATE work for a @{Tasking.Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission. -- Use the method @{#DESIGNATE.SetMission}() to set the @{Mission} object for the designate function. -- -- ## 7. Status Report diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 6d0204b22..cea1f948b 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -52,7 +52,7 @@ -- Use the radio menu F10 to consult the scores while running the mission. -- Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission. -- --- # 1) @{Scoring#SCORING} class, extends @{Core.Base#BASE} +-- # 1) @{Functional.Scoring#SCORING} class, extends @{Core.Base#BASE} -- -- ## 1.1) Set the destroy score or penalty scale -- diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index 0c76973dd..c27511cde 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -2,35 +2,35 @@ -- -- === -- --- The @{DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. +-- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. -- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. -- -- 1.1) DETECTION_MANAGER constructor: -- ----------------------------------- --- * @{DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. +-- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. -- -- 1.2) DETECTION_MANAGER reporting: -- --------------------------------- --- Derived DETECTION_MANAGER classes will reports detected units using the method @{DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour. +-- Derived DETECTION_MANAGER classes will reports detected units using the method @{#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour. -- --- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetRefreshTimeInterval}(). --- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}(). --- Derived classes need to implement the method @{DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- The time interval in seconds of the reporting can be changed using the methods @{#DETECTION_MANAGER.SetRefreshTimeInterval}(). +-- To control how long a reporting message is displayed, use @{#DETECTION_MANAGER.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. -- --- Reporting can be started and stopped using the methods @{DetectionManager#DETECTION_MANAGER.StartReporting}() and @{DetectionManager#DETECTION_MANAGER.StopReporting}() respectively. --- If an ad-hoc report is requested, use the method @{DetectionManager#DETECTION_MANAGER#ReportNow}(). +-- Reporting can be started and stopped using the methods @{#DETECTION_MANAGER.StartReporting}() and @{#DETECTION_MANAGER.StopReporting}() respectively. +-- If an ad-hoc report is requested, use the method @{#DETECTION_MANAGER#ReportNow}(). -- -- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. -- -- === -- --- 2) @{DetectionManager#DETECTION_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER} +-- 2) @{#DETECTION_REPORTING} class, extends @{#DETECTION_MANAGER} -- === --- The @{DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class. +-- The @{#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Tasking.DetectionManager#DETECTION_MANAGER} class. -- -- 2.1) DETECTION_REPORTING constructor: -- ------------------------------- --- The @{DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance. +-- The @{#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance. -- -- -- === diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 962770e14..f76cbf7fe 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -31,9 +31,9 @@ -- * @{#TASK.AssignToGroup}():Assign a task to a group (of players). -- * @{#TASK.AddProcess}():Add a @{Process} to a task. -- * @{#TASK.RemoveProcesses}():Remove a running @{Process} from a running task. --- * @{#TASK.SetStateMachine}():Set a @{Fsm} to a task. --- * @{#TASK.RemoveStateMachine}():Remove @{Fsm} from a task. --- * @{#TASK.HasStateMachine}():Enquire if the task has a @{Fsm} +-- * @{#TASK.SetStateMachine}():Set a @{Core.Fsm} to a task. +-- * @{#TASK.RemoveStateMachine}():Remove @{Core.Fsm} from a task. +-- * @{#TASK.HasStateMachine}():Enquire if the task has a @{Core.Fsm} -- * @{#TASK.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK}. -- * @{#TASK.UnAssignFromUnit}(): Unassign the task from a unit. -- * @{#TASK.SetTimeOut}(): Set timer in seconds before task gets cancelled if not assigned. diff --git a/Moose Development/Moose/Tasking/TaskZoneCapture.lua b/Moose Development/Moose/Tasking/TaskZoneCapture.lua index e32ea58bf..fb1ab81c5 100644 --- a/Moose Development/Moose/Tasking/TaskZoneCapture.lua +++ b/Moose Development/Moose/Tasking/TaskZoneCapture.lua @@ -18,10 +18,10 @@ do -- TASK_ZONE_GOAL -- @field Core.ZoneGoal#ZONE_GOAL ZoneGoal -- @extends Tasking.Task#TASK - --- # TASK_ZONE_GOAL class, extends @{Task#TASK} + --- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK} -- -- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone. - -- The TASK_ZONE_GOAL is implemented using a @{Fsm#FSM_TASK}, and has the following statuses: + -- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process -- * **Planned**: The A2G task is planned. @@ -167,12 +167,12 @@ do -- TASK_ZONE_CAPTURE -- @field Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoal -- @extends #TASK_ZONE_GOAL - --- # TASK_ZONE_CAPTURE class, extends @{TaskZoneGoal#TASK_ZONE_GOAL} + --- # TASK_ZONE_CAPTURE class, extends @{Tasking.TaskZoneGoal#TASK_ZONE_GOAL} -- -- The TASK_ZONE_CAPTURE class defines an Suppression or Extermination of Air Defenses task for a human player to be executed. -- These tasks are important to be executed as they will help to achieve air superiority at the vicinity. -- - -- The TASK_ZONE_CAPTURE is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks + -- The TASK_ZONE_CAPTURE is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks -- based on detected enemy ground targets. -- -- @field #TASK_ZONE_CAPTURE diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index 0a18e28cc..5fb22050b 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -19,8 +19,8 @@ do -- TASK_A2A -- @extends Tasking.Task#TASK --- Defines Air To Air tasks for a @{Set} of Target Units, - -- based on the tasking capabilities defined in @{Task#TASK}. - -- The TASK_A2A is implemented using a @{Fsm#FSM_TASK}, and has the following statuses: + -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. + -- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process -- * **Planned**: The A2A task is planned. @@ -364,10 +364,10 @@ do -- TASK_A2A_INTERCEPT --- Defines an intercept task for a human player to be executed. -- When enemy planes need to be intercepted by human players, use this task type to urgen the players to get out there! -- - -- The TASK_A2A_INTERCEPT is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks + -- The TASK_A2A_INTERCEPT is used by the @{Tasking.Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks -- based on detected airborne enemy targets intruding friendly airspace. -- - -- The task is defined for a @{Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is intercepting the targets. + -- The task is defined for a @{Tasking.Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is intercepting the targets. -- The task is given a name and a briefing, that is used in the menu structure and in the reporting. -- -- @field #TASK_A2A_INTERCEPT @@ -463,10 +463,10 @@ do -- TASK_A2A_SWEEP -- Most likely, these enemy planes are hidden in the mountains or are flying under radar. -- These enemy planes need to be sweeped by human players, and use this task type to urge the players to get out there and find those enemy fighters. -- - -- The TASK_A2A_SWEEP is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create sweep tasks + -- The TASK_A2A_SWEEP is used by the @{Tasking.Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create sweep tasks -- based on detected airborne enemy targets intruding friendly airspace, for which the detection has been lost for more than 60 seconds. -- - -- The task is defined for a @{Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is sweeping the targets. + -- The task is defined for a @{Tasking.Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is sweeping the targets. -- The task is given a name and a briefing, that is used in the menu structure and in the reporting. -- -- @field #TASK_A2A_SWEEP @@ -570,10 +570,10 @@ do -- TASK_A2A_ENGAGE --- Defines an engage task for a human player to be executed. -- When enemy planes are close to human players, use this task type is used urge the players to get out there! -- - -- The TASK_A2A_ENGAGE is used by the @{Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create engage tasks + -- The TASK_A2A_ENGAGE is used by the @{Tasking.Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create engage tasks -- based on detected airborne enemy targets intruding friendly airspace. -- - -- The task is defined for a @{Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is engaging the targets. + -- The task is defined for a @{Tasking.Mission#MISSION}, where a friendly @{Core.Set#SET_GROUP} consisting of GROUPs with one human players each, is engaging the targets. -- The task is given a name and a briefing, that is used in the menu structure and in the reporting. -- -- @field #TASK_A2A_ENGAGE diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 9b68fd38a..ddbb7b148 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -80,7 +80,7 @@ do -- TASK_A2A_DISPATCHER -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. -- It all depends on what the desired effect is. -- - -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. + -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional.Detection#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. -- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network, -- increasing or decreasing the radar coverage of the Early Warning System. -- diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index d30eff7aa..51294075d 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -19,8 +19,8 @@ do -- TASK_A2G -- @extends Tasking.Task#TASK --- The TASK_A2G class defines Air To Ground tasks for a @{Set} of Target Units, - -- based on the tasking capabilities defined in @{Task#TASK}. - -- The TASK_A2G is implemented using a @{Fsm#FSM_TASK}, and has the following statuses: + -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. + -- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process -- * **Planned**: The A2G task is planned. @@ -369,7 +369,7 @@ do -- TASK_A2G_SEAD --- Defines an Suppression or Extermination of Air Defenses task for a human player to be executed. -- These tasks are important to be executed as they will help to achieve air superiority at the vicinity. -- - -- The TASK_A2G_SEAD is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks + -- The TASK_A2G_SEAD is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks -- based on detected enemy ground targets. -- -- @field #TASK_A2G_SEAD @@ -461,7 +461,7 @@ do -- TASK_A2G_BAI -- These tasks are more strategic in nature and are most of the time further away from friendly forces. -- BAI tasks can also be used to express the abscence of friendly forces near the vicinity. -- - -- The TASK_A2G_BAI is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create BAI tasks + -- The TASK_A2G_BAI is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create BAI tasks -- based on detected enemy ground targets. -- -- @field #TASK_A2G_BAI @@ -554,7 +554,7 @@ do -- TASK_A2G_CAS -- Defines an Close Air Support task for a human player to be executed. -- Friendly forces will be in the vicinity within 6km from the enemy. -- - -- The TASK_A2G_CAS is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create CAS tasks + -- The TASK_A2G_CAS is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create CAS tasks -- based on detected enemy ground targets. -- -- @field #TASK_A2G_CAS diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 200877922..cb6edeb49 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -32,7 +32,7 @@ do -- TASK_CARGO -- @extends Tasking.Task#TASK --- - -- # TASK_CARGO class, extends @{Task#TASK} + -- # TASK_CARGO class, extends @{Tasking.Task#TASK} -- -- ## A flexible tasking system -- @@ -119,7 +119,7 @@ do -- TASK_CARGO -- ## Handle TASK_CARGO Events ... -- -- The TASK_CARGO classes define @{Cargo} transport tasks, - -- based on the tasking capabilities defined in @{Task#TASK}. + -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. -- -- ### Specific TASK_CARGO Events -- @@ -130,7 +130,7 @@ do -- TASK_CARGO -- -- ### Standard TASK_CARGO Events -- - -- The TASK_CARGO is implemented using a @{Statemachine#FSM_TASK}, and has the following standard statuses: + -- The TASK_CARGO is implemented using a @{Core.Fsm#FSM_TASK}, and has the following standard statuses: -- -- * **None**: Start of the process. -- * **Planned**: The cargo task is planned. diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index 1fd738087..7644674da 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -82,7 +82,7 @@ do -- TASK_CARGO_DISPATCHER -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. -- It all depends on what the desired effect is. -- - -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. + -- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional.Detection#DETECTION_BASE} object that is given as the input parameter of the TASK\_A2A\_DISPATCHER class. -- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network, -- increasing or decreasing the radar coverage of the Early Warning System. -- diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index dc7f31c62..8c2d76406 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -2,25 +2,25 @@ -- -- === -- --- 1) @{Task_Manager#TASK_MANAGER} class, extends @{Fsm#FSM} +-- 1) @{Tasking.Task_Manager#TASK_MANAGER} class, extends @{Core.Fsm#FSM} -- === --- The @{Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. +-- The @{Tasking.Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. -- Reportings can be done in several manners, and it is up to the derived classes if TASK_MANAGER to model the reporting behaviour. -- -- 1.1) TASK_MANAGER constructor: -- ----------------------------------- --- * @{Task_Manager#TASK_MANAGER.New}(): Create a new TASK_MANAGER instance. +-- * @{Tasking.Task_Manager#TASK_MANAGER.New}(): Create a new TASK_MANAGER instance. -- -- 1.2) TASK_MANAGER reporting: -- --------------------------------- --- Derived TASK_MANAGER classes will manage tasks using the method @{Task_Manager#TASK_MANAGER.ManageTasks}(). This method implements polymorphic behaviour. +-- Derived TASK_MANAGER classes will manage tasks using the method @{Tasking.Task_Manager#TASK_MANAGER.ManageTasks}(). This method implements polymorphic behaviour. -- --- The time interval in seconds of the task management can be changed using the methods @{Task_Manager#TASK_MANAGER.SetRefreshTimeInterval}(). --- To control how long a reporting message is displayed, use @{Task_Manager#TASK_MANAGER.SetReportDisplayTime}(). --- Derived classes need to implement the method @{Task_Manager#TASK_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- The time interval in seconds of the task management can be changed using the methods @{Tasking.Task_Manager#TASK_MANAGER.SetRefreshTimeInterval}(). +-- To control how long a reporting message is displayed, use @{Tasking.Task_Manager#TASK_MANAGER.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Tasking.Task_Manager#TASK_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. -- --- Task management can be started and stopped using the methods @{Task_Manager#TASK_MANAGER.StartTasks}() and @{Task_Manager#TASK_MANAGER.StopTasks}() respectively. --- If an ad-hoc report is requested, use the method @{Task_Manager#TASK_MANAGER#ManageTasks}(). +-- Task management can be started and stopped using the methods @{Tasking.Task_Manager#TASK_MANAGER.StartTasks}() and @{Tasking.Task_Manager#TASK_MANAGER.StopTasks}() respectively. +-- If an ad-hoc report is requested, use the method @{Tasking.Task_Manager#TASK_MANAGER#ManageTasks}(). -- -- The default task management interval is every 60 seconds. -- diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index 7352537f7..7df3c0586 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -411,8 +411,8 @@ function CLIENT:IsTransport() return self.ClientTransport end ---- Shows the @{AI_Cargo#CARGO} contained within the CLIENT to the player as a message. --- The @{AI_Cargo#CARGO} is shown using the @{Message#MESSAGE} distribution system. +--- Shows the @{AI.AI_Cargo#CARGO} contained within the CLIENT to the player as a message. +-- The @{AI.AI_Cargo#CARGO} is shown using the @{Core.Message#MESSAGE} distribution system. -- @param #CLIENT self function CLIENT:ShowCargo() self:F() @@ -445,7 +445,7 @@ end -- @param #string Message is the text describing the message. -- @param #number MessageDuration is the duration in seconds that the Message should be displayed. -- @param #string MessageCategory is the category of the message (the title). --- @param #number MessageInterval is the interval in seconds between the display of the @{Message#MESSAGE} when the CLIENT is in the air. +-- @param #number MessageInterval is the interval in seconds between the display of the @{Core.Message#MESSAGE} when the CLIENT is in the air. -- @param #string MessageID is the identifier of the message when displayed with intervals. function CLIENT:Message( Message, MessageDuration, MessageCategory, MessageInterval, MessageID ) self:F( { Message, MessageDuration, MessageCategory, MessageInterval } ) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index dd570df5e..776cf923c 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -185,7 +185,7 @@ function GROUP:GetDCSObject() return nil end ---- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. +--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Position The 3D position vectors of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. @@ -722,7 +722,7 @@ function GROUP:GetCoordinate() end ---- Returns a random @{DCSTypes#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP. +--- Returns a random @{DCS#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP. -- @param #GROUP self -- @param #number Radius -- @return DCS#Vec3 The random 3D point vector around the first UNIT of the GROUP. diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index 1b9b46995..f67ec389e 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -27,7 +27,7 @@ -- -- The OBJECT class provides the following functions to construct a OBJECT instance: -- --- * @{Object#OBJECT.New}(): Create a OBJECT instance. +-- * @{Wrapper.Object#OBJECT.New}(): Create a OBJECT instance. -- -- @field #OBJECT OBJECT = { diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index b60ee07be..23b85806a 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -69,7 +69,7 @@ function POSITIONABLE:New( PositionableName ) return self end ---- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. +--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Position The 3D position vectors of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. @@ -89,7 +89,7 @@ function POSITIONABLE:GetPositionVec3() return nil end ---- Returns the @{DCSTypes#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission. +--- Returns the @{DCS#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Vec2 The 2D point vector of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. @@ -185,7 +185,7 @@ function POSITIONABLE:GetCoordinate() end ---- Returns a random @{DCSTypes#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. +--- Returns a random @{DCS#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @param #number Radius -- @return DCS#Vec3 The 3D point vector of the POSITIONABLE. @@ -220,7 +220,7 @@ function POSITIONABLE:GetRandomVec3( Radius ) return nil end ---- Returns the @{DCSTypes#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. +--- Returns the @{DCS#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Vec3 The 3D point vector of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. @@ -713,7 +713,7 @@ function POSITIONABLE:Message( Message, Duration, Name ) return nil end ---- Create a @{Radio#RADIO}, to allow radio transmission for this POSITIONABLE. +--- Create a @{Core.Radio#RADIO}, to allow radio transmission for this POSITIONABLE. -- Set parameters with the methods provided, then use RADIO:Broadcast() to actually broadcast the message -- @param #POSITIONABLE self -- @return Core.Radio#RADIO Radio @@ -722,7 +722,7 @@ function POSITIONABLE:GetRadio() --R2.1 return RADIO:New(self) end ---- Create a @{Radio#BEACON}, to allow this POSITIONABLE to broadcast beacon signals +--- Create a @{Core.Radio#BEACON}, to allow this POSITIONABLE to broadcast beacon signals -- @param #POSITIONABLE self -- @return Core.Radio#RADIO Radio function POSITIONABLE:GetBeacon() --R2.1 diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 9a9cb9ff2..01d9af957 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -19,7 +19,7 @@ --- Wrapper class to handle Scenery objects that are defined on the map. -- --- The @{Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: +-- The @{Wrapper.Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: -- -- * Wraps the DCS Scenery objects. -- * Support all DCS Scenery APIs. diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index 27800cff0..a591522af 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -18,7 +18,7 @@ --- Wrapper class to handle Static objects. -- -- Note that Statics are almost the same as Units, but they don't have a controller. --- The @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: +-- The @{Wrapper.Static#STATIC} class is a wrapper class to handle the DCS Static objects: -- -- * Wraps the DCS Static objects. -- * Support all DCS Static APIs. From e9a055219e3036418443d7f2722a8fa9a383bd6e Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 2 Jun 2018 19:13:26 +0200 Subject: [PATCH 151/170] ARTY v0.9.8-buggy Improved marker assignments. There is a bug that makes DCS crash when a group is ordered to move and reaches its destination, i.e. arrives. --- .../Moose/Functional/Artillery.lua | 281 +++++++++++------- 1 file changed, 180 insertions(+), 101 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 2857d755a..03fdf5035 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -459,7 +459,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.8" +ARTY.version="0.9.8-buggy" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -856,17 +856,21 @@ end function ARTY:RemoveTarget(name) self:F2(name) local id=self:_GetTargetIndexByName(name) + if id then + + -- Remove target from table. self:T(ARTY.id..string.format("Group %s: Removing target %s (id=%d).", self.Controllable:GetName(), name, id)) table.remove(self.targets, id) + + -- Delete marker belonging to this engagement. + local batteryname,markTargetID, markMoveID=self:_GetMarkIDfromName(name) + if batteryname==self.Controllable:GetName() and markTargetID~=nil then + COORDINATE:RemoveMark(markTargetID) + end + end self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) - if self.currentTarget then - if self.currentTarget.name==name then - self:T(ARTY.id..string.format("Group %s: Cancelling current target %s.", self.Controllable:GetName(), name)) - self:CeaseFire(self.currentTarget) - end - end end --- Delete a move from move list. @@ -875,16 +879,17 @@ end function ARTY:RemoveMove(name) self:F2(name) local id=self:_GetMoveIndexByName(name) + if id then + -- Remove move from table. self:T(ARTY.id..string.format("Group %s: Removing move %s (id=%d).", self.Controllable:GetName(), name, id)) table.remove(self.moves, id) - end - self:T(ARTY.id..string.format("Group %s: Number of moves = %d.", self.Controllable:GetName(), #self.moves)) - if self.currentMove then - if self.currentMove.name==name then - self:T(ARTY.id..string.format("Group %s: Cancelling current move %s.", self.Controllable:GetName(), name)) - self:Arrived() - end + env.info("FF debug remove move") + -- Delete marker belonging to this relocation move. + --local batteryname,markTargetID,markMoveID=self:_GetMarkIDfromName(name) + --if batteryname==self.Controllable:GetName() and markMoveID~=nil then + --COORDINATE:RemoveMark(markMoveID) + --end end end @@ -1110,6 +1115,62 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:__Status(self.StatusInterval) end +--- Extract engagement assignments and parameters from mark text. +-- @param #ARTY self +-- @param #string text Marker text. +-- @return #boolean If true, authentification successful. +function ARTY:_MarkerKeyAuthentification(text) + + -- Set battery and coalition. + local batteryname=self.Controllable:GetName() + local batterycoalition=self.Controllable:GetCoalition() + + -- Get assignment. + local mykey=nil + if self.markkey~=nil then + + -- keywords are split by "," + local keywords=self:_split(text, ",") + for _,key in pairs(keywords) do + local s=self:_split(key, " ") + local val=s[2] + if key:lower():find("key") then + mykey=tonumber(val) + self:T(ARTY.id..string.format("Authorisation Key=%s.", val)) + end + end + + end + + -- Check if the authorization key is required and if it is valid. + local _validkey=true + + -- Check if group needs authorization. + if self.markkey~=nil then + -- Assume key is incorrect. + _validkey=false + + -- If key was found, check if matches. + if mykey~=nil then + _validkey=self.markkey==mykey + end + self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) + + -- Send message + local text="" + if mykey==nil then + text=string.format("%s, authorization required but did not receive a key!", batteryname) + elseif _validkey==false then + text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(mykey)) + elseif _validkey==true then + text=string.format("%s, authentification successful!", batteryname) + end + MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + end + + return _validkey +end + --- Extract engagement assignments and parameters from mark text. -- @param #ARTY self -- @param #string text Marker text to be analyzed. @@ -1123,6 +1184,7 @@ function ARTY:_Markertext(text) assignment.move=false assignment.engage=false assignment.readonly=false + assignment.cancelcurrent=false assignment.time=nil assignment.nshells=nil assignment.prio=nil @@ -1133,7 +1195,7 @@ function ARTY:_Markertext(text) assignment.onroad=nil assignment.key=nil - if text:lower():find("arty") then + if text:lower():find("arty") then if text:lower():find("engage") then assignment.engage=true elseif text:lower():find("move") then @@ -1210,19 +1272,18 @@ function ARTY:_Markertext(text) assignment.speed=tonumber(val) self:T2(ARTY.id..string.format("Key Speed=%s.", val)) - elseif key:lower():find("road") then + elseif key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")then assignment.onroad=true self:T2(ARTY.id..string.format("Key Onroad=true.")) - - elseif key:lower():find("key") then - - assignment.key=tonumber(val) - self:T(ARTY.id..string.format("Key Key=%s.", val)) - - elseif key:lower():find("irrevocable") then + + elseif key:lower():find("irrevocable") or key:lower():find("readonly") then assignment.readonly=true self:T2(ARTY.id..string.format("Key Readonly=true.")) + + elseif key:lower():find("cancel current") then + assignment.cancelcurrent=true + self:T2(ARTY.id..string.format("Key Cancel Current=true.")) end end @@ -1278,6 +1339,58 @@ function ARTY:onEvent(Event) end +--- Create a name for an engagement initiated by placing a marker. +-- @param #ARTY self +-- @param #number markerid ID of the placed marker. +-- @return #string Name of target engagement. +function ARTY:_MarkTargetName(markerid) + return string.format("BATTERY=%s, Marked Target ID=%d", self.Controllable:GetName(), markerid) +end + +--- Create a name for a relocation move initiated by placing a marker. +-- @param #ARTY self +-- @param #number markerid ID of the placed marker. +-- @return #string Name of relocation move. +function ARTY:_MarkMoveName(markerid) + return string.format("BATTERY=%s, Marked Relocation ID=%d", self.Controllable:GetName(), markerid) +end + +--- Create a name for a relocation move initiated by placing a marker. +-- @param #ARTY self +-- @param #sting name Name of the assignment. +-- @return #string Name of the ARTY group or nil +-- @return #number ID of the marked target or nil. +-- @return #number ID of the marked relocation move or nil +function ARTY:_GetMarkIDfromName(name) + + -- keywords are split by "," + local keywords=self:_split(name, ",") + + local battery=nil + local markTID=nil + local markMID=nil + + for _,key in pairs(keywords) do + + local str=self:_split(key, "=") + local par=str[1] + local val=str[2] + + if par:find("BATTERY") then + battery=val + end + if par:find("Marked Target ID") then + markTID=tonumber(val) + end + if par:find("Marked Relocation ID") then + markMID=tonumber(val) + end + + end + + return battery, markTID, markMID +end + --- Function called when a F10 map mark was removed. -- @param #ARTY self -- @param #table Event Event data. @@ -1293,18 +1406,20 @@ function ARTY:_OnEventMarkRemove(Event) local _canceltarget=false local _name="" local _id=nil + if Event.text:find("Marked Relocation") then _cancelmove=true - _name=string.format("BATTERY %s Marked Relocation ID=%d", batteryname, Event.idx) + _name=self:_MarkMoveName(Event.idx) _id=self:_GetMoveIndexByName(_name) elseif Event.text:find("Marked Target") then _canceltarget=true - _name=string.format("BATTERY %s Marked Target ID=%d", batteryname, Event.idx) + _name=self:_MarkTargetName(Event.idx) _id=self:_GetTargetIndexByName(_name) else return end + -- Check if there is a task which matches. if _id==nil then return end @@ -1312,48 +1427,25 @@ function ARTY:_OnEventMarkRemove(Event) -- Check if the coalition is the same or an authorization key has been defined. if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then - -- Get assignment. - local mykey=nil - if self.markkey~=nil then - -- keywords are split by "," - local keywords=self:_split(Event.text, ",") - for _,key in pairs(keywords) do - local s=self:_split(key, " ") - local val=s[2] - if key:lower():find("key") then - mykey=tonumber(val) - self:T(ARTY.id..string.format("Key Key=%s.", val)) - end - end - end - - -- Check if the authorization key is required and if it is valid. - local _validkey=true - if self.markkey~=nil then - _validkey=false - if mykey~=nil then - _validkey=self.markkey==mykey - end - self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) - local text="" - if mykey==nil then - text=string.format("%s, authorization required but did not receive a key!", batteryname) - elseif _validkey==false then - text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(mykey)) - elseif _validkey==true then - text=string.format("%s, authentification successful!", batteryname) - end - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) - end + -- Authentify key + local _validkey=self:_MarkerKeyAuthentification(Event.text) -- Check if we have the right coalition. if _validkey then -- This should be the unique name of the target or move. if _cancelmove then - self:RemoveMove(_name) + if self.currentMove and self.currentMove.name==_name then + self:Arrived() + else + self:RemoveMove(_name) + end elseif _canceltarget then - self:RemoveTarget(_name) + if self.currentTarget and self.currentTarget.name==_name then + self:CeaseFire(self.currentTarget) + else + self:RemoveTarget(_name) + end end end @@ -1397,24 +1489,19 @@ function ARTY:_OnEventMarkChange(Event) if not (_assign.engage or _assign.move) or (not _assigned) then return end - + -- Check if the authorization key is required and if it is valid. - local _validkey=true - if self.markkey~=nil then - _validkey=false - if _assign.key~=nil then - _validkey=self.markkey==_assign.key + local _validkey=self:_MarkerKeyAuthentification(Event.text) + + -- Cancel current target. + if _validkey and _assign.cancelcurrent then + if _assign.move and self.currentMove then + self:Arrived() end - self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(_assign.key), tostring(_validkey))) - local text="" - if _assign.key==nil then - text=string.format("%s, authorization required but did not receive a key!", batteryname) - elseif _validkey==false then - text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(_assign.key)) - elseif _validkey==true then - text=string.format("%s, authentification successful!", batteryname) + if _assign.engage and self.currentTarget then + self:CeaseFire(self.currentTarget) end - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + return end -- We are meant. @@ -1430,17 +1517,18 @@ function ARTY:_OnEventMarkChange(Event) -- Also I don't know who can see the mark which was created. _coord:RemoveMark(Event.idx) + -- Anticipate marker ID. + -- WARNING: Make sure, no marks are set until the COORDINATE:MarkToCoalition() is called or the target/move name will be wrong and target cannot be removed by deleting its marker. local _id=UTILS._MarkID+1 if _assign.move then -- Create a new name. This determins the string we search when deleting a move! - local _name=string.format("BATTERY %s Marked Relocation ID=%d", batteryname, _id) - self:E(ARTY.id.._name) + local _name=self:_MarkMoveName(_id) local text=string.format("%s, received new relocation assignment.", batteryname) text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) -- Assign a relocation of the arty group. local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) @@ -1451,11 +1539,7 @@ function ARTY:_OnEventMarkChange(Event) -- Create new target name. local clock=tostring(self:_SecondsToClock(_move.time)) - local _road="Off Road" - if _move.onroad==true then - _road="On Road" - end - local _markertext=_movename..string.format(", Time %s, Speed %d km/h, %s.", clock, _move.speed, _road) + local _markertext=_movename..string.format(", Time=%s, Speed=%d km/h, Use Roads=%s.", clock, _move.speed, tostring(_move.onroad)) -- Create a new mark. This will trigger the mark added event. local _randomcoord=_coord:GetRandomCoordinateInRadius(100) @@ -1465,8 +1549,7 @@ function ARTY:_OnEventMarkChange(Event) else -- Create a new name. - local _name=string.format("BATTERY %s Marked Target ID=%d", batteryname, _id) - self:E(ARTY.id.._name) + local _name=self:_MarkTargetName(_id) local text=string.format("%s, received new target assignment.", batteryname) text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) @@ -1476,6 +1559,9 @@ function ARTY:_OnEventMarkChange(Event) if _assign.prio then text=text..string.format("\nPrio %d",_assign.prio) end + if _assign.prio then + text=text..string.format("\nRadius %d m",_assign.radius) + end if _assign.nshells then text=text..string.format("\nShots %d",_assign.nshells) end @@ -1485,7 +1571,7 @@ function ARTY:_OnEventMarkChange(Event) if _assign.weapontype then text=text..string.format("\nWeapon %s",self:_WeaponTypeName(_assign.weapontype)) end - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) + MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) -- Assign a new firing engagement. -- Note, we set unique=true so this target gets only added once. @@ -1498,7 +1584,7 @@ function ARTY:_OnEventMarkChange(Event) -- Create new target name. local clock=tostring(self:_SecondsToClock(_target.time)) local weapon=self:_WeaponTypeName(_target.weapontype) - local _markertext=_targetname..string.format(", Priority %d, Radius=%d m, Shots %d, Engagements=%d, Weapon %s, Time %s", _target.prio, _target.radius, _target.nshells, _target.maxengage, weapon, clock) + local _markertext=_targetname..string.format(", Priority=%d, Radius=%d m, Shots=%d, Engagements=%d, Weapon=%s, Time=%s", _target.prio, _target.radius, _target.nshells, _target.maxengage, weapon, clock) -- Create a new mark. This will trigger the mark added event. local _randomcoord=_coord:GetRandomCoordinateInRadius(250) @@ -1547,6 +1633,11 @@ function ARTY:_StatusReport() for i=1,#self.targets do text=text..string.format("- %s\n", self:_TargetInfo(self.targets[i])) end + if self.currentMove then + text=text..string.format("Current Move = %s\n", tostring(self.currentMove.name)) + else + text=text..string.format("Current Move = %s\n", "none") + end text=text..string.format("Moves:\n") for i=1,#self.moves do text=text..string.format("- %s\n", self:_MoveInfo(self.moves[i])) @@ -1669,18 +1760,6 @@ function ARTY:_NuclearBlast(_coord) end ---- Eventhandler for shot event. --- @param #ARTY self --- @param Core.Event#EVENTDATA EventData -function ARTY:_OnMarkAdded(EventData) - self:F(EventData) - if EventData.MarkCoordinate then - local coord=EventData.MarkCoordinate --Core.Point#COORDINATE - - coord:SmokeGreen() - end -end - --- Eventhandler for shot event. -- @param #ARTY self -- @param Core.Event#EVENTDATA EventData @@ -2453,8 +2532,8 @@ function ARTY:onafterArrived(Controllable, From, Event, To) -- Remove executed move from queue. if self.currentMove then - self:RemoveMove(self.currentMove.name) - self.currentMove=nil + --self:RemoveMove(self.currentMove.name) + --self.currentMove=nil end end From 0d246d3f49841b8d8986be29d6059a4124842fca Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 3 Jun 2018 00:58:24 +0200 Subject: [PATCH 152/170] ARTY v0.9.9 ARTY: Fixed CTD bug. Caused by group:ClearTasks() when no task is assigned (group arrived). Many other improvements Cleared up function location. MESSAGES: Added optional clear screen parameter. --- Moose Development/Moose/Core/Message.lua | 22 +- .../Moose/Functional/Artillery.lua | 1826 +++++++++-------- .../Moose/Wrapper/Controllable.lua | 4 +- 3 files changed, 956 insertions(+), 896 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 926284332..e11f807ea 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -66,6 +66,7 @@ MESSAGE.Type = { -- @param #string MessageText is the text of the Message. -- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. -- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ". +-- @param #boolean ClearScreen (optional) Clear all previous messages. -- @return #MESSAGE -- @usage -- -- Create a series of new Messages. @@ -77,7 +78,7 @@ MESSAGE.Type = { -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" ) -- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" ) -- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score") -function MESSAGE:New( MessageText, MessageDuration, MessageCategory ) +function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen ) local self = BASE:Inherit( self, BASE:New() ) self:F( { MessageText, MessageDuration, MessageCategory } ) @@ -94,6 +95,11 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory ) else self.MessageCategory = "" end + + self.ClearScreen=false + if ClearScreen~=nil then + self.ClearScreen=ClearScreen + end self.MessageDuration = MessageDuration or 5 self.MessageTime = timer.getTime() @@ -114,18 +120,24 @@ end -- @param self -- @param #string MessageText is the text of the Message. -- @param #MESSAGE.Type MessageType The type of the message. +-- @param #boolean ClearScreen (optional) Clear all previous messages. -- @return #MESSAGE -- @usage -- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information ) -- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information ) -- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update ) -- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update ) -function MESSAGE:NewType( MessageText, MessageType ) +function MESSAGE:NewType( MessageText, MessageType, ClearScreen ) local self = BASE:Inherit( self, BASE:New() ) self:F( { MessageText } ) self.MessageType = MessageType + + self.ClearScreen=false + if ClearScreen~=nil then + self.ClearScreen=ClearScreen + end self.MessageTime = timer.getTime() self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1) @@ -170,7 +182,7 @@ function MESSAGE:ToClient( Client, Settings ) if self.MessageDuration ~= 0 then local ClientGroupID = Client:GetClientGroupID() self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) + trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen) end end @@ -194,7 +206,7 @@ function MESSAGE:ToGroup( Group, Settings ) if self.MessageDuration ~= 0 then self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) + trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen ) end end @@ -262,7 +274,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 ) + trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen ) end end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 03fdf5035..17cdccf94 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -51,7 +51,7 @@ -- @field #number Nshells0 Initial amount of shells of the whole group. -- @field #number Nrockets0 Initial amount of rockets of the whole group. -- @field #number Nmissiles0 Initial amount of missiles of the whole group. --- @field #number Nukes0 Initial amount of tactical nukes of the whole group. +-- @field #number Nukes0 Initial amount of tactical nukes of the whole group. Default is 0. -- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. -- @field #number StatusInterval Update interval in seconds between status updates. Default 10 seconds. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. @@ -459,7 +459,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.8-buggy" +ARTY.version="0.9.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -855,6 +855,8 @@ end -- @param #string name Name of the target. function ARTY:RemoveTarget(name) self:F2(name) + + -- Get target ID from namd local id=self:_GetTargetIndexByName(name) if id then @@ -864,11 +866,13 @@ function ARTY:RemoveTarget(name) table.remove(self.targets, id) -- Delete marker belonging to this engagement. - local batteryname,markTargetID, markMoveID=self:_GetMarkIDfromName(name) - if batteryname==self.Controllable:GetName() and markTargetID~=nil then - COORDINATE:RemoveMark(markTargetID) - end - + if self.markallow then + local batteryname,markTargetID, markMoveID=self:_GetMarkIDfromName(name) + if batteryname==self.Controllable:GetName() and markTargetID~=nil then + COORDINATE:RemoveMark(markTargetID) + end + end + end self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) end @@ -878,19 +882,26 @@ end -- @param #string name Name of the target. function ARTY:RemoveMove(name) self:F2(name) + + -- Get move ID from name. local id=self:_GetMoveIndexByName(name) if id then + -- Remove move from table. self:T(ARTY.id..string.format("Group %s: Removing move %s (id=%d).", self.Controllable:GetName(), name, id)) table.remove(self.moves, id) - env.info("FF debug remove move") + -- Delete marker belonging to this relocation move. - --local batteryname,markTargetID,markMoveID=self:_GetMarkIDfromName(name) - --if batteryname==self.Controllable:GetName() and markMoveID~=nil then - --COORDINATE:RemoveMark(markMoveID) - --end + if self.markallow then + local batteryname,markTargetID,markMoveID=self:_GetMarkIDfromName(name) + if batteryname==self.Controllable:GetName() and markMoveID~=nil then + COORDINATE:RemoveMark(markMoveID) + end + end + end + self:T(ARTY.id..string.format("Group %s: Number of moves = %d.", self.Controllable:GetName(), #self.moves)) end --- Delete ALL targets from current target list. @@ -1015,7 +1026,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) -- Debug output. local text=string.format("Started ARTY version %s for group %s.", ARTY.version, Controllable:GetName()) self:E(ARTY.id..text) - MESSAGE:New(text, 10):ToAllIf(self.Debug) + MESSAGE:New(text, 5):ToAllIf(self.Debug) -- Get Ammo. self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:GetAmmo(self.Debug) @@ -1027,10 +1038,11 @@ function ARTY:onafterStart(Controllable, From, Event, To) if self.nukefires==nil then self.nukefires=20/1000/1000*self.nukerange*self.nukerange end - if self.Nukes==nil then - self.Nukes0=self.Nshells0 + if self.Nukes~=nil then + self.Nukes0=math.min(self.Nukes, self.Nshells0) else - self.Nukes0=self.Nukes + self.Nukes=0 + self.Nukes0=0 end local text=string.format("\n******************************************************\n") @@ -1106,510 +1118,25 @@ function ARTY:onafterStart(Controllable, From, Event, To) -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) - self:HandleEvent(EVENTS.MarkAdded, self._OnEventMarkAdded) + --self:HandleEvent(EVENTS.MarkAdded, self._OnEventMarkAdded) - -- Add DCS event handler. - world.addEventHandler(self) + -- Add DCS event handler - necessary for S_EVENT_MARK_* events. So we only start it, if this was requested. + if self.markallow then + world.addEventHandler(self) + end -- Start checking status. self:__Status(self.StatusInterval) end ---- Extract engagement assignments and parameters from mark text. --- @param #ARTY self --- @param #string text Marker text. --- @return #boolean If true, authentification successful. -function ARTY:_MarkerKeyAuthentification(text) - - -- Set battery and coalition. - local batteryname=self.Controllable:GetName() - local batterycoalition=self.Controllable:GetCoalition() - - -- Get assignment. - local mykey=nil - if self.markkey~=nil then - - -- keywords are split by "," - local keywords=self:_split(text, ",") - for _,key in pairs(keywords) do - local s=self:_split(key, " ") - local val=s[2] - if key:lower():find("key") then - mykey=tonumber(val) - self:T(ARTY.id..string.format("Authorisation Key=%s.", val)) - end - end - - end - - -- Check if the authorization key is required and if it is valid. - local _validkey=true - - -- Check if group needs authorization. - if self.markkey~=nil then - -- Assume key is incorrect. - _validkey=false - - -- If key was found, check if matches. - if mykey~=nil then - _validkey=self.markkey==mykey - end - self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) - - -- Send message - local text="" - if mykey==nil then - text=string.format("%s, authorization required but did not receive a key!", batteryname) - elseif _validkey==false then - text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(mykey)) - elseif _validkey==true then - text=string.format("%s, authentification successful!", batteryname) - end - MESSAGE:New(text, 20):ToCoalitionIf(batterycoalition, self.report or self.Debug) - end - - return _validkey -end - ---- Extract engagement assignments and parameters from mark text. --- @param #ARTY self --- @param #string text Marker text to be analyzed. --- @return #table Table with assignment parameters, e.g. number of shots, radius, time etc. -function ARTY:_Markertext(text) - self:F(text) - - -- Assignment parameters. - local assignment={} - assignment.battery={} - assignment.move=false - assignment.engage=false - assignment.readonly=false - assignment.cancelcurrent=false - assignment.time=nil - assignment.nshells=nil - assignment.prio=nil - assignment.maxengage=nil - assignment.radius=nil - assignment.weapontype=nil - assignment.speed=nil - assignment.onroad=nil - assignment.key=nil - - if text:lower():find("arty") then - if text:lower():find("engage") then - assignment.engage=true - elseif text:lower():find("move") then - assignment.move=true - else - self:E(ARTY.id.."ERROR: Neither ENGAGE nor MOVE keyword specified!") - return - end - - -- keywords are split by "," - local keywords=self:_split(text, ",") - - for _,key in pairs(keywords) do - - local s=self:_split(key, " ") - local val=s[2] - - -- Battery name, i.e. which ARTY group should fire. - if key:lower():find("battery") then - - local v=self:_split(key, '"') - - for i=2,#v,2 do - table.insert(assignment.battery, v[i]) - self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) - end - - elseif key:lower():find("time") then - - if val:lower():find("now") then - assignment.time=self:_SecondsToClock(timer.getTime0()+5) - else - assignment.time=val - end - self:T2(ARTY.id..string.format("Key Time=%s.", val)) - - elseif key:lower():find("shots") then - - assignment.nshells=tonumber(s[2]) - self:T(ARTY.id..string.format("Key Shots=%s.", val)) - - elseif key:lower():find("prio") then - - assignment.prio=tonumber(val) - self:T2(string.format("Key Prio=%s.", val)) - - elseif key:lower():find("maxengage") then - - assignment.maxengage=tonumber(val) - self:T2(ARTY.id..string.format("Key Maxengage=%s.", val)) - - elseif key:lower():find("radius") then - - assignment.radius=tonumber(val) - self:T2(ARTY.id..string.format("Key Radius=%s.", val)) - - elseif key:lower():find("weapon") then - - if val:lower():find("cannon") then - assignment.weapontype=ARTY.WeaponType.Cannon - elseif val:lower():find("rocket") then - assignment.weapontype=ARTY.WeaponType.Rockets - elseif val:lower():find("missile") then - assignment.weapontype=ARTY.WeaponType.GuidedMissile - elseif val:lower():find("nuke") then - assignment.weapontype=ARTY.WeaponType.TacticalNukes - else - assignment.weapontype=ARTY.WeaponType.Auto - end - self:T2(ARTY.id..string.format("Key Weapon=%s.", val)) - - elseif key:lower():find("speed") then - - assignment.speed=tonumber(val) - self:T2(ARTY.id..string.format("Key Speed=%s.", val)) - - elseif key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")then - - assignment.onroad=true - self:T2(ARTY.id..string.format("Key Onroad=true.")) - - elseif key:lower():find("irrevocable") or key:lower():find("readonly") then - assignment.readonly=true - self:T2(ARTY.id..string.format("Key Readonly=true.")) - - elseif key:lower():find("cancel current") then - assignment.cancelcurrent=true - self:T2(ARTY.id..string.format("Key Cancel Current=true.")) - end - - end - else - self:T2(ARTY.id..string.format("This is NO arty command:\n%s", tostring(text))) - end - - return assignment -end - ---- After "Start" event. Initialized ROE and alarm state. Starts the event handler. --- @param #ARTY self --- @param #table Event -function ARTY:onEvent(Event) - - if Event == nil or Event.idx == nil then - self:T3("Skipping onEvent. Event or Event.idx unknown.") - return true - end - - -- Set battery and coalition. - local batteryname=self.Controllable:GetName() - local batterycoalition=self.Controllable:GetCoalition() - - self:T(string.format("Event captured = %s", tostring(batteryname))) - self:T(string.format("Event id = %s", tostring(Event.id))) - self:T(string.format("Event time = %s", tostring(Event.time))) - self:T(string.format("Event idx = %s", tostring(Event.idx))) - self:T(string.format("Event coalition = %s", tostring(Event.coalition))) - self:T(string.format("Event group id = %s", tostring(Event.groupID))) - self:T(string.format("Event text = %s", tostring(Event.text))) - self:E({eventid=Event.id, vec3=Event.pos}) - if Event.initiator~=nil then - local _unitname=Event.initiator:getName() - self:T(string.format("Event ini unit name = %s", tostring(_unitname))) - end - - if Event.id==world.event.S_EVENT_MARK_ADDED then - self:E({event="S_EVENT_MARK_ADDED", battery=batteryname, vec3=Event.pos}) - - elseif Event.id==world.event.S_EVENT_MARK_CHANGE then - self:E({event="S_EVENT_MARK_CHANGE", battery=batteryname, vec3=Event.pos}) - - -- Handle event. - self:_OnEventMarkChange(Event) - - elseif Event.id==world.event.S_EVENT_MARK_REMOVED then - self:E({event="S_EVENT_MARK_REMOVED", battery=batteryname, vec3=Event.pos}) - - -- Hande event. - self:_OnEventMarkRemove(Event) - end - -end - ---- Create a name for an engagement initiated by placing a marker. --- @param #ARTY self --- @param #number markerid ID of the placed marker. --- @return #string Name of target engagement. -function ARTY:_MarkTargetName(markerid) - return string.format("BATTERY=%s, Marked Target ID=%d", self.Controllable:GetName(), markerid) -end - ---- Create a name for a relocation move initiated by placing a marker. --- @param #ARTY self --- @param #number markerid ID of the placed marker. --- @return #string Name of relocation move. -function ARTY:_MarkMoveName(markerid) - return string.format("BATTERY=%s, Marked Relocation ID=%d", self.Controllable:GetName(), markerid) -end - ---- Create a name for a relocation move initiated by placing a marker. --- @param #ARTY self --- @param #sting name Name of the assignment. --- @return #string Name of the ARTY group or nil --- @return #number ID of the marked target or nil. --- @return #number ID of the marked relocation move or nil -function ARTY:_GetMarkIDfromName(name) - - -- keywords are split by "," - local keywords=self:_split(name, ",") - - local battery=nil - local markTID=nil - local markMID=nil - - for _,key in pairs(keywords) do - - local str=self:_split(key, "=") - local par=str[1] - local val=str[2] - - if par:find("BATTERY") then - battery=val - end - if par:find("Marked Target ID") then - markTID=tonumber(val) - end - if par:find("Marked Relocation ID") then - markMID=tonumber(val) - end - - end - - return battery, markTID, markMID -end - ---- Function called when a F10 map mark was removed. --- @param #ARTY self --- @param #table Event Event data. -function ARTY:_OnEventMarkRemove(Event) - - -- Get battery coalition and name. - local batterycoalition=self.Controllable:GetCoalition() - local batteryname=self.Controllable:GetName() - - if Event.text~=nil and Event.text:find("BATTERY") then - - local _cancelmove=false - local _canceltarget=false - local _name="" - local _id=nil - - if Event.text:find("Marked Relocation") then - _cancelmove=true - _name=self:_MarkMoveName(Event.idx) - _id=self:_GetMoveIndexByName(_name) - elseif Event.text:find("Marked Target") then - _canceltarget=true - _name=self:_MarkTargetName(Event.idx) - _id=self:_GetTargetIndexByName(_name) - else - return - end - - -- Check if there is a task which matches. - if _id==nil then - return - end - - -- Check if the coalition is the same or an authorization key has been defined. - if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then - - -- Authentify key - local _validkey=self:_MarkerKeyAuthentification(Event.text) - - -- Check if we have the right coalition. - if _validkey then - - -- This should be the unique name of the target or move. - if _cancelmove then - if self.currentMove and self.currentMove.name==_name then - self:Arrived() - else - self:RemoveMove(_name) - end - elseif _canceltarget then - if self.currentTarget and self.currentTarget.name==_name then - self:CeaseFire(self.currentTarget) - else - self:RemoveTarget(_name) - end - end - - end - - end - - end -end - ---- Function called when a F10 map mark was changed. --- @param #ARTY self --- @param #table Event Event data. -function ARTY:_OnEventMarkChange(Event) - - -- Check if marker has a text and the "arty" keyword. - if Event.text~=nil and Event.text:lower():find("arty") then - - -- Get battery coalition and name. - local batterycoalition=self.Controllable:GetCoalition() - local batteryname=self.Controllable:GetName() - - -- Check if the coalition is the same or an authorization key has been defined. - if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then - - -- Evaluate marker text and extract parameters. - local _assign=self:_Markertext(Event.text) - - -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. - local _assigned=true - if #_assign.battery>0 then - _assigned=false - for _,bat in pairs(_assign.battery) do - self:T2(ARTY.id..string.format("Compare battery names %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) - if batteryname==bat then - _assigned=true - end - end - end - - -- Check if ENGAGE or MOVE keywords were found. - if not (_assign.engage or _assign.move) or (not _assigned) then - return - end - - -- Check if the authorization key is required and if it is valid. - local _validkey=self:_MarkerKeyAuthentification(Event.text) - - -- Cancel current target. - if _validkey and _assign.cancelcurrent then - if _assign.move and self.currentMove then - self:Arrived() - end - if _assign.engage and self.currentTarget then - self:CeaseFire(self.currentTarget) - end - return - end - - -- We are meant. - if _validkey then - - -- Convert (wrong x-->z, z-->x) vec3 - local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} - - -- Get coordinate from vec3. - local _coord=COORDINATE:NewFromVec3(vec3) - - -- Remove old mark because it might contain confidential data such as the key. - -- Also I don't know who can see the mark which was created. - _coord:RemoveMark(Event.idx) - - -- Anticipate marker ID. - -- WARNING: Make sure, no marks are set until the COORDINATE:MarkToCoalition() is called or the target/move name will be wrong and target cannot be removed by deleting its marker. - local _id=UTILS._MarkID+1 - - if _assign.move then - - -- Create a new name. This determins the string we search when deleting a move! - local _name=self:_MarkMoveName(_id) - - local text=string.format("%s, received new relocation assignment.", batteryname) - text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) - MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) - - -- Assign a relocation of the arty group. - local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) - - if _movename~=nil then - local _mid=self:_GetMoveIndexByName(_movename) - local _move=self.moves[_mid] - - -- Create new target name. - local clock=tostring(self:_SecondsToClock(_move.time)) - local _markertext=_movename..string.format(", Time=%s, Speed=%d km/h, Use Roads=%s.", clock, _move.speed, tostring(_move.onroad)) - - -- Create a new mark. This will trigger the mark added event. - local _randomcoord=_coord:GetRandomCoordinateInRadius(100) - _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) - end - - else - - -- Create a new name. - local _name=self:_MarkTargetName(_id) - - local text=string.format("%s, received new target assignment.", batteryname) - text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) - if _assign.time then - text=text..string.format("\nTime %s",_assign.time) - end - if _assign.prio then - text=text..string.format("\nPrio %d",_assign.prio) - end - if _assign.prio then - text=text..string.format("\nRadius %d m",_assign.radius) - end - if _assign.nshells then - text=text..string.format("\nShots %d",_assign.nshells) - end - if _assign.maxengage then - text=text..string.format("\nEngagements %d",_assign.maxengage) - end - if _assign.weapontype then - text=text..string.format("\nWeapon %s",self:_WeaponTypeName(_assign.weapontype)) - end - MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) - - -- Assign a new firing engagement. - -- Note, we set unique=true so this target gets only added once. - local _targetname=self:AssignTargetCoord(_coord,_assign.prio,_assign.radius,_assign.nshells,_assign.maxengage,_assign.time,_assign.weapontype, _name, true) - - if _targetname~=nil then - local _tid=self:_GetTargetIndexByName(_targetname) - local _target=self.targets[_tid] - - -- Create new target name. - local clock=tostring(self:_SecondsToClock(_target.time)) - local weapon=self:_WeaponTypeName(_target.weapontype) - local _markertext=_targetname..string.format(", Priority=%d, Radius=%d m, Shots=%d, Engagements=%d, Weapon=%s, Time=%s", _target.prio, _target.radius, _target.nshells, _target.maxengage, weapon, clock) - - -- Create a new mark. This will trigger the mark added event. - local _randomcoord=_coord:GetRandomCoordinateInRadius(250) - _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) - end - end - end - - end - end - -end - --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self function ARTY:_StatusReport() -- Get Ammo. local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() - local Nnukes - if self.Nukes==nil then - Nnukes=0 - else - Nnukes=self.Nukes - end + local Nnukes=self.Nukes + local Tnow=timer.getTime() local Clock=self:_SecondsToClock(timer.getAbsTime()) @@ -1651,115 +1178,6 @@ end -- Event Handling ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Model a nuclear blast/destruction by creating fires and destroy scenery. --- @param #ARTY self --- @param Core.Point#COORDINATE _coord Coordinate of the impact point (center of the blast). -function ARTY:_NuclearBlast(_coord) - - local S0=self.nukewarhead - local R0=self.nukerange - - -- Number of fires - local N0=self.nukefires - - -- Create an explosion at the last known position. - _coord:Explosion(S0) - - -- Huge fire at direct impact point. - --if self.nukefire then - _coord:BigSmokeAndFireHuge() - --end - - -- Create a table of fire coordinates within the demolition zone. - local _fires={} - for i=1,N0 do - local _fire=_coord:GetRandomCoordinateInRadius(R0) - local _dist=_fire:Get2DDistance(_coord) - table.insert(_fires, {distance=_dist, coord=_fire}) - end - - -- Sort scenery wrt to distance from impact point. - local _sort = function(a,b) return a.distance < b.distance end - table.sort(_fires,_sort) - - local function _explosion(R) - -- At R=R0 ==> explosion strength is 1% of S0 at impact point. - local alpha=math.log(100) - local strength=S0*math.exp(-alpha*R/R0) - self:T2(ARTY.id..string.format("Nuclear explosion strength s(%.1f m) = %.5f (s/s0=%.1f %%), alpha=%.3f", R, strength, strength/S0*100, alpha)) - return strength - end - - local function ignite(_fires) - for _,fire in pairs(_fires) do - local _fire=fire.coord --Core.Point#COORDINATE - - -- Get distance to impact and calc exponential explosion strength. - local R=_fire:Get2DDistance(_coord) - local S=_explosion(R) - self:T2(ARTY.id..string.format("Explosion r=%.1f, s=%.3f", R, S)) - - -- Get a random Big Smoke and fire object. - local _preset=math.random(0,7) - local _density=S/S0 --math.random()+0.1 - - _fire:BigSmokeAndFire(_preset,_density) - _fire:Explosion(S) - - end - end - - if self.nukefire==true then - ignite(_fires) - end - ---[[ - local ZoneNuke=ZONE_RADIUS:New("Nukezone", _coord:GetVec2(), 2000) - - -- Scan for Scenery objects. - ZoneNuke:Scan(Object.Category.SCENERY) - - -- Array with all possible hideouts, i.e. scenery objects in the vicinity of the group. - local scenery={} - - for SceneryTypeName, SceneryData in pairs(ZoneNuke:GetScannedScenery()) do - for SceneryName, SceneryObject in pairs(SceneryData) do - - local SceneryObject = SceneryObject -- Wrapper.Scenery#SCENERY - - -- Position of the scenery object. - local spos=SceneryObject:GetCoordinate() - - -- Distance from group to impact point. - local distance= spos:Get2DDistance(_coord) - - -- Place markers on every possible scenery object. - if self.Debug then - local MarkerID=spos:MarkToAll(string.format("%s scenery object %s", self.Controllable:GetName(), SceneryObject:GetTypeName())) - local text=string.format("%s scenery: %s, Coord %s", self.Controllable:GetName(), SceneryObject:GetTypeName(), SceneryObject:GetCoordinate():ToStringLLDMS()) - self:T2(SUPPRESSION.id..text) - end - - -- Add to table. - table.insert(scenery, {object=SceneryObject, distance=distance}) - - --SceneryObject:Destroy() - end - end - - -- Sort scenery wrt to distance from impact point. --- local _sort = function(a,b) return a.distance < b.distance end --- table.sort(scenery,_sort) - --- for _,object in pairs(scenery) do --- local sobject=object -- Wrapper.Scenery#SCENERY --- sobject:Destroy() --- end - -]] - -end - --- Eventhandler for shot event. -- @param #ARTY self -- @param Core.Event#EVENTDATA EventData @@ -1833,8 +1251,7 @@ function ARTY:_OnEventShot(EventData) self:T(ARTY.id..string.format("ARTY %s: Tracking of weapon starts in two seconds.", self.Controllable:GetName())) timer.scheduleFunction(_TrackWeapon, EventData.weapon, timer.getTime() + 2.0) end - - + -- Get current ammo. local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() @@ -1927,6 +1344,278 @@ function ARTY:_OnEventShot(EventData) end end +--- After "Start" event. Initialized ROE and alarm state. Starts the event handler. +-- @param #ARTY self +-- @param #table Event +function ARTY:onEvent(Event) + + if Event == nil or Event.idx == nil then + self:T3("Skipping onEvent. Event or Event.idx unknown.") + return true + end + + -- Set battery and coalition. + local batteryname=self.Controllable:GetName() + local batterycoalition=self.Controllable:GetCoalition() + + self:T(string.format("Event captured = %s", tostring(batteryname))) + self:T(string.format("Event id = %s", tostring(Event.id))) + self:T(string.format("Event time = %s", tostring(Event.time))) + self:T(string.format("Event idx = %s", tostring(Event.idx))) + self:T(string.format("Event coalition = %s", tostring(Event.coalition))) + self:T(string.format("Event group id = %s", tostring(Event.groupID))) + self:T(string.format("Event text = %s", tostring(Event.text))) + self:E({eventid=Event.id, vec3=Event.pos}) + if Event.initiator~=nil then + local _unitname=Event.initiator:getName() + self:T(string.format("Event ini unit name = %s", tostring(_unitname))) + end + + if Event.id==world.event.S_EVENT_MARK_ADDED then + self:E({event="S_EVENT_MARK_ADDED", battery=batteryname, vec3=Event.pos}) + + elseif Event.id==world.event.S_EVENT_MARK_CHANGE then + self:E({event="S_EVENT_MARK_CHANGE", battery=batteryname, vec3=Event.pos}) + + -- Handle event. + self:_OnEventMarkChange(Event) + + elseif Event.id==world.event.S_EVENT_MARK_REMOVED then + self:E({event="S_EVENT_MARK_REMOVED", battery=batteryname, vec3=Event.pos}) + + -- Hande event. + self:_OnEventMarkRemove(Event) + end + +end + +--- Function called when a F10 map mark was removed. +-- @param #ARTY self +-- @param #table Event Event data. +function ARTY:_OnEventMarkRemove(Event) + + -- Get battery coalition and name. + local batterycoalition=self.Controllable:GetCoalition() + local batteryname=self.Controllable:GetName() + + if Event.text~=nil and Event.text:find("BATTERY") then + + -- Init defaults. + local _cancelmove=false + local _canceltarget=false + local _name="" + local _id=nil + + -- Check for key phrases of relocation or engagements in marker text. If not, return. + if Event.text:find("Marked Relocation") then + _cancelmove=true + _name=self:_MarkMoveName(Event.idx) + _id=self:_GetMoveIndexByName(_name) + elseif Event.text:find("Marked Target") then + _canceltarget=true + _name=self:_MarkTargetName(Event.idx) + _id=self:_GetTargetIndexByName(_name) + else + return + end + + -- Check if there is a task which matches. + if _id==nil then + return + end + + -- Check if the coalition is the same or an authorization key has been defined. + if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then + + -- Authentify key + local _validkey=self:_MarkerKeyAuthentification(Event.text) + + -- Check if we have the right coalition. + if _validkey then + + -- This should be the unique name of the target or move. + if _cancelmove then + if self.currentMove and self.currentMove.name==_name then + self.Controllable:ClearTasks() + self:Arrived() + else + self:RemoveMove(_name) + end + elseif _canceltarget then + if self.currentTarget and self.currentTarget.name==_name then + self:CeaseFire(self.currentTarget) + self:RemoveTarget(_name) + else + self:RemoveTarget(_name) + end + end + + end + end + end +end + +--- Function called when a F10 map mark was changed. This happens when a user enters text. +-- @param #ARTY self +-- @param #table Event Event data. +function ARTY:_OnEventMarkChange(Event) + + -- Check if marker has a text and the "arty" keyword. + if Event.text~=nil and Event.text:lower():find("arty") then + + -- Get battery coalition and name. + local batterycoalition=self.Controllable:GetCoalition() + local batteryname=self.Controllable:GetName() + + -- Check if the coalition is the same or an authorization key has been defined. + if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then + + -- Evaluate marker text and extract parameters. + local _assign=self:_Markertext(Event.text) + + -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. + local _assigned=true + if #_assign.battery>0 then + _assigned=false + for _,bat in pairs(_assign.battery) do + self:T2(ARTY.id..string.format("Compare battery names %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) + if batteryname==bat then + _assigned=true + end + end + end + + -- We were not addressed. + if not _assigned then + return + end + + -- Check if ENGAGE or MOVE or REQUEST keywords were found. + if not (_assign.engage or _assign.move or _assign.request) then + return + end + + -- Check if the authorization key is required and if it is valid. + local _validkey=self:_MarkerKeyAuthentification(Event.text) + + -- Handle requests and return. + if _assign.request and _validkey then + if _assign.requestammo then + self:_MarkRequestAmmo() + end + -- Done! + return + end + + -- Cancel current target and return. + if _assign.cancelcurrent and _validkey then + if _assign.move and self.currentMove then + self.Controllable:ClearTasks() + self:Arrived() + end + if _assign.engage and self.currentTarget then + self:CeaseFire(self.currentTarget) + end + return + end + + -- Handle engagements and relocations. + if _validkey then + + -- Convert (wrong x-->z, z-->x) vec3 + local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} + + -- Get coordinate from vec3. + local _coord=COORDINATE:NewFromVec3(vec3) + + -- Remove old mark because it might contain confidential data such as the key. + -- Also I don't know who can see the mark which was created. + _coord:RemoveMark(Event.idx) + + -- Anticipate marker ID. + -- WARNING: Make sure, no marks are set until the COORDINATE:MarkToCoalition() is called or the target/move name will be wrong and target cannot be removed by deleting its marker. + local _id=UTILS._MarkID+1 + + if _assign.move then + + -- Create a new name. This determins the string we search when deleting a move! + local _name=self:_MarkMoveName(_id) + + local text=string.format("%s, received new relocation assignment.", batteryname) + text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) + MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) + + -- Assign a relocation of the arty group. + local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) + + if _movename~=nil then + local _mid=self:_GetMoveIndexByName(_movename) + local _move=self.moves[_mid] + + -- Create new target name. + local clock=tostring(self:_SecondsToClock(_move.time)) + local _markertext=_movename..string.format(", Time=%s, Speed=%d km/h, Use Roads=%s.", clock, _move.speed, tostring(_move.onroad)) + + -- Create a new mark. This will trigger the mark added event. + local _randomcoord=_coord:GetRandomCoordinateInRadius(100) + _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) + else + local text=string.format("%s, relocation not possible.", batteryname) + MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) + end + + else + + -- Create a new name. + local _name=self:_MarkTargetName(_id) + + local text=string.format("%s, received new target assignment.", batteryname) + text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) + if _assign.time then + text=text..string.format("\nTime %s",_assign.time) + end + if _assign.prio then + text=text..string.format("\nPrio %d",_assign.prio) + end + if _assign.prio then + text=text..string.format("\nRadius %d m",_assign.radius) + end + if _assign.nshells then + text=text..string.format("\nShots %d",_assign.nshells) + end + if _assign.maxengage then + text=text..string.format("\nEngagements %d",_assign.maxengage) + end + if _assign.weapontype then + text=text..string.format("\nWeapon %s",self:_WeaponTypeName(_assign.weapontype)) + end + MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) + + -- Assign a new firing engagement. + -- Note, we set unique=true so this target gets only added once. + local _targetname=self:AssignTargetCoord(_coord,_assign.prio,_assign.radius,_assign.nshells,_assign.maxengage,_assign.time,_assign.weapontype, _name, true) + + if _targetname~=nil then + local _tid=self:_GetTargetIndexByName(_targetname) + local _target=self.targets[_tid] + + -- Create new target name. + local clock=tostring(self:_SecondsToClock(_target.time)) + local weapon=self:_WeaponTypeName(_target.weapontype) + local _markertext=_targetname..string.format(", Priority=%d, Radius=%d m, Shots=%d, Engagements=%d, Weapon=%s, Time=%s", _target.prio, _target.radius, _target.nshells, _target.maxengage, weapon, clock) + + -- Create a new mark. This will trigger the mark added event. + local _randomcoord=_coord:GetRandomCoordinateInRadius(250) + _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) + end + end + end + + end + end + +end + --- Event handler for event Dead. -- @param #ARTY self -- @param Core.Event#EVENTDATA EventData @@ -2017,7 +1706,6 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Get a commaned move to another location. local _move=self:_CheckMoves() - if (self:is("CombatReady") or self:is("Firing")) and _move then -- Group is combat ready or firing but we have a move. @@ -2049,7 +1737,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To) end end - + -- Call status again in ~10 sec. self:__Status(self.StatusInterval) end @@ -2193,11 +1881,11 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report) - if self.Debug then - local _coord=target.coord --Core.Point#COORDINATE - local text=string.format("ARTY %s, Target %s, n=%d, weapon=%s", self.Controllable:GetName(), target.name, target.nshells, self:_WeaponTypeName(target.weapontype)) - _coord:MarkToAll(text) - end + --if self.Debug then + -- local _coord=target.coord --Core.Point#COORDINATE + -- local text=string.format("ARTY %s, Target %s, n=%d, weapon=%s", self.Controllable:GetName(), target.name, target.nshells, self:_WeaponTypeName(target.weapontype)) + -- _coord:MarkToAll(text) + --end -- Start firing. self:_FireAtCoord(target.coord, target.radius, target.nshells, target.weapontype) @@ -2226,7 +1914,7 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) -- Get target array index. local id=self:_GetTargetIndexByName(target.name) - -- Increase engaged counter + -- We have a target. if id then -- Target was actually engaged. (Could happen that engagement was aborted while group was still aiming.) if self.Nshots>0 then @@ -2270,7 +1958,7 @@ function ARTY:onafterWinchester(Controllable, From, Event, To) -- Send message. local text=string.format("%s, winchester!", Controllable:GetName()) self:T(ARTY.id..text) - MESSAGE:New(text, 30):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) + MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report or self.Debug) end @@ -2522,8 +2210,8 @@ function ARTY:onafterArrived(Controllable, From, Event, To) -- Set alarm state to auto. self.Controllable:OptionAlarmStateAuto() - -- Clear Tasks - self.Controllable:ClearTasks() + -- WARNING: calling ClearTasks() here causes CTD of DCS when move is over. Dont know why? combotask? + --self.Controllable:ClearTasks() -- Send message local text=string.format("%s, arrived at destination.", Controllable:GetName()) @@ -2532,10 +2220,10 @@ function ARTY:onafterArrived(Controllable, From, Event, To) -- Remove executed move from queue. if self.currentMove then - --self:RemoveMove(self.currentMove.name) - --self.currentMove=nil + self:RemoveMove(self.currentMove.name) + self.currentMove=nil end - + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -2553,7 +2241,7 @@ function ARTY:onafterNewTarget(Controllable, From, Event, To, target) -- Debug message. local text=string.format("Adding new target %s.", target.name) - --MESSAGE:New(text, 30):ToAllIf(self.Debug) + MESSAGE:New(text, 5):ToAllIf(self.Debug) self:T(ARTY.id..text) end @@ -2570,7 +2258,7 @@ function ARTY:onafterNewMove(Controllable, From, Event, To, move) -- Debug message. local text=string.format("Adding new move %s.", move.name) - MESSAGE:New(text, 30):ToAllIf(self.Debug) + MESSAGE:New(text, 5):ToAllIf(self.Debug) self:T(ARTY.id..text) end @@ -2596,7 +2284,7 @@ function ARTY:onafterDead(Controllable, From, Event, To) -- Message. local text=string.format("%s, one of our units just died! %d units left.", self.Controllable:GetName(), nunits) - MESSAGE:New(text, 10):ToAllIf(self.Debug) + MESSAGE:New(text, 5):ToAllIf(self.Debug) self:T(ARTY.id..text) -- Go to stop state. @@ -2665,6 +2353,217 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype) group:SetTask(fire) end +--- Model a nuclear blast/destruction by creating fires and destroy scenery. +-- @param #ARTY self +-- @param Core.Point#COORDINATE _coord Coordinate of the impact point (center of the blast). +function ARTY:_NuclearBlast(_coord) + + local S0=self.nukewarhead + local R0=self.nukerange + + -- Number of fires + local N0=self.nukefires + + -- Create an explosion at the last known position. + _coord:Explosion(S0) + + -- Huge fire at direct impact point. + --if self.nukefire then + _coord:BigSmokeAndFireHuge() + --end + + -- Create a table of fire coordinates within the demolition zone. + local _fires={} + for i=1,N0 do + local _fire=_coord:GetRandomCoordinateInRadius(R0) + local _dist=_fire:Get2DDistance(_coord) + table.insert(_fires, {distance=_dist, coord=_fire}) + end + + -- Sort scenery wrt to distance from impact point. + local _sort = function(a,b) return a.distance < b.distance end + table.sort(_fires,_sort) + + local function _explosion(R) + -- At R=R0 ==> explosion strength is 1% of S0 at impact point. + local alpha=math.log(100) + local strength=S0*math.exp(-alpha*R/R0) + self:T2(ARTY.id..string.format("Nuclear explosion strength s(%.1f m) = %.5f (s/s0=%.1f %%), alpha=%.3f", R, strength, strength/S0*100, alpha)) + return strength + end + + local function ignite(_fires) + for _,fire in pairs(_fires) do + local _fire=fire.coord --Core.Point#COORDINATE + + -- Get distance to impact and calc exponential explosion strength. + local R=_fire:Get2DDistance(_coord) + local S=_explosion(R) + self:T2(ARTY.id..string.format("Explosion r=%.1f, s=%.3f", R, S)) + + -- Get a random Big Smoke and fire object. + local _preset=math.random(0,7) + local _density=S/S0 --math.random()+0.1 + + _fire:BigSmokeAndFire(_preset,_density) + _fire:Explosion(S) + + end + end + + if self.nukefire==true then + ignite(_fires) + end + +--[[ + local ZoneNuke=ZONE_RADIUS:New("Nukezone", _coord:GetVec2(), 2000) + + -- Scan for Scenery objects. + ZoneNuke:Scan(Object.Category.SCENERY) + + -- Array with all possible hideouts, i.e. scenery objects in the vicinity of the group. + local scenery={} + + for SceneryTypeName, SceneryData in pairs(ZoneNuke:GetScannedScenery()) do + for SceneryName, SceneryObject in pairs(SceneryData) do + + local SceneryObject = SceneryObject -- Wrapper.Scenery#SCENERY + + -- Position of the scenery object. + local spos=SceneryObject:GetCoordinate() + + -- Distance from group to impact point. + local distance= spos:Get2DDistance(_coord) + + -- Place markers on every possible scenery object. + if self.Debug then + local MarkerID=spos:MarkToAll(string.format("%s scenery object %s", self.Controllable:GetName(), SceneryObject:GetTypeName())) + local text=string.format("%s scenery: %s, Coord %s", self.Controllable:GetName(), SceneryObject:GetTypeName(), SceneryObject:GetCoordinate():ToStringLLDMS()) + self:T2(SUPPRESSION.id..text) + end + + -- Add to table. + table.insert(scenery, {object=SceneryObject, distance=distance}) + + --SceneryObject:Destroy() + end + end + + -- Sort scenery wrt to distance from impact point. +-- local _sort = function(a,b) return a.distance < b.distance end +-- table.sort(scenery,_sort) + +-- for _,object in pairs(scenery) do +-- local sobject=object -- Wrapper.Scenery#SCENERY +-- sobject:Destroy() +-- end + +]] + +end + +--- Route group to a certain point. +-- @param #ARTY self +-- @param Wrapper.Group#GROUP group Group to route. +-- @param Core.Point#COORDINATE ToCoord Coordinate where we want to go. +-- @param #number Speed Speed in km/h. +-- @param #boolean OnRoad If true, use (mainly) roads. +function ARTY:_Move(group, ToCoord, Speed, OnRoad) + + -- Clear all tasks. + group:ClearTasks() + group:OptionAlarmStateGreen() + group:OptionROEHoldFire() + + -- Set formation. + local formation = "Off Road" + + -- Default speed is 30 km/h. + Speed=Speed or 30 + + -- Current coordinates of group. + local cpini=group:GetCoordinate() + + -- Distance between current and final point. + local dist=cpini:Get2DDistance(ToCoord) + + -- Waypoint and task arrays. + local path={} + local task={} + + -- First waypoint is the current position of the group. + path[#path+1]=cpini:WaypointGround(Speed, formation) + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + -- Route group on road if requested. + if OnRoad then + + -- Path on road (only first and last points) + local _first=cpini:GetClosestPointToRoad() + local _last=ToCoord:GetClosestPointToRoad() + + -- First point on road. + path[#path+1]=_first:WaypointGround(Speed, "On Road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + -- Last point on road. + path[#path+1]=_last:WaypointGround(Speed, "On Road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + end + + -- Last waypoint at ToCoord. + path[#path+1]=ToCoord:WaypointGround(Speed, formation) + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, true) + + + -- Init waypoints of the group. + local Waypoints={} + + -- New points are added to the default route. + for i=1,#path do + table.insert(Waypoints, i, path[i]) + end + + -- Set task for all waypoints. + for i=1,#Waypoints do + group:SetTaskWaypoint(Waypoints[i], task[i]) + end + + -- Submit task and route group along waypoints. + group:Route(Waypoints) + +end + +--- Function called when group is passing a waypoint. +-- @param Wrapper.Group#GROUP group Group for which waypoint passing should be monitored. +-- @param #ARTY arty ARTY object. +-- @param #number i Waypoint number that has been reached. +-- @param #boolean final True if it is the final waypoint. +function ARTY._PassingWaypoint(group, arty, i, final) + + -- Debug message. + local text=string.format("%s, passing waypoint %d.", group:GetName(), i) + if final then + text=string.format("%s, arrived at destination.", group:GetName()) + end + arty:T(ARTY.id..text) + + --[[ + if final then + MESSAGE:New(text, 10):ToCoalitionIf(group:GetCoalition(), arty.Debug or arty.report) + else + MESSAGE:New(text, 10):ToAllIf(arty.Debug) + end + ]] + + -- Arrived event. + if final and arty.Controllable:GetName()==group:GetName() then + arty:Arrived() + end + +end + --- Relocate to another position, e.g. after an engagement to avoid couter strikes. -- @param #ARTY self function ARTY:_Relocate() @@ -2695,155 +2594,6 @@ function ARTY:_Relocate() end end ---- Sort targets with respect to priority and number of times it was already engaged. --- @param #ARTY self -function ARTY:_SortTargetQueuePrio() - self:F2() - - -- Sort results table wrt times they have already been engaged. - local function _sort(a, b) - return (a.engaged < b.engaged) or (a.engaged==b.engaged and a.prio < b.prio) - end - table.sort(self.targets, _sort) - - -- Debug output. - self:T3(ARTY.id.."Sorted targets wrt prio and number of engagements:") - for i=1,#self.targets do - local _target=self.targets[i] - self:T3(ARTY.id..string.format("Target %s", self:_TargetInfo(_target))) - end -end - ---- Sort array with respect to time. Array elements must have a .time entry. --- @param #ARTY self --- @param #table queue Array to sort. Should have elemnt .time. -function ARTY:_SortQueueTime(queue) - self:F3({queue=queue}) - - -- Sort targets w.r.t attack time. - local function _sort(a, b) - if a.time == nil and b.time == nil then - return false - end - if a.time == nil then - return false - end - if b.time == nil then - return true - end - return a.time < b.time - end - table.sort(queue, _sort) - - -- Debug output. - self:T3(ARTY.id.."Sorted queue wrt time:") - for i=1,#queue do - local _queue=queue[i] - local _time=tostring(_queue.time) - local _clock=tostring(self:_SecondsToClock(_queue.time)) - self:T3(ARTY.id..string.format("%s: time=%s, clock=%s", _queue.name, _time, _clock)) - end - -end - ---- Check all timed targets and return the target which should be attacked next. --- @param #ARTY self --- @return #table Target which is due to be attacked now. -function ARTY:_CheckTimedTargets() - self:F3() - - -- Current time. - local Tnow=timer.getAbsTime() - - -- Sort Targets wrt time. - self:_SortQueueTime(self.targets) - - for i=1,#self.targets do - local _target=self.targets[i] - - -- Debug info. - self:T3(ARTY.id..string.format("Check TIMED target %d: %s", i, self:_TargetInfo(_target))) - - -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. - if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then - - -- Check if group currently has a target and whether its priorty is lower than the timed target. - if self.currentTarget then - if self.currentTarget.prio > _target.prio then - -- Current target under attack but has lower priority than this target. - self:T2(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInfo(_target))) - return _target - end - else - -- No current target. - self:T2(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) - return _target - end - end - end - - return nil -end - ---- Check all moves and return the one which should be executed next. --- @param #ARTY self --- @return #table Move which is due. -function ARTY:_CheckMoves() - self:F3() - - -- Current time. - local Tnow=timer.getAbsTime() - - -- Sort Targets wrt time. - self:_SortQueueTime(self.moves) - - -- Check if we are currently firing. - local firing=false - if self.currentTarget then - firing=true - end - - for i=1,#self.moves do - local _move=self.moves[i] - - -- Check if time for move is reached. - if Tnow >= _move.time and (firing==false or _move.cancel) then - return _move - end - end - - return nil -end - ---- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. --- @param #ARTY self --- @return #table Target which is due to be attacked now or nil if no target could be found. -function ARTY:_CheckNormalTargets() - self:F3() - - -- Sort targets w.r.t. prio and number times engaged already. - self:_SortTargetQueuePrio() - - -- Loop over all sorted targets. - for i=1,#self.targets do - local _target=self.targets[i] - - -- Debug info. - self:T3(ARTY.id..string.format("Check NORMAL target %d: %s", i, self:_TargetInfo(_target))) - - -- Check that target no time, is not under fire currently and in range. - if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then - - -- Debug info. - self:T2(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) - - return _target - end - end - - return nil -end - --- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up. -- @param #ARTY self -- @param #boolean display Display ammo table as message to all. Default false. @@ -3007,6 +2757,405 @@ function ARTY:GetAmmo(display) return nammo, nshells, nrockets, nmissiles end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Mark Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Extract engagement assignments and parameters from mark text. +-- @param #ARTY self +-- @param #string text Marker text. +-- @return #boolean If true, authentification successful. +function ARTY:_MarkerKeyAuthentification(text) + + -- Set battery and coalition. + local batteryname=self.Controllable:GetName() + local batterycoalition=self.Controllable:GetCoalition() + + -- Get assignment. + local mykey=nil + if self.markkey~=nil then + + -- keywords are split by "," + local keywords=self:_split(text, ",") + for _,key in pairs(keywords) do + local s=self:_split(key, " ") + local val=s[2] + if key:lower():find("key") then + mykey=tonumber(val) + self:T(ARTY.id..string.format("Authorisation Key=%s.", val)) + end + end + + end + + -- Check if the authorization key is required and if it is valid. + local _validkey=true + + -- Check if group needs authorization. + if self.markkey~=nil then + -- Assume key is incorrect. + _validkey=false + + -- If key was found, check if matches. + if mykey~=nil then + _validkey=self.markkey==mykey + end + self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) + + -- Send message + local text="" + if mykey==nil then + text=string.format("%s, authorization required but did not receive a key!", batteryname) + elseif _validkey==false then + text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(mykey)) + elseif _validkey==true then + text=string.format("%s, authentification successful!", batteryname) + end + MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) + end + + return _validkey +end + +--- Extract engagement assignments and parameters from mark text. +-- @param #ARTY self +-- @param #string text Marker text to be analyzed. +-- @return #table Table with assignment parameters, e.g. number of shots, radius, time etc. +function ARTY:_Markertext(text) + self:F(text) + + -- Assignment parameters. + local assignment={} + assignment.battery={} + assignment.move=false + assignment.engage=false + assignment.request=false + assignment.readonly=false + assignment.cancelcurrent=false + --assignment.time=nil + --assignment.nshells=nil + --assignment.prio=nil + --assignment.maxengage=nil + --assignment.radius=nil + --assignment.weapontype=nil + --assignment.speed=nil + --assignment.onroad=nil + --assignment.key=nil + + if text:lower():find("arty") then + if text:lower():find("engage") then + assignment.engage=true + elseif text:lower():find("move") then + assignment.move=true + elseif text:lower():find("request") then + assignment.request=true + else + self:E(ARTY.id.."ERROR: Neither ENGAGE nor MOVE keyword specified!") + return + end + + -- keywords are split by "," + local keywords=self:_split(text, ",") + + for _,key in pairs(keywords) do + + local s=self:_split(key, " ") + local val=s[2] + + -- Battery name, i.e. which ARTY group should fire. + if key:lower():find("battery") then + + local v=self:_split(key, '"') + + for i=2,#v,2 do + table.insert(assignment.battery, v[i]) + self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) + end + + elseif key:lower():find("time") then + + if val:lower():find("now") then + assignment.time=self:_SecondsToClock(timer.getTime0()+5) + else + assignment.time=val + end + self:T2(ARTY.id..string.format("Key Time=%s.", val)) + + elseif key:lower():find("shots") then + + assignment.nshells=tonumber(s[2]) + self:T(ARTY.id..string.format("Key Shots=%s.", val)) + + elseif key:lower():find("prio") then + + assignment.prio=tonumber(val) + self:T2(string.format("Key Prio=%s.", val)) + + elseif key:lower():find("maxengage") then + + assignment.maxengage=tonumber(val) + self:T2(ARTY.id..string.format("Key Maxengage=%s.", val)) + + elseif key:lower():find("radius") then + + assignment.radius=tonumber(val) + self:T2(ARTY.id..string.format("Key Radius=%s.", val)) + + elseif key:lower():find("weapon") then + + if val:lower():find("cannon") then + assignment.weapontype=ARTY.WeaponType.Cannon + elseif val:lower():find("rocket") then + assignment.weapontype=ARTY.WeaponType.Rockets + elseif val:lower():find("missile") then + assignment.weapontype=ARTY.WeaponType.GuidedMissile + elseif val:lower():find("nuke") then + assignment.weapontype=ARTY.WeaponType.TacticalNukes + else + assignment.weapontype=ARTY.WeaponType.Auto + end + self:T2(ARTY.id..string.format("Key Weapon=%s.", val)) + + elseif key:lower():find("speed") then + + assignment.speed=tonumber(val) + self:T2(ARTY.id..string.format("Key Speed=%s.", val)) + + elseif key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")then + + assignment.onroad=true + self:T2(ARTY.id..string.format("Key Onroad=true.")) + + elseif key:lower():find("irrevocable") or key:lower():find("readonly") then + assignment.readonly=true + self:T2(ARTY.id..string.format("Key Readonly=true.")) + + elseif key:lower():find("cancel current") then + assignment.cancelcurrent=true + self:T2(ARTY.id..string.format("Key Cancel Current=true.")) + elseif assignment.request and key:lower():find("ammo") then + assignment.requestammo=true + end + + end + else + self:T2(ARTY.id..string.format("This is NO arty command:\n%s", tostring(text))) + end + + return assignment +end + +--- Request ammo. +-- @param #ARTY self +function ARTY:_MarkRequestAmmo() + self:GetAmmo(true) +end + +--- Create a name for an engagement initiated by placing a marker. +-- @param #ARTY self +-- @param #number markerid ID of the placed marker. +-- @return #string Name of target engagement. +function ARTY:_MarkTargetName(markerid) + return string.format("BATTERY=%s, Marked Target ID=%d", self.Controllable:GetName(), markerid) +end + +--- Create a name for a relocation move initiated by placing a marker. +-- @param #ARTY self +-- @param #number markerid ID of the placed marker. +-- @return #string Name of relocation move. +function ARTY:_MarkMoveName(markerid) + return string.format("BATTERY=%s, Marked Relocation ID=%d", self.Controllable:GetName(), markerid) +end + +--- Create a name for a relocation move initiated by placing a marker. +-- @param #ARTY self +-- @param #string name Name of the assignment. +-- @return #string Name of the ARTY group or nil +-- @return #number ID of the marked target or nil. +-- @return #number ID of the marked relocation move or nil +function ARTY:_GetMarkIDfromName(name) + + -- keywords are split by "," + local keywords=self:_split(name, ",") + + local battery=nil + local markTID=nil + local markMID=nil + + for _,key in pairs(keywords) do + + local str=self:_split(key, "=") + local par=str[1] + local val=str[2] + + if par:find("BATTERY") then + battery=val + end + if par:find("Marked Target ID") then + markTID=tonumber(val) + end + if par:find("Marked Relocation ID") then + markMID=tonumber(val) + end + + end + + return battery, markTID, markMID +end + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Helper Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Sort targets with respect to priority and number of times it was already engaged. +-- @param #ARTY self +function ARTY:_SortTargetQueuePrio() + self:F2() + + -- Sort results table wrt times they have already been engaged. + local function _sort(a, b) + return (a.engaged < b.engaged) or (a.engaged==b.engaged and a.prio < b.prio) + end + table.sort(self.targets, _sort) + + -- Debug output. + self:T3(ARTY.id.."Sorted targets wrt prio and number of engagements:") + for i=1,#self.targets do + local _target=self.targets[i] + self:T3(ARTY.id..string.format("Target %s", self:_TargetInfo(_target))) + end +end + +--- Sort array with respect to time. Array elements must have a .time entry. +-- @param #ARTY self +-- @param #table queue Array to sort. Should have elemnt .time. +function ARTY:_SortQueueTime(queue) + self:F3({queue=queue}) + + -- Sort targets w.r.t attack time. + local function _sort(a, b) + if a.time == nil and b.time == nil then + return false + end + if a.time == nil then + return false + end + if b.time == nil then + return true + end + return a.time < b.time + end + table.sort(queue, _sort) + + -- Debug output. + self:T3(ARTY.id.."Sorted queue wrt time:") + for i=1,#queue do + local _queue=queue[i] + local _time=tostring(_queue.time) + local _clock=tostring(self:_SecondsToClock(_queue.time)) + self:T3(ARTY.id..string.format("%s: time=%s, clock=%s", _queue.name, _time, _clock)) + end + +end + +--- Check all timed targets and return the target which should be attacked next. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now. +function ARTY:_CheckTimedTargets() + self:F3() + + -- Current time. + local Tnow=timer.getAbsTime() + + -- Sort Targets wrt time. + self:_SortQueueTime(self.targets) + + for i=1,#self.targets do + local _target=self.targets[i] + + -- Debug info. + self:T3(ARTY.id..string.format("Check TIMED target %d: %s", i, self:_TargetInfo(_target))) + + -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. + if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then + + -- Check if group currently has a target and whether its priorty is lower than the timed target. + if self.currentTarget then + if self.currentTarget.prio > _target.prio then + -- Current target under attack but has lower priority than this target. + self:T2(ARTY.id..string.format("Found TIMED HIGH PRIO target %s.", self:_TargetInfo(_target))) + return _target + end + else + -- No current target. + self:T2(ARTY.id..string.format("Found TIMED target %s.", self:_TargetInfo(_target))) + return _target + end + end + end + + return nil +end + +--- Check all moves and return the one which should be executed next. +-- @param #ARTY self +-- @return #table Move which is due. +function ARTY:_CheckMoves() + self:F3() + + -- Current time. + local Tnow=timer.getAbsTime() + + -- Sort Targets wrt time. + self:_SortQueueTime(self.moves) + + -- Check if we are currently firing. + local firing=false + if self.currentTarget then + firing=true + end + + for i=1,#self.moves do + local _move=self.moves[i] + + -- Check if time for move is reached. + if Tnow >= _move.time and (firing==false or _move.cancel) then + return _move + end + end + + return nil +end + +--- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now or nil if no target could be found. +function ARTY:_CheckNormalTargets() + self:F3() + + -- Sort targets w.r.t. prio and number times engaged already. + self:_SortTargetQueuePrio() + + -- Loop over all sorted targets. + for i=1,#self.targets do + local _target=self.targets[i] + + -- Debug info. + self:T3(ARTY.id..string.format("Check NORMAL target %d: %s", i, self:_TargetInfo(_target))) + + -- Check that target no time, is not under fire currently and in range. + if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then + + -- Debug info. + self:T2(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) + + return _target + end + end + + return nil +end --- Check whether shooting started within a certain time (~5 min). If not, the current target is considered invalid and removed from the target list. -- @param #ARTY self @@ -3084,8 +3233,6 @@ function ARTY:_GetMoveIndexByName(name) return nil end - - --- Check if a name is unique. If not, a new unique name can be created by adding a running index #01, #02, ... -- @param #ARTY self -- @param #table givennames Table with entries of already given names. Must contain a .name item. @@ -3178,7 +3325,7 @@ function ARTY:_TargetInRange(target) -- Debug output. if not _inrange then self:T(ARTY.id..text) - MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + MESSAGE:New(text, 5):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) end -- Remove target if ARTY group cannot move. No change to be ever in range. @@ -3355,106 +3502,7 @@ function ARTY:_ClockToSeconds(clock) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Route group to a certain point. --- @param #ARTY self --- @param Wrapper.Group#GROUP group Group to route. --- @param Core.Point#COORDINATE ToCoord Coordinate where we want to go. --- @param #number Speed Speed in km/h. --- @param #boolean OnRoad If true, use (mainly) roads. -function ARTY:_Move(group, ToCoord, Speed, OnRoad) - - -- Clear all tasks. - group:ClearTasks() - group:OptionAlarmStateGreen() - group:OptionROEHoldFire() - - -- Set formation. - local formation = "Off road" - - -- Default speed is 30 km/h. - Speed=Speed or 30 - - -- Current coordinates of group. - local cpini=group:GetCoordinate() - - -- Distance between current and final point. - local dist=cpini:Get2DDistance(ToCoord) - - -- Waypoint and task arrays. - local path={} - local task={} - - -- First waypoint is the current position of the group. - path[#path+1]=cpini:WaypointGround(Speed, formation) - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - - -- Route group on road if requested. - if OnRoad then - - -- Path on road (only first and last points) - local _first=cpini:GetClosestPointToRoad() - local _last=ToCoord:GetClosestPointToRoad() - - -- First point on road. - path[#path+1]=_first:WaypointGround(Speed, "On Road") - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - - -- Last point on road. - path[#path+1]=_last:WaypointGround(Speed, "On Road") - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - - end - - -- Last waypoint at ToCoord. - path[#path+1]=ToCoord:WaypointGround(Speed, formation) - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, true) - - - -- Init waypoints of the group. - local Waypoints={} - - -- New points are added to the default route. - for i=1,#path do - table.insert(Waypoints, i, path[i]) - end - - -- Set task for all waypoints. - for i=1,#Waypoints do - group:SetTaskWaypoint(Waypoints[i], task[i]) - end - - -- Submit task and route group along waypoints. - group:Route(Waypoints) - -end - ---- Function called when group is passing a waypoint. --- @param Wrapper.Group#GROUP group Group for which waypoint passing should be monitored. --- @param #ARTY arty ARTY object. --- @param #number i Waypoint number that has been reached. --- @param #boolean final True if it is the final waypoint. -function ARTY._PassingWaypoint(group, arty, i, final) - - -- Debug message. - local text=string.format("%s, passing waypoint %d.", group:GetName(), i) - if final then - text=string.format("%s, arrived at destination.", group:GetName()) - end - arty:T(ARTY.id..text) - - --[[ - if final then - MESSAGE:New(text, 10):ToCoalitionIf(group:GetCoalition(), arty.Debug or arty.report) - else - MESSAGE:New(text, 10):ToAllIf(arty.Debug) - end - ]] - - -- Arrived event. - if final and arty.Controllable:GetName()==group:GetName() then - arty:Arrived() - end - -end \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 5e7a15ef9..c438e751c 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -355,9 +355,9 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) local function SetTask( Controller, DCSTask ) if self and self:IsAlive() then local Controller = self:_GetController() - self:I( "Before SetTask" ) + --self:I( "Before SetTask" ) Controller:setTask( DCSTask ) - self:I( "After SetTask" ) + --self:I( "After SetTask" ) else BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } ) end From bf7523fa8530c09a35fd3a4bffaea4065beecdce Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 3 Jun 2018 01:00:16 +0200 Subject: [PATCH 153/170] messages clearsceen --- Moose Development/Moose/Core/Message.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index e11f807ea..f496796a1 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -317,7 +317,7 @@ function MESSAGE:ToAll() if self.MessageDuration ~= 0 then self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) + trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen ) end return self From 7b3f84f468db36e156ea5c7e334783a01ca1adee Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 3 Jun 2018 08:05:42 +0200 Subject: [PATCH 154/170] orbit with speed --- Moose Development/Moose/AI/AI_Cargo_Helicopter.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index a92dd1e95..e8b7d24ce 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -254,7 +254,7 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() ) - if Distance > 500 then + if Distance > 2000 then self:__Queue( -10, Coordinate ) else @@ -348,7 +348,7 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina Route[#Route+1] = WaypointTo local Tasks = {} - Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 80 ), 0, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) ) + Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 80 ), 150, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) ) Route[#Route].task = Helicopter:TaskCombo( Tasks ) Route[#Route+1] = WaypointTo @@ -641,7 +641,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin local Tasks = {} Tasks[#Tasks+1] = Helicopter:TaskFunction( "AI_CARGO_HELICOPTER._Deploy", self, Coordinate ) - Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), 0, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) ) + Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), 150, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) ) --Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) Route[#Route].task = Helicopter:TaskCombo( Tasks ) From bd7c822def1053379ae81c3af3ae8224513fae44 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 3 Jun 2018 09:14:27 +0200 Subject: [PATCH 155/170] Documentation --- .../Moose/AI/AI_A2A_Dispatcher.lua | 19 +++++++++++ Moose Development/Moose/AI/AI_Balancer.lua | 9 +++++- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 14 +++++++- .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 2 +- Moose Development/Moose/AI/AI_Formation.lua | 32 ++++--------------- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 1dd660b49..7a017f854 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1,5 +1,24 @@ --- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI. -- +-- +-- Features: +-- +-- * Setup quickly an A2A defense system for a coalition. +-- * Setup (CAP) Control Air Patrols at defined zones to enhance your A2A defenses. +-- * Setup (GCI) Ground Control Intercept at defined airbases to enhance your A2A defenses. +-- * Define and use an EWR (Early Warning Radar) network. +-- * Define squadrons at airbases. +-- * Enable airbases for A2A defenses. +-- * Add different plane types to different squadrons. +-- * Add multiple squadrons to different airbases. +-- * Define different ranges to engage upon intruders. +-- * Establish an automatic in air refuel process for CAP using refuel tankers. +-- * Setup default settings for all squadrons and A2A defenses. +-- * Setup specific settings for specific squadrons. +-- * Quickly setup an A2A defense system using @{#AI_A2A_GCICAP}. +-- * Setup a more advanced defense system using @{#AI_A2A_DISPATCHER}. +-- +-- -- # QUICK START GUIDE -- -- There are basically two classes available to model an A2A defense system. diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 845826703..607a22ecc 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -1,4 +1,11 @@ ---- **AI** -- (2.1) - Balance player slots with AI to create an engaging simulation environment, independent of the amount of players. +--- **AI** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players. +-- +-- ** Features:** +-- +-- * Automatically spawn AI as a replacement of free player slots for a coalition. +-- * Make the AI to perform tasks. +-- * Define a maximum amount of AI to be active at the same time. +-- * Configure the behaviour of AI when a human joins a slot for which an AI is active. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index cb400cecc..cf4fda279 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -1,5 +1,17 @@ ---- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using APCs. +--- **AI** -- Models the intelligent transportation of infantry and other cargo using APCs. -- +-- **Features:** +-- +-- * Quickly transport cargo to various deploy zones using ground vehicles (APCs, trucks ...). +-- * Various @{Cargo.Cargo#CARGO} types can be transported. These are infantry groups and crates. +-- * Define a list of deploy zones of various types to transport the cargo to. +-- * The vehicles follow the roads to ensure the fastest possible cargo transportation over the ground. +-- * Multiple vehicles can transport multiple cargo as one vehicle group. +-- * Multiple vehicle groups can be enabled as one collaborating transportation process. +-- * Infantry loaded as cargo, will unboard in case enemies are nearby and will help defending the vehicles. +-- * Different ranges can be setup for enemy defenses. +-- * Different options can be setup to tweak the cargo transporation behaviour. +-- -- === -- -- ### Author: **FlightControl** diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index 8a53f1069..eabc91dc4 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -1,4 +1,4 @@ ---- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters. +--- **AI** -- Models the intelligent transportation of infantry and other cargo using Helicopters. -- -- The @{#AI_CARGO_DISPATCHER_HELICOPTER} classes implements the dynamic dispatching of cargo transportation tasks for helicopters. -- diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index e262a67e4..af5805bb4 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -1,31 +1,11 @@ ---- **AI** -- (R2.2) - Build large airborne formations of aircraft. +--- **AI** -- Build large airborne formations of aircraft. -- --- === +-- **Features:** +-- +-- * Build in-air formations consisting of more than 40 aircraft as one group. +-- * Build different formation types. +-- * Assign a group leader that will guide the large formation path. -- --- AI_FORMATION makes AI @{Wrapper.Group}s fly in formation of various compositions. --- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! --- The purpose of the class is to: --- --- * Make formation building a process that can be managed while in flight, rather than a task. --- * Human players can guide formations, consisting of larget planes. --- * Build large formations (like a large bomber field). --- * Form formations that DCS does not support off the shelve. --- --- A few remarks: --- --- * Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild. --- * Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader. --- * Formations may take a while to build up. --- --- As a result, the AI_FORMATION is not perfect, but is very useful to: --- --- * Model large formations when flying straight line. --- * Make humans guide a large formation, when the planes are wide from each other. --- --- There are the following types of classes defined: --- --- * @{#AI_FORMATION}: Create a formation from several @{GROUP}s. --- -- === -- -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20Formation) From 6a71921270e316951bd322f28c6f5cce6cd99518 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 3 Jun 2018 18:07:00 +0200 Subject: [PATCH 156/170] Documentation AI --- Moose Development/Moose/AI/AI_BAI.lua | 11 ++++++++++- Moose Development/Moose/AI/AI_CAP.lua | 12 ++++++++++-- Moose Development/Moose/AI/AI_CAS.lua | 11 ++++++++++- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 6 +++--- Moose Development/Moose/AI/AI_Patrol.lua | 8 +++++++- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index 0265e7113..42bccbf06 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -1,4 +1,13 @@ ---- **AI** -- (R2.1) - Manages the independent process of Battlefield Air Interdiction (bombing) for airplanes. +--- **AI** -- Peform Battlefield Area Interdiction (BAI) within an engagement zone. +-- +-- **Features:** +-- +-- * Hold and standby within a patrol zone. +-- * Engage upon command the assigned targets within an engagement zone. +-- * Loop the zone until all targets are eliminated. +-- * Trigger different events upon the results achieved. +-- * After combat, return to the patrol zone and hold. +-- * RTB when commanded or after out of fuel. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index e98f4f135..1ffdbc23b 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -1,4 +1,12 @@ ---- **AI** -- (R2.1) - Manages the independent process of Combat Air Patrol (CAP) for airplanes. +--- **AI** -- Perform Combat Air Patrolling (CAP) for airplanes. +-- +-- **Features:** +-- +-- * Patrol AI airplanes within a given zone. +-- * Trigger detected events when enemy airplanes are detected. +-- * Manage a fuel treshold to RTB on time. +-- * Engage the enemy when detected. +-- -- -- === -- @@ -31,7 +39,7 @@ -- @extends AI.AI_Patrol#AI_PATROL_ZONE --- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} +--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 7ddb55876..33e07849d 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -1,4 +1,13 @@ ---- **AI** -- (R2.1) - Manages the independent process of Close Air Support for airplanes. +--- **AI** -- Perform Close Air Support (CAS) near friendlies. +-- +-- **Features:** +-- +-- * Hold and standby within a patrol zone. +-- * Engage upon command the enemies within an engagement zone. +-- * Loop the zone until all enemies are eliminated. +-- * Trigger different events upon the results achieved. +-- * After combat, return to the patrol zone and hold. +-- * RTB when commanded or after fuel. -- -- === -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index cf4fda279..561125786 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -91,7 +91,7 @@ AI_CARGO_DISPATCHER_APC = { -- @param Core.Set#SET_GROUP SetAPC The collection of APC @{Wrapper.Group}s. -- @param Core.Set#SET_CARGO SetCargo The collection of @{Cargo} derived objects. -- @param Core.Set#SET_ZONE SetDeployZone The collection of deploy @{Zone}s, which are used to where the cargo will be deployed by the APCs. --- @param #number CombatRadius The cargo will be unloaded from the APC and engage the enemy if the enemy is within CombatRadius range. The radius is in meters, the default value is 500 meters. +-- @param DCS#Distance CombatRadius The cargo will be unloaded from the APC and engage the enemy if the enemy is within CombatRadius range. The radius is in meters, the default value is 500 meters. -- @return #AI_CARGO_DISPATCHER_APC -- @usage -- @@ -101,9 +101,9 @@ AI_CARGO_DISPATCHER_APC = { -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() -- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, 500 ) -- -function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones, CombatRadius ) +function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, CombatRadius ) - local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_APC + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC self.CombatRadius = CombatRadius or 500 diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index c89ab36e0..1f70d0015 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -1,4 +1,10 @@ ---- **AI** -- (R2.1) - Manages the independent process of Air Patrol for airplanes. +--- **AI** -- Perform Air Patrolling for airplanes. +-- +-- **Features:** +-- +-- * Patrol AI airplanes within a given zone. +-- * Trigger detected events when enemy airplanes are detected. +-- * Manage a fuel treshold to RTB on time. -- -- === -- From 83fab80d881d64a3ea104ff587b4486600892d66 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 3 Jun 2018 21:50:07 +0200 Subject: [PATCH 157/170] Updated documentation. --- Moose Development/Moose/Tasking/CommandCenter.lua | 11 +++++++++-- Moose Development/Moose/Tasking/Mission.lua | 10 +++++++++- .../Moose/Tasking/Task_A2A_Dispatcher.lua | 14 ++++++++++++-- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 13 ++++++++++++- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 131e8e4b9..e8f9204e4 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -1,5 +1,12 @@ ---- **Tasking** -- A COMMANDCENTER is the owner of multiple missions within MOOSE. --- A COMMANDCENTER governs multiple missions, the tasking and the reporting. +--- **Tasking** -- A command center governs multiple missions, and takes care of the reporting and communications. +-- +-- **Features:** +-- +-- * Govern multiple missions. +-- * Communicate to coalitions, groups. +-- * Assign tasks. +-- * Manage the menus. +-- * Manage reference zones. -- -- === -- diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index ced7f3d1a..c2f9f2de1 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -1,4 +1,12 @@ ---- **Tasking** -- A MISSION is the main owner of a Mission orchestration within MOOSE. +--- **Tasking** -- A mission models a goal to be achieved through the execution and completion of tasks by human players. +-- +-- **Features:** +-- +-- * A mission has a goal to be achieved, through the execution and completion of tasks of different categories by human players. +-- * A mission manages these tasks. +-- * A mission has a state, that indicates the fase of the mission. +-- * A mission has a menu structure, that facilitates mission reports and tasking menus. +-- * A mission can assign a task to a player. -- -- === -- diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index ddbb7b148..8f85ef7d2 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -1,7 +1,17 @@ ---- **Tasking** - The TASK_A2A_DISPATCHER creates and manages player TASK_A2A tasks based on detected targets. +--- **Tasking** - Dynamically allocates A2A tasks to human players, based on detected airborne targets through an EWR network. -- --- Implement the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of EWR installation groups. +-- **Features:** -- +-- * Dynamically assign tasks to human players based on detected targets. +-- * Dynamically change the tasks as the tactical situation evolves during the mission. +-- * Dynamically assign (CAP) Control Air Patrols tasks for human players to perform CAP. +-- * Dynamically assign (GCI) Ground Control Intercept tasks for human players to perform GCI. +-- * Dynamically assign Engage tasks for human players to engage on close-by airborne bogeys. +-- * Define and use an EWR (Early Warning Radar) network. +-- * Define different ranges to engage upon intruders. +-- * Keep task achievements. +-- * Score task achievements. +-- -- === -- -- ### Author: **FlightControl** diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index d9dae1ab4..13cd2c5e7 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -1,5 +1,16 @@ ---- **Tasking** - The TASK\_A2G\_DISPATCHER dispatches A2G Tasks to Players based on enemy location detection. +--- **Tasking** -- Dynamically allocates A2G tasks to human players, based on detected ground targets through reconnaissance. -- +-- **Features:** +-- +-- * Dynamically assign tasks to human players based on detected targets. +-- * Dynamically change the tasks as the tactical situation evolves during the mission. +-- * Dynamically assign (CAS) Close Air Support tasks for human players. +-- * Dynamically assign (BAI) Battlefield Air Interdiction tasks for human players. +-- * Dynamically assign (SEAD) Supression of Enemy Air Defense tasks for human players to eliminate G2A missile threats. +-- * Define and use an EWR (Early Warning Radar) network. +-- * Define different ranges to engage upon intruders. +-- * Keep task achievements. +-- * Score task achievements.-- -- === -- -- ### Author: **FlightControl** From 2d43af7c0d98b8389c9e3e5cb38f051c1a4f4429 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 3 Jun 2018 22:02:26 +0200 Subject: [PATCH 158/170] docu --- Moose Development/Moose/AI/AI_Balancer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 607a22ecc..1b18bf79d 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -1,6 +1,6 @@ --- **AI** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players. -- --- ** Features:** +-- **Features:** -- -- * Automatically spawn AI as a replacement of free player slots for a coalition. -- * Make the AI to perform tasks. From 0a34cfdafae50c17cb77807e36499339e961f566 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 3 Jun 2018 23:38:15 +0200 Subject: [PATCH 159/170] ARTY v0.9.91 - Added automatic relocation if not in firing range. - Added first version of ARTY DB with artillery unit parameters min/max firing range. --- Moose Development/Moose/Core/Message.lua | 11 +- .../Moose/Functional/Artillery.lua | 269 ++++++++++++++++-- .../Moose/Functional/Suppression.lua | 2 +- 3 files changed, 264 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 4ca1d4bc3..b50f52ddb 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -66,7 +66,7 @@ MESSAGE.Type = { -- @param #string MessageText is the text of the Message. -- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. -- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ". --- @param #boolean ClearScreen (optional) Clear all previous messages. +-- @param #boolean ClearScreen (optional) Clear all previous messages if true. -- @return #MESSAGE -- @usage -- -- Create a series of new Messages. @@ -147,6 +147,15 @@ end +--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc. +-- @param #MESSAGE self +-- @return #MESSAGE +function MESSAGE:Clear() + self:F() + self.ClearScreen=true + return self +end + --- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player". diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index ba42d1c14..70a513e2e 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -88,6 +88,9 @@ -- @field #boolean markallow If true, Players are allowed to assign targets and moves for ARTY group by placing markers on the F10 map. Default is false. -- @field #number markkey Authorization key. Only player who know this key can assign targets and moves via markers on the F10 map. Default no authorization required. -- @field #boolean markreadonly Marks for targets are readonly and cannot be removed by players. Default is false. +-- @field #boolean autorelocate ARTY group will automatically move to within the max/min firing range. +-- @field #number autorelocatemaxdist Max distance [m] the ARTY group will travel to get within firing range. Default 50000 m = 50 km. +-- @field #boolean autorelocateonroad ARTY group will use mainly road to automatically get within firing range. Default is false. -- @extends Core.Fsm#FSM_CONTROLLABLE --- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can @@ -218,6 +221,7 @@ -- * @{#ARTY.WeaponType}.UnguidedAny: Any unguided weapon (cannons or rockes) will be used. -- * @{#ARTY.WeaponType}.GuidedMissile: Any guided missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. -- * @{#ARTY.WeaponType}.CruiseMissile: Only cruise missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. +-- * @{#ARTY.WeaponType}.TacticalNukes: Use tactical nuclear shells. This works only with units that have shells and is described below. -- -- ## Assigning Moves -- The ARTY group can be commanded to move. This is done by the @{#ARTY.AssignMoveCoord}(*coord*,*time*,*speed*,*onroad*,*cancel*,*name*) function. @@ -258,13 +262,15 @@ -- -- ## Tactical Nukes -- --- ARTY groups that can fire shells can also be used to fire tactical nukes. This is simply achieved by setting the weapon type to **ARTY.WeaponType.TacticalNukes** in the +-- ARTY groups that can fire shells can also be used to fire tactical nukes. This is achieved by setting the weapon type to **ARTY.WeaponType.TacticalNukes** in the -- @{#ARTY.AssignTargetCoord}() function. +-- +-- By default, they group does not have any nukes available. To give the group the ability the function @{#ARTY.SetTacNukeShells}(*n*) can be used. +-- This supplies the group with *n* nuclear shells, where *n* is restricted to the number of conventional shells the group can carry. +-- Note that the group must always have convenctional shells left in order to fire a nuclear shell. -- -- The default explostion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT. --- --- By default, all available conventional shells can be used as nuclear shells. However, it is possible to restrict the number with the @{#ARTY.SetTacNukeShells}(*n*) function --- to only have *n* nuclear shells available. Note that the group must always have convenctional shells left in order to fire a nuclear shell. +-- -- -- ## Assignments via Markers on F10 Map -- @@ -438,6 +444,9 @@ ARTY={ markallow=false, markkey=nil, markreadonly=false, + autorelocate=false, + autorelocatemaxdist=50000, + autorelocateonroad=false, } --- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag @@ -453,13 +462,54 @@ ARTY.WeaponType={ TacticalNukes=666, } +--- Database of common artillery unit properties. +-- @list db +ARTY.db={ + ["2B11 mortar"] = { + minrange = 500, + maxrange = 7000, + }, + ["SAU 2-C9"] = { + minrange = 500, + maxrange = 7000, + }, + ["SPH M109 Paladin"] = { + minrange = 300, + maxrange = 22000, + }, + ["SAU Gvozdika"] = { + minrange = 300, + maxrange = 15000, + }, + ["SAU Akatsia"] = { + minrange = 300, + maxrange = 17000, + }, + ["SAU Msta"] = { + minrange = 300, + maxrange = 23500, + }, + ["MLRS M270"] = { + minrange = 10000, + maxrange = 32000, + }, + ["Grad-URAL"] = { + minrange = 5000, + maxrange = 19000, + }, + ["Smerch"] = { + minrange = 20000, + maxrange = 70000, + } +} + --- Some ID to identify who we are in output of the DCS.log file. -- @field #string id ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.9" +ARTY.version="0.9.91" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -826,6 +876,21 @@ function ARTY:SetRearmingPlace(coord) self.RearmingPlaceCoord=coord end +--- Set automatic relocation of ARTY group if a target is assigned which is out of range. The unit will drive automatically towards or away from the target to be in max/min firing range. +-- @param #ARTY self +-- @param #number maxdistance (Optional) The maximum distance in km the group will travel to get within firing range. Default is 50 km. No automatic relocation is performed if targets are assigned which are further away. +-- @param #boolean onroad (Optional) If true, ARTY group uses roads whenever possible. Default false, i.e. group will move in a straight line to the assigned coordinate. +function ARTY:SetAutomaticRelocate(maxdistance, onroad) + self:F({distance=maxdistance, onroad=onroad}) + self.autorelocate=true + self.autorelocatemaxdist=maxdistance or 50 + self.autorelocatemaxdist=self.autorelocatemaxdist*1000 + if onroad==nil then + onroad=false + end + self.autorelocateonroad=onroad +end + --- Report messages of ARTY group turned on. This is the default. -- @param #ARTY self function ARTY:SetReportON() @@ -1045,6 +1110,18 @@ function ARTY:onafterStart(Controllable, From, Event, To) self.Nukes0=0 end + -- Check if we have and arty type that is in the DB. + local _dbproperties=self:_CheckDB(self.DisplayName) + self:T({dbproperties=_dbproperties}) + if _dbproperties~=nil then + for property,value in pairs(_dbproperties) do + self:T({property=property, value=value}) + --if self[property]==nil then + self[property]=value + --end + end + end + local text=string.format("\n******************************************************\n") text=text..string.format("Arty group = %s\n", Controllable:GetName()) text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery)) @@ -1079,6 +1156,9 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Relocate after fire = %s\n", tostring(self.relocateafterfire)) text=text..string.format("Relocate min dist. = %d m\n", self.relocateRmin) text=text..string.format("Relocate max dist. = %d m\n", self.relocateRmax) + text=text..string.format("Auto move in range = %s\n", tostring(self.autorelocate)) + text=text..string.format("Auto move dist. max = %.1f km\n", self.autorelocatemaxdist/1000) + text=text..string.format("Auto move on road = %s\n", tostring(self.autorelocateonroad)) text=text..string.format("Marker assignments = %s\n", tostring(self.markallow)) text=text..string.format("Marker auth. key = %s\n", tostring(self.markkey)) text=text..string.format("Marker readonly = %s\n", tostring(self.markreadonly)) @@ -1129,6 +1209,20 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:__Status(self.StatusInterval) end +--- Check the DB for properties of the specified artillery unit type. +-- @param #ARTY self +-- @return #table Properties of the requested artillery type. Returns nil if no matching DB entry could be found. +function ARTY:_CheckDB(displayname) + for _type,_properties in pairs(ARTY.db) do + self:T({type=_type, properties=_properties}) + if _type==displayname then + self:T({type=_type, properties=_properties}) + return _properties + end + end + return nil +end + --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self function ARTY:_StatusReport() @@ -1209,7 +1303,7 @@ function ARTY:_OnEventShot(EventData) -- Debug output. local text=string.format("%s, fired shot %d of %d with weapon %s on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name) self:T(ARTY.id..text) - MESSAGE:New(text, 5):ToAllIf(self.report or self.Debug) + MESSAGE:New(text, 5):Clear():ToAllIf(self.report or self.Debug) -- Last known position of the weapon fired. local _lastpos={x=0, y=0, z=0} @@ -1484,7 +1578,7 @@ function ARTY:_OnEventMarkChange(Event) end end end - + -- We were not addressed. if not _assigned then return @@ -1696,9 +1790,12 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Check that firing started after ~5 min. If not, target is removed. self:_CheckShootingStarted() end + + + -- Check if targets are in range and update target.inrange value. + self:_CheckTargetsInRange() - - -- Get a valid timed target if it is due to be attacked. + -- Get a valid timed target if it is due to be attacked. local _timedTarget=self:_CheckTimedTargets() -- Get a valid normal target (one that is not timed). @@ -2239,6 +2336,9 @@ end function ARTY:onafterNewTarget(Controllable, From, Event, To, target) self:_EventFromTo("onafterNewTarget", Event, From, To) + -- Check if target is in range. + --local _inrange, _toofar, _tooclose=self:_TargetInRange(target, self.report or self.Debug) + -- Debug message. local text=string.format("Adding new target %s.", target.name) MESSAGE:New(text, 5):ToAllIf(self.Debug) @@ -2831,6 +2931,7 @@ function ARTY:_Markertext(text) assignment.engage=false assignment.request=false assignment.readonly=false + assignment.canceltarget=false assignment.cancelcurrent=false --assignment.time=nil --assignment.nshells=nil @@ -2881,10 +2982,10 @@ function ARTY:_Markertext(text) end self:T2(ARTY.id..string.format("Key Time=%s.", val)) - elseif key:lower():find("shots") then + elseif key:lower():find("shot") then assignment.nshells=tonumber(s[2]) - self:T(ARTY.id..string.format("Key Shots=%s.", val)) + self:T(ARTY.id..string.format("Key Shot=%s.", val)) elseif key:lower():find("prio") then @@ -2927,12 +3028,20 @@ function ARTY:_Markertext(text) self:T2(ARTY.id..string.format("Key Onroad=true.")) elseif key:lower():find("irrevocable") or key:lower():find("readonly") then + assignment.readonly=true self:T2(ARTY.id..string.format("Key Readonly=true.")) + + elseif key:lower():find("canceltarget") then + + assignment.canceltarget=true + self:T2(ARTY.id..string.format("Key Cancel Target (before move)=true.")) - elseif key:lower():find("cancel current") then + elseif key:lower():find("cancelcurrent") then + assignment.cancelcurrent=true self:T2(ARTY.id..string.format("Key Cancel Current=true.")) + elseif assignment.request and key:lower():find("ammo") then assignment.requestammo=true end @@ -3059,6 +3168,122 @@ function ARTY:_SortQueueTime(queue) end +--- Heading from point a to point b in degrees. +--@param #ARTY self +--@param Core.Point#COORDINATE a Coordinate. +--@param Core.Point#COORDINATE b Coordinate. +--@return #number angle Angle from a to b in degrees. +function ARTY:_GetHeading(a, b) + local dx = b.x-a.x + local dy = b.z-a.z + local angle = math.deg(math.atan2(dy,dx)) + if angle < 0 then + angle = 360 + angle + end + return angle +end + +--- Check all targets whether they are in range. +-- @param #ARTY self +function ARTY:_CheckTargetsInRange() + + for i=1,#self.targets do + local _target=self.targets[i] + + self:T(ARTY.id..string.format("Before: Target %s - in range = %s", _target.name, tostring(_target.inrange))) + + -- Check if target is in range. + local _inrange,_toofar,_tooclose=self:_TargetInRange(_target) + self:T(ARTY.id..string.format("Inbetw: Target %s - in range = %s, toofar = %s, tooclose = %s", _target.name, tostring(_target.inrange), tostring(_toofar), tostring(_tooclose))) + + -- Init default for assigning moves into range. + local _movetowards=false + local _moveaway=false + + if _target.inrange==nil then + + -- First time the check is performed. We call the function again and send a message. + _target.inrange,_toofar,_tooclose=self:_TargetInRange(_target, self.report or self.Debug) + + -- Send group towards/away from target. + if _toofar then + _movetowards=true + elseif _tooclose then + _moveaway=true + end + + elseif _target.inrange==true then + + -- Target was in range at previous check... + + if _toofar then --...but is now too far away. + _movetowards=true + elseif _tooclose then --...but is now too close. + _moveaway=true + end + + elseif _target.inrange==false then + + -- Target was out of range at previous check. + + if _inrange then + -- Inform coalition that target is now in range. + local text=string.format("%s, target %s is now in range.", self.Controllable:GetName(), _target.name) + self:T(ARTY.id..text) + MESSAGE:New(text,10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + end + + end + + -- Assign a relocation command so that the unit will be in range of the requested target. + if self.autorelocate and (_movetowards or _moveaway) then + + -- Get current position. + local _from=self.Controllable:GetCoordinate() + local _dist=_from:Get2DDistance(_target.coord) + + if _dist<=self.autorelocatemaxdist then + + local _tocoord --Core.Point#COORDINATE + local _name="" + local _safetymargin=500 + + if _movetowards then + + -- Target was in range on previous check but now we are too far away. + local _waytogo=_dist-self.maxrange+_safetymargin + local _heading=self:_GetHeading(_from,_target.coord) + _tocoord=_from:Translate(_waytogo, _heading) + _name=string.format("Relocation to within max firing range of target %s", _target.name) + + elseif _moveaway then + + -- Target was in range on previous check but now we are too far away. + local _waytogo=_dist-self.minrange+_safetymargin + local _heading=self:_GetHeading(_target.coord,_from) + _tocoord=_from:Translate(_waytogo, _heading) + _name=string.format("Relocation to within min firing range of target %s", _target.name) + + end + + -- Send info message. + MESSAGE:New(_name.." assigned.", 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + + -- Assign relocation move. + self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true) + + end + + end + + -- Update value. + _target.inrange=_inrange + + self:T(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange))) + + end +end + --- Check all timed targets and return the target which should be attacked next. -- @param #ARTY self -- @return #table Target which is due to be attacked now. @@ -3303,37 +3528,49 @@ end --- Check if target is in range. -- @param #ARTY self -- @param #table target Target table. +-- @param #boolean message (Optional) If true, send a message to the coalition if the target is not in range. Default is no message is send. -- @return #boolean True if target is in range, false otherwise. -function ARTY:_TargetInRange(target) +-- @return #boolean True if ARTY group is too far away from the target, i.e. distance > max firing range. +-- @return #boolean True if ARTY group is too close to the target, i.e. distance < min finring range. +function ARTY:_TargetInRange(target, message) self:F3(target) + + -- Default is no message. + if message==nil then + message=false + end -- Distance between ARTY group and target. local _dist=self.Controllable:GetCoordinate():Get2DDistance(target.coord) -- Assume we are in range. local _inrange=true + local _tooclose=false + local _toofar=false local text="" if _dist < self.minrange then _inrange=false + _tooclose=true text=string.format("%s, target is out of range. Distance of %.1f km is below min range of %.1f km.", self.Controllable:GetName(), _dist/1000, self.minrange/1000) elseif _dist > self.maxrange then _inrange=false + _toofar=true text=string.format("%s, target is out of range. Distance of %.1f km is greater than max range of %.1f km.", self.Controllable:GetName(), _dist/1000, self.maxrange/1000) end -- Debug output. if not _inrange then self:T(ARTY.id..text) - MESSAGE:New(text, 5):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + MESSAGE:New(text, 5):ToCoalitionIf(self.Controllable:GetCoalition(), (self.report and message) or (self.Debug and message)) end - -- Remove target if ARTY group cannot move. No change to be ever in range. + -- Remove target if ARTY group cannot move, e.g. Mortas. No chance to be ever in range. if self.SpeedMax<1 and _inrange==false then self:RemoveTarget(target.name) end - return _inrange + return _inrange,_toofar,_tooclose end --- Get the weapon type name, which should be used to attack the target. diff --git a/Moose Development/Moose/Functional/Suppression.lua b/Moose Development/Moose/Functional/Suppression.lua index c0d2278ef..805008e45 100644 --- a/Moose Development/Moose/Functional/Suppression.lua +++ b/Moose Development/Moose/Functional/Suppression.lua @@ -1725,7 +1725,7 @@ end --@param Core.Point#COORDINATE a Coordinate. --@param Core.Point#COORDINATE b Coordinate. --@return #number angle Angle from a to b in degrees. -function SUPPRESSION:_Heading(a, b, distance) +function SUPPRESSION:_Heading(a, b) local dx = b.x-a.x local dy = b.z-a.z local angle = math.deg(math.atan2(dy,dx)) From 8b667071b7a76e34ac11f2c5bfe7f18625af543a Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 5 Jun 2018 00:28:52 +0200 Subject: [PATCH 160/170] ARTY v0.9.92 - adjusted DB - other minor fixes and improvements --- .../Moose/Functional/Artillery.lua | 138 ++++++++++++------ .../Moose/Wrapper/Controllable.lua | 6 +- 2 files changed, 98 insertions(+), 46 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 70a513e2e..5bec76c49 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -59,7 +59,7 @@ -- @field #string Type Type of the ARTY group. -- @field #string DisplayName Extended type name of the ARTY group. -- @field #number IniGroupStrength Inital number of units in the ARTY group. --- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". +-- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". This is automatically derived from the DCS descriptor table. -- @field #number SpeedMax Maximum speed of ARTY group in km/h. This is determined from the DCS descriptor table. -- @field #number Speed Default speed in km/h the ARTY group moves at. Maximum speed possible is 80% of maximum speed the group can do. -- @field #number RearmingDistance Safe distance in meters between ARTY group and rearming group or place at which rearming is possible. Default 100 m. @@ -286,11 +286,12 @@ -- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible. -- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50. -- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5. --- * *engage* Number of times the target is engaged. Default is 1. +-- * *maxengage* Number of times the target is engaged. Default is 1. -- * *radius* Scattering radius of the fired shots in meters. Default is 100 m. -- * *weapon* Type of weapon to be used. Valid parameters are *cannon*, *rocket*, *missile*, *nuke*. Default is automatic selection. -- * *battery* Name of the ARTY group that the target is assigned to. Note that the name is case sensitive and has to be given in quotation marks. Default is all ARTY groups of the right coalition. -- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. +-- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are examples of valid marker texts: -- arty engage! @@ -307,9 +308,11 @@ -- -- * *time* Time for which which the relocation/move is schedules, e.g. 08:42. Default is as soon as possible. -- * *speed* The speed in km/h the group will drive at. Default is 70% of its max possible speed. --- * *onroad* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate. --- * *cancel* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over. +-- * *on road* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate. +-- * *canceltarget* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over. -- * *battery* Name of the ARTY group that the relocation is assigned to. +-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. +-- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are some examples: -- arty move! time 23:45, speed 50, onroad, cancel @@ -431,7 +434,7 @@ ARTY={ ammorockets={}, ammomissiles={}, Nshots=0, - minrange=100, + minrange=300, maxrange=1000000, nukewarhead=75000, Nukes=nil, @@ -465,42 +468,61 @@ ARTY.WeaponType={ --- Database of common artillery unit properties. -- @list db ARTY.db={ - ["2B11 mortar"] = { - minrange = 500, - maxrange = 7000, + ["2B11 mortar"] = { -- type "2B11 mortar" + minrange = 500, -- correct? + maxrange = 7000, -- 7 km + reloadtime = 30, -- 30 sec }, - ["SAU 2-C9"] = { - minrange = 500, - maxrange = 7000, + ["SPH 2S1 Gvozdika"] = { -- type "SAU Gvozdika" + minrange = 300, -- correct? + maxrange = 15000, -- 15 km + reloadtime = nil, -- unknown }, - ["SPH M109 Paladin"] = { - minrange = 300, - maxrange = 22000, + ["SPH 2S19 Msta"] = { --type "SAU Msta", alias "2S19 Msta" + minrange = 300, -- correct? + maxrange = 23500, -- 23.5 km + reloadtime = nil, -- unknown }, - ["SAU Gvozdika"] = { - minrange = 300, - maxrange = 15000, + ["SPH 2S3 Akatsia"] = { -- type "SAU Akatsia", alias "2S3 Akatsia" + minrange = 300, -- correct? + maxrange = 17000, -- 17 km + reloadtime = nil, -- unknown }, - ["SAU Akatsia"] = { - minrange = 300, - maxrange = 17000, + ["SPH 2S9 Nona"] = { --type "SAU 2-C9" + minrange = 500, -- correct? + maxrange = 7000, -- 7 km + reloadtime = nil, -- unknown }, - ["SAU Msta"] = { - minrange = 300, - maxrange = 23500, + ["SPH M109 Paladin"] = { -- type "M-109", alias "M109" + minrange = 300, -- correct? + maxrange = 22000, -- 22 km + reloadtime = nil, -- unknown }, - ["MLRS M270"] = { - minrange = 10000, - maxrange = 32000, + ["SpGH Dana"] = { -- type "SpGH_Dana" + minrange = 300, -- correct? + maxrange = 18700, -- 18.7 km + reloadtime = nil, -- unknown }, - ["Grad-URAL"] = { - minrange = 5000, - maxrange = 19000, + ["MLRS BM-21 Grad"] = { --type "Grad-URAL", alias "MLRS BM-21 Grad" + minrange = 5000, -- 5 km + maxrange = 19000, -- 19 km + reloadtime = 420, -- 7 min + }, + ["MLRS 9K57 Uragan BM-27"] = { -- type "Uragan_BM-27" + minrange = 11500, -- 11.5 km + maxrange = 35800, -- 35.8 km + reloadtime = 840, -- 14 min + }, + ["MLRS 9A52 Smerch"] = { -- type "Smerch" + minrange = 20000, -- 20 km + maxrange = 70000, -- 70 km + reloadtime = 2160, -- 36 min + }, + ["MLRS M270"] = { --type "MRLS", alias "M270 MRLS" + minrange = 10000, -- 10 km + maxrange = 32000, -- 32 km + reloadtime = 540, -- 9 min }, - ["Smerch"] = { - minrange = 20000, - maxrange = 70000, - } } --- Some ID to identify who we are in output of the DCS.log file. @@ -509,7 +531,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.91" +ARTY.version="0.9.92" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -759,8 +781,9 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) -- Get max speed of group. local speedmax=self.Controllable:GetSpeedMax() - -- Default speed is 70% of max speed. + -- Set speed. if speed then + -- Make sure, given speed is less than max phycially possible speed of group. speed=math.min(speed, speedmax) elseif self.Speed then speed=self.Speed @@ -1640,7 +1663,7 @@ function ARTY:_OnEventMarkChange(Event) MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) -- Assign a relocation of the arty group. - local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.cancel,_name, true) + local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.canceltarget,_name, true) if _movename~=nil then local _mid=self:_GetMoveIndexByName(_movename) @@ -2566,7 +2589,7 @@ end -- @param #ARTY self -- @param Wrapper.Group#GROUP group Group to route. -- @param Core.Point#COORDINATE ToCoord Coordinate where we want to go. --- @param #number Speed Speed in km/h. +-- @param #number Speed (Optional) Speed in km/h. Default is 70% of max speed the group can do. -- @param #boolean OnRoad If true, use (mainly) roads. function ARTY:_Move(group, ToCoord, Speed, OnRoad) @@ -2578,8 +2601,14 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Set formation. local formation = "Off Road" - -- Default speed is 30 km/h. - Speed=Speed or 30 + -- Get max speed of group. + local SpeedMax=group:GetSpeedMax() + + -- Set speed. + Speed=Speed or SpeedMax*0.7 + + -- Make sure, we do not go above max speed possible. + Speed=math.min(Speed, SpeedMax) -- Current coordinates of group. local cpini=group:GetCoordinate() @@ -2757,11 +2786,30 @@ function ARTY:GetAmmo(display) -- Get the weapon category: shell=0, missile=1, rocket=2, bomb=3 local Category=ammotable[w].desc.category + -- Get missile category: Weapon.MissileCategory AAM=1, SAM=2, BM=3, ANTI_SHIP=4, CRUISE=5, OTHER=6 local MissileCategory=nil if Category==Weapon.Category.MISSILE then MissileCategory=ammotable[w].desc.missileCategory end + local function missilecat(n) + local cat="unknown" + if n==1 then + cat="air-to-air" + elseif n==2 then + cat="surface-to-air" + elseif n==3 then + cat="ballistic" + elseif n==4 then + cat="anti-ship" + elseif n==5 then + cat="cruise" + elseif n==6 then + cat="other" + end + return cat + end + -- Check for correct shell type. local _gotshell=false if #self.ammoshells>0 then @@ -2812,7 +2860,7 @@ function ARTY:GetAmmo(display) nshells=nshells+Nammo -- Debug info. - text=text..string.format("- %d shells of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d shells of type %s\n", Nammo, Tammo) elseif _gotrocket then @@ -2820,15 +2868,17 @@ function ARTY:GetAmmo(display) nrockets=nrockets+Nammo -- Debug info. - text=text..string.format("- %d rockets of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d rockets of type %s\n", Nammo, Tammo) elseif _gotmissile then - -- Add up all rockets. - nmissiles=nmissiles+Nammo + -- Add up all cruise missiles (category 5) + if MissileCategory==5 then + nmissiles=nmissiles+Nammo + end -- Debug info. - text=text..string.format("- %d missiles of type %s (category=%d, missile category=%s)\n", Nammo, Tammo, Category, tostring(MissileCategory)) + text=text..string.format("- %d %s missiles of type %s\n", Nammo, missilecat(MissileCategory), Tammo) else diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 8e52ecb58..d539dd098 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2651,8 +2651,10 @@ function CONTROLLABLE:OptionAlarmStateGreen() if self:IsGround() then Controller:setOption( AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ALARM_STATE, AI.Option.Naval.val.ALARM_STATE.GREEN ) + elseif self:IsShip() then + -- AI.Option.Naval.id.ALARM_STATE does not seem to exist! + --Controller:setOption( AI.Option.Naval.id.ALARM_STATE, AI.Option.Naval.val.ALARM_STATE.GREEN ) + Controller:setOption( AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN ) end return self From a2790f500c9c6f32a5909491d59aec202e8793b5 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 6 Jun 2018 00:51:59 +0200 Subject: [PATCH 161/170] ARTY v0.9.93 added new mark parameters LLDMS coordinate assignment --- Moose Development/Moose/Core/Point.lua | 22 + .../Moose/Functional/Artillery.lua | 388 ++++++++++++------ 2 files changed, 283 insertions(+), 127 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index bf20bc91b..543bce752 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -251,6 +251,28 @@ do -- COORDINATE return { x = self.x, y = self.z } end + --- Returns the coordinate from the latitude and longitude given in decimal degrees. + -- @param #COORDINATE self + -- @param #number latitude Latitude in decimal degrees. + -- @param #number longitude Longitude in decimal degrees. + -- @param #number altitude (Optional) Altitude in meters. Default is the land height at the coordinate. + -- @return #COORDINATE + function COORDINATE:NewFromLLDD( latitude, longitude, altitude) + + -- Returns a point from latitude and longitude in the vec3 format. + local vec3=coord.LLtoLO(latitude, longitude) + + -- Convert vec3 to coordinate object. + local _coord=self:NewFromVec3(vec3) + + -- Adjust height + if altitude==nil then + _coord.y=altitude + end + + return _coord + end + --- Returns if the 2 coordinates are at the same 2D position. -- @param #COORDINATE self diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 5bec76c49..48d2ab37c 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -531,7 +531,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.92" +ARTY.version="0.9.93" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1139,9 +1139,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) if _dbproperties~=nil then for property,value in pairs(_dbproperties) do self:T({property=property, value=value}) - --if self[property]==nil then self[property]=value - --end end end @@ -1475,14 +1473,13 @@ function ARTY:onEvent(Event) local batteryname=self.Controllable:GetName() local batterycoalition=self.Controllable:GetCoalition() - self:T(string.format("Event captured = %s", tostring(batteryname))) - self:T(string.format("Event id = %s", tostring(Event.id))) - self:T(string.format("Event time = %s", tostring(Event.time))) - self:T(string.format("Event idx = %s", tostring(Event.idx))) - self:T(string.format("Event coalition = %s", tostring(Event.coalition))) - self:T(string.format("Event group id = %s", tostring(Event.groupID))) - self:T(string.format("Event text = %s", tostring(Event.text))) - self:E({eventid=Event.id, vec3=Event.pos}) + self:T2(string.format("Event captured = %s", tostring(batteryname))) + self:T2(string.format("Event id = %s", tostring(Event.id))) + self:T2(string.format("Event time = %s", tostring(Event.time))) + self:T2(string.format("Event idx = %s", tostring(Event.idx))) + self:T2(string.format("Event coalition = %s", tostring(Event.coalition))) + self:T2(string.format("Event group id = %s", tostring(Event.groupID))) + self:T2(string.format("Event text = %s", tostring(Event.text))) if Event.initiator~=nil then local _unitname=Event.initiator:getName() self:T(string.format("Event ini unit name = %s", tostring(_unitname))) @@ -1589,6 +1586,11 @@ function ARTY:_OnEventMarkChange(Event) -- Evaluate marker text and extract parameters. local _assign=self:_Markertext(Event.text) + + -- Check if ENGAGE or MOVE or REQUEST keywords were found. + if _assign==nil or not (_assign.engage or _assign.move or _assign.request) then + return + end -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. local _assigned=true @@ -1606,11 +1608,6 @@ function ARTY:_OnEventMarkChange(Event) if not _assigned then return end - - -- Check if ENGAGE or MOVE or REQUEST keywords were found. - if not (_assign.engage or _assign.move or _assign.request) then - return - end -- Check if the authorization key is required and if it is valid. local _validkey=self:_MarkerKeyAuthentification(Event.text) @@ -1620,7 +1617,16 @@ function ARTY:_OnEventMarkChange(Event) if _assign.requestammo then self:_MarkRequestAmmo() end - -- Done! + if _assign.requestmoves then + self:_MarkRequestMoves() + end + if _assign.requesttargets then + self:_MarkRequestTargets() + end + if _assign.requestrearming then + self:Rearm() + end + -- Requests Done ==> End of story! return end @@ -1649,6 +1655,11 @@ function ARTY:_OnEventMarkChange(Event) -- Also I don't know who can see the mark which was created. _coord:RemoveMark(Event.idx) + -- Coordinate was given in text, e.g. as lat, long. + if _assign.coord then + _coord=_assign.coord + end + -- Anticipate marker ID. -- WARNING: Make sure, no marks are set until the COORDINATE:MarkToCoalition() is called or the target/move name will be wrong and target cannot be removed by deleting its marker. local _id=UTILS._MarkID+1 @@ -2594,7 +2605,7 @@ end function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Clear all tasks. - group:ClearTasks() + --group:ClearTasks() group:OptionAlarmStateGreen() group:OptionROEHoldFire() @@ -2983,122 +2994,147 @@ function ARTY:_Markertext(text) assignment.readonly=false assignment.canceltarget=false assignment.cancelcurrent=false - --assignment.time=nil - --assignment.nshells=nil - --assignment.prio=nil - --assignment.maxengage=nil - --assignment.radius=nil - --assignment.weapontype=nil - --assignment.speed=nil - --assignment.onroad=nil - --assignment.key=nil - if text:lower():find("arty") then - if text:lower():find("engage") then - assignment.engage=true - elseif text:lower():find("move") then - assignment.move=true - elseif text:lower():find("request") then - assignment.request=true - else - self:E(ARTY.id.."ERROR: Neither ENGAGE nor MOVE keyword specified!") - return - end + -- Check for correct keywords. + if text:lower():find("arty engage") or text:lower():find("arty attack") then + assignment.engage=true + elseif text:lower():find("arty move") or text:lower():find("arty relocate") then + assignment.move=true + elseif text:lower():find("arty request") then + assignment.request=true + else + self:E(ARTY.id..'ERROR: Neither "ARTY ENGAGE" nor "ARTY MOVE" nor "ARTY RELOCATE" nor "ARTY REQUEST" keyword specified!') + return nil + end - -- keywords are split by "," - local keywords=self:_split(text, ",") + -- keywords are split by "," + local keywords=self:_split(text, ",") + + for _,key in pairs(keywords) do - for _,key in pairs(keywords) do + local s=self:_split(key, " ") + local val=s[2] + + -- Battery name, i.e. which ARTY group should fire. + if key:lower():find("battery") then + + local v=self:_split(key, '"') + + for i=2,#v,2 do + table.insert(assignment.battery, v[i]) + self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) + end + + elseif key:lower():find("time") then - local s=self:_split(key, " ") - local val=s[2] + if val:lower():find("now") then + assignment.time=self:_SecondsToClock(timer.getTime0()+2) + else + assignment.time=val + end + self:T2(ARTY.id..string.format("Key Time=%s.", val)) + + elseif key:lower():find("shot") then - -- Battery name, i.e. which ARTY group should fire. - if key:lower():find("battery") then + assignment.nshells=tonumber(s[2]) + self:T(ARTY.id..string.format("Key Shot=%s.", val)) + + elseif key:lower():find("prio") then + + assignment.prio=tonumber(val) + self:T2(string.format("Key Prio=%s.", val)) + + elseif key:lower():find("maxengage") then + + assignment.maxengage=tonumber(val) + self:T2(ARTY.id..string.format("Key Maxengage=%s.", val)) + + elseif key:lower():find("radius") then + + assignment.radius=tonumber(val) + self:T2(ARTY.id..string.format("Key Radius=%s.", val)) + + elseif key:lower():find("weapon") then + + if val:lower():find("cannon") then + assignment.weapontype=ARTY.WeaponType.Cannon + elseif val:lower():find("rocket") then + assignment.weapontype=ARTY.WeaponType.Rockets + elseif val:lower():find("missile") then + assignment.weapontype=ARTY.WeaponType.GuidedMissile + elseif val:lower():find("nuke") then + assignment.weapontype=ARTY.WeaponType.TacticalNukes + else + assignment.weapontype=ARTY.WeaponType.Auto + end + self:T2(ARTY.id..string.format("Key Weapon=%s.", val)) + + elseif key:lower():find("speed") then + + assignment.speed=tonumber(val) + self:T2(ARTY.id..string.format("Key Speed=%s.", val)) + + elseif key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")then + + assignment.onroad=true + self:T2(ARTY.id..string.format("Key Onroad=true.")) + + elseif key:lower():find("irrevocable") or key:lower():find("readonly") then + + assignment.readonly=true + self:T2(ARTY.id..string.format("Key Readonly=true.")) + + elseif key:lower():find("canceltarget") then + + assignment.canceltarget=true + self:T2(ARTY.id..string.format("Key Cancel Target (before move)=true.")) + + elseif key:lower():find("cancelcurrent") then + + assignment.cancelcurrent=true + self:T2(ARTY.id..string.format("Key Cancel Current=true.")) + + elseif assignment.request and key:lower():find("rearm") then + + assignment.requestrearming=true + self:T2(ARTY.id..string.format("Key Request Rearming=true.")) + + elseif assignment.request and key:lower():find("ammo") then + + assignment.requestammo=true + self:T2(ARTY.id..string.format("Key Request Ammo=true.")) + + elseif assignment.request and key:lower():find("target") then + + assignment.requesttargets=true + self:T2(ARTY.id..string.format("Key Request Targets=true.")) + + elseif assignment.request and (key:lower():find("move") or key:lower():find("relocation")) then + + assignment.requestmoves=true + self:T2(ARTY.id..string.format("Key Request Moves=true.")) + + elseif key:lower():find("lldms") then + + local _flat = "%d+:%d+:%d+%s*[N,S]" + local _flon = "%d+:%d+:%d+%s*[W,E]" + local _lat=key:match(_flat) + local _lon=key:match(_flon) + self:T2(ARTY.id..string.format("Key LLDMS: lat=%s, long=%s", _lat,_lon)) + + if _lat and _lon then + + -- Convert DMS string to DD numbers format. + local _latitude, _longitude=self:_LLDMS2DD(_lat, _lon) + self:T2(ARTY.id..string.format("Key LLDMS: lat=%.3f, long=%.3f", _latitude,_longitude)) - local v=self:_split(key, '"') - - for i=2,#v,2 do - table.insert(assignment.battery, v[i]) - self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) + -- Convert LL to coordinate object. + if _latitude and _longitude then + assignment.coord=COORDINATE:NewFromLLDD(_latitude,_longitude) end - elseif key:lower():find("time") then - - if val:lower():find("now") then - assignment.time=self:_SecondsToClock(timer.getTime0()+5) - else - assignment.time=val - end - self:T2(ARTY.id..string.format("Key Time=%s.", val)) - - elseif key:lower():find("shot") then - - assignment.nshells=tonumber(s[2]) - self:T(ARTY.id..string.format("Key Shot=%s.", val)) - - elseif key:lower():find("prio") then - - assignment.prio=tonumber(val) - self:T2(string.format("Key Prio=%s.", val)) - - elseif key:lower():find("maxengage") then - - assignment.maxengage=tonumber(val) - self:T2(ARTY.id..string.format("Key Maxengage=%s.", val)) - - elseif key:lower():find("radius") then - - assignment.radius=tonumber(val) - self:T2(ARTY.id..string.format("Key Radius=%s.", val)) - - elseif key:lower():find("weapon") then - - if val:lower():find("cannon") then - assignment.weapontype=ARTY.WeaponType.Cannon - elseif val:lower():find("rocket") then - assignment.weapontype=ARTY.WeaponType.Rockets - elseif val:lower():find("missile") then - assignment.weapontype=ARTY.WeaponType.GuidedMissile - elseif val:lower():find("nuke") then - assignment.weapontype=ARTY.WeaponType.TacticalNukes - else - assignment.weapontype=ARTY.WeaponType.Auto - end - self:T2(ARTY.id..string.format("Key Weapon=%s.", val)) - - elseif key:lower():find("speed") then - - assignment.speed=tonumber(val) - self:T2(ARTY.id..string.format("Key Speed=%s.", val)) - - elseif key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")then - - assignment.onroad=true - self:T2(ARTY.id..string.format("Key Onroad=true.")) - - elseif key:lower():find("irrevocable") or key:lower():find("readonly") then - - assignment.readonly=true - self:T2(ARTY.id..string.format("Key Readonly=true.")) - - elseif key:lower():find("canceltarget") then - - assignment.canceltarget=true - self:T2(ARTY.id..string.format("Key Cancel Target (before move)=true.")) - - elseif key:lower():find("cancelcurrent") then - - assignment.cancelcurrent=true - self:T2(ARTY.id..string.format("Key Cancel Current=true.")) - - elseif assignment.request and key:lower():find("ammo") then - assignment.requestammo=true - end - - end - else - self:T2(ARTY.id..string.format("This is NO arty command:\n%s", tostring(text))) + end + end end return assignment @@ -3110,6 +3146,44 @@ function ARTY:_MarkRequestAmmo() self:GetAmmo(true) end +--- Request Moves. +-- @param #ARTY self +function ARTY:_MarkRequestMoves() + local text=string.format("%s, relocations:", self.Controllable:GetName()) + if self.currentMove then + text=text..string.format("\n- %s", self:_MoveInfo(self.currentMove)) + else + text=text..string.format("\n- no current relocation") + end + if #self.moves>0 then + for _,move in pairs(self.moves) do + text=text..string.format("\n- %s", self:_MoveInfo(move)) + end + else + text=text..string.format("\n- no more relocations") + end + MESSAGE:New(text, 20):Clear():ToCoalition(self.Controllable:GetCoalition()) +end + +--- Request Targets. +-- @param #ARTY self +function ARTY:_MarkRequestTargets() + local text=string.format("%s, targets:", self.Controllable:GetName()) + if self.currentTarget then + text=text..string.format("\n- %s", self:_TargetInfo(self.currentTarget)) + else + text=text..string.format("\n- no current target") + end + if #self.targets>0 then + for _,target in pairs(self.targets) do + text=text..string.format("\n- %s", self:_TargetInfo(target)) + end + else + text=text..string.format("\n- no more targets") + end + MESSAGE:New(text, 20):Clear():ToCoalition(self.Controllable:GetCoalition()) +end + --- Create a name for an engagement initiated by placing a marker. -- @param #ARTY self -- @param #number markerid ID of the placed marker. @@ -3320,7 +3394,7 @@ function ARTY:_CheckTargetsInRange() MESSAGE:New(_name.." assigned.", 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) -- Assign relocation move. - self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true) + self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true) end @@ -3716,6 +3790,66 @@ function ARTY:_MoveInfo(move) return string.format("%s: time=%s, speed=%d, onroad=%s, cancel=%s", move.name, _clock, move.speed, tostring(move.onroad), tostring(move.cancel)) end +--- Convert Latitude and Lontigude from DMS to DD. +-- @param #ARTY self +-- @param #string l1 Latitude or longitude as string in the format DD:MM:SS N/S/W/E +-- @param #string l2 Latitude or longitude as string in the format DD:MM:SS N/S/W/E +-- @return #number Latitude in decimal degree format. +-- @return #number Longitude in decimal degree format. +function ARTY:_LLDMS2DD(l1,l2) + self:F2(l1,l2) + + -- Make an array of lat and long. + local _latlong={l1,l2} + + local _latitude=nil + local _longitude=nil + + for _,ll in pairs(_latlong) do + + -- Format is expected as "DD:MM:SS" or "D:M:S". + local _format = "%d+:%d+:%d+" + local _ldms=ll:match(_format) + + if ldms then + + -- Split DMS to degrees, minutes and seconds. + local _dms=self:_split(_ldms, ":") + local _deg=tonumber(_dms[1]) + local _min=tonumber(_dms[2]) + local _sec=tonumber(_dms[3]) + + -- Convert DMS to DD. + local function DMS2DD(d,m,s) + return d+m/60+s/3600 + end + + -- Detect with hemisphere is meant. + if ll:match("N") then + _latitude=DMS2DD(_deg,_min,_sec) + elseif ll:match("S") then + _latitude=-DMS2DD(_deg,_min,_sec) + elseif ll:match("W") then + _longitude=-DMS2DD(_deg,_min,_sec) + elseif ll:match("E") then + _longitude=DMS2DD(_deg,_min,_sec) + end + + -- Debug text. + local text=string.format("DMS %02d Deg %02d min %02d sec",_deg,_min,_sec) + self:T2(ARTY.id..text) + + end + end + + -- Debug text. + local text=string.format("\nLatitude %.3f", _latitude) + text=text..string.format("\nLongitude %.3f", _longitude) + self:T2(ARTY.id..text) + + return _latitude,_longitude +end + --- Convert time in seconds to hours, minutes and seconds. -- @param #ARTY self -- @param #number seconds Time in seconds. From 38a03f4cbc06fff4204fe015f9fdf3f4d378cd69 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 6 Jun 2018 22:57:04 +0200 Subject: [PATCH 162/170] ARTY v0.9.94 Bug fixes and improvements. --- .../Moose/Functional/Artillery.lua | 164 +++++++++++++----- 1 file changed, 117 insertions(+), 47 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 48d2ab37c..7920bb774 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -277,8 +277,8 @@ -- Targets and relocations can be assigned by players via placing a mark on the F10 map. The marker text must contain certain keywords. -- -- This feature can be turned on with the @{#ARTY.SetMarkAssignmentsOn}(*key*). The parameter *key* is optional. When set, it can be used as PIN, i.e. only --- player who know the correct key are able to assign targets or relocations. Default behavior is that all players belonging to the same coalition as the --- ARTY group are able to assign targets and moves. +-- players who know the correct key are able to assign and cancel targets or relocations. Default behavior is that all players belonging to the same coalition as the +-- ARTY group are able to assign targets and moves without a key. -- -- ### Target Assignments -- A new target can be assigned by writing **arty engage** in the marker text. This can be followed by a comma separated lists of optional keywords and parameters: @@ -297,7 +297,8 @@ -- arty engage! -- arty engage! shots 20, prio 10, time 08:15, weapon cannons -- arty engage! battery "Blue Paladin 1" "Blue MRLS 1", shots 10, time 10:15 --- arty engage! battery "Blue Paladin 1", key 666 +-- arty engage! battery "Blue MRLS 1", key 666 +-- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15 -- -- Note that the keywords and parameters are case insensitve. Only exception are the battery group names. These must be exactly the same as the names of the goups defined -- in the mission editor. @@ -315,9 +316,33 @@ -- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are some examples: --- arty move! time 23:45, speed 50, onroad, cancel --- arty move! battery "Blue Paladin", onroad --- arty move, cancel, speed 10, onroad +-- arty move +-- arty move! time 23:45, speed 50, on road +-- arty move! battery "Blue Paladin" +-- arty move, battery "Blue MRLS", canceltarget, speed 10, on road +-- +-- ### Coordinate Independent Commands +-- +-- There are a couple of commands, which are independent of the position where the marker is placed. +-- These commands are +-- arty move, cancelcurrent +-- which will cancel the current relocation movement. Of course, this can be combined with the *battery* keyword to address a certain battery. +-- Same goes for targets, e.g. +-- arty engage, battery "Paladin Alpha", cancelcurrent +-- which will cancel all running firing tasks. +-- +-- ### General Requests +-- +-- Marks can also be to send requests to the ARTY group. This is done by the keyword **arty request**, which can have the keywords +-- * *target* All assigned targets are reported. +-- * *move* All assigned relocation moves are reported. +-- * *ammo* Current ammunition status is reported. +-- +-- For example +-- arty request, ammo +-- arty request, battery "Paladin Bravo", targets +-- arty request, battery "MRLS Charly", move +-- -- -- ## Fine Tuning -- @@ -414,6 +439,7 @@ ARTY={ Nmissiles0=0, Nukes0=0, FullAmmo=0, + defaultROE="weapon_hold", StatusInterval=10, WaitForShotTime=300, DCSdesc=nil, @@ -531,7 +557,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.93" +ARTY.version="0.9.94" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -556,6 +582,8 @@ ARTY.version="0.9.93" -- TODO: Improve handling of special weapons. When winchester if using selected weapons? -- TODO: Handle rearming for ships. -- TODO: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location. +-- TODO: Add set commands via markers. E.g. set rearming place. +-- TODO: Test stationary types like mortas ==> rearming etc. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1216,6 +1244,9 @@ function ARTY:onafterStart(Controllable, From, Event, To) self:T(ARTY.id..text) end + -- Set default ROE to weapon hold. + self.Controllable:OptionROEHoldFire() + -- Add event handler. self:HandleEvent(EVENTS.Shot, self._OnEventShot) self:HandleEvent(EVENTS.Dead, self._OnEventDead) @@ -1246,7 +1277,13 @@ end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self -function ARTY:_StatusReport() +-- @param #boolean display (Optional) If true, send message to coalition. Default false. +function ARTY:_StatusReport(display) + + -- Set default. + if display==nil then + display=false + end -- Get Ammo. local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() @@ -1286,6 +1323,7 @@ function ARTY:_StatusReport() end text=text..string.format("******************************************************") env.info(ARTY.id..text) + MESSAGE:New(text, 20):Clear():ToCoalitionIf(self.Controllable:GetCoalition(), display) end @@ -1623,6 +1661,9 @@ function ARTY:_OnEventMarkChange(Event) if _assign.requesttargets then self:_MarkRequestTargets() end + if _assign.requeststatus then + self:_MarkRequestStatus() + end if _assign.requestrearming then self:Rearm() end @@ -1646,6 +1687,8 @@ function ARTY:_OnEventMarkChange(Event) if _validkey then -- Convert (wrong x-->z, z-->x) vec3 + -- TODO: This needs to be "fixed", once DCS gives the correct numbers for x and z. + -- local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z} local vec3={y=Event.pos.y, x=Event.pos.z, z=Event.pos.x} -- Get coordinate from vec3. @@ -1807,6 +1850,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To) if self:is("Rearmed") then local distance=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) self:T2(ARTY.id..string.format("%s: Rearmed. Distance ARTY to InitalCoord = %d m", Controllable:GetName(), distance)) + -- Check that ARTY group is back and set it to combat ready. if distance <= self.RearmingDistance then self:T2(ARTY.id..string.format("%s: Rearmed ==> CombatReady", Controllable:GetName())) self:CombatReady() @@ -2062,6 +2106,9 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) self:RemoveTarget(target.name) end + -- Set ROE to weapon hold. + self.Controllable:OptionROEHoldFire() + -- Clear tasks. self.Controllable:ClearTasks() @@ -2105,6 +2152,14 @@ end function ARTY:onbeforeRearm(Controllable, From, Event, To) self:_EventFromTo("onbeforeRearm", Event, From, To) + local _rearmed=self:_CheckRearmed() + if _rearmed then + self:T(ARTY.id..string.format("%s, group is already armed to the teeth. Rearming request denied!", self.Controllable:GetName())) + return false + else + self:T(ARTY.id..string.format("%s, group might be rearmed.", self.Controllable:GetName())) + end + -- Check if a reaming unit or rearming place was specified. if self.RearmingGroup and self.RearmingGroup:IsAlive() then return true @@ -2128,6 +2183,9 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Coordinate of ARTY unit. local coordARTY=self.Controllable:GetCoordinate() + -- Remember current coordinates so that we find our way back home. + self.InitialCoord=coordARTY + -- Coordinate of rearming group. local coordRARM=nil if self.RearmingGroup then @@ -2152,7 +2210,9 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Route ARTY group to rearming place. if dA > self.RearmingDistance then - self:Move(self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2), self.Speed, self.RearmingArtyOnRoad) + local _tocoord=self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2) + self:AssignMoveCoord(_tocoord, nil, self.Speed, self.RearmingArtyOnRoad, false, "Relocate to rearming place", true) + --self:Move(, self.Speed, self.RearmingArtyOnRoad) end -- Route Rearming group to rearming place. @@ -2193,7 +2253,8 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Route ARTY group to rearming place. if dA > self.RearmingDistance then - self:Move(self:_VicinityCoord(self.RearmingPlaceCoord), self.Speed, self.RearmingArtyOnRoad) + local _tocoord=self:_VicinityCoord(self.RearmingPlaceCoord) + self:AssignMoveCoord(_tocoord, nil, self.Speed, self.RearmingArtyOnRoad, false, "Relocate to rearming place", true) end end @@ -2222,7 +2283,8 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) -- Route ARTY group back to where it came from (if distance is > 100 m). local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) if d1 > self.RearmingDistance then - self:Move(self.InitialCoord, self.Speed, self.RearmingArtyOnRoad) + --self:Move(self.InitialCoord, self.Speed, self.RearmingArtyOnRoad) + self:AssignMoveCoord(self.InitialCoord, nil, self.Speed, self.RearmingArtyOnRoad, false, "After rearm back to initial pos", true) end -- Route unit back to where it came from (if distance is > 100 m). @@ -2370,9 +2432,6 @@ end function ARTY:onafterNewTarget(Controllable, From, Event, To, target) self:_EventFromTo("onafterNewTarget", Event, From, To) - -- Check if target is in range. - --local _inrange, _toofar, _tooclose=self:_TargetInRange(target, self.report or self.Debug) - -- Debug message. local text=string.format("Adding new target %s.", target.name) MESSAGE:New(text, 5):ToAllIf(self.Debug) @@ -2569,7 +2628,7 @@ function ARTY:_NuclearBlast(_coord) -- Distance from group to impact point. local distance= spos:Get2DDistance(_coord) - -- Place markers on every possible scenery object. + -- Place markers on every possible scenery object. if self.Debug then local MarkerID=spos:MarkToAll(string.format("%s scenery object %s", self.Controllable:GetName(), SceneryObject:GetTypeName())) local text=string.format("%s scenery: %s, Coord %s", self.Controllable:GetName(), SceneryObject:GetTypeName(), SceneryObject:GetCoordinate():ToStringLLDMS()) @@ -3009,6 +3068,7 @@ function ARTY:_Markertext(text) -- keywords are split by "," local keywords=self:_split(text, ",") + self:T({keywords=keywords}) for _,key in pairs(keywords) do @@ -3025,7 +3085,7 @@ function ARTY:_Markertext(text) self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) end - elseif key:lower():find("time") then + elseif (assignment.engage or assignment.move) and key:lower():find("time") then if val:lower():find("now") then assignment.time=self:_SecondsToClock(timer.getTime0()+2) @@ -3034,27 +3094,27 @@ function ARTY:_Markertext(text) end self:T2(ARTY.id..string.format("Key Time=%s.", val)) - elseif key:lower():find("shot") then + elseif assignment.engage and key:lower():find("shot") then assignment.nshells=tonumber(s[2]) self:T(ARTY.id..string.format("Key Shot=%s.", val)) - elseif key:lower():find("prio") then + elseif assignment.engage and key:lower():find("prio") then assignment.prio=tonumber(val) self:T2(string.format("Key Prio=%s.", val)) - elseif key:lower():find("maxengage") then + elseif assignment.engage and key:lower():find("maxengage") then assignment.maxengage=tonumber(val) self:T2(ARTY.id..string.format("Key Maxengage=%s.", val)) - elseif key:lower():find("radius") then + elseif assignment.engage and key:lower():find("radius") then assignment.radius=tonumber(val) self:T2(ARTY.id..string.format("Key Radius=%s.", val)) - elseif key:lower():find("weapon") then + elseif assignment.engage and key:lower():find("weapon") then if val:lower():find("cannon") then assignment.weapontype=ARTY.WeaponType.Cannon @@ -3069,12 +3129,12 @@ function ARTY:_Markertext(text) end self:T2(ARTY.id..string.format("Key Weapon=%s.", val)) - elseif key:lower():find("speed") then + elseif assignment.move and key:lower():find("speed") then assignment.speed=tonumber(val) self:T2(ARTY.id..string.format("Key Speed=%s.", val)) - elseif key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")then + elseif assignment.move and (key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")) then assignment.onroad=true self:T2(ARTY.id..string.format("Key Onroad=true.")) @@ -3084,12 +3144,12 @@ function ARTY:_Markertext(text) assignment.readonly=true self:T2(ARTY.id..string.format("Key Readonly=true.")) - elseif key:lower():find("canceltarget") then + elseif assignment.move and key:lower():find("canceltarget") then assignment.canceltarget=true self:T2(ARTY.id..string.format("Key Cancel Target (before move)=true.")) - elseif key:lower():find("cancelcurrent") then + elseif (assignment.engage or assignment.move) and key:lower():find("cancelcurrent") then assignment.cancelcurrent=true self:T2(ARTY.id..string.format("Key Cancel Current=true.")) @@ -3108,7 +3168,12 @@ function ARTY:_Markertext(text) assignment.requesttargets=true self:T2(ARTY.id..string.format("Key Request Targets=true.")) - + + elseif assignment.request and key:lower():find("status") then + + assignment.requeststatus=true + self:T2(ARTY.id..string.format("Key Request Status=true.")) + elseif assignment.request and (key:lower():find("move") or key:lower():find("relocation")) then assignment.requestmoves=true @@ -3140,27 +3205,32 @@ function ARTY:_Markertext(text) return assignment end ---- Request ammo. +--- Request ammo via mark. -- @param #ARTY self function ARTY:_MarkRequestAmmo() self:GetAmmo(true) end +--- Request status via mark. +-- @param #ARTY self +function ARTY:_MarkRequestStatus() + self:_StatusReport(true) +end + --- Request Moves. -- @param #ARTY self function ARTY:_MarkRequestMoves() local text=string.format("%s, relocations:", self.Controllable:GetName()) - if self.currentMove then - text=text..string.format("\n- %s", self:_MoveInfo(self.currentMove)) - else - text=text..string.format("\n- no current relocation") - end if #self.moves>0 then for _,move in pairs(self.moves) do - text=text..string.format("\n- %s", self:_MoveInfo(move)) + if self.currentMove and move.name == self.currentMove.name then + text=text..string.format("\n- %s (current)", self:_MoveInfo(move)) + else + text=text..string.format("\n- %s", self:_MoveInfo(move)) + end end else - text=text..string.format("\n- no more relocations") + text=text..string.format("\n- no queued relocations") end MESSAGE:New(text, 20):Clear():ToCoalition(self.Controllable:GetCoalition()) end @@ -3169,17 +3239,16 @@ end -- @param #ARTY self function ARTY:_MarkRequestTargets() local text=string.format("%s, targets:", self.Controllable:GetName()) - if self.currentTarget then - text=text..string.format("\n- %s", self:_TargetInfo(self.currentTarget)) - else - text=text..string.format("\n- no current target") - end if #self.targets>0 then for _,target in pairs(self.targets) do - text=text..string.format("\n- %s", self:_TargetInfo(target)) + if self.currentTarget and target.name == self.currentTarget.name then + text=text..string.format("\n- %s (current)", self:_TargetInfo(target)) + else + text=text..string.format("\n- %s", self:_TargetInfo(target)) + end end else - text=text..string.format("\n- no more targets") + text=text..string.format("\n- no queued targets") end MESSAGE:New(text, 20):Clear():ToCoalition(self.Controllable:GetCoalition()) end @@ -3200,7 +3269,7 @@ function ARTY:_MarkMoveName(markerid) return string.format("BATTERY=%s, Marked Relocation ID=%d", self.Controllable:GetName(), markerid) end ---- Create a name for a relocation move initiated by placing a marker. +--- Get the marker ID from the assigned task name. -- @param #ARTY self -- @param #string name Name of the assignment. -- @return #string Name of the ARTY group or nil @@ -3552,14 +3621,14 @@ function ARTY:_GetTargetIndexByName(name) for i=1,#self.targets do local targetname=self.targets[i].name - self:T(ARTY.id..string.format("Have target with name %s. Index = %d", targetname, i)) + self:T3(ARTY.id..string.format("Have target with name %s. Index = %d", targetname, i)) if targetname==name then - self:T(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) + self:T2(ARTY.id..string.format("Found target with name %s. Index = %d", name, i)) return i end end - self:E(ARTY.id..string.format("ERROR: Target with name %s could not be found!", name)) + self:T2(ARTY.id..string.format("WARNING: Target with name %s could not be found. (This can happen.)", name)) return nil end @@ -3572,13 +3641,14 @@ function ARTY:_GetMoveIndexByName(name) for i=1,#self.moves do local movename=self.moves[i].name + self:T3(ARTY.id..string.format("Have move with name %s. Index = %d", movename, i)) if movename==name then self:T2(ARTY.id..string.format("Found move with name %s. Index = %d", name, i)) return i end end - self:E(ARTY.id..string.format("ERROR: Move with name %s could not be found!", name)) + self:T2(ARTY.id..string.format("WARNING: Move with name %s could not be found. (This can happen.)", name)) return nil end @@ -3739,7 +3809,7 @@ function ARTY:_VicinityCoord(coord, rmin, rmax) local vec2=coord:GetRandomVec2InRadius(rmax, rmin) local pops=COORDINATE:NewFromVec2(vec2) -- Debug info. - self:T(ARTY.id..string.format("Vicinity distance = %d (rmin=%d, rmax=%d)", pops:Get2DDistance(coord), rmin, rmax)) + self:T3(ARTY.id..string.format("Vicinity distance = %d (rmin=%d, rmax=%d)", pops:Get2DDistance(coord), rmin, rmax)) return pops end From 8b3d7ebf048309e2b7757c726f12c1a16dd2efbf Mon Sep 17 00:00:00 2001 From: alexproust <38035263+alexproust@users.noreply.github.com> Date: Thu, 7 Jun 2018 12:57:10 +0200 Subject: [PATCH 163/170] Update Routines.lua Correction MessageToBlue function --- Moose Development/Moose/Utilities/Routines.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Utilities/Routines.lua b/Moose Development/Moose/Utilities/Routines.lua index 285f270d7..c63359c2e 100644 --- a/Moose Development/Moose/Utilities/Routines.lua +++ b/Moose Development/Moose/Utilities/Routines.lua @@ -2290,7 +2290,7 @@ end function MessageToBlue( MsgText, MsgTime, MsgName ) --trace.f() - MESSAGE:New( MsgText, MsgTime, "To Blue Coalition" ):ToCoalition( coalition.side.RED ) + MESSAGE:New( MsgText, MsgTime, "To Blue Coalition" ):ToCoalition( coalition.side.BLUE ) end function getCarrierHeight( CarrierGroup ) From c6fc571c957b73acd0f4677f08df86f76d831edf Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 8 Jun 2018 00:00:41 +0200 Subject: [PATCH 164/170] ARTY adjusted docu some improvemens --- Moose Development/Moose/Core/Point.lua | 25 ++- .../Moose/Functional/Artillery.lua | 143 +++++++++++------- 2 files changed, 103 insertions(+), 65 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 543bce752..b7688ad82 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -957,26 +957,25 @@ do -- COORDINATE -- The first point is the closest point on road of the given coordinate. The last point is the closest point on road of the ToCoord. Hence, the coordinate itself and the final ToCoord are not necessarily included in the path. -- @param #COORDINATE self -- @param #COORDINATE ToCoord Coordinate of destination. - -- @return #table Table of coordinates on road. + -- @return #table Table of coordinates on road. If no path on road can be found, nil is returned. function COORDINATE:GetPathOnRoad(ToCoord) -- DCS API function returning a table of vec2. local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z) - --Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) - --Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) - --Path[#Path+1]=self:GetClosestPointToRoad() - --Path[#Path+1]=ToCoord:GetClosestPointToRoad() - -- I've removed this stuff because it severely slows down DCS in case of paths with a lot of segments. - -- Just the beginning and the end point is sufficient. - local Path={} - --Path[#Path+1]=self - for i, v in ipairs(path) do - Path[#Path+1]=COORDINATE:NewFromVec2(v) - end - --Path[#Path+1]=ToCoord + if path then + --Path[#Path+1]=self + for i, v in ipairs(path) do + Path[#Path+1]=COORDINATE:NewFromVec2(v) + end + --Path[#Path+1]=ToCoord + else + -- There are cases where no path on road can be found. + return nil + end + return Path end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 7920bb774..fde0f379c 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -2,17 +2,20 @@ -- -- === -- --- The ARTY class can be used to easily assign and manage targets for artillery units. +-- The ARTY class can be used to easily assign and manage targets for artillery units using an advanced queueing system. -- -- ## Features: -- -- * Multiple targets can be assigned. No restriction on number of targets. -- * Targets can be given a priority. Engagement of targets is executed a according to their priority. -- * Engagements can be scheduled, i.e. will be executed at a certain time of the day. +-- * Multiple relocations of the group can be assigned and scheduled via queueing system. -- * Special weapon types can be selected for each attack, e.g. cruise missiles for Naval units. --- * Automatic rearming once the artillery is out of ammo. +-- * Automatic rearming once the artillery is out of ammo (optional). +-- * Automatic relocation after each firing engagement to prevent counter strikes (optional). +-- * Automatic relocation movements to get the battery within firing range (optional). +-- * Simulation of tactical nuclear shells. -- * New targets can be added during the mission, e.g. when they are detected by recon units. --- * Modeling of tactical nuclear shells. -- * Targets and relocations can be assigned by placing markers on the F10 map. -- * Finite state machine implementation. Mission designer can interact when certain events occur. -- @@ -276,31 +279,31 @@ -- -- Targets and relocations can be assigned by players via placing a mark on the F10 map. The marker text must contain certain keywords. -- --- This feature can be turned on with the @{#ARTY.SetMarkAssignmentsOn}(*key*). The parameter *key* is optional. When set, it can be used as PIN, i.e. only +-- This feature can be turned on with the @{#ARTY.SetMarkAssignmentsOn}(*key*, *readonly*). The parameter *key* is optional. When set, it can be used as PIN, i.e. only -- players who know the correct key are able to assign and cancel targets or relocations. Default behavior is that all players belonging to the same coalition as the -- ARTY group are able to assign targets and moves without a key. -- -- ### Target Assignments --- A new target can be assigned by writing **arty engage** in the marker text. This can be followed by a comma separated lists of optional keywords and parameters: +-- A new target can be assigned by writing **arty engage** in the marker text. This can be followed by a **comma separated list** of optional keywords and parameters: -- -- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible. --- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50. +-- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50, i.e. medium priority. -- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5. -- * *maxengage* Number of times the target is engaged. Default is 1. -- * *radius* Scattering radius of the fired shots in meters. Default is 100 m. -- * *weapon* Type of weapon to be used. Valid parameters are *cannon*, *rocket*, *missile*, *nuke*. Default is automatic selection. --- * *battery* Name of the ARTY group that the target is assigned to. Note that the name is case sensitive and has to be given in quotation marks. Default is all ARTY groups of the right coalition. +-- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition. -- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. --- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker. +-- * *readonly* The marker is readonly and cannot be deleted by users. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are examples of valid marker texts: --- arty engage! --- arty engage! shots 20, prio 10, time 08:15, weapon cannons --- arty engage! battery "Blue Paladin 1" "Blue MRLS 1", shots 10, time 10:15 --- arty engage! battery "Blue MRLS 1", key 666 +-- arty engage +-- arty engage, shots 20, prio 10, time 08:15, weapon cannons +-- arty engage, battery "Blue Paladin 1" "Blue MRLS 1", shots 10, time 10:15 +-- arty engage, battery "Blue MRLS 1", key 666 -- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15 -- --- Note that the keywords and parameters are case insensitve. Only exception are the battery group names. These must be exactly the same as the names of the goups defined +-- Note that the keywords and parameters are *case insensitve*. Only exception are the battery group names. These must be exactly the same as the names of the goups defined -- in the mission editor. -- -- ### Relocation Assignments @@ -317,8 +320,8 @@ -- -- Here are some examples: -- arty move --- arty move! time 23:45, speed 50, on road --- arty move! battery "Blue Paladin" +-- arty move, time 23:45, speed 50, on road +-- arty move, battery "Blue Paladin" -- arty move, battery "Blue MRLS", canceltarget, speed 10, on road -- -- ### Coordinate Independent Commands @@ -334,6 +337,7 @@ -- ### General Requests -- -- Marks can also be to send requests to the ARTY group. This is done by the keyword **arty request**, which can have the keywords +-- -- * *target* All assigned targets are reported. -- * *move* All assigned relocation moves are reported. -- * *ammo* Current ammunition status is reported. @@ -348,6 +352,8 @@ -- -- The mission designer has a few options to tailor the ARTY object according to his needs. -- +-- * @{#ARTY.SetAutomaticRelocate}(*maxdist*, *onroad*) lets the ARTY group automatically move to within firing range if a current target is outside the min/max firing range. The +-- optional parameter *maxdist* is the maximum distance im km the group will move. If the distance is greater no relocation is performed. Default is 50 km. -- * @{#ARTY.SetRelocateAfterEngagement}() will cause the ARTY group to change its position after each firing assignment. -- * @{#ARTY.SetRelocateDistance}(*rmax*, *rmin*) sets the max/min distance for relocation of the group. Default distance is randomly between 300 and 800 m. -- * @{#ARTY.RemoveAllTargets}() removes all targets from the target queue. @@ -1423,36 +1429,7 @@ function ARTY:_OnEventShot(EventData) local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.Controllable:GetName(), _nammo, _nshells, _nrockets, _nmissiles)) self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) - - -- Special weapon type requested ==> Check if corresponding ammo is empty. - local _partlyoutofammo=false - if self.currentTarget.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then - - self:T(ARTY.id..string.format("Group %s, cannons requested but shells empty.", self.Controllable:GetName())) - _partlyoutofammo=true - - elseif self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then - - self:T(ARTY.id..string.format("Group %s, tactical nukes requested but nukes empty.", self.Controllable:GetName())) - _partlyoutofammo=true - - elseif self.currentTarget.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then - - self:T(ARTY.id..string.format("Group %s, rockets requested but rockets empty.", self.Controllable:GetName())) - _partlyoutofammo=true - - elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - - self:T(ARTY.id..string.format("Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName())) - _partlyoutofammo=true - - elseif (self.currentTarget.weapontype==ARTY.WeaponType.GuidedMissile or self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile or self.currentTarget.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then - - self:T(ARTY.id..string.format("Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName())) - _partlyoutofammo=true - - end - + -- Check if number of shots reached max. local _ceasefire=false local _relocate=false @@ -1469,6 +1446,10 @@ function ARTY:_OnEventShot(EventData) end end + -- Check if we are partly out of ammo. + -- TODO: move this to status. + local _partlyoutofammo=self:_CheckOutOfAmmo() + -- Check if we are (partly) out of ammo. if _outofammo or _partlyoutofammo then _ceasefire=true @@ -1497,6 +1478,51 @@ function ARTY:_OnEventShot(EventData) end end +--- Check if group is (partly) out of ammo. +-- @param #ARTY self +-- @return @boolean True if any target in the queue requests a weapon type that is null. +function ARTY:_CheckOutOfAmmo() + + -- Get current ammo. + local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() + + -- Special weapon type requested ==> Check if corresponding ammo is empty. + local _partlyoutofammo=false + + for _,Target in pairs(self.targets) do + + if Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then + + self:T(ARTY.id..string.format("Group %s, cannons requested but shells empty.", self.Controllable:GetName())) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then + + self:T(ARTY.id..string.format("Group %s, tactical nukes requested but nukes empty.", self.Controllable:GetName())) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then + + self:T(ARTY.id..string.format("Group %s, rockets requested but rockets empty.", self.Controllable:GetName())) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then + + self:T(ARTY.id..string.format("Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName())) + _partlyoutofammo=true + + elseif (Target.weapontype==ARTY.WeaponType.GuidedMissile or Target.weapontype==ARTY.WeaponType.CruiseMissile or Target.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then + + self:T(ARTY.id..string.format("Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName())) + _partlyoutofammo=true + + end + + end + + return _partlyoutofammo +end + --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self -- @param #table Event @@ -2319,15 +2345,15 @@ function ARTY:_CheckRearmed() -- Rearming status in per cent. local _rearmpc=nammo/self.FullAmmo*100 - -- Send message. + -- Send message if rearming > 1% complete if _rearmpc>1 then - local text=string.format("%s, rearming %d %% complete.", self.Controllable:GetName(), _rearmpc) + local text=string.format("%s, rearming %d %% complete. nammo=%d , fullammo=%d", self.Controllable:GetName(), _rearmpc, nammo, self.FullAmmo) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) end -- Return if ammo is full. - if nammo==self.FullAmmo then + if nammo>=self.FullAmmo then return true else return false @@ -2664,7 +2690,7 @@ end function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Clear all tasks. - --group:ClearTasks() + group:ClearTasks() group:OptionAlarmStateGreen() group:OptionROEHoldFire() @@ -2681,7 +2707,7 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) Speed=math.min(Speed, SpeedMax) -- Current coordinates of group. - local cpini=group:GetCoordinate() + local cpini=group:GetCoordinate() -- Core.Point#COORDINATE -- Distance between current and final point. local dist=cpini:Get2DDistance(ToCoord) @@ -2698,8 +2724,17 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) if OnRoad then -- Path on road (only first and last points) - local _first=cpini:GetClosestPointToRoad() - local _last=ToCoord:GetClosestPointToRoad() + --local _first=cpini:GetClosestPointToRoad() + --local _last=ToCoord:GetClosestPointToRoad() + + local _pathonroad=cpini:GetPathOnRoad(ToCoord) + local _first=_pathonroad[1] + local _last=_pathonroad[#_pathonroad] + + if self.Debug then + _first:SmokeBlue() + _last:SmokeBlue() + end -- First point on road. path[#path+1]=_first:WaypointGround(Speed, "On Road") @@ -2715,6 +2750,10 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) path[#path+1]=ToCoord:WaypointGround(Speed, formation) task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, true) + if self.Debug then + cpini:SmokeBlue() + ToCoord:SmokeBlue() + end -- Init waypoints of the group. local Waypoints={} From 403f22bd2b1d82bc14110bcc814521f585ab8f37 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 9 Jun 2018 18:33:20 +0200 Subject: [PATCH 165/170] ARTY v0.9.95 Reworked rearming behavior for selected weapons. Many other improvements. --- .../Moose/Functional/Artillery.lua | 519 +++++++++++------- 1 file changed, 319 insertions(+), 200 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index fde0f379c..aa9a043c2 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -354,8 +354,8 @@ -- -- * @{#ARTY.SetAutomaticRelocate}(*maxdist*, *onroad*) lets the ARTY group automatically move to within firing range if a current target is outside the min/max firing range. The -- optional parameter *maxdist* is the maximum distance im km the group will move. If the distance is greater no relocation is performed. Default is 50 km. --- * @{#ARTY.SetRelocateAfterEngagement}() will cause the ARTY group to change its position after each firing assignment. --- * @{#ARTY.SetRelocateDistance}(*rmax*, *rmin*) sets the max/min distance for relocation of the group. Default distance is randomly between 300 and 800 m. +-- * @{#ARTY.SetRelocateAfterEngagement}(*rmax*, *rmin*) will cause the ARTY group to change its position after each firing assignment. +-- Optional parameters *rmax*, *rmin* define the max/min distance for relocation of the group. Default distance is randomly between 300 and 800 m. -- * @{#ARTY.RemoveAllTargets}() removes all targets from the target queue. -- * @{#ARTY.RemoveTarget}(*name*) deletes the target with *name* from the target queue. -- * @{#ARTY.SetMaxFiringRange}(*range*) defines the maximum firing range. Targets further away than this distance are not engaged. @@ -563,7 +563,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.94" +ARTY.version="0.9.95" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -811,18 +811,15 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) -- Default is current time if no time was specified. time=time or self:_SecondsToClock(timer.getAbsTime()) - - -- Get max speed of group. - local speedmax=self.Controllable:GetSpeedMax() - + -- Set speed. if speed then - -- Make sure, given speed is less than max phycially possible speed of group. - speed=math.min(speed, speedmax) + -- Make sure, given speed is less than max physiaclly possible speed of group. + speed=math.min(speed, self.SpeedMax) elseif self.Speed then - speed=self.Speed + speed=self.Speed else - speed=speedmax*0.7 + speed=self.SpeedMax*0.7 end -- Default is off road. @@ -1096,19 +1093,10 @@ end --- Set relocate after firing. Group will find a new location after each engagement. Default is off -- @param #ARTY self --- @param #number switch (Optional) If true, activate relocation. If false, deactivate relocation. -function ARTY:SetRelocateAfterEngagement(switch) - if switch==nil then - switch=true - end - self.relocateafterfire=switch -end - ---- Set relocation distance. --- @param #ARTY self -- @param #number rmax (Optional) Max distance in meters, the group will move to relocate. Default is 800 m. -- @param #number rmin (Optional) Min distance in meters, the group will move to relocate. Default is 300 m. -function ARTY:SetRelocateDistance(rmax, rmin) +function ARTY:SetRelocateAfterEngagement(rmax, rmin) + self.relocateafterfire=true self.relocateRmax=rmax or 800 self.relocateRmin=rmin or 300 end @@ -1221,6 +1209,10 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do text=text..string.format("- %s\n", self:_TargetInfo(target)) + local possible=self:_CheckWeaponTypePossible(target) + if not possible then + self:E(ARTY.id..string.format("WARNING: Selected weapon type %s is not possible", self:_WeaponTypeName(target.weapontype))) + end if self.Debug then local zone=ZONE_RADIUS:New(target.name, target.coord:GetVec2(), target.radius) zone:BoundZone(180, coalition.side.NEUTRAL) @@ -1414,46 +1406,55 @@ function ARTY:_OnEventShot(EventData) -- Get current ammo. local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() - -- Decrease available nukes. + -- Decrease available nukes because we just fired one. if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes then self.Nukes=self.Nukes-1 end + -- Check if we are completely out of ammo. local _outofammo=false - if _nammo==0 then + if _nammo==0 then self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) _outofammo=true end + -- Check if we are out of ammo of the weapon type used for this target. + -- Note that should not happen because we only open fire with the available number of shots. + local _partlyoutofammo=self:_CheckOutOfAmmo({self.currentTarget}) + -- Weapon type name for current target. local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.Controllable:GetName(), _nammo, _nshells, _nrockets, _nmissiles)) self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) - -- Check if number of shots reached max. + local _ceasefire=false local _relocate=false + + -- Check if number of shots reached max. if self.Nshots >= self.currentTarget.nshells then + + -- Debug message local text=string.format("Group %s stop firing on target %s.", self.Controllable:GetName(), self.currentTarget.name) self:T(ARTY.id..text) MESSAGE:New(text, 5):ToAllIf(self.Debug) -- Cease fire. _ceasefire=true - - if self.relocateafterfire then - _relocate=true - end + + -- Relocate if enabled. + _relocate=self.relocateafterfire end - -- Check if we are partly out of ammo. - -- TODO: move this to status. - local _partlyoutofammo=self:_CheckOutOfAmmo() - -- Check if we are (partly) out of ammo. if _outofammo or _partlyoutofammo then _ceasefire=true - end + end + + -- Relocate position. + if _relocate then + self:_Relocate() + end -- Cease fire on current target. if _ceasefire then @@ -1462,26 +1463,22 @@ function ARTY:_OnEventShot(EventData) -- Group is out of ammo (or partly and can rearm) ==> Winchester (==> Rearm). if _outofammo or (_partlyoutofammo and self.RearmingGroup ~=nil) then - self:Winchester() - return + --self:Winchester() + --return end - -- Relocate position - if _relocate then - self:_Relocate() - end - else - self:E(ARTY.id..string.format("ERROR: No current target for group %s?!", self.Controllable:GetName())) + self:E(ARTY.id..string.format("WARNING: No current target for group %s?!", self.Controllable:GetName())) end end end end ---- Check if group is (partly) out of ammo. +--- Check if group is (partly) out of ammo of a special weapon type. -- @param #ARTY self --- @return @boolean True if any target in the queue requests a weapon type that is null. -function ARTY:_CheckOutOfAmmo() +-- @param #table targets Table of targets. +-- @return @boolean True if any target requests a weapon type that is empty. +function ARTY:_CheckOutOfAmmo(targets) -- Get current ammo. local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() @@ -1489,31 +1486,46 @@ function ARTY:_CheckOutOfAmmo() -- Special weapon type requested ==> Check if corresponding ammo is empty. local _partlyoutofammo=false - for _,Target in pairs(self.targets) do + for _,Target in pairs(targets) do - if Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then + if Target.weapontype==ARTY.WeaponType.Auto and _nammo==0 then + + self:T(ARTY.id..string.format("Group %s, auto weapon requested for target %s but all ammo is empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then - self:T(ARTY.id..string.format("Group %s, cannons requested but shells empty.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s, cannons requested for target %s but shells empty.", self.Controllable:GetName(), Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then - self:T(ARTY.id..string.format("Group %s, tactical nukes requested but nukes empty.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s, tactical nukes requested for target %s but nukes empty.", self.Controllable:GetName(), Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then - self:T(ARTY.id..string.format("Group %s, rockets requested but rockets empty.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s, rockets requested for target %s but rockets empty.", self.Controllable:GetName(), Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - self:T(ARTY.id..string.format("Group %s, unguided weapon requested but shells AND rockets empty.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s, unguided weapon requested for target %s but shells AND rockets empty.", self.Controllable:GetName(), Target.name)) _partlyoutofammo=true - elseif (Target.weapontype==ARTY.WeaponType.GuidedMissile or Target.weapontype==ARTY.WeaponType.CruiseMissile or Target.weapontype==ARTY.WeaponType.AntiShipMissile) and _nmissiles==0 then + elseif Target.weapontype==ARTY.WeaponType.GuidedMissile and _nmissiles==0 then - self:T(ARTY.id..string.format("Group %s, guided, anti-ship or cruise missiles requested but all missiles empty.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s, guided missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then + + self:T(ARTY.id..string.format("Group %s, cruise missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.AntiShipMissile and _nmissiles==0 then + + self:T(ARTY.id..string.format("Group %s, anti-ship missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) _partlyoutofammo=true end @@ -1614,16 +1626,22 @@ function ARTY:_OnEventMarkRemove(Event) -- This should be the unique name of the target or move. if _cancelmove then if self.currentMove and self.currentMove.name==_name then + -- We do clear tasks here because in Arrived() it can cause a CTD if the group did actually arrive! self.Controllable:ClearTasks() + -- Current move is removed here. In contrast to RemoveTarget() there are is no maxengage parameter. self:Arrived() else + -- Remove move from queue self:RemoveMove(_name) end elseif _canceltarget then if self.currentTarget and self.currentTarget.name==_name then + -- Cease fire. self:CeaseFire(self.currentTarget) + -- We still need to remove the target, because there might be more planned engagements (maxengage>1). self:RemoveTarget(_name) else + -- Remove target from queue self:RemoveTarget(_name) end end @@ -1852,13 +1870,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To) self:_StatusReport() end - -- Group is out of ammo. - if self:is("OutOfAmmo") then - self:T2(ARTY.id..string.format("%s: OutOfAmmo. ==> Rearm", Controllable:GetName())) - self:Rearm() - end - - -- Group is out of moving. + -- Group on the move. if self:is("Moving") then self:T2(ARTY.id..string.format("%s: Moving", Controllable:GetName())) end @@ -1895,10 +1907,23 @@ function ARTY:onafterStatus(Controllable, From, Event, To) self:_CheckShootingStarted() end - -- Check if targets are in range and update target.inrange value. self:_CheckTargetsInRange() + -- Check if selected weapon type for target is possible at all. E.g. request rockets for Paladin. + local notpossible={} + for i=1,#self.targets do + local _target=self.targets[i] + local possible=self:_CheckWeaponTypePossible(_target) + if not possible then + table.insert(notpossible, _target.name) + end + end + for _,targetname in pairs(notpossible) do + self:E(ARTY.id..string.format("%s: Removing target %s because requested weapon is not possible with this type of unit.", self.Controllable:GetName(), targetname)) + self:RemoveTarget(targetname) + end + -- Get a valid timed target if it is due to be attacked. local _timedTarget=self:_CheckTimedTargets() @@ -1908,36 +1933,55 @@ function ARTY:onafterStatus(Controllable, From, Event, To) -- Get a commaned move to another location. local _move=self:_CheckMoves() - if (self:is("CombatReady") or self:is("Firing")) and _move then - -- Group is combat ready or firing but we have a move. - self:T2(ARTY.id..string.format("%s: CombatReady/Firing ==> Move", Controllable:GetName())) + if _move then -- Command to move. - self.currentMove=_move - self:Move(_move.coord, _move.speed, _move.onroad) + self:Move(_move) - elseif self:is("CombatReady") or (self:is("Firing") and _timedTarget) then - -- Group is combat ready or firing but we have a high prio timed target. - self:T2(ARTY.id..string.format("%s: CombatReady or Firing+Timed Target ==> OpenFire", Controllable:GetName())) + elseif _timedTarget then - -- Engage target. - if _timedTarget then - - -- Cease fire on current target first. - if self.currentTarget then - self:CeaseFire(self.currentTarget) - end - - -- Open fire on timed target. - self:OpenFire(_timedTarget) - - elseif _normalTarget then - - -- Open fire on normal target. - self:OpenFire(_normalTarget) - + -- Cease fire on current target first. + if self.currentTarget then + self:CeaseFire(self.currentTarget) end + + -- Open fire on timed target. + self:OpenFire(_timedTarget) + + elseif _normalTarget then + + -- Open fire on normal target. + self:OpenFire(_normalTarget) + end + + -- Get ammo. + local nammo, nshells, nrockets, nmissiles=self:GetAmmo() + + -- Check if we have a target in the queue for which weapons are still available. + local gotsome=false + if #self.targets>0 then + for i=1,#self.targets do + local _target=self.targets[i] + if self:_CheckWeaponTypeAvailable(_target)>0 then + gotsome=true + end + end + else + -- No targets in the queue. + gotsome=true + end + + -- No ammo available. Either completely blank or only queued targets for ammo which is out. + if (nammo==0 or not gotsome) and not (self:is("Moving") or self:is("Rearming") or self:is("OutOfAmmo")) then + self:Winchester() + end + + -- Group is out of ammo. + if self:is("OutOfAmmo") then + self:T2(ARTY.id..string.format("%s: OutOfAmmo ==> Rearm ==> Rearming", Controllable:GetName())) + self:Rearm() + end -- Call status again in ~10 sec. self:__Status(self.StatusInterval) @@ -1985,33 +2029,16 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) -- Deny transition. return false end - - -- Get ammo. - local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() - local nfire=Nammo - if target.weapontype==ARTY.WeaponType.Auto then - nfire=Nammo - elseif target.weapontype==ARTY.WeaponType.Cannon then - nfire=Nshells - elseif target.weapontype==ARTY.WeaponType.TacticalNukes then - nfire=self.Nukes - elseif target.weapontype==ARTY.WeaponType.Rockets then - nfire=Nrockets - elseif target.weapontype==ARTY.WeaponType.UnguidedAny then - nfire=Nshells+Nrockets - elseif target.weapontype==ARTY.WeaponType.GuidedMissile then - nfire=Nmissiles - elseif target.weapontype==ARTY.WeaponType.CruiseMissile then - nfire=Nmissiles - elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then - nfire=Nmissiles - end + + -- Get the number of available shells, rockets or missiles requested for this target. + local nfire=self:_CheckWeaponTypeAvailable(target) -- Adjust if less than requested ammo is left. target.nshells=math.min(target.nshells, nfire) -- No ammo left ==> deny transition. if target.nshells<1 then + local text=string.format("%s, no ammo left to engage target %s with selected weapon type %s.") return false end @@ -2237,8 +2264,7 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Route ARTY group to rearming place. if dA > self.RearmingDistance then local _tocoord=self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2) - self:AssignMoveCoord(_tocoord, nil, self.Speed, self.RearmingArtyOnRoad, false, "Relocate to rearming place", true) - --self:Move(, self.Speed, self.RearmingArtyOnRoad) + self:AssignMoveCoord(_tocoord, nil, nil, self.RearmingArtyOnRoad, false, "REARMING MOVE TO REARMING PLACE", true) end -- Route Rearming group to rearming place. @@ -2280,7 +2306,7 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Route ARTY group to rearming place. if dA > self.RearmingDistance then local _tocoord=self:_VicinityCoord(self.RearmingPlaceCoord) - self:AssignMoveCoord(_tocoord, nil, self.Speed, self.RearmingArtyOnRoad, false, "Relocate to rearming place", true) + self:AssignMoveCoord(_tocoord, nil, nil, self.RearmingArtyOnRoad, false, "REARMING MOVE TO REARMING PLACE", true) end end @@ -2307,10 +2333,9 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) self.Nukes=self.Nukes0 -- Route ARTY group back to where it came from (if distance is > 100 m). - local d1=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) - if d1 > self.RearmingDistance then - --self:Move(self.InitialCoord, self.Speed, self.RearmingArtyOnRoad) - self:AssignMoveCoord(self.InitialCoord, nil, self.Speed, self.RearmingArtyOnRoad, false, "After rearm back to initial pos", true) + local dist=self.Controllable:GetCoordinate():Get2DDistance(self.InitialCoord) + if dist > self.RearmingDistance then + self:AssignMoveCoord(self.InitialCoord, nil, nil, self.RearmingArtyOnRoad, false, "REARMING MOVE REARMING COMPLETE", true) end -- Route unit back to where it came from (if distance is > 100 m). @@ -2352,7 +2377,7 @@ function ARTY:_CheckRearmed() MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) end - -- Return if ammo is full. + -- Return if ammo is full. Strangely, I got the case that a Paladin got one more shell than it can max carry, i.e. 40 not 39 when rearming when it still had some ammo left. if nammo>=self.FullAmmo then return true else @@ -2369,20 +2394,27 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. +-- @param #table move Table containing the move parameters. -- @param Core.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. -- @param #boolean OnRoad If true group should move on road mainly. -- @return #boolean If true, proceed to onafterMove. -function ARTY:onbeforeMove(Controllable, From, Event, To, ToCoord, OnRoad) +function ARTY:onbeforeMove(Controllable, From, Event, To, move) self:_EventFromTo("onbeforeMove", Event, From, To) -- Check if group can actually move... - if self.SpeedMax==0 then + if self.SpeedMax<1 then return false end - -- Cease fire first. + -- Check if group is engaging. if self.currentTarget then - self:CeaseFire(self.currentTarget) + if move.cancel then + -- Cancel current target. + self:CeaseFire(self.currentTarget) + else + -- We should not cancel. + return false + end end return true @@ -2394,10 +2426,8 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param Core.Point#COORDINATE ToCoord Coordinate to which the ARTY group should move. --- @param #number Speed Speed in km/h at which the grou p should move. --- @param #boolean OnRoad If true group should move on road mainly. -function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, Speed, OnRoad) +-- @param #table move Table containing the move parameters. +function ARTY:onafterMove(Controllable, From, Event, To, move) self:_EventFromTo("onafterMove", Event, From, To) -- Set alarm state to green and ROE to weapon hold. @@ -2405,15 +2435,18 @@ function ARTY:onafterMove(Controllable, From, Event, To, ToCoord, Speed, OnRoad) self.Controllable:OptionROEHoldFire() -- Take care of max speed. - local _Speed=math.min(Speed, self.SpeedMax) + local _Speed=math.min(move.speed, self.SpeedMax) -- Smoke coordinate if self.Debug then - ToCoord:SmokeRed() + move.coord:SmokeRed() end + + -- Set current move. + self.currentMove=move -- Route group to coodinate. - self:_Move(self.Controllable, ToCoord, _Speed, OnRoad) + self:_Move(self.Controllable, move.coord, move.speed, move.onroad) end @@ -2454,7 +2487,6 @@ end -- @param #string Event Event. -- @param #string To To state. -- @param #table target Array holding the target parameters. --- @return #boolean If true, proceed to onafterOpenfire. function ARTY:onafterNewTarget(Controllable, From, Event, To, target) self:_EventFromTo("onafterNewTarget", Event, From, To) @@ -2471,7 +2503,6 @@ end -- @param #string Event Event. -- @param #string To To state. -- @param #table move Array holding the move parameters. --- @return #boolean If true, proceed to onafterOpenfire. function ARTY:onafterNewMove(Controllable, From, Event, To, move) self:_EventFromTo("onafterNewTarget", Event, From, To) @@ -2688,6 +2719,7 @@ end -- @param #number Speed (Optional) Speed in km/h. Default is 70% of max speed the group can do. -- @param #boolean OnRoad If true, use (mainly) roads. function ARTY:_Move(group, ToCoord, Speed, OnRoad) + self:F2({group=group:GetName(), Speed=Speed, OnRoad=OnRoad}) -- Clear all tasks. group:ClearTasks() @@ -2722,28 +2754,31 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Route group on road if requested. if OnRoad then - - -- Path on road (only first and last points) - --local _first=cpini:GetClosestPointToRoad() - --local _last=ToCoord:GetClosestPointToRoad() + -- Get path on road. local _pathonroad=cpini:GetPathOnRoad(ToCoord) - local _first=_pathonroad[1] - local _last=_pathonroad[#_pathonroad] + + -- Check if we actually got a path. There are situations where nil is returned. In that case, we go directly. + if _pathonroad then + + -- Just take the first and last point. + local _first=_pathonroad[1] + local _last=_pathonroad[#_pathonroad] - if self.Debug then - _first:SmokeBlue() - _last:SmokeBlue() + if self.Debug then + _first:SmokeGreen() + _last:SmokeGreen() + end + + -- First point on road. + path[#path+1]=_first:WaypointGround(Speed, "On Road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + -- Last point on road. + path[#path+1]=_last:WaypointGround(Speed, "On Road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) end - -- First point on road. - path[#path+1]=_first:WaypointGround(Speed, "On Road") - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - - -- Last point on road. - path[#path+1]=_last:WaypointGround(Speed, "On Road") - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - end -- Last waypoint at ToCoord. @@ -2828,7 +2863,7 @@ function ARTY:_Relocate() -- Assign relocation. if _gotit then - self:AssignMoveCoord(_new, nil, nil, false, false) + self:AssignMoveCoord(_new, nil, nil, false, false, "RELOCATION MOVE AFTER FIRING") end end @@ -2901,30 +2936,13 @@ function ARTY:GetAmmo(display) MissileCategory=ammotable[w].desc.missileCategory end - local function missilecat(n) - local cat="unknown" - if n==1 then - cat="air-to-air" - elseif n==2 then - cat="surface-to-air" - elseif n==3 then - cat="ballistic" - elseif n==4 then - cat="anti-ship" - elseif n==5 then - cat="cruise" - elseif n==6 then - cat="other" - end - return cat - end -- Check for correct shell type. local _gotshell=false if #self.ammoshells>0 then -- User explicitly specified the valid type(s) of shells. for _,_type in pairs(self.ammoshells) do - if string.match(Tammo, _type) then + if string.match(Tammo, _type) and Category==Weapon.Category.SHELL then _gotshell=true end end @@ -2938,7 +2956,7 @@ function ARTY:GetAmmo(display) local _gotrocket=false if #self.ammorockets>0 then for _,_type in pairs(self.ammorockets) do - if string.match(Tammo, _type) then + if string.match(Tammo, _type) and Category==Weapon.Category.ROCKET then _gotrocket=true end end @@ -2952,7 +2970,7 @@ function ARTY:GetAmmo(display) local _gotmissile=false if #self.ammomissiles>0 then for _,_type in pairs(self.ammomissiles) do - if string.match(Tammo,_type) then + if string.match(Tammo,_type) and Category==Weapon.Category.MISSILE then _gotmissile=true end end @@ -2982,12 +3000,12 @@ function ARTY:GetAmmo(display) elseif _gotmissile then -- Add up all cruise missiles (category 5) - if MissileCategory==5 then + if MissileCategory==Weapon.MissileCategory.CRUISE then nmissiles=nmissiles+Nammo end -- Debug info. - text=text..string.format("- %d %s missiles of type %s\n", Nammo, missilecat(MissileCategory), Tammo) + text=text..string.format("- %d %s missiles of type %s\n", Nammo, self:_MissileCategoryName(MissileCategory), Tammo) else @@ -3016,6 +3034,29 @@ function ARTY:GetAmmo(display) return nammo, nshells, nrockets, nmissiles end +--- Returns a name of a missile category. +-- @param #ARTY self +-- @param #number categorynumber Number of missile category from weapon missile category enumerator. See https://wiki.hoggitworld.com/view/DCS_Class_Weapon +-- @return #string Missile category name. +function ARTY:_MissileCategoryName(categorynumber) + local cat="unknown" + if categorynumber==Weapon.MissileCategory.AAM then + cat="air-to-air" + elseif categorynumber==Weapon.MissileCategory.SAM then + cat="surface-to-air" + elseif categorynumber==Weapon.MissileCategory.BM then + cat="ballistic" + elseif categorynumber==Weapon.MissileCategory.ANTI_SHIP then + cat="anti-ship" + elseif categorynumber==Weapon.MissileCategory.CRUISE then + cat="cruise" + elseif categorynumber==Weapon.MissileCategory.OTHER then + cat="other" + end + return cat +end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Mark Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3111,6 +3152,7 @@ function ARTY:_Markertext(text) for _,key in pairs(keywords) do + -- Split keyphrase by space. First one is the key and second, ... the parameter(s) until the next comma. local s=self:_split(key, " ") local val=s[2] @@ -3516,6 +3558,40 @@ function ARTY:_CheckTargetsInRange() end end +--- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. +-- @param #ARTY self +-- @return #table Target which is due to be attacked now or nil if no target could be found. +function ARTY:_CheckNormalTargets() + self:F3() + + -- Sort targets w.r.t. prio and number times engaged already. + self:_SortTargetQueuePrio() + + -- No target engagements if rearming! + if self:is("Rearming") then + return nil + end + + -- Loop over all sorted targets. + for i=1,#self.targets do + local _target=self.targets[i] + + -- Debug info. + self:T3(ARTY.id..string.format("Check NORMAL target %d: %s", i, self:_TargetInfo(_target))) + + -- Check that target no time, is not under fire currently and in range. + if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) and self:_CheckWeaponTypeAvailable(_target)>0 then + + -- Debug info. + self:T2(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) + + return _target + end + end + + return nil +end + --- Check all timed targets and return the target which should be attacked next. -- @param #ARTY self -- @return #table Target which is due to be attacked now. @@ -3528,6 +3604,11 @@ function ARTY:_CheckTimedTargets() -- Sort Targets wrt time. self:_SortQueueTime(self.targets) + -- No target engagements if rearming! + if self:is("Rearming") then + return nil + end + for i=1,#self.targets do local _target=self.targets[i] @@ -3535,7 +3616,7 @@ function ARTY:_CheckTimedTargets() self:T3(ARTY.id..string.format("Check TIMED target %d: %s", i, self:_TargetInfo(_target))) -- Check if target has an attack time which has already passed. Also check that target is not under fire already and that it is in range. - if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) then + if _target.time and Tnow>=_target.time and _target.underfire==false and self:_TargetInRange(_target) and self:_CheckWeaponTypeAvailable(_target)>0 then -- Check if group currently has a target and whether its priorty is lower than the timed target. if self.currentTarget then @@ -3550,6 +3631,7 @@ function ARTY:_CheckTimedTargets() return _target end end + end return nil @@ -3572,12 +3654,18 @@ function ARTY:_CheckMoves() if self.currentTarget then firing=true end - + + -- Loop over all moves in queue. for i=1,#self.moves do + + -- Shortcut. local _move=self.moves[i] - -- Check if time for move is reached. - if Tnow >= _move.time and (firing==false or _move.cancel) then + if string.find(_move.name, "REARMING MOVE") and ((self.currentMove and self.currentMove.name~=_move.name) or self.currentMove==nil) then + -- We got an rearming assignment which has priority. + return _move + elseif (Tnow >= _move.time) and (firing==false or _move.cancel) and (not self.currentMove) and (not self:is("Rearming")) then + -- Time for move is reached and maybe current target should be cancelled. return _move end end @@ -3585,35 +3673,6 @@ function ARTY:_CheckMoves() return nil end ---- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. --- @param #ARTY self --- @return #table Target which is due to be attacked now or nil if no target could be found. -function ARTY:_CheckNormalTargets() - self:F3() - - -- Sort targets w.r.t. prio and number times engaged already. - self:_SortTargetQueuePrio() - - -- Loop over all sorted targets. - for i=1,#self.targets do - local _target=self.targets[i] - - -- Debug info. - self:T3(ARTY.id..string.format("Check NORMAL target %d: %s", i, self:_TargetInfo(_target))) - - -- Check that target no time, is not under fire currently and in range. - if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged and self:_TargetInRange(_target) then - - -- Debug info. - self:T2(ARTY.id..string.format("Found NORMAL target %s", self:_TargetInfo(_target))) - - return _target - end - end - - return nil -end - --- Check whether shooting started within a certain time (~5 min). If not, the current target is considered invalid and removed from the target list. -- @param #ARTY self function ARTY:_CheckShootingStarted() @@ -3691,6 +3750,66 @@ function ARTY:_GetMoveIndexByName(name) return nil end +--- Check if a selected weapon type is available for this target, i.e. if the current amount of ammo of this weapon type is currently available. +-- @param #ARTY self +-- @param #boolean target Target array data structure. +-- @return #number Amount of shells, rockets or missiles available of the weapon type selected for the target. +function ARTY:_CheckWeaponTypeAvailable(target) + + -- Get current ammo of group. + local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo() + + -- Check if enough ammo is there for the selected weapon type. + local nfire=Nammo + if target.weapontype==ARTY.WeaponType.Auto then + nfire=Nammo + elseif target.weapontype==ARTY.WeaponType.Cannon then + nfire=Nshells + elseif target.weapontype==ARTY.WeaponType.TacticalNukes then + nfire=self.Nukes + elseif target.weapontype==ARTY.WeaponType.Rockets then + nfire=Nrockets + elseif target.weapontype==ARTY.WeaponType.UnguidedAny then + nfire=Nshells+Nrockets + elseif target.weapontype==ARTY.WeaponType.GuidedMissile then + nfire=Nmissiles + elseif target.weapontype==ARTY.WeaponType.CruiseMissile then + nfire=Nmissiles + elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then + nfire=Nmissiles + end + + return nfire +end +--- Check if a selected weapon type is in principle possible for this group. The current amount of ammo might be zero but the group still can be rearmed at a later point in time. +-- @param #ARTY self +-- @param #boolean target Target array data structure. +-- @return #boolean True if the group can carry this weapon type, false otherwise. +function ARTY:_CheckWeaponTypePossible(target) + + -- Check if enough ammo is there for the selected weapon type. + local possible=false + if target.weapontype==ARTY.WeaponType.Auto then + possible=self.Nammo0>0 + elseif target.weapontype==ARTY.WeaponType.Cannon then + possible=self.Nshells0>0 + elseif target.weapontype==ARTY.WeaponType.TacticalNukes then + possible=self.Nukes0>0 + elseif target.weapontype==ARTY.WeaponType.Rockets then + possible=self.Nrockets0>0 + elseif target.weapontype==ARTY.WeaponType.UnguidedAny then + possible=self.Nshells0+self.Nrockets0>0 + elseif target.weapontype==ARTY.WeaponType.GuidedMissile then + possible=self.Nmissiles0>0 + elseif target.weapontype==ARTY.WeaponType.CruiseMissile then + possible=self.Nmissiles0>0 + elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then + possible=self.Nmissiles0>0 + end + + return possible +end + --- Check if a name is unique. If not, a new unique name can be created by adding a running index #01, #02, ... -- @param #ARTY self -- @param #table givennames Table with entries of already given names. Must contain a .name item. From e8ff1534273d35d9f8689af8d4c53339d288476b Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 10 Jun 2018 00:05:55 +0200 Subject: [PATCH 166/170] ARTY v0.9.96 Improved marker logic. --- .../Moose/Functional/Artillery.lua | 366 +++++++++--------- 1 file changed, 191 insertions(+), 175 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index aa9a043c2..27e1a2d6a 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -55,7 +55,6 @@ -- @field #number Nrockets0 Initial amount of rockets of the whole group. -- @field #number Nmissiles0 Initial amount of missiles of the whole group. -- @field #number Nukes0 Initial amount of tactical nukes of the whole group. Default is 0. --- @field #number FullAmmo Full amount of all ammunition taking the number of alive units into account. -- @field #number StatusInterval Update interval in seconds between status updates. Default 10 seconds. -- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted. Default is 300 seconds. -- @field #table DCSdesc DCS descriptors of the ARTY group. @@ -63,6 +62,8 @@ -- @field #string DisplayName Extended type name of the ARTY group. -- @field #number IniGroupStrength Inital number of units in the ARTY group. -- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". This is automatically derived from the DCS descriptor table. +-- @field #boolean ismobile If true, ARTY group can move. +-- @field #string alias Name of the ARTY group. -- @field #number SpeedMax Maximum speed of ARTY group in km/h. This is determined from the DCS descriptor table. -- @field #number Speed Default speed in km/h the ARTY group moves at. Maximum speed possible is 80% of maximum speed the group can do. -- @field #number RearmingDistance Safe distance in meters between ARTY group and rearming group or place at which rearming is possible. Default 100 m. @@ -221,8 +222,6 @@ -- * @{#ARTY.WeaponType}.Auto: Automatic weapon selection by the DCS logic. This is the default setting. -- * @{#ARTY.WeaponType}.Cannon: Only cannons are used during the attack. Corresponding ammo type are shells and can be defined by @{#ARTY.SetShellTypes}. -- * @{#ARTY.WeaponType}.Rockets: Only unguided are used during the attack. Corresponding ammo type are rockets/nurs and can be defined by @{#ARTY.SetRocketTypes}. --- * @{#ARTY.WeaponType}.UnguidedAny: Any unguided weapon (cannons or rockes) will be used. --- * @{#ARTY.WeaponType}.GuidedMissile: Any guided missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. -- * @{#ARTY.WeaponType}.CruiseMissile: Only cruise missiles are used during the attack. Corresponding ammo type are missiles and can be defined by @{#ARTY.SetMissileTypes}. -- * @{#ARTY.WeaponType}.TacticalNukes: Use tactical nuclear shells. This works only with units that have shells and is described below. -- @@ -294,6 +293,8 @@ -- * *weapon* Type of weapon to be used. Valid parameters are *cannon*, *rocket*, *missile*, *nuke*. Default is automatic selection. -- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition. -- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. +-- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant here. The group will engage the coordinates given in the lldms keyword. +-- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below. This can be useful when coordinates in this format are obtained from elsewhere. -- * *readonly* The marker is readonly and cannot be deleted by users. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are examples of valid marker texts: @@ -302,6 +303,7 @@ -- arty engage, battery "Blue Paladin 1" "Blue MRLS 1", shots 10, time 10:15 -- arty engage, battery "Blue MRLS 1", key 666 -- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15 +-- arty engage, lldms 41:51:00N 41:47:58E -- -- Note that the keywords and parameters are *case insensitve*. Only exception are the battery group names. These must be exactly the same as the names of the goups defined -- in the mission editor. @@ -316,6 +318,8 @@ -- * *canceltarget* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over. -- * *battery* Name of the ARTY group that the relocation is assigned to. -- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. +-- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant. The group will move to the coordinates given in the lldms keyword. +-- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below. -- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are some examples: @@ -323,18 +327,9 @@ -- arty move, time 23:45, speed 50, on road -- arty move, battery "Blue Paladin" -- arty move, battery "Blue MRLS", canceltarget, speed 10, on road +-- arty move, lldms 41:51:00N 41:47:58E -- --- ### Coordinate Independent Commands --- --- There are a couple of commands, which are independent of the position where the marker is placed. --- These commands are --- arty move, cancelcurrent --- which will cancel the current relocation movement. Of course, this can be combined with the *battery* keyword to address a certain battery. --- Same goes for targets, e.g. --- arty engage, battery "Paladin Alpha", cancelcurrent --- which will cancel all running firing tasks. --- --- ### General Requests +-- ### Requests -- -- Marks can also be to send requests to the ARTY group. This is done by the keyword **arty request**, which can have the keywords -- @@ -347,6 +342,17 @@ -- arty request, battery "Paladin Bravo", targets -- arty request, battery "MRLS Charly", move -- +-- The actual location of the marker is irrelevant for these requests. +-- +-- ### Cancel +-- +-- Current actions can be cancelled by the keyword **arty cancel**. Actions that can be cancelled are current engagements, relocations and rearming assignments. +-- +-- For example +-- arty cancel, target, battery "Paladin Bravo" +-- arty cancel, move +-- arty cancel, rearming, battery "MRLS Charly" +-- -- -- ## Fine Tuning -- @@ -444,13 +450,13 @@ ARTY={ Nrockets0=0, Nmissiles0=0, Nukes0=0, - FullAmmo=0, - defaultROE="weapon_hold", StatusInterval=10, WaitForShotTime=300, DCSdesc=nil, Type=nil, DisplayName=nil, + alias=nil, + ismobile=true, IniGroupStrength=0, IsArtillery=nil, RearmingDistance=100, @@ -490,10 +496,10 @@ ARTY.WeaponType={ Auto=1073741822, Cannon=805306368, Rockets=30720, - UnguidedAny=805339120, - GuidedMissile=268402688, + --UnguidedAny=805339120, + --GuidedMissile=268402688, CruiseMissile=2097152, - AntiShipMissile=65536, + --AntiShipMissile=65536, TacticalNukes=666, } @@ -563,7 +569,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.95" +ARTY.version="0.9.96" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -596,9 +602,9 @@ ARTY.version="0.9.95" --- Creates a new ARTY object. -- @param #ARTY self -- @param Wrapper.Group#GROUP group The GROUP object for which artillery tasks should be assigned. --- @return #ARTY ARTY object. --- @return nil If group does not exist or is not a ground or naval group. -function ARTY:New(group) +-- @param alias (Optional) Alias name the group will be calling itself when sending messages. +-- @return #ARTY ARTY object or nil if group does not exist or is not a ground or naval group. +function ARTY:New(group, alias) BASE:F2(group) -- Inherits from FSM_CONTROLLABLE @@ -616,11 +622,17 @@ function ARTY:New(group) if group:IsGround()==false and group:IsShip()==false then self:E(ARTY.id..string.format("ERROR: ARTY group %s has to be a GROUND or SHIP group!", group:GetName())) return nil - end + end -- Set the controllable for the FSM. self:SetControllable(group) + if alias~=nil then + self.alias=tostring(alias) + else + self.alias=group:GetName() + end + -- Set the initial coordinates of the ARTY group. self.InitialCoord=group:GetCoordinate() @@ -628,9 +640,7 @@ function ARTY:New(group) local DCSgroup=Group.getByName(group:GetName()) local DCSunit=DCSgroup:getUnit(1) self.DCSdesc=DCSunit:getDesc() - - --self.DCSdesc=group:GetDesc() - + -- DCS descriptors. self:T3(ARTY.id.."DCS descriptors for group "..group:GetName()) for id,desc in pairs(self.DCSdesc) do @@ -640,6 +650,13 @@ function ARTY:New(group) -- Maximum speed in km/h. self.SpeedMax=group:GetSpeedMax() + -- Group is mobile or not (e.g. mortars). + if self.SpeedMax>1 then + self.ismobile=true + else + self.ismobile=false + end + -- Set speed to 0.7 of maximum. self.Speed=self.SpeedMax * 0.7 @@ -790,6 +807,12 @@ end -- @return #string Name of the move. Can be used for further reference, e.g. deleting the move from the list. function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) self:F({coord=coord, time=time, speed=speed, onroad=onroad, cancel=cancel, name=name, unique=unique}) + + -- Reject move if the group is immobile. + if not self.ismobile then + self:T(ARTY.id..string.format("%s: group is immobile. Rejecting move request!", self.Controllable:GetName())) + return nil + end -- Default if unique==nil then @@ -1165,6 +1188,13 @@ function ARTY:onafterStart(Controllable, From, Event, To) end end + -- Some mobility consitency checks if group cannot move. + if not self.ismobile then + self.RearmingPlaceCoord=nil + self.relocateafterfire=false + self.autorelocate=false + end + local text=string.format("\n******************************************************\n") text=text..string.format("Arty group = %s\n", Controllable:GetName()) text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery)) @@ -1173,6 +1203,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Number of units = %d\n", self.IniGroupStrength) text=text..string.format("Speed max = %d km/h\n", self.SpeedMax) text=text..string.format("Speed default = %d km/h\n", self.Speed) + text=text..string.format("Is mobile = %s\n", tostring(self.ismobile)) text=text..string.format("Min range = %.1f km\n", self.minrange/1000) text=text..string.format("Max range = %.1f km\n", self.maxrange/1000) text=text..string.format("Total ammo count = %d\n", self.Nammo0) @@ -1358,7 +1389,7 @@ function ARTY:_OnEventShot(EventData) self.Nshots=self.Nshots+1 -- Debug output. - local text=string.format("%s, fired shot %d of %d with weapon %s on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name) + local text=string.format("%s, fired shot %d of %d with weapon %s on target %s.", self.alias, self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name) self:T(ARTY.id..text) MESSAGE:New(text, 5):Clear():ToAllIf(self.report or self.Debug) @@ -1427,7 +1458,7 @@ function ARTY:_OnEventShot(EventData) self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.Controllable:GetName(), _nammo, _nshells, _nrockets, _nmissiles)) self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) - + -- Default switches for cease fire and relocation. local _ceasefire=false local _relocate=false @@ -1474,66 +1505,6 @@ function ARTY:_OnEventShot(EventData) end end ---- Check if group is (partly) out of ammo of a special weapon type. --- @param #ARTY self --- @param #table targets Table of targets. --- @return @boolean True if any target requests a weapon type that is empty. -function ARTY:_CheckOutOfAmmo(targets) - - -- Get current ammo. - local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() - - -- Special weapon type requested ==> Check if corresponding ammo is empty. - local _partlyoutofammo=false - - for _,Target in pairs(targets) do - - if Target.weapontype==ARTY.WeaponType.Auto and _nammo==0 then - - self:T(ARTY.id..string.format("Group %s, auto weapon requested for target %s but all ammo is empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then - - self:T(ARTY.id..string.format("Group %s, cannons requested for target %s but shells empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then - - self:T(ARTY.id..string.format("Group %s, tactical nukes requested for target %s but nukes empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then - - self:T(ARTY.id..string.format("Group %s, rockets requested for target %s but rockets empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then - - self:T(ARTY.id..string.format("Group %s, unguided weapon requested for target %s but shells AND rockets empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.GuidedMissile and _nmissiles==0 then - - self:T(ARTY.id..string.format("Group %s, guided missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then - - self:T(ARTY.id..string.format("Group %s, cruise missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - elseif Target.weapontype==ARTY.WeaponType.AntiShipMissile and _nmissiles==0 then - - self:T(ARTY.id..string.format("Group %s, anti-ship missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) - _partlyoutofammo=true - - end - - end - - return _partlyoutofammo -end --- After "Start" event. Initialized ROE and alarm state. Starts the event handler. -- @param #ARTY self @@ -1670,7 +1641,7 @@ function ARTY:_OnEventMarkChange(Event) local _assign=self:_Markertext(Event.text) -- Check if ENGAGE or MOVE or REQUEST keywords were found. - if _assign==nil or not (_assign.engage or _assign.move or _assign.request) then + if _assign==nil or not (_assign.engage or _assign.move or _assign.request or _assign.cancel) then return end @@ -1716,13 +1687,20 @@ function ARTY:_OnEventMarkChange(Event) end -- Cancel current target and return. - if _assign.cancelcurrent and _validkey then - if _assign.move and self.currentMove then + if _assign.cancel and _validkey then + if _assign.cancelmove and self.currentMove then self.Controllable:ClearTasks() self:Arrived() - end - if _assign.engage and self.currentTarget then + elseif _assign.canceltarget and self.currentTarget then + self.currentTarget.engaged=self.currentTarget.engaged+1 self:CeaseFire(self.currentTarget) + elseif _assign.cancelrearm and self.is("Rearming") then + local nammo=self:GetAmmo() + if nammo>0 then + self:Rearmed() + else + self:Winchester() + end end return end @@ -1761,7 +1739,7 @@ function ARTY:_OnEventMarkChange(Event) MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) -- Assign a relocation of the arty group. - local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.canceltarget,_name, true) + local _movename=self:AssignMoveCoord(_coord, _assign.time, _assign.speed, _assign.onroad, _assign.movecanceltarget,_name, true) if _movename~=nil then local _mid=self:_GetMoveIndexByName(_movename) @@ -2087,18 +2065,9 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target) elseif target.weapontype==ARTY.WeaponType.Rockets then nfire=Nrockets _type="rockets" - elseif target.weapontype==ARTY.WeaponType.UnguidedAny then - nfire=Nshells+Nrockets - _type="shells or rockets" - elseif target.weapontype==ARTY.WeaponType.GuidedMissile then - nfire=Nmissiles - _type="guided missiles" elseif target.weapontype==ARTY.WeaponType.CruiseMissile then nfire=Nmissiles _type="cruise missiles" - elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then - nfire=Nmissiles - _type="anti-ship missiles" end -- Adjust if less than requested ammo is left. @@ -2165,6 +2134,8 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) -- Clear tasks. self.Controllable:ClearTasks() + else + self:E(ARTY.id.."ERROR: No target in cease fire for group %s.", self.Controllable:GetName()) end -- Set number of shots to zero. @@ -2365,20 +2336,21 @@ function ARTY:_CheckRearmed() end -- Full Ammo count. - self.FullAmmo=self.Nammo0 * nunits / self.IniGroupStrength + local FullAmmo=self.Nammo0 * nunits / self.IniGroupStrength -- Rearming status in per cent. - local _rearmpc=nammo/self.FullAmmo*100 + local _rearmpc=nammo/FullAmmo*100 -- Send message if rearming > 1% complete if _rearmpc>1 then - local text=string.format("%s, rearming %d %% complete. nammo=%d , fullammo=%d", self.Controllable:GetName(), _rearmpc, nammo, self.FullAmmo) + local text=string.format("%s, rearming %d %% complete.", self.alias, _rearmpc) self:T(ARTY.id..text) MESSAGE:New(text, 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) end - -- Return if ammo is full. Strangely, I got the case that a Paladin got one more shell than it can max carry, i.e. 40 not 39 when rearming when it still had some ammo left. - if nammo>=self.FullAmmo then + -- Return if ammo is full. + -- TODO: Strangely, I got the case that a Paladin got one more shell than it can max carry, i.e. 40 not 39 when rearming when it still had some ammo left. Need to report. + if nammo>=FullAmmo then return true else return false @@ -2402,7 +2374,7 @@ function ARTY:onbeforeMove(Controllable, From, Event, To, move) self:_EventFromTo("onbeforeMove", Event, From, To) -- Check if group can actually move... - if self.SpeedMax<1 then + if not self.ismobile then return false end @@ -2528,10 +2500,7 @@ function ARTY:onafterDead(Controllable, From, Event, To) if units~=nil then nunits=#units end - - -- Adjust full ammo count - self.FullAmmo=self.Nammo0*nunits/self.IniGroupStrength - + -- Message. local text=string.format("%s, one of our units just died! %d units left.", self.Controllable:GetName(), nunits) MESSAGE:New(text, 5):ToAllIf(self.Debug) @@ -2785,10 +2754,10 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) path[#path+1]=ToCoord:WaypointGround(Speed, formation) task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, true) - if self.Debug then - cpini:SmokeBlue() - ToCoord:SmokeBlue() - end + --if self.Debug then + -- cpini:SmokeBlue() + -- ToCoord:SmokeBlue() + --end -- Init waypoints of the group. local Waypoints={} @@ -2927,6 +2896,9 @@ function ARTY:GetAmmo(display) -- Typename of current weapon local Tammo=ammotable[w]["desc"]["typeName"] + local _weaponString = self:_split(Tammo,"%.") + local _weaponName = _weaponString[#_weaponString] + -- Get the weapon category: shell=0, missile=1, rocket=2, bomb=3 local Category=ammotable[w].desc.category @@ -2987,7 +2959,7 @@ function ARTY:GetAmmo(display) nshells=nshells+Nammo -- Debug info. - text=text..string.format("- %d shells of type %s\n", Nammo, Tammo) + text=text..string.format("- %d shells of type %s\n", Nammo, _weaponName) elseif _gotrocket then @@ -2995,7 +2967,7 @@ function ARTY:GetAmmo(display) nrockets=nrockets+Nammo -- Debug info. - text=text..string.format("- %d rockets of type %s\n", Nammo, Tammo) + text=text..string.format("- %d rockets of type %s\n", Nammo, _weaponName) elseif _gotmissile then @@ -3005,7 +2977,7 @@ function ARTY:GetAmmo(display) end -- Debug info. - text=text..string.format("- %d %s missiles of type %s\n", Nammo, self:_MissileCategoryName(MissileCategory), Tammo) + text=text..string.format("- %d %s missiles of type %s\n", Nammo, self:_MissileCategoryName(MissileCategory), _weaponName) else @@ -3130,9 +3102,12 @@ function ARTY:_Markertext(text) assignment.move=false assignment.engage=false assignment.request=false + assignment.cancel=false assignment.readonly=false + assignment.movecanceltarget=false + assignment.cancelmove=false assignment.canceltarget=false - assignment.cancelcurrent=false + assignment.cancelrearm=false -- Check for correct keywords. if text:lower():find("arty engage") or text:lower():find("arty attack") then @@ -3140,9 +3115,11 @@ function ARTY:_Markertext(text) elseif text:lower():find("arty move") or text:lower():find("arty relocate") then assignment.move=true elseif text:lower():find("arty request") then - assignment.request=true + assignment.request=true + elseif text:lower():find("arty cancel") then + assignment.cancel=true else - self:E(ARTY.id..'ERROR: Neither "ARTY ENGAGE" nor "ARTY MOVE" nor "ARTY RELOCATE" nor "ARTY REQUEST" keyword specified!') + self:E(ARTY.id..'ERROR: Neither "ARTY ENGAGE" nor "ARTY MOVE" nor "ARTY RELOCATE" nor "ARTY REQUEST" nor "ARTY CANCEL" keyword specified!') return nil end @@ -3150,11 +3127,12 @@ function ARTY:_Markertext(text) local keywords=self:_split(text, ",") self:T({keywords=keywords}) - for _,key in pairs(keywords) do + for _,keyphrase in pairs(keywords) do -- Split keyphrase by space. First one is the key and second, ... the parameter(s) until the next comma. - local s=self:_split(key, " ") - local val=s[2] + local str=self:_split(keyphrase, " ") + local key=str[1] + local val=str[2] -- Battery name, i.e. which ARTY group should fire. if key:lower():find("battery") then @@ -3177,7 +3155,7 @@ function ARTY:_Markertext(text) elseif assignment.engage and key:lower():find("shot") then - assignment.nshells=tonumber(s[2]) + assignment.nshells=tonumber(val) self:T(ARTY.id..string.format("Key Shot=%s.", val)) elseif assignment.engage and key:lower():find("prio") then @@ -3202,7 +3180,7 @@ function ARTY:_Markertext(text) elseif val:lower():find("rocket") then assignment.weapontype=ARTY.WeaponType.Rockets elseif val:lower():find("missile") then - assignment.weapontype=ARTY.WeaponType.GuidedMissile + assignment.weapontype=ARTY.WeaponType.CruiseMissile elseif val:lower():find("nuke") then assignment.weapontype=ARTY.WeaponType.TacticalNukes else @@ -3225,16 +3203,11 @@ function ARTY:_Markertext(text) assignment.readonly=true self:T2(ARTY.id..string.format("Key Readonly=true.")) - elseif assignment.move and key:lower():find("canceltarget") then + elseif assignment.move and (key:lower():find("cancel target") or key:lower():find("cancel target")) then - assignment.canceltarget=true + assignment.movecanceltarget=true self:T2(ARTY.id..string.format("Key Cancel Target (before move)=true.")) - elseif (assignment.engage or assignment.move) and key:lower():find("cancelcurrent") then - - assignment.cancelcurrent=true - self:T2(ARTY.id..string.format("Key Cancel Current=true.")) - elseif assignment.request and key:lower():find("rearm") then assignment.requestrearming=true @@ -3259,20 +3232,35 @@ function ARTY:_Markertext(text) assignment.requestmoves=true self:T2(ARTY.id..string.format("Key Request Moves=true.")) - + + elseif assignment.cancel and (key:lower():find("engagement") or key:lower():find("attack") or key:lower():find("target")) then + + assignment.canceltarget=true + self:T2(ARTY.id..string.format("Key Cancel Target=true.")) + + elseif assignment.cancel and (key:lower():find("move") or key:lower():find("relocation")) then + + assignment.cancelmove=true + self:T2(ARTY.id..string.format("Key Cancel Move=true.")) + + elseif assignment.cancel and key:lower():find("rearm") then + + assignment.cancelrearm=true + self:T2(ARTY.id..string.format("Key Cancel Rearm=true.")) + elseif key:lower():find("lldms") then local _flat = "%d+:%d+:%d+%s*[N,S]" local _flon = "%d+:%d+:%d+%s*[W,E]" - local _lat=key:match(_flat) - local _lon=key:match(_flon) - self:T2(ARTY.id..string.format("Key LLDMS: lat=%s, long=%s", _lat,_lon)) + local _lat=keyphrase:match(_flat) + local _lon=keyphrase:match(_flon) + self:T2(ARTY.id..string.format("Key LLDMS: lat=%s, long=%s format=DMS", _lat,_lon)) if _lat and _lon then -- Convert DMS string to DD numbers format. local _latitude, _longitude=self:_LLDMS2DD(_lat, _lon) - self:T2(ARTY.id..string.format("Key LLDMS: lat=%.3f, long=%.3f", _latitude,_longitude)) + self:T2(ARTY.id..string.format("Key LLDMS: lat=%.3f, long=%.3f format=DD", _latitude,_longitude)) -- Convert LL to coordinate object. if _latitude and _longitude then @@ -3464,11 +3452,11 @@ function ARTY:_CheckTargetsInRange() for i=1,#self.targets do local _target=self.targets[i] - self:T(ARTY.id..string.format("Before: Target %s - in range = %s", _target.name, tostring(_target.inrange))) + self:T3(ARTY.id..string.format("Before: Target %s - in range = %s", _target.name, tostring(_target.inrange))) -- Check if target is in range. local _inrange,_toofar,_tooclose=self:_TargetInRange(_target) - self:T(ARTY.id..string.format("Inbetw: Target %s - in range = %s, toofar = %s, tooclose = %s", _target.name, tostring(_target.inrange), tostring(_toofar), tostring(_tooclose))) + self:T3(ARTY.id..string.format("Inbetw: Target %s - in range = %s, toofar = %s, tooclose = %s", _target.name, tostring(_target.inrange), tostring(_toofar), tostring(_tooclose))) -- Init default for assigning moves into range. local _movetowards=false @@ -3502,7 +3490,7 @@ function ARTY:_CheckTargetsInRange() if _inrange then -- Inform coalition that target is now in range. - local text=string.format("%s, target %s is now in range.", self.Controllable:GetName(), _target.name) + local text=string.format("%s, target %s is now in range.", self.alias, _target.name) self:T(ARTY.id..text) MESSAGE:New(text,10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) end @@ -3528,15 +3516,15 @@ function ARTY:_CheckTargetsInRange() local _waytogo=_dist-self.maxrange+_safetymargin local _heading=self:_GetHeading(_from,_target.coord) _tocoord=_from:Translate(_waytogo, _heading) - _name=string.format("Relocation to within max firing range of target %s", _target.name) + _name=string.format("%s, relocation to within max firing range of target %s", self.alias, _target.name) elseif _moveaway then - -- Target was in range on previous check but now we are too far away. - local _waytogo=_dist-self.minrange+_safetymargin - local _heading=self:_GetHeading(_target.coord,_from) - _tocoord=_from:Translate(_waytogo, _heading) - _name=string.format("Relocation to within min firing range of target %s", _target.name) + -- Target was in range on previous check but now we are too far away. + local _waytogo=_dist-self.minrange+_safetymargin + local _heading=self:_GetHeading(_target.coord,_from) + _tocoord=_from:Translate(_waytogo, _heading) + _name=string.format("%s, relocation to within min firing range of target %s", self.alias, _target.name) end @@ -3553,7 +3541,7 @@ function ARTY:_CheckTargetsInRange() -- Update value. _target.inrange=_inrange - self:T(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange))) + self:T3(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange))) end end @@ -3750,6 +3738,52 @@ function ARTY:_GetMoveIndexByName(name) return nil end +--- Check if group is (partly) out of ammo of a special weapon type. +-- @param #ARTY self +-- @param #table targets Table of targets. +-- @return @boolean True if any target requests a weapon type that is empty. +function ARTY:_CheckOutOfAmmo(targets) + + -- Get current ammo. + local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo() + + -- Special weapon type requested ==> Check if corresponding ammo is empty. + local _partlyoutofammo=false + + for _,Target in pairs(targets) do + + if Target.weapontype==ARTY.WeaponType.Auto and _nammo==0 then + + self:T(ARTY.id..string.format("Group %s, auto weapon requested for target %s but all ammo is empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then + + self:T(ARTY.id..string.format("Group %s, cannons requested for target %s but shells empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then + + self:T(ARTY.id..string.format("Group %s, tactical nukes requested for target %s but nukes empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then + + self:T(ARTY.id..string.format("Group %s, rockets requested for target %s but rockets empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + elseif Target.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then + + self:T(ARTY.id..string.format("Group %s, cruise missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) + _partlyoutofammo=true + + end + + end + + return _partlyoutofammo +end + --- Check if a selected weapon type is available for this target, i.e. if the current amount of ammo of this weapon type is currently available. -- @param #ARTY self -- @param #boolean target Target array data structure. @@ -3769,14 +3803,8 @@ function ARTY:_CheckWeaponTypeAvailable(target) nfire=self.Nukes elseif target.weapontype==ARTY.WeaponType.Rockets then nfire=Nrockets - elseif target.weapontype==ARTY.WeaponType.UnguidedAny then - nfire=Nshells+Nrockets - elseif target.weapontype==ARTY.WeaponType.GuidedMissile then - nfire=Nmissiles elseif target.weapontype==ARTY.WeaponType.CruiseMissile then nfire=Nmissiles - elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then - nfire=Nmissiles end return nfire @@ -3797,14 +3825,8 @@ function ARTY:_CheckWeaponTypePossible(target) possible=self.Nukes0>0 elseif target.weapontype==ARTY.WeaponType.Rockets then possible=self.Nrockets0>0 - elseif target.weapontype==ARTY.WeaponType.UnguidedAny then - possible=self.Nshells0+self.Nrockets0>0 - elseif target.weapontype==ARTY.WeaponType.GuidedMissile then - possible=self.Nmissiles0>0 elseif target.weapontype==ARTY.WeaponType.CruiseMissile then possible=self.Nmissiles0>0 - elseif target.weapontype==ARTY.WeaponType.AntiShipMissile then - possible=self.Nmissiles0>0 end return possible @@ -3904,11 +3926,11 @@ function ARTY:_TargetInRange(target, message) if _dist < self.minrange then _inrange=false _tooclose=true - text=string.format("%s, target is out of range. Distance of %.1f km is below min range of %.1f km.", self.Controllable:GetName(), _dist/1000, self.minrange/1000) + text=string.format("%s, target is out of range. Distance of %.1f km is below min range of %.1f km.", self.alias, _dist/1000, self.minrange/1000) elseif _dist > self.maxrange then _inrange=false _toofar=true - text=string.format("%s, target is out of range. Distance of %.1f km is greater than max range of %.1f km.", self.Controllable:GetName(), _dist/1000, self.maxrange/1000) + text=string.format("%s, target is out of range. Distance of %.1f km is greater than max range of %.1f km.", self.alias, _dist/1000, self.maxrange/1000) end -- Debug output. @@ -3918,7 +3940,7 @@ function ARTY:_TargetInRange(target, message) end -- Remove target if ARTY group cannot move, e.g. Mortas. No chance to be ever in range. - if self.SpeedMax<1 and _inrange==false then + if not self.ismobile and _inrange==false then self:RemoveTarget(target.name) end @@ -3938,14 +3960,8 @@ function ARTY:_WeaponTypeName(tnumber) name="Cannons" elseif tnumber==ARTY.WeaponType.Rockets then name="Rockets" - elseif tnumber==ARTY.WeaponType.UnguidedAny then - name="Unguided Weapons" -- (Cannon or Rockets) elseif tnumber==ARTY.WeaponType.CruiseMissile then name="Cruise Missiles" - elseif tnumber==ARTY.WeaponType.GuidedMissile then - name="Guided Missiles" - elseif tnumber==ARTY.WeaponType.AntiShipMissile then - name="Anti-Ship Missiles" elseif tnumber==ARTY.WeaponType.TacticalNukes then name="Tactical Nukes" end @@ -4039,7 +4055,7 @@ function ARTY:_LLDMS2DD(l1,l2) local _format = "%d+:%d+:%d+" local _ldms=ll:match(_format) - if ldms then + if _ldms then -- Split DMS to degrees, minutes and seconds. local _dms=self:_split(_ldms, ":") @@ -4071,8 +4087,8 @@ function ARTY:_LLDMS2DD(l1,l2) end -- Debug text. - local text=string.format("\nLatitude %.3f", _latitude) - text=text..string.format("\nLongitude %.3f", _longitude) + local text=string.format("\nLatitude %s", tostring(_latitude)) + text=text..string.format("\nLongitude %s", tostring(_longitude)) self:T2(ARTY.id..text) return _latitude,_longitude From ba2d359af2cc39d454611747f7b4d5a96ce98eed Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 10 Jun 2018 23:35:22 +0200 Subject: [PATCH 167/170] ARTY 1.0.0 - Added pseudo functions for FMS states. - Fixed a few bugs. --- Moose Development/Moose/Core/Event.lua | 5 +- .../Moose/Functional/Artillery.lua | 478 ++++++++++++++---- 2 files changed, 393 insertions(+), 90 deletions(-) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 4592d634e..a1be00587 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -933,7 +933,9 @@ function EVENT:onEvent( Event ) Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName() --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() end - + +-- @FC: something like this should be added. +--[[ if Event.idx then Event.MarkID=Event.idx Event.MarkVec3=Event.pos @@ -942,6 +944,7 @@ function EVENT:onEvent( Event ) Event.MarkCoalition=Event.coalition Event.MarkGroupID = Event.groupID end +]] if Event.cargo then Event.Cargo = Event.cargo diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 27e1a2d6a..61201a6bf 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -63,12 +63,13 @@ -- @field #number IniGroupStrength Inital number of units in the ARTY group. -- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery". This is automatically derived from the DCS descriptor table. -- @field #boolean ismobile If true, ARTY group can move. +-- @field #string groupname Name of the ARTY group as defined in the mission editor. -- @field #string alias Name of the ARTY group. -- @field #number SpeedMax Maximum speed of ARTY group in km/h. This is determined from the DCS descriptor table. -- @field #number Speed Default speed in km/h the ARTY group moves at. Maximum speed possible is 80% of maximum speed the group can do. -- @field #number RearmingDistance Safe distance in meters between ARTY group and rearming group or place at which rearming is possible. Default 100 m. -- @field Wrapper.Group#GROUP RearmingGroup Unit designated to rearm the ARTY group. --- @field #number RearmingGroupSpeed Speed in km/h the rearming unit moves at. Default 50 km/h. +-- @field #number RearmingGroupSpeed Speed in km/h the rearming unit moves at. Default is 50% of the max speed possible of the group. -- @field #boolean RearmingGroupOnRoad If true, rearming group will move to ARTY group or rearming place using mainly roads. Default false. -- @field Core.Point#COORDINATE RearmingGroupCoord Initial coordinates of the rearming unit. After rearming complete, the unit will return to this position. -- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there. @@ -358,15 +359,15 @@ -- -- The mission designer has a few options to tailor the ARTY object according to his needs. -- --- * @{#ARTY.SetAutomaticRelocate}(*maxdist*, *onroad*) lets the ARTY group automatically move to within firing range if a current target is outside the min/max firing range. The +-- * @{#ARTY.SetAutoRelocateToFiringRange}(*maxdist*, *onroad*) lets the ARTY group automatically move to within firing range if a current target is outside the min/max firing range. The -- optional parameter *maxdist* is the maximum distance im km the group will move. If the distance is greater no relocation is performed. Default is 50 km. --- * @{#ARTY.SetRelocateAfterEngagement}(*rmax*, *rmin*) will cause the ARTY group to change its position after each firing assignment. +-- * @{#ARTY.SetAutoRelocateAfterEngagement}(*rmax*, *rmin*) will cause the ARTY group to change its position after each firing assignment. -- Optional parameters *rmax*, *rmin* define the max/min distance for relocation of the group. Default distance is randomly between 300 and 800 m. -- * @{#ARTY.RemoveAllTargets}() removes all targets from the target queue. -- * @{#ARTY.RemoveTarget}(*name*) deletes the target with *name* from the target queue. -- * @{#ARTY.SetMaxFiringRange}(*range*) defines the maximum firing range. Targets further away than this distance are not engaged. -- * @{#ARTY.SetMinFiringRange}(*range*) defines the minimum firing range. Targets closer than this distance are not engaged. --- * @{#ARTY.SetRearmingGroup}(*group*) sets the group resposible for rearming of the ARTY group once it is out of ammo. +-- * @{#ARTY.SetRearmingGroup}(*group*) sets the group responsible for rearming of the ARTY group once it is out of ammo. -- * @{#ARTY.SetReportON}() and @{#ARTY.SetReportOFF}() can be used to enable/disable status reports of the ARTY group send to all coalition members. -- * @{#ARTY.SetWaitForShotTime}(*waittime*) sets the time after which a target is deleted from the queue if no shooting event occured after the target engagement started. -- Default is 300 seconds. Note that this can for example happen, when the assigned target is out of range. @@ -455,13 +456,14 @@ ARTY={ DCSdesc=nil, Type=nil, DisplayName=nil, + groupname=nil, alias=nil, ismobile=true, IniGroupStrength=0, IsArtillery=nil, RearmingDistance=100, RearmingGroup=nil, - RearmingGroupSpeed=50, + RearmingGroupSpeed=nil, RearmingGroupOnRoad=false, RearmingGroupCoord=nil, RearmingPlaceCoord=nil, @@ -569,7 +571,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="0.9.96" +ARTY.version="1.0.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -586,18 +588,19 @@ ARTY.version="0.9.96" -- DONE: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example. -- DONE: Improve assigned time for engagement. Next day? -- DONE: Improve documentation. --- TODO: Add pseudo user transitions. OnAfter... +-- DONE: Add pseudo user transitions. OnAfter... -- DONE: Make reaming unit a group. -- DONE: Write documenation. -- DONE: Add command move to make arty group move. -- DONE: remove schedulers for status event. --- TODO: Improve handling of special weapons. When winchester if using selected weapons? --- TODO: Handle rearming for ships. --- TODO: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location. +-- DONE: Improve handling of special weapons. When winchester if using selected weapons? +-- TODO: Handle rearming for ships. How? +-- DONE: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location. -- TODO: Add set commands via markers. E.g. set rearming place. --- TODO: Test stationary types like mortas ==> rearming etc. +-- DONE: Test stationary types like mortas ==> rearming etc. +-- TODO: Add hit event and make the arty group relocate. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Creates a new ARTY object. -- @param #ARTY self @@ -627,10 +630,14 @@ function ARTY:New(group, alias) -- Set the controllable for the FSM. self:SetControllable(group) + -- Set the group name + self.groupname=group:GetName() + + -- Set an alias name. if alias~=nil then self.alias=tostring(alias) else - self.alias=group:GetName() + self.alias=self.groupname end -- Set the initial coordinates of the ARTY group. @@ -706,6 +713,268 @@ function ARTY:New(group, alias) -- Unknown transitons. To be checked if adding these causes problems. self:AddTransition("Rearming", "Arrived", "Rearming") self:AddTransition("Rearming", "Move", "Rearming") + + + --- User function for OnAfter "NewTarget" event. + -- @function [parent=#ARTY] OnAfterNewTarget + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + + --- User function for OnAfter "OpenFire" event. + -- @function [parent=#ARTY] OnAfterOpenFire + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + + --- User function for OnAfter "CeaseFire" event. + -- @function [parent=#ARTY] OnAfterCeaseFire + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table target Array holding the target info. + + --- User function for OnAfer "NewMove" event. + -- @function [parent=#ARTY] OnAfterNewMove + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table move Array holding the move info. + + --- User function for OnAfer "Move" event. + -- @function [parent=#ARTY] OnAfterMove + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param #table move Array holding the move info. + + --- User function for OnAfer "Arrived" event. + -- @function [parent=#ARTY] OnAfterArrvied + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnAfter "Winchester" event. + -- @function [parent=#ARTY] OnAfterWinchester + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnAfter "Rearm" event. + -- @function [parent=#ARTY] OnAfterRearm + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnAfter "Rearmed" event. + -- @function [parent=#ARTY] OnAfterRearmed + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnAfter "Start" event. + -- @function [parent=#ARTY] OnAfterStart + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnAfter "Status" event. + -- @function [parent=#ARTY] OnAfterStatus + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnAfter "Dead" event. + -- @function [parent=#ARTY] OnAfterDead + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- User function for OnEnter "CombatReady" state. + -- @function [parent=#ARTY] OnEnterCombatReady + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "Firing" state. + -- @function [parent=#ARTY] OnEnterFiring + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "OutOfAmmo" state. + -- @function [parent=#ARTY] OnEnterOutOfAmmo + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "Rearming" state. + -- @function [parent=#ARTY] OnEnterRearming + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "Rearmed" state. + -- @function [parent=#ARTY] OnEnterRearmed + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + --- User function for OnEnter "Moving" state. + -- @function [parent=#ARTY] OnEnterMoving + -- @param #ARTY self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + + + --- Function to start the ARTY FSM process. + -- @function [parent=#ARTY] Start + -- @param #ARTY self + + --- Function to start the ARTY FSM process after a delay. + -- @function [parent=#ARTY] __Start + -- @param #ARTY self + -- @param #number Delay before start in seconds. + + --- Function to update the status of the ARTY group and tigger FSM events. Triggers the FSM event "Status". + -- @function [parent=#ARTY] Status + -- @param #ARTY self + + --- Function to update the status of the ARTY group and tigger FSM events after a delay. Triggers the FSM event "Status". + -- @function [parent=#ARTY] __Status + -- @param #ARTY self + -- @param #number Delay in seconds. + + --- Function called when a unit of the ARTY group died. Triggers the FSM event "Dead". + -- @function [parent=#ARTY] Dead + -- @param #ARTY self + + --- Function called when a unit of the ARTY group died after a delay. Triggers the FSM event "Dead". + -- @function [parent=#ARTY] __Dead + -- @param #ARTY self + -- @param #number Delay in seconds. + + --- Add a new target for the ARTY group. Triggers the FSM event "NewTarget". + -- @function [parent=#ARTY] NewTarget + -- @param #ARTY self + -- @param #table target Array holding the target data. + + --- Add a new target for the ARTY group with a delay. Triggers the FSM event "NewTarget". + -- @function [parent=#ARTY] __NewTarget + -- @param #ARTY self + -- @param #number delay Delay in seconds. + -- @param #table target Array holding the target data. + + --- Add a new relocation move for the ARTY group. Triggers the FSM event "NewMove". + -- @function [parent=#ARTY] NewMove + -- @param #ARTY self + -- @param #table move Array holding the relocation move data. + + --- Add a new relocation for the ARTY group after a delay. Triggers the FSM event "NewMove". + -- @function [parent=#ARTY] __NewMove + -- @param #ARTY self + -- @param #number delay Delay in seconds. + -- @param #table move Array holding the relocation move data. + + --- Order ARTY group to open fire on a target. Triggers the FSM event "OpenFire". + -- @function [parent=#ARTY] OpenFire + -- @param #ARTY self + -- @param #table target Array holding the target data. + + --- Order ARTY group to open fire on a target with a delay. Triggers the FSM event "Move". + -- @function [parent=#ARTY] __OpenFire + -- @param #ARTY self + -- @param #number delay Delay in seconds. + -- @param #table target Array holding the target data. + + --- Order ARTY group to cease firing on a target. Triggers the FSM event "CeaseFire". + -- @function [parent=#ARTY] CeaseFire + -- @param #ARTY self + -- @param #table target Array holding the target data. + + --- Order ARTY group to cease firing on a target after a delay. Triggers the FSM event "CeaseFire". + -- @function [parent=#ARTY] __CeaseFire + -- @param #ARTY self + -- @param #number delay Delay in seconds. + -- @param #table target Array holding the target data. + + --- Order ARTY group to move to another location. Triggers the FSM event "Move". + -- @function [parent=#ARTY] Move + -- @param #ARTY self + -- @param #table move Array holding the relocation move data. + + --- Order ARTY group to move to another location after a delay. Triggers the FSM event "Move". + -- @function [parent=#ARTY] __Move + -- @param #ARTY self + -- @param #number delay Delay in seconds. + -- @param #table move Array holding the relocation move data. + + --- Tell ARTY group it has arrived at its destination. Triggers the FSM event "Arrived". + -- @function [parent=#ARTY] Arrived + -- @param #ARTY self + + --- Tell ARTY group it has arrived at its destination after a delay. Triggers the FSM event "Arrived". + -- @function [parent=#ARTY] __Arrived + -- @param #ARTY self + -- @param #number delay Delay in seconds. + + --- Tell ARTY group it is combat ready. Triggers the FSM event "CombatReady". + -- @function [parent=#ARTY] CombatReady + -- @param #ARTY self + + --- Tell ARTY group it is combat ready after a delay. Triggers the FSM event "CombatReady". + -- @function [parent=#ARTY] __CombatReady + -- @param #ARTY self + -- @param #number delay Delay in seconds. + + --- Tell ARTY group it is out of ammo. Triggers the FSM event "Winchester". + -- @function [parent=#ARTY] Winchester + -- @param #ARTY self + + --- Tell ARTY group it is out of ammo after a delay. Triggers the FSM event "Winchester". + -- @function [parent=#ARTY] __Winchester + -- @param #ARTY self + -- @param #number delay Delay in seconds. + return self end @@ -776,7 +1045,7 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w -- Target name should be unique and is not. if unique==true and _unique==false then - self:T(ARTY.id..string.format("%s: target %s should have a unique name but name was already given. Rejecting target!", self.Controllable:GetName(), _name)) + self:T(ARTY.id..string.format("%s: target %s should have a unique name but name was already given. Rejecting target!", self.groupname, _name)) return nil end @@ -810,7 +1079,7 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) -- Reject move if the group is immobile. if not self.ismobile then - self:T(ARTY.id..string.format("%s: group is immobile. Rejecting move request!", self.Controllable:GetName())) + self:T(ARTY.id..string.format("%s: group is immobile. Rejecting move request!", self.groupname)) return nil end @@ -828,7 +1097,7 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) -- Move name should be unique and is not. if unique==true and _unique==false then - self:T(ARTY.id..string.format("%s: move %s should have a unique name but name was already given. Rejecting move!", self.Controllable:GetName(), _name)) + self:T(ARTY.id..string.format("%s: move %s should have a unique name but name was already given. Rejecting move!", self.groupname, _name)) return nil end @@ -909,7 +1178,7 @@ end --- Assign a group, which is responsible for rearming the ARTY group. If the group is too far away from the ARTY group it will be guided towards the ARTY group. -- @param #ARTY self --- @param Wrapper.Group#GROUP group Group that is supposed to rearm the ARTY group. +-- @param Wrapper.Group#GROUP group Group that is supposed to rearm the ARTY group. For the blue coalition, this is often a unarmed M818 transport whilst for red an unarmed Ural-375 transport can be used. function ARTY:SetRearmingGroup(group) self:F({group=group}) self.RearmingGroup=group @@ -917,10 +1186,10 @@ end --- Set the speed the rearming group moves at towards the ARTY group or the rearming place. -- @param #ARTY self --- @param #number speed Speed in km/h. Default 50 km/h. +-- @param #number speed Speed in km/h. function ARTY:SetRearmingGroupSpeed(speed) self:F({speed=speed}) - self.RearmingGroupSpeed=speed or 50 + self.RearmingGroupSpeed=speed end --- Define if rearming group uses mainly roads to drive to the ARTY group or rearming place. @@ -957,7 +1226,7 @@ end -- @param #ARTY self -- @param #number maxdistance (Optional) The maximum distance in km the group will travel to get within firing range. Default is 50 km. No automatic relocation is performed if targets are assigned which are further away. -- @param #boolean onroad (Optional) If true, ARTY group uses roads whenever possible. Default false, i.e. group will move in a straight line to the assigned coordinate. -function ARTY:SetAutomaticRelocate(maxdistance, onroad) +function ARTY:SetAutoRelocateToFiringRange(maxdistance, onroad) self:F({distance=maxdistance, onroad=onroad}) self.autorelocate=true self.autorelocatemaxdist=maxdistance or 50 @@ -968,6 +1237,19 @@ function ARTY:SetAutomaticRelocate(maxdistance, onroad) self.autorelocateonroad=onroad end +--- Set relocate after firing. Group will find a new location after each engagement. Default is off +-- @param #ARTY self +-- @param #number rmax (Optional) Max distance in meters, the group will move to relocate. Default is 800 m. +-- @param #number rmin (Optional) Min distance in meters, the group will move to relocate. Default is 300 m. +function ARTY:SetAutoRelocateAfterEngagement(rmax, rmin) + self.relocateafterfire=true + self.relocateRmax=rmax or 800 + self.relocateRmin=rmin or 300 + + -- Ensure that Rmin<=Rmax + self.relocateRmin=math.min(self.relocateRmin, self.relocateRmax) +end + --- Report messages of ARTY group turned on. This is the default. -- @param #ARTY self function ARTY:SetReportON() @@ -1004,19 +1286,19 @@ function ARTY:RemoveTarget(name) if id then -- Remove target from table. - self:T(ARTY.id..string.format("Group %s: Removing target %s (id=%d).", self.Controllable:GetName(), name, id)) + self:T(ARTY.id..string.format("Group %s: Removing target %s (id=%d).", self.groupname, name, id)) table.remove(self.targets, id) -- Delete marker belonging to this engagement. if self.markallow then local batteryname,markTargetID, markMoveID=self:_GetMarkIDfromName(name) - if batteryname==self.Controllable:GetName() and markTargetID~=nil then + if batteryname==self.groupname and markTargetID~=nil then COORDINATE:RemoveMark(markTargetID) end end end - self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.Controllable:GetName(), #self.targets)) + self:T(ARTY.id..string.format("Group %s: Number of targets = %d.", self.groupname, #self.targets)) end --- Delete a move from move list. @@ -1031,19 +1313,19 @@ function ARTY:RemoveMove(name) if id then -- Remove move from table. - self:T(ARTY.id..string.format("Group %s: Removing move %s (id=%d).", self.Controllable:GetName(), name, id)) + self:T(ARTY.id..string.format("Group %s: Removing move %s (id=%d).", self.groupname, name, id)) table.remove(self.moves, id) -- Delete marker belonging to this relocation move. if self.markallow then local batteryname,markTargetID,markMoveID=self:_GetMarkIDfromName(name) - if batteryname==self.Controllable:GetName() and markMoveID~=nil then + if batteryname==self.groupname and markMoveID~=nil then COORDINATE:RemoveMark(markMoveID) end end end - self:T(ARTY.id..string.format("Group %s: Number of moves = %d.", self.Controllable:GetName(), #self.moves)) + self:T(ARTY.id..string.format("Group %s: Number of moves = %d.", self.groupname, #self.moves)) end --- Delete ALL targets from current target list. @@ -1114,16 +1396,6 @@ function ARTY:SetTacNukeFires(nfires, range) self.nukerange=range end ---- Set relocate after firing. Group will find a new location after each engagement. Default is off --- @param #ARTY self --- @param #number rmax (Optional) Max distance in meters, the group will move to relocate. Default is 800 m. --- @param #number rmin (Optional) Min distance in meters, the group will move to relocate. Default is 300 m. -function ARTY:SetRelocateAfterEngagement(rmax, rmin) - self.relocateafterfire=true - self.relocateRmax=rmax or 800 - self.relocateRmin=rmin or 300 -end - --- Enable assigning targets and moves by placing markers on the F10 map. -- @param #ARTY self -- @param #number key (Optional) Authorization key. Only players knowing this key can assign targets. Default is no authorization required. @@ -1193,10 +1465,31 @@ function ARTY:onafterStart(Controllable, From, Event, To) self.RearmingPlaceCoord=nil self.relocateafterfire=false self.autorelocate=false + self.RearmingGroupSpeed=20 + end + + -- Set Rearming group speed if not specified by user + if self.RearmingGroup then + + -- Get max speed of rearming group. + local speedmax=self.RearmingGroup:GetSpeedMax() + self:T(ARTY.id..string.format("%s, rearming group %s max speed = %.1f km/h.", self.groupname, self.RearmingGroup:GetName(), speedmax)) + + if self.RearmingGroupSpeed==nil then + -- Set rearming group speed to 50% of max possible speed. + self.RearmingGroupSpeed=speedmax*0.5 + else + -- Ensure that speed is <= max speed. + self.RearmingGroupSpeed=math.min(self.RearmingGroupSpeed, self.RearmingGroup:GetSpeedMax()) + end + else + -- Just to have a reasonable number for output format below. + self.RearmingGroupSpeed=23 end local text=string.format("\n******************************************************\n") - text=text..string.format("Arty group = %s\n", Controllable:GetName()) + text=text..string.format("Arty group = %s\n", self.groupname) + text=text..string.format("Arty alias = %s\n", self.alias) text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery)) text=text..string.format("Type = %s\n", self.Type) text=text..string.format("Display Name = %s\n", self.DisplayName) @@ -1230,7 +1523,7 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Relocate after fire = %s\n", tostring(self.relocateafterfire)) text=text..string.format("Relocate min dist. = %d m\n", self.relocateRmin) text=text..string.format("Relocate max dist. = %d m\n", self.relocateRmax) - text=text..string.format("Auto move in range = %s\n", tostring(self.autorelocate)) + text=text..string.format("Auto move in range = %s\n", tostring(self.autorelocate)) text=text..string.format("Auto move dist. max = %.1f km\n", self.autorelocatemaxdist/1000) text=text..string.format("Auto move on road = %s\n", tostring(self.autorelocateonroad)) text=text..string.format("Marker assignments = %s\n", tostring(self.markallow)) @@ -1322,7 +1615,7 @@ function ARTY:_StatusReport(display) local Clock=self:_SecondsToClock(timer.getAbsTime()) local text=string.format("\n******************* STATUS ***************************\n") - text=text..string.format("ARTY group = %s\n", self.Controllable:GetName()) + text=text..string.format("ARTY group = %s\n", self.groupname) text=text..string.format("Clock = %s\n", Clock) text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("Total ammo count = %d\n", Nammo) @@ -1381,7 +1674,7 @@ function ARTY:_OnEventShot(EventData) if group and group:IsAlive() then - if EventData.IniGroupName == self.Controllable:GetName() then + if EventData.IniGroupName == self.groupname then if self.currentTarget then @@ -1406,7 +1699,7 @@ function ARTY:_OnEventShot(EventData) return _weapon:getPoint() end) - self:T(ARTY.id..string.format("ARTY %s: Weapon still in air: %s", self.Controllable:GetName(), tostring(_status))) + self:T(ARTY.id..string.format("ARTY %s: Weapon still in air: %s", self.groupname, tostring(_status))) if _status then @@ -1430,7 +1723,7 @@ function ARTY:_OnEventShot(EventData) -- Start track the shell if we want to model a tactical nuke. if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes>0 then - self:T(ARTY.id..string.format("ARTY %s: Tracking of weapon starts in two seconds.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("ARTY %s: Tracking of weapon starts in two seconds.", self.groupname)) timer.scheduleFunction(_TrackWeapon, EventData.weapon, timer.getTime() + 2.0) end @@ -1445,7 +1738,7 @@ function ARTY:_OnEventShot(EventData) -- Check if we are completely out of ammo. local _outofammo=false if _nammo==0 then - self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("Group %s completely out of ammo.", self.groupname)) _outofammo=true end @@ -1455,8 +1748,8 @@ function ARTY:_OnEventShot(EventData) -- Weapon type name for current target. local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype) - self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.Controllable:GetName(), _nammo, _nshells, _nrockets, _nmissiles)) - self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.Controllable:GetName(), _weapontype)) + self:T(ARTY.id..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.groupname, _nammo, _nshells, _nrockets, _nmissiles)) + self:T(ARTY.id..string.format("Group %s uses weapontype %s for current target.", self.groupname, _weapontype)) -- Default switches for cease fire and relocation. local _ceasefire=false @@ -1466,7 +1759,7 @@ function ARTY:_OnEventShot(EventData) if self.Nshots >= self.currentTarget.nshells then -- Debug message - local text=string.format("Group %s stop firing on target %s.", self.Controllable:GetName(), self.currentTarget.name) + local text=string.format("Group %s stop firing on target %s.", self.groupname, self.currentTarget.name) self:T(ARTY.id..text) MESSAGE:New(text, 5):ToAllIf(self.Debug) @@ -1499,7 +1792,7 @@ function ARTY:_OnEventShot(EventData) end else - self:E(ARTY.id..string.format("WARNING: No current target for group %s?!", self.Controllable:GetName())) + self:E(ARTY.id..string.format("WARNING: No current target for group %s?!", self.groupname)) end end end @@ -1517,7 +1810,7 @@ function ARTY:onEvent(Event) end -- Set battery and coalition. - local batteryname=self.Controllable:GetName() + local batteryname=self.groupname local batterycoalition=self.Controllable:GetCoalition() self:T2(string.format("Event captured = %s", tostring(batteryname))) @@ -1557,7 +1850,7 @@ function ARTY:_OnEventMarkRemove(Event) -- Get battery coalition and name. local batterycoalition=self.Controllable:GetCoalition() - local batteryname=self.Controllable:GetName() + local batteryname=self.groupname if Event.text~=nil and Event.text:find("BATTERY") then @@ -1632,7 +1925,7 @@ function ARTY:_OnEventMarkChange(Event) -- Get battery coalition and name. local batterycoalition=self.Controllable:GetCoalition() - local batteryname=self.Controllable:GetName() + local batteryname=self.groupname -- Check if the coalition is the same or an authorization key has been defined. if (batterycoalition==Event.coalition and self.markkey==nil) or self.markkey~=nil then @@ -1650,7 +1943,7 @@ function ARTY:_OnEventMarkChange(Event) if #_assign.battery>0 then _assigned=false for _,bat in pairs(_assign.battery) do - self:T2(ARTY.id..string.format("Compare battery names %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) + self:T3(ARTY.id..string.format("Compare battery names %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) if batteryname==bat then _assigned=true end @@ -1694,7 +1987,7 @@ function ARTY:_OnEventMarkChange(Event) elseif _assign.canceltarget and self.currentTarget then self.currentTarget.engaged=self.currentTarget.engaged+1 self:CeaseFire(self.currentTarget) - elseif _assign.cancelrearm and self.is("Rearming") then + elseif _assign.cancelrearm and self:is("Rearming") then local nammo=self:GetAmmo() if nammo>0 then self:Rearmed() @@ -1770,7 +2063,7 @@ function ARTY:_OnEventMarkChange(Event) if _assign.prio then text=text..string.format("\nPrio %d",_assign.prio) end - if _assign.prio then + if _assign.radius then text=text..string.format("\nRadius %d m",_assign.radius) end if _assign.nshells then @@ -1816,7 +2109,7 @@ function ARTY:_OnEventDead(EventData) self:F(EventData) -- Name of controllable. - local _name=self.Controllable:GetName() + local _name=self.groupname -- Check for correct group. if EventData.IniGroupName==_name then @@ -1898,7 +2191,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To) end end for _,targetname in pairs(notpossible) do - self:E(ARTY.id..string.format("%s: Removing target %s because requested weapon is not possible with this type of unit.", self.Controllable:GetName(), targetname)) + self:E(ARTY.id..string.format("%s: Removing target %s because requested weapon is not possible with this type of unit.", self.groupname, targetname)) self:RemoveTarget(targetname) end @@ -1995,7 +2288,7 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) -- Check that group has no current target already. if self.currentTarget then -- This should not happen. Some earlier check failed. - self:E(ARTY.id..string.format("ERROR: Group %s already has a target %s!", self.Controllable:GetName(), self.currentTarget.name)) + self:E(ARTY.id..string.format("ERROR: Group %s already has a target %s!", self.groupname, self.currentTarget.name)) -- Deny transition. return false end @@ -2003,7 +2296,7 @@ function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target) -- Check if target is in range. if not self:_TargetInRange(target) then -- This should not happen. Some earlier check failed. - self:E(ARTY.id..string.format("ERROR: Group %s, target %s is out of range!", self.Controllable:GetName(), self.currentTarget.name)) + self:E(ARTY.id..string.format("ERROR: Group %s, target %s is out of range!", self.groupname, self.currentTarget.name)) -- Deny transition. return false end @@ -2135,7 +2428,7 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target) self.Controllable:ClearTasks() else - self:E(ARTY.id.."ERROR: No target in cease fire for group %s.", self.Controllable:GetName()) + self:E(ARTY.id.."ERROR: No target in cease fire for group %s.", self.groupname) end -- Set number of shots to zero. @@ -2178,10 +2471,10 @@ function ARTY:onbeforeRearm(Controllable, From, Event, To) local _rearmed=self:_CheckRearmed() if _rearmed then - self:T(ARTY.id..string.format("%s, group is already armed to the teeth. Rearming request denied!", self.Controllable:GetName())) + self:T(ARTY.id..string.format("%s, group is already armed to the teeth. Rearming request denied!", self.groupname)) return false else - self:T(ARTY.id..string.format("%s, group might be rearmed.", self.Controllable:GetName())) + self:T(ARTY.id..string.format("%s, group might be rearmed.", self.groupname)) end -- Check if a reaming unit or rearming place was specified. @@ -2240,7 +2533,8 @@ function ARTY:onafterRearm(Controllable, From, Event, To) -- Route Rearming group to rearming place. if dR > self.RearmingDistance then - self:_Move(self.RearmingGroup, self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2), self.RearmingGroupSpeed, self.RearmingGroupOnRoad) + local ToCoord=self:_VicinityCoord(self.RearmingPlaceCoord, self.RearmingDistance/4, self.RearmingDistance/2) + self:_Move(self.RearmingGroup, ToCoord, self.RearmingGroupSpeed, self.RearmingGroupOnRoad) end elseif self.RearmingGroup then @@ -2314,6 +2608,9 @@ function ARTY:onafterRearmed(Controllable, From, Event, To) local d=self.RearmingGroup:GetCoordinate():Get2DDistance(self.RearmingGroupCoord) if d > self.RearmingDistance then self:_Move(self.RearmingGroup, self.RearmingGroupCoord, self.RearmingGroupSpeed, self.RearmingGroupOnRoad) + else + -- Clear tasks. + self.RearmingGroup:ClearTasks() end end @@ -2502,7 +2799,7 @@ function ARTY:onafterDead(Controllable, From, Event, To) end -- Message. - local text=string.format("%s, one of our units just died! %d units left.", self.Controllable:GetName(), nunits) + local text=string.format("%s, one of our units just died! %d units left.", self.groupname, nunits) MESSAGE:New(text, 5):ToAllIf(self.Debug) self:T(ARTY.id..text) @@ -2800,7 +3097,7 @@ function ARTY._PassingWaypoint(group, arty, i, final) ]] -- Arrived event. - if final and arty.Controllable:GetName()==group:GetName() then + if final and arty.groupname==group:GetName() then arty:Arrived() end @@ -2868,7 +3165,7 @@ function ARTY:GetAmmo(display) if unit and unit:IsAlive() then -- Output. - local text=string.format("ARTY group %s - unit %s:\n", self.Controllable:GetName(), unit:GetName()) + local text=string.format("ARTY group %s - unit %s:\n", self.groupname, unit:GetName()) -- Get ammo table. local ammotable=unit:GetAmmo() @@ -3040,7 +3337,7 @@ end function ARTY:_MarkerKeyAuthentification(text) -- Set battery and coalition. - local batteryname=self.Controllable:GetName() + local batteryname=self.groupname local batterycoalition=self.Controllable:GetCoalition() -- Get assignment. @@ -3133,11 +3430,14 @@ function ARTY:_Markertext(text) local str=self:_split(keyphrase, " ") local key=str[1] local val=str[2] + + -- Debug output. + self:T3(ARTY.id..string.format("%s, keyphrase = %s, key = %s, val = %s", self.groupname, tostring(keyphrase), tostring(key), tostring(val))) -- Battery name, i.e. which ARTY group should fire. if key:lower():find("battery") then - local v=self:_split(key, '"') + local v=self:_split(keyphrase, '"') for i=2,#v,2 do table.insert(assignment.battery, v[i]) @@ -3193,57 +3493,57 @@ function ARTY:_Markertext(text) assignment.speed=tonumber(val) self:T2(ARTY.id..string.format("Key Speed=%s.", val)) - elseif assignment.move and (key:lower():find("on road") or key:lower():find("onroad") or key:lower():find("use road")) then + elseif assignment.move and (keyphrase:lower():find("on road") or keyphrase:lower():find("onroad") or keyphrase:lower():find("use road")) then assignment.onroad=true self:T2(ARTY.id..string.format("Key Onroad=true.")) - elseif key:lower():find("irrevocable") or key:lower():find("readonly") then + elseif keyphrase:lower():find("irrevocable") or keyphrase:lower():find("readonly") then assignment.readonly=true self:T2(ARTY.id..string.format("Key Readonly=true.")) - elseif assignment.move and (key:lower():find("cancel target") or key:lower():find("cancel target")) then + elseif assignment.move and (keyphrase:lower():find("cancel target") or keyphrase:lower():find("canceltarget")) then assignment.movecanceltarget=true self:T2(ARTY.id..string.format("Key Cancel Target (before move)=true.")) - elseif assignment.request and key:lower():find("rearm") then + elseif assignment.request and keyphrase:lower():find("rearm") then assignment.requestrearming=true self:T2(ARTY.id..string.format("Key Request Rearming=true.")) - elseif assignment.request and key:lower():find("ammo") then + elseif assignment.request and keyphrase:lower():find("ammo") then assignment.requestammo=true self:T2(ARTY.id..string.format("Key Request Ammo=true.")) - elseif assignment.request and key:lower():find("target") then + elseif assignment.request and keyphrase:lower():find("target") then assignment.requesttargets=true self:T2(ARTY.id..string.format("Key Request Targets=true.")) - elseif assignment.request and key:lower():find("status") then + elseif assignment.request and keyphrase:lower():find("status") then assignment.requeststatus=true self:T2(ARTY.id..string.format("Key Request Status=true.")) - elseif assignment.request and (key:lower():find("move") or key:lower():find("relocation")) then + elseif assignment.request and (keyphrase:lower():find("move") or keyphrase:lower():find("relocation")) then assignment.requestmoves=true self:T2(ARTY.id..string.format("Key Request Moves=true.")) - elseif assignment.cancel and (key:lower():find("engagement") or key:lower():find("attack") or key:lower():find("target")) then + elseif assignment.cancel and (keyphrase:lower():find("engagement") or keyphrase:lower():find("attack") or keyphrase:lower():find("target")) then assignment.canceltarget=true self:T2(ARTY.id..string.format("Key Cancel Target=true.")) - elseif assignment.cancel and (key:lower():find("move") or key:lower():find("relocation")) then + elseif assignment.cancel and (keyphrase:lower():find("move") or keyphrase:lower():find("relocation")) then assignment.cancelmove=true self:T2(ARTY.id..string.format("Key Cancel Move=true.")) - elseif assignment.cancel and key:lower():find("rearm") then + elseif assignment.cancel and keyphrase:lower():find("rearm") then assignment.cancelrearm=true self:T2(ARTY.id..string.format("Key Cancel Rearm=true.")) @@ -3289,7 +3589,7 @@ end --- Request Moves. -- @param #ARTY self function ARTY:_MarkRequestMoves() - local text=string.format("%s, relocations:", self.Controllable:GetName()) + local text=string.format("%s, relocations:", self.groupname) if #self.moves>0 then for _,move in pairs(self.moves) do if self.currentMove and move.name == self.currentMove.name then @@ -3307,7 +3607,7 @@ end --- Request Targets. -- @param #ARTY self function ARTY:_MarkRequestTargets() - local text=string.format("%s, targets:", self.Controllable:GetName()) + local text=string.format("%s, targets:", self.groupname) if #self.targets>0 then for _,target in pairs(self.targets) do if self.currentTarget and target.name == self.currentTarget.name then @@ -3327,7 +3627,7 @@ end -- @param #number markerid ID of the placed marker. -- @return #string Name of target engagement. function ARTY:_MarkTargetName(markerid) - return string.format("BATTERY=%s, Marked Target ID=%d", self.Controllable:GetName(), markerid) + return string.format("BATTERY=%s, Marked Target ID=%d", self.groupname, markerid) end --- Create a name for a relocation move initiated by placing a marker. @@ -3335,7 +3635,7 @@ end -- @param #number markerid ID of the placed marker. -- @return #string Name of relocation move. function ARTY:_MarkMoveName(markerid) - return string.format("BATTERY=%s, Marked Relocation ID=%d", self.Controllable:GetName(), markerid) + return string.format("BATTERY=%s, Marked Relocation ID=%d", self.groupname, markerid) end --- Get the marker ID from the assigned task name. @@ -3679,14 +3979,14 @@ function ARTY:_CheckShootingStarted() -- Debug info if self.Nshots==0 then - self:T(ARTY.id..string.format("%s, waiting for %d seconds for first shot on target %s.", self.Controllable:GetName(), dt, name)) + self:T(ARTY.id..string.format("%s, waiting for %d seconds for first shot on target %s.", self.groupname, dt, name)) end -- Check if we waited long enough and no shot was fired. if dt > self.WaitForShotTime and self.Nshots==0 then -- Debug info. - self:T(ARTY.id..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.Controllable:GetName(), self.WaitForShotTime, name)) + self:T(ARTY.id..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.groupname, self.WaitForShotTime, name)) -- CeaseFire. self:CeaseFire(self.currentTarget) @@ -3754,27 +4054,27 @@ function ARTY:_CheckOutOfAmmo(targets) if Target.weapontype==ARTY.WeaponType.Auto and _nammo==0 then - self:T(ARTY.id..string.format("Group %s, auto weapon requested for target %s but all ammo is empty.", self.Controllable:GetName(), Target.name)) + self:T(ARTY.id..string.format("Group %s, auto weapon requested for target %s but all ammo is empty.", self.groupname, Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then - self:T(ARTY.id..string.format("Group %s, cannons requested for target %s but shells empty.", self.Controllable:GetName(), Target.name)) + self:T(ARTY.id..string.format("Group %s, cannons requested for target %s but shells empty.", self.groupname, Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes<=0 then - self:T(ARTY.id..string.format("Group %s, tactical nukes requested for target %s but nukes empty.", self.Controllable:GetName(), Target.name)) + self:T(ARTY.id..string.format("Group %s, tactical nukes requested for target %s but nukes empty.", self.groupname, Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.Rockets and _nrockets==0 then - self:T(ARTY.id..string.format("Group %s, rockets requested for target %s but rockets empty.", self.Controllable:GetName(), Target.name)) + self:T(ARTY.id..string.format("Group %s, rockets requested for target %s but rockets empty.", self.groupname, Target.name)) _partlyoutofammo=true elseif Target.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then - self:T(ARTY.id..string.format("Group %s, cruise missiles requested for target %s but all missiles empty.", self.Controllable:GetName(), Target.name)) + self:T(ARTY.id..string.format("Group %s, cruise missiles requested for target %s but all missiles empty.", self.groupname, Target.name)) _partlyoutofammo=true end @@ -3994,7 +4294,7 @@ end -- @param #string From From state. -- @param #string To To state. function ARTY:_EventFromTo(BA, Event, From, To) - local text=string.format("%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To) + local text=string.format("%s: %s EVENT %s: %s --> %s", BA, self.groupname, Event, From, To) self:T3(ARTY.id..text) end From d5d2de75776863ea5495196f7047912e36125773 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sun, 10 Jun 2018 23:41:07 +0200 Subject: [PATCH 168/170] Controllable alarm state ships don't have option to change alarm state to other than green --- Moose Development/Moose/Wrapper/Controllable.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index d539dd098..0b56cc0d7 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -2654,7 +2654,6 @@ function CONTROLLABLE:OptionAlarmStateGreen() elseif self:IsShip() then -- AI.Option.Naval.id.ALARM_STATE does not seem to exist! --Controller:setOption( AI.Option.Naval.id.ALARM_STATE, AI.Option.Naval.val.ALARM_STATE.GREEN ) - Controller:setOption( AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN ) end return self From 3fee4a87daaa151020fbb562c009e798f60c6167 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 11 Jun 2018 20:29:58 +0200 Subject: [PATCH 169/170] ARTY v1.0.1 Added cluster and alias assignment via marks. --- .../Moose/Functional/Artillery.lua | 142 +++++++++++++++--- 1 file changed, 118 insertions(+), 24 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 61201a6bf..d2c1ad784 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -65,6 +65,7 @@ -- @field #boolean ismobile If true, ARTY group can move. -- @field #string groupname Name of the ARTY group as defined in the mission editor. -- @field #string alias Name of the ARTY group. +-- @field #table clusters Table of names of clusters the group belongs to. Can be used to address all groups within the cluster simultaniously. -- @field #number SpeedMax Maximum speed of ARTY group in km/h. This is determined from the DCS descriptor table. -- @field #number Speed Default speed in km/h the ARTY group moves at. Maximum speed possible is 80% of maximum speed the group can do. -- @field #number RearmingDistance Safe distance in meters between ARTY group and rearming group or place at which rearming is possible. Default 100 m. @@ -293,6 +294,8 @@ -- * *radius* Scattering radius of the fired shots in meters. Default is 100 m. -- * *weapon* Type of weapon to be used. Valid parameters are *cannon*, *rocket*, *missile*, *nuke*. Default is automatic selection. -- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition. +-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks. +-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks. -- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. -- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant here. The group will engage the coordinates given in the lldms keyword. -- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below. This can be useful when coordinates in this format are obtained from elsewhere. @@ -305,9 +308,13 @@ -- arty engage, battery "Blue MRLS 1", key 666 -- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15 -- arty engage, lldms 41:51:00N 41:47:58E +-- arty engage, alias "Bob", weapon missiles +-- arty engage, cluster "All Mortas" +-- arty engage, cluster "Northern Batteries" "Southern Batteries" +-- arty engage, cluster "Northern Batteries", cluster "Southern Batteries" -- --- Note that the keywords and parameters are *case insensitve*. Only exception are the battery group names. These must be exactly the same as the names of the goups defined --- in the mission editor. +-- Note that the keywords and parameters are *case insensitve*. Only exception are the battery, alias and cluster names. +-- These must be exactly the same as the names of the goups defined in the mission editor or the aliases and cluster names defined in the script. -- -- ### Relocation Assignments -- @@ -318,6 +325,8 @@ -- * *on road* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate. -- * *canceltarget* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over. -- * *battery* Name of the ARTY group that the relocation is assigned to. +-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks. +-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks. -- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. -- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant. The group will move to the coordinates given in the lldms keyword. -- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below. @@ -329,6 +338,10 @@ -- arty move, battery "Blue Paladin" -- arty move, battery "Blue MRLS", canceltarget, speed 10, on road -- arty move, lldms 41:51:00N 41:47:58E +-- arty move, alias "Bob", weapon missiles +-- arty move, cluster "All Howitzer" +-- arty move, cluster "Northern Batteries" "Southern Batteries" +-- arty move, cluster "Northern Batteries", cluster "Southern Batteries" -- -- ### Requests -- @@ -341,7 +354,7 @@ -- For example -- arty request, ammo -- arty request, battery "Paladin Bravo", targets --- arty request, battery "MRLS Charly", move +-- arty request, cluster "All Mortars", move -- -- The actual location of the marker is irrelevant for these requests. -- @@ -363,6 +376,7 @@ -- optional parameter *maxdist* is the maximum distance im km the group will move. If the distance is greater no relocation is performed. Default is 50 km. -- * @{#ARTY.SetAutoRelocateAfterEngagement}(*rmax*, *rmin*) will cause the ARTY group to change its position after each firing assignment. -- Optional parameters *rmax*, *rmin* define the max/min distance for relocation of the group. Default distance is randomly between 300 and 800 m. +-- * @{#ARTY.AddToCluster}(*clusters*) Can be used to add the ARTY group to one or more clusters. All groups in a cluster can be addressed simultaniously with one marker command. -- * @{#ARTY.RemoveAllTargets}() removes all targets from the target queue. -- * @{#ARTY.RemoveTarget}(*name*) deletes the target with *name* from the target queue. -- * @{#ARTY.SetMaxFiringRange}(*range*) defines the maximum firing range. Targets further away than this distance are not engaged. @@ -458,6 +472,7 @@ ARTY={ DisplayName=nil, groupname=nil, alias=nil, + clusters={}, ismobile=true, IniGroupStrength=0, IsArtillery=nil, @@ -571,7 +586,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="1.0.0" +ARTY.version="1.0.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -605,7 +620,7 @@ ARTY.version="1.0.0" --- Creates a new ARTY object. -- @param #ARTY self -- @param Wrapper.Group#GROUP group The GROUP object for which artillery tasks should be assigned. --- @param alias (Optional) Alias name the group will be calling itself when sending messages. +-- @param alias (Optional) Alias name the group will be calling itself when sending messages. Default is the group name. -- @return #ARTY ARTY object or nil if group does not exist or is not a ground or naval group. function ARTY:New(group, alias) BASE:F2(group) @@ -1136,6 +1151,38 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique) return _name end +--- Set alias, i.e. the name the group will use when sending messages. +-- @param #ARTY self +-- @param #string alias The alias for the group. +function ARTY:SetAlias(alias) + self:F({alias=alias}) + self.alias=tostring(alias) +end + +--- Add ARTY group to one or more clusters. Enables addressing all ARTY groups within a cluster simultaniously via marker assignments. +-- @param #ARTY self +-- @param #table clusters Table of cluster names the group should belong to. +function ARTY:AddToCluster(clusters) + self:F({clusters=clusters}) + + -- Convert input to table. + local names + if type(clusters)=="table" then + names=clusters + elseif type(clusters)=="string" then + names={clusters} + else + -- error message + self:E(ARTY.id.."ERROR: Input parameter must be a string or a table in ARTY:AddToCluster()!") + return + end + + -- Add names to cluster array. + for _,cluster in pairs(names) do + table.insert(self.clusters, cluster) + end +end + --- Set minimum firing range. Targets closer than this distance are not engaged. -- @param #ARTY self -- @param #number range Min range in kilometers. Default is 0.1 km. @@ -1529,6 +1576,10 @@ function ARTY:onafterStart(Controllable, From, Event, To) text=text..string.format("Marker assignments = %s\n", tostring(self.markallow)) text=text..string.format("Marker auth. key = %s\n", tostring(self.markkey)) text=text..string.format("Marker readonly = %s\n", tostring(self.markreadonly)) + text=text..string.format("Clusters:\n") + for _,cluster in pairs(self.clusters) do + text=text..string.format("- %s\n", tostring(cluster)) + end text=text..string.format("******************************************************\n") text=text..string.format("Targets:\n") for _, target in pairs(self.targets) do @@ -1810,10 +1861,10 @@ function ARTY:onEvent(Event) end -- Set battery and coalition. - local batteryname=self.groupname - local batterycoalition=self.Controllable:GetCoalition() + --local batteryname=self.groupname + --local batterycoalition=self.Controllable:GetCoalition() - self:T2(string.format("Event captured = %s", tostring(batteryname))) + self:T2(string.format("Event captured = %s", tostring(self.groupname))) self:T2(string.format("Event id = %s", tostring(Event.id))) self:T2(string.format("Event time = %s", tostring(Event.time))) self:T2(string.format("Event idx = %s", tostring(Event.idx))) @@ -1822,20 +1873,20 @@ function ARTY:onEvent(Event) self:T2(string.format("Event text = %s", tostring(Event.text))) if Event.initiator~=nil then local _unitname=Event.initiator:getName() - self:T(string.format("Event ini unit name = %s", tostring(_unitname))) + self:T2(string.format("Event ini unit name = %s", tostring(_unitname))) end if Event.id==world.event.S_EVENT_MARK_ADDED then - self:E({event="S_EVENT_MARK_ADDED", battery=batteryname, vec3=Event.pos}) + self:T2({event="S_EVENT_MARK_ADDED", battery=self.groupname, vec3=Event.pos}) elseif Event.id==world.event.S_EVENT_MARK_CHANGE then - self:E({event="S_EVENT_MARK_CHANGE", battery=batteryname, vec3=Event.pos}) + self:T({event="S_EVENT_MARK_CHANGE", battery=self.groupname, vec3=Event.pos}) -- Handle event. self:_OnEventMarkChange(Event) elseif Event.id==world.event.S_EVENT_MARK_REMOVED then - self:E({event="S_EVENT_MARK_REMOVED", battery=batteryname, vec3=Event.pos}) + self:T2({event="S_EVENT_MARK_REMOVED", battery=self.groupname, vec3=Event.pos}) -- Hande event. self:_OnEventMarkRemove(Event) @@ -1938,16 +1989,38 @@ function ARTY:_OnEventMarkChange(Event) return end - -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. - local _assigned=true - if #_assign.battery>0 then - _assigned=false + -- Check if job is assigned to this ARTY group. Default is for all ARTY groups. + local _assigned=false + + -- If any array is filled something has been assigned. + if #_assign.battery>0 or #_assign.aliases>0 or #_assign.cluster>0 then + + -- Loop over batteries. for _,bat in pairs(_assign.battery) do - self:T3(ARTY.id..string.format("Compare battery names %s=%s ==> %s",batteryname, bat, tostring(batteryname==bat))) - if batteryname==bat then + if self.groupname==bat then _assigned=true end end + + -- Loop over aliases. + for _,alias in pairs(_assign.aliases) do + if self.alias==alias then + _assigned=true + end + end + + -- Loop over clusters. + for _,bat in pairs(_assign.cluster) do + for _,cluster in pairs(self.clusters) do + if cluster==bat then + _assigned=true + end + end + end + + else + -- No one explicitly assigned ==> we assume to be assigned. + _assigned=true end -- We were not addressed. @@ -1995,6 +2068,7 @@ function ARTY:_OnEventMarkChange(Event) self:Winchester() end end + -- Cancels Done ==> End of story! return end @@ -2027,7 +2101,7 @@ function ARTY:_OnEventMarkChange(Event) -- Create a new name. This determins the string we search when deleting a move! local _name=self:_MarkMoveName(_id) - local text=string.format("%s, received new relocation assignment.", batteryname) + local text=string.format("%s, received new relocation assignment.", self.alias) text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) @@ -2046,7 +2120,7 @@ function ARTY:_OnEventMarkChange(Event) local _randomcoord=_coord:GetRandomCoordinateInRadius(100) _randomcoord:MarkToCoalition(_markertext, batterycoalition, self.markreadonly or _assign.readonly) else - local text=string.format("%s, relocation not possible.", batteryname) + local text=string.format("%s, relocation not possible.", self.alias) MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) end @@ -2055,7 +2129,7 @@ function ARTY:_OnEventMarkChange(Event) -- Create a new name. local _name=self:_MarkTargetName(_id) - local text=string.format("%s, received new target assignment.", batteryname) + local text=string.format("%s, received new target assignment.", self.alias) text=text..string.format("\nCoordinates %s",_coord:ToStringLLDMS()) if _assign.time then text=text..string.format("\nTime %s",_assign.time) @@ -3374,11 +3448,11 @@ function ARTY:_MarkerKeyAuthentification(text) -- Send message local text="" if mykey==nil then - text=string.format("%s, authorization required but did not receive a key!", batteryname) + text=string.format("%s, authorization required but did not receive a key!", self.alias) elseif _validkey==false then - text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", batteryname, tostring(mykey)) + text=string.format("%s, authorization required but did receive an incorrect key (key=%s)!", self.alias, tostring(mykey)) elseif _validkey==true then - text=string.format("%s, authentification successful!", batteryname) + text=string.format("%s, authentification successful!", self.alias) end MESSAGE:New(text, 10):ToCoalitionIf(batterycoalition, self.report or self.Debug) end @@ -3396,6 +3470,8 @@ function ARTY:_Markertext(text) -- Assignment parameters. local assignment={} assignment.battery={} + assignment.aliases={} + assignment.cluster={} assignment.move=false assignment.engage=false assignment.request=false @@ -3443,6 +3519,24 @@ function ARTY:_Markertext(text) table.insert(assignment.battery, v[i]) self:T2(ARTY.id..string.format("Key Battery=%s.", v[i])) end + + elseif key:lower():find("alias") then + + local v=self:_split(keyphrase, '"') + + for i=2,#v,2 do + table.insert(assignment.aliases, v[i]) + self:T2(ARTY.id..string.format("Key Aliases=%s.", v[i])) + end + + elseif key:lower():find("cluster") then + + local v=self:_split(keyphrase, '"') + + for i=2,#v,2 do + table.insert(assignment.cluster, v[i]) + self:T2(ARTY.id..string.format("Key Cluster=%s.", v[i])) + end elseif (assignment.engage or assignment.move) and key:lower():find("time") then From 89e67ba54d6b16bbb2be7b5e5fc36dc1ac04d29c Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 12 Jun 2018 19:50:21 +0200 Subject: [PATCH 170/170] ARTY v1.0.2 Changed behavior that if no arty group is addressed explicitly, nothing is happening. Before all groups were addressed. --- .../Moose/Functional/Artillery.lua | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index d2c1ad784..fa5d346d9 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -285,33 +285,40 @@ -- ARTY group are able to assign targets and moves without a key. -- -- ### Target Assignments --- A new target can be assigned by writing **arty engage** in the marker text. This can be followed by a **comma separated list** of optional keywords and parameters: +-- A new target can be assigned by writing **arty engage** in the marker text. +-- This is followed by a **comma separated list** of (optional) keywords and parameters. +-- First, it is important to address the ARTY group or groups that should engage. This can be done in numrous ways. The keywords are *battery*, *alias*, *cluster*. +-- It is also possible to address all ARTY groups by the keyword *everyone* or *allbatteries*. These two can be used synonymously. +-- **Note that**, if no battery is assigned nothing will happen. -- +-- * *everyone* or *allbatteries* The target is assigned to all batteries. +-- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition. +-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks. +-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks. +-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. -- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible. -- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50, i.e. medium priority. -- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5. -- * *maxengage* Number of times the target is engaged. Default is 1. -- * *radius* Scattering radius of the fired shots in meters. Default is 100 m. -- * *weapon* Type of weapon to be used. Valid parameters are *cannon*, *rocket*, *missile*, *nuke*. Default is automatic selection. --- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition. --- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks. --- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks. --- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement. -- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant here. The group will engage the coordinates given in the lldms keyword. -- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below. This can be useful when coordinates in this format are obtained from elsewhere. -- * *readonly* The marker is readonly and cannot be deleted by users. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are examples of valid marker texts: --- arty engage +-- arty engage, battery "Blue Paladin Alpha" +-- arty engage, everyone +-- arty engage, allbatteries +-- arty engage, alias "Bob", weapon missiles +-- arty engage, cluster "All Mortas" +-- arty engage, cluster "Northern Batteries" "Southern Batteries" +-- arty engage, cluster "Northern Batteries", cluster "Southern Batteries" -- arty engage, shots 20, prio 10, time 08:15, weapon cannons -- arty engage, battery "Blue Paladin 1" "Blue MRLS 1", shots 10, time 10:15 -- arty engage, battery "Blue MRLS 1", key 666 -- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15 -- arty engage, lldms 41:51:00N 41:47:58E --- arty engage, alias "Bob", weapon missiles --- arty engage, cluster "All Mortas" --- arty engage, cluster "Northern Batteries" "Southern Batteries" --- arty engage, cluster "Northern Batteries", cluster "Southern Batteries" -- -- Note that the keywords and parameters are *case insensitve*. Only exception are the battery, alias and cluster names. -- These must be exactly the same as the names of the goups defined in the mission editor or the aliases and cluster names defined in the script. @@ -333,15 +340,14 @@ -- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker. -- -- Here are some examples: --- arty move --- arty move, time 23:45, speed 50, on road -- arty move, battery "Blue Paladin" -- arty move, battery "Blue MRLS", canceltarget, speed 10, on road --- arty move, lldms 41:51:00N 41:47:58E +-- arty move, cluster "mobile", lldms 41:51:00N 41:47:58E -- arty move, alias "Bob", weapon missiles -- arty move, cluster "All Howitzer" -- arty move, cluster "Northern Batteries" "Southern Batteries" -- arty move, cluster "Northern Batteries", cluster "Southern Batteries" +-- arty move, everyone -- -- ### Requests -- @@ -352,7 +358,7 @@ -- * *ammo* Current ammunition status is reported. -- -- For example --- arty request, ammo +-- arty request, everyone, ammo -- arty request, battery "Paladin Bravo", targets -- arty request, cluster "All Mortars", move -- @@ -586,7 +592,7 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="1.0.1" +ARTY.version="1.0.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -614,6 +620,7 @@ ARTY.version="1.0.1" -- TODO: Add set commands via markers. E.g. set rearming place. -- DONE: Test stationary types like mortas ==> rearming etc. -- TODO: Add hit event and make the arty group relocate. +-- TODO: Add illumination and smoke. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1901,7 +1908,7 @@ function ARTY:_OnEventMarkRemove(Event) -- Get battery coalition and name. local batterycoalition=self.Controllable:GetCoalition() - local batteryname=self.groupname + --local batteryname=self.groupname if Event.text~=nil and Event.text:find("BATTERY") then @@ -1986,6 +1993,7 @@ function ARTY:_OnEventMarkChange(Event) -- Check if ENGAGE or MOVE or REQUEST keywords were found. if _assign==nil or not (_assign.engage or _assign.move or _assign.request or _assign.cancel) then + self:T(ARTY.id..string.format("WARNING: %s, no keyword ENGAGE, MOVE, REQUEST or CANCEL in mark text! Command will not be executed. Text:\n%s", self.groupname, Event.text)) return end @@ -1993,7 +2001,10 @@ function ARTY:_OnEventMarkChange(Event) local _assigned=false -- If any array is filled something has been assigned. - if #_assign.battery>0 or #_assign.aliases>0 or #_assign.cluster>0 then + if _assign.everyone then + -- Everyone was addressed. + _assigned=true + else --#_assign.battery>0 or #_assign.aliases>0 or #_assign.cluster>0 then -- Loop over batteries. for _,bat in pairs(_assign.battery) do @@ -2017,14 +2028,12 @@ function ARTY:_OnEventMarkChange(Event) end end end - - else - -- No one explicitly assigned ==> we assume to be assigned. - _assigned=true + end -- We were not addressed. if not _assigned then + self:T3(ARTY.id..string.format("INFO: ARTY group %s was not addressed! Mark text:\n%s", self.groupname, Event.text)) return end @@ -3411,7 +3420,7 @@ end function ARTY:_MarkerKeyAuthentification(text) -- Set battery and coalition. - local batteryname=self.groupname + --local batteryname=self.groupname local batterycoalition=self.Controllable:GetCoalition() -- Get assignment. @@ -3443,7 +3452,7 @@ function ARTY:_MarkerKeyAuthentification(text) if mykey~=nil then _validkey=self.markkey==mykey end - self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", batteryname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) + self:T2(ARTY.id..string.format("%s, authkey=%s == %s=playerkey ==> valid=%s", self.groupname, tostring(self.markkey), tostring(mykey), tostring(_validkey))) -- Send message local text="" @@ -3472,6 +3481,7 @@ function ARTY:_Markertext(text) assignment.battery={} assignment.aliases={} assignment.cluster={} + assignment.everyone=false assignment.move=false assignment.engage=false assignment.request=false @@ -3537,6 +3547,11 @@ function ARTY:_Markertext(text) table.insert(assignment.cluster, v[i]) self:T2(ARTY.id..string.format("Key Cluster=%s.", v[i])) end + + elseif keyphrase:lower():find("everyone") or keyphrase:lower():find("all batteries") or keyphrase:lower():find("allbatteries") then + + assignment.everyone=true + self:T(ARTY.id..string.format("Key Everyone=true.")) elseif (assignment.engage or assignment.move) and key:lower():find("time") then