From 11c7cea1ded1795e9198279a06756058945485f1 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 19 Mar 2016 01:45:15 +0100 Subject: [PATCH 01/14] New ESCORT class, first version ... This class does now detection reporting to the main client group. --- Moose/Base.lua | 1 + Moose/Client.lua | 2 +- Moose/Database.lua | 1 + Moose/Escort.lua | 109 +++++++++++++++++++++++++++++++++++++++++++++ Moose/Group.lua | 25 +++++++++++ Moose/Routines.lua | 2 +- Moose/Unit.lua | 11 +++++ 7 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 Moose/Escort.lua diff --git a/Moose/Base.lua b/Moose/Base.lua index 3fab73c90..3a1a56dc2 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -22,6 +22,7 @@ _TraceClass = { --CARGO_SLINGLOAD = true, --CARGO_ZONE = true, --CLEANUP = true, + ESCORT = true, } --- The BASE Class diff --git a/Moose/Client.lua b/Moose/Client.lua index e5438f541..332bce256 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -307,7 +307,7 @@ self:T() self.Messages[MessageId].MessageTime = timer.getTime() self.Messages[MessageId].MessageDuration = MessageDuration if MessageInterval == nil then - self.Messages[MessageId].MessageInterval = 600 + self.Messages[MessageId].MessageInterval = 0 else self.Messages[MessageId].MessageInterval = MessageInterval end diff --git a/Moose/Database.lua b/Moose/Database.lua index d20f79f23..27265637b 100644 --- a/Moose/Database.lua +++ b/Moose/Database.lua @@ -1,6 +1,7 @@ --- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor. -- Administers the Spawning of new Groups within the DCSRTE and administers these new Groups within the DATABASE object(s). -- @module DATABASE +-- @author FlightControl Include.File( "Routines" ) Include.File( "Base" ) diff --git a/Moose/Escort.lua b/Moose/Escort.lua new file mode 100644 index 000000000..a9fbd3722 --- /dev/null +++ b/Moose/Escort.lua @@ -0,0 +1,109 @@ +--- Taking the lead of AI escorting your flight. +-- The ESCORT class allows you to interact with escoring AI on your flight and take the lead. +-- The following commands will be available: +-- +-- * Pop-up and Scan Area +-- * Re-Join Formation +-- * Hold Position in x km +-- * Report identified targets +-- * Perform tasks per identified target: Report vector to target, paint target, kill target +-- +-- @module ESCORT +-- @author FlightControl + +Include.File( "Routines" ) +Include.File( "Base" ) +Include.File( "Database" ) +Include.File( "Group" ) +Include.File( "Zone" ) + +--- ESCORT class +-- @type +-- +ESCORT = { + ClassName = "ESCORT", + EscortName = nil, -- The Escort Name + Targets = {}, -- The identified targets +} + +--- ESCORT class constructor for an AI group +-- @param self +-- @param #CLIENT EscortClient The client escorted by the EscortGroup. +-- @param #GROUP EscortGroup The group AI escorting the EscortClient. +-- @param #string EscortName Name of the escort. +-- @return #ESCORT self +function ESCORT:New( EscortClient, EscortGroup, EscortName ) + local self = BASE:Inherit( self, BASE:New() ) + self:T( { EscortClient, EscortGroup, EscortName } ) + + self.EscortClient = EscortClient + self.EscortGroup = EscortGroup + self.EscortName = EscortName + + self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 10 ) +end + +function ESCORT:_ScanForTargets() + self:T() + + if self.EscortGroup:IsAlive() then + local EscortTargets = self.EscortGroup:GetDetectedTargets() + + local EscortTargetMessages = "" + for EscortTargetID, EscortTarget in pairs( EscortTargets ) do + local EscortObject = EscortTarget.object + self:T( EscortObject ) + if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then + + local EscortTargetMessage = "" + + local EscortTargetUnit = UNIT:New( EscortObject ) + + local EscortTargetCategoryName = EscortTargetUnit:GetCategoryName() + local EscortTargetCategoryType = EscortTargetUnit:GetTypeName() + + + -- local EscortTargetIsDetected, + -- EscortTargetIsVisible, + -- EscortTargetLastTime, + -- EscortTargetKnowType, + -- EscortTargetKnowDistance, + -- EscortTargetLastPos, + -- EscortTargetLastVelocity + -- = self.EscortGroup:IsTargetDetected( EscortObject ) + -- + -- self:T( { EscortTargetIsDetected, + -- EscortTargetIsVisible, + -- EscortTargetLastTime, + -- EscortTargetKnowType, + -- EscortTargetKnowDistance, + -- EscortTargetLastPos, + -- EscortTargetLastVelocity } ) + + if EscortTarget.distance then + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() + local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 + self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) + if Distance <= 8 then + EscortTargetMessage = EscortTargetMessage .. " - " .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") " + EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" + if EscortTarget.visible then + EscortTargetMessage = EscortTargetMessage .. " visual contact" + end + end + end + + if EscortTargetMessage ~= "" then + EscortTargetMessages = EscortTargetMessages .. EscortTargetMessage .. "\n" + end + end + end + + if EscortTargetMessages ~= "" then + self.EscortClient:Message( EscortTargetMessages:gsub("\n$",""), 20, "/ESCORT.DetectedTargets", self.EscortName .. " reporting detected targets within 8 km range:" ) + end + else + routines.removeFunction( self.ScanForTargetsFunction ) + end +end diff --git a/Moose/Group.lua b/Moose/Group.lua index 1103b13be..d1768fd21 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -130,6 +130,16 @@ function GROUP:GetPoint() return GroupPoint end +--- Gets the current Point of the GROUP in VEC3 format. +-- @return #Vec3 Current Vec3 position of the group. +function GROUP:GetPositionVec3() + self:T( self.GroupName ) + + local GroupPoint = self:GetUnit(1):GetPositionVec3() + self:T( GroupPoint ) + return GroupPoint +end + --- Destroy a GROUP -- Note that this destroy method also raises a destroy event at run-time. -- So all event listeners will catch the destroy event of this GROUP. @@ -441,3 +451,18 @@ function GROUP:_GetController() return self.DCSGroup:getController() end + +function GROUP:GetDetectedTargets() + + return self:_GetController():getDetectedTargets() + +end + +function GROUP:IsTargetDetected( DCSObject ) + + local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + = self:_GetController():isTargetDetected( DCSObject ) + + return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + +end \ No newline at end of file diff --git a/Moose/Routines.lua b/Moose/Routines.lua index c591ef9c4..d8a61bde6 100644 --- a/Moose/Routines.lua +++ b/Moose/Routines.lua @@ -422,7 +422,7 @@ routines.tostringBR = function(az, dist, alt, metric) dist = routines.utils.round(routines.utils.metersToNM(dist), 2) end - local s = string.format('%03d°', az) .. ' for ' .. dist + local s = string.format('%03d', az) .. ' for ' .. dist if alt then if metric then diff --git a/Moose/Unit.lua b/Moose/Unit.lua index 6432e3b10..7af365ca5 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -9,6 +9,13 @@ Include.File( "Message" ) -- @type UNIT = { ClassName="UNIT", + CategoryName = { + [Unit.Category.AIRPLANE] = "Airplane", + [Unit.Category.HELICOPTER] = "Helicoper", + [Unit.Category.GROUND_UNIT] = "Ground Unit", + [Unit.Category.SHIP] = "Ship", + [Unit.Category.STRUCTURE] = "Structure", + } } function UNIT:New( DCSUnit ) @@ -112,3 +119,7 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) return false end +function UNIT:GetCategoryName() + return self.CategoryName[ self.DCSUnit:getDesc().category ] +end + From 560e3d643f8f7b32e854a3bf43ae3af1ef13d235 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 24 Mar 2016 11:00:49 +0100 Subject: [PATCH 02/14] Worked on DCS function prototyping Found in LDT the means to create using luadoc function prototypes using a documentation mechanism. Am reworking now the DCS function manual to a luadoc structure. --- DCS/Airbase.doclua | 53 ++++++++ DCS/CoalitionObject.doclua | 17 +++ DCS/Controller.doclua | 116 +++++++++++++++++ DCS/DCSTypes.lua | 231 ++++++++++++++++++++++++++++++++++ DCS/Group.doclua | 82 ++++++++++++ DCS/Object.doclua | 73 +++++++++++ DCS/StaticObject.doclua | 34 +++++ DCS/Time.doclua | 2 + DCS/Unit.doclua | 241 ++++++++++++++++++++++++++++++++++++ DCS/env.doclua | 27 ++++ DCS/timer.doclua | 45 +++++++ Embedded/Moose_Embedded.lua | 32 ++--- Moose/Base.lua | 16 ++- Moose/Cargo.lua | 18 +-- Moose/Client.lua | 92 ++++++++------ Moose/Escort.lua | 159 ++++++++++++++++++++++-- Moose/Group.lua | 185 ++++++++++++++++++++++++++- Moose/Menu.lua | 34 ++++- Moose/Message.lua | 11 +- Moose/Mission.lua | 4 +- 20 files changed, 1381 insertions(+), 91 deletions(-) create mode 100644 DCS/Airbase.doclua create mode 100644 DCS/CoalitionObject.doclua create mode 100644 DCS/Controller.doclua create mode 100644 DCS/DCSTypes.lua create mode 100644 DCS/Group.doclua create mode 100644 DCS/Object.doclua create mode 100644 DCS/StaticObject.doclua create mode 100644 DCS/Time.doclua create mode 100644 DCS/Unit.doclua create mode 100644 DCS/env.doclua create mode 100644 DCS/timer.doclua diff --git a/DCS/Airbase.doclua b/DCS/Airbase.doclua new file mode 100644 index 000000000..679a09981 --- /dev/null +++ b/DCS/Airbase.doclua @@ -0,0 +1,53 @@ +------------------------------------------------------------------------------- +-- @module Airbase +-- @extends CoalitionObject#CoalitionObject + +--- Represents airbases: airdromes, helipads and ships with flying decks or landing pads. +-- @type Airbase +-- @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#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/DCS/CoalitionObject.doclua b/DCS/CoalitionObject.doclua new file mode 100644 index 000000000..ee189fd77 --- /dev/null +++ b/DCS/CoalitionObject.doclua @@ -0,0 +1,17 @@ +------------------------------------------------------------------------------- +-- @module CoalitionObject +-- @extends Object#Object + +--- @type CoalitionObject + +--- Returns coalition of the object. +-- @function [parent=#CoalitionObject] getCoalition +-- @param self +-- @return #coalition.side + +--- Returns object country. +-- @function [parent=#CoalitionObject] getCountry +-- @param self +-- @return #country.id + +CoalitionObject = {} --#CoalitionObject diff --git a/DCS/Controller.doclua b/DCS/Controller.doclua new file mode 100644 index 000000000..0f434cd30 --- /dev/null +++ b/DCS/Controller.doclua @@ -0,0 +1,116 @@ +------------------------------------------------------------------------------- +-- @module Controller +-- TODO Add Task templates + +--- 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 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 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 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/DCS/DCSTypes.lua b/DCS/DCSTypes.lua new file mode 100644 index 000000000..1bb654f73 --- /dev/null +++ b/DCS/DCSTypes.lua @@ -0,0 +1,231 @@ + +--- 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 + + +--- @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' ) \ No newline at end of file diff --git a/DCS/Group.doclua b/DCS/Group.doclua new file mode 100644 index 000000000..4aeb17653 --- /dev/null +++ b/DCS/Group.doclua @@ -0,0 +1,82 @@ +------------------------------------------------------------------------------- +-- @module 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=#Airbase] getByName +-- @param #string name +-- @return #Group + +-- Member Functions + +--- returns true if the group exist or false otherwise. +-- @function [parent=#Airbase] isExist +-- @param self +-- @return #boolean + +--- Destroys the group and all of its units. +-- @function [parent=#Airbase] destroy +-- @param self + +--- Returns category of the group. +-- @function [parent=#Airbase] getCategory +-- @param self +-- @return #Group.Category + +--TODO check coalition.side +--- Returns coalition of the group. +-- @function [parent=#Airbase] getCoalition +-- @param self +-- @return #coalition.side + +--- Returns the group's name. This is the same name assigned to the group in Mission Editor. +-- @function [parent=#Airbase] getName +-- @param self +-- @return #string + +--- Returns the group identifier. +-- @function [parent=#Airbase] getID +-- @param self +-- @return #ID + +--- Returns the unit with number unitNumber. If the unit is not exists the function will return nil. +-- @function [parent=#Airbase] getUnit +-- @param self +-- @param #number unitNumber +-- @return 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=#Airbase] getSize +-- @param 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=#Airbase] getInitialSize +-- @param self +-- @return #number + +--- Returns array of the units present in the group now. Destroyed units will not be enlisted at all. +-- @function [parent=#Airbase] getUnits +-- @param self +-- @return #list array of Units + +--- Returns controller of the group. +-- @function [parent=#Airbase] getController +-- @param self +-- @return Controller#Controller + +Group = {} --#Group diff --git a/DCS/Object.doclua b/DCS/Object.doclua new file mode 100644 index 000000000..fcd3c2416 --- /dev/null +++ b/DCS/Object.doclua @@ -0,0 +1,73 @@ +------------------------------------------------------------------------------- +-- @module 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 self +-- @return #boolean + +--- @function [parent=#Object] destroy +-- @param self + +--- @function [parent=#Object] getCategory +-- @param self +-- @return #Object.Category + +--- Returns type name of the Object. +-- @function [parent=#Object] getTypeName +-- @param self +-- @return #string + +--- Returns object descriptor. +-- @function [parent=#Object] getDesc +-- @param self +-- @return #Object.Desc + +--- Returns true if the object belongs to the category. +-- @function [parent=#Object] hasAttribute +-- @param 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 self +-- @return #string + +--- Returns object coordinates for current time. +-- @function [parent=#Object] getPoint +-- @param self +-- @return #Vec3 + +--- Returns object position for current time. +-- @function [parent=#Object] getPosition +-- @param self +-- @return #Position3 + +--- Returns the unit's velocity vector. +-- @function [parent=#Object] getVelocity +-- @param self +-- @return #Vec3 + +--- Returns true if the unit is in air. +-- @function [parent=#Object] inAir +-- @param self +-- @return #boolean + +Object = {} --#Object + diff --git a/DCS/StaticObject.doclua b/DCS/StaticObject.doclua new file mode 100644 index 000000000..2aa818548 --- /dev/null +++ b/DCS/StaticObject.doclua @@ -0,0 +1,34 @@ +------------------------------------------------------------------------------- +-- @module StaticObject + + +------------------------------------------------------------------------------- +-- @module StaticObject +-- @extends CoalitionObject#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 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 self +-- @return #StaticObject.ID + +--- Returns descriptor of the StaticObject. +-- @function [parent=#StaticObject] getDesc +-- @param self +-- @return #StaticObject.Desc + + +StaticObject = {} --#StaticObject diff --git a/DCS/Time.doclua b/DCS/Time.doclua new file mode 100644 index 000000000..95b1efcc1 --- /dev/null +++ b/DCS/Time.doclua @@ -0,0 +1,2 @@ +-- @type ModelTime +-- @extends #number diff --git a/DCS/Unit.doclua b/DCS/Unit.doclua new file mode 100644 index 000000000..1e420182e --- /dev/null +++ b/DCS/Unit.doclua @@ -0,0 +1,241 @@ +------------------------------------------------------------------------------- +-- @module Unit +-- @extends CoalitionObject#CoalitionObject + +--- @type Unit +-- @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#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#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#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#Unit.DescAircraft +-- @field #Distance HmaxStat static ceiling + +--- A vehicle descriptor. +-- @type Unit.DescVehicle +-- @extends 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 Unit#Unit.Sensor +-- @field #Unit.OpticType opticType + +--- A radar. +-- @type Unit.Radar +-- @extends 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 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 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 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 self +-- @return #string + +--- returns the unit's unique identifier. +-- @function [parent=#Unit] getID +-- @param 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 self +-- @return #number + +--- Returns controller of the unit if it exist and nil otherwise +-- @function [parent=#Unit] getController +-- @param self +-- @return #Controller + +--- Returns the unit's group if it exist and nil otherwise +-- @function [parent=#Unit] getGroup +-- @param self +-- @return Group#Group + +--- Returns the unit's callsign - the localized string. +-- @function [parent=#Unit] getCallsign +-- @param self +-- @return #string + +--- Returns the unit's health. Dead units has health <= 1.0 +-- @function [parent=#Unit] getLife +-- @param self +-- @return #number + +--- returns the unit's initial health. +-- @function [parent=#Unit] getLife0 +-- @param 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 self +-- @return #number + +--- Returns the unit ammunition. +-- @function [parent=#Unit] getAmmo +-- @param self +-- @return #Unit.Ammo + +--- Returns the unit sensors. +-- @function [parent=#Unit] getSensors +-- @param 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 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 self +-- @return #boolean, Object#Object + +--- Returns unit descriptor. Descriptor type depends on unit category. +-- @function [parent=#Unit] getDesc +-- @param self +-- @return Unit#Unit.Desc + + +Unit = {} --#Unit diff --git a/DCS/env.doclua b/DCS/env.doclua new file mode 100644 index 000000000..c6fe98776 --- /dev/null +++ b/DCS/env.doclua @@ -0,0 +1,27 @@ +------------------------------------------------------------------------------- +-- @module 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 diff --git a/DCS/timer.doclua b/DCS/timer.doclua new file mode 100644 index 000000000..56127eb4a --- /dev/null +++ b/DCS/timer.doclua @@ -0,0 +1,45 @@ +------------------------------------------------------------------------------- +-- @module 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 diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index 73d4157cb..cb2282790 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -5287,7 +5287,7 @@ function CARGO_GROUP:Spawn( Client ) elseif self:IsStatusLoading() then local Client = self:IsLoadingToClient() - if Client and Client:ClientGroup() then + if Client and Client:GetDCSGroup() then SpawnCargo = false else local CargoGroup = Group.getByName( self.CargoName ) @@ -5301,7 +5301,7 @@ function CARGO_GROUP:Spawn( Client ) local ClientLoaded = self:IsLoadedInClient() -- Now test if another Client is alive (not this one), and it has the CARGO, then this cargo does not need to be initialized and spawned. if ClientLoaded and ClientLoaded ~= Client then - local ClientGroup = Client:ClientGroup() + local ClientGroup = Client:GetDCSGroup() if ClientLoaded:GetClientGroupDCSUnit() and ClientLoaded:GetClientGroupDCSUnit():isExist() then SpawnCargo = false else @@ -5487,7 +5487,7 @@ function CARGO_PACKAGE:Spawn( Client ) -- this needs to be checked thoroughly - local CargoClientGroup = self.CargoClient:ClientGroup() + local CargoClientGroup = self.CargoClient:GetDCSGroup() if not CargoClientGroup then if not self.CargoClientSpawn then self.CargoClientSpawn = SPAWN:New( self.CargoClient:GetClientGroupName() ):Limit( 1, 1 ) @@ -5502,7 +5502,7 @@ function CARGO_PACKAGE:Spawn( Client ) elseif self:IsStatusLoading() or self:IsStatusLoaded() then local CargoClientLoaded = self:IsLoadedInClient() - if CargoClientLoaded and CargoClientLoaded:ClientGroup() then + if CargoClientLoaded and CargoClientLoaded:GetDCSGroup() then SpawnCargo = false end @@ -5527,7 +5527,7 @@ self:T() local Near = false - if self.CargoClient and self.CargoClient:ClientGroup() then + if self.CargoClient and self.CargoClient:GetDCSGroup() then self:T( self.CargoClient.ClientName ) self:T( 'Client Exists.' ) @@ -5553,8 +5553,8 @@ self:T() local CarrierPosOnBoard = ClientUnit:getPoint() local CarrierPosMoveAway = ClientUnit:getPoint() - local CargoHostGroup = self.CargoClient:ClientGroup() - local CargoHostName = self.CargoClient:ClientGroup():getName() + local CargoHostGroup = self.CargoClient:GetDCSGroup() + local CargoHostName = self.CargoClient:GetDCSGroup():getName() local CargoHostUnits = CargoHostGroup:getUnits() local CargoPos = CargoHostUnits[1]:getPoint() @@ -5637,7 +5637,7 @@ self:T() local OnBoarded = false - if self.CargoClient and self.CargoClient:ClientGroup() then + if self.CargoClient and self.CargoClient:GetDCSGroup() then if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), self.CargoClient:ClientPosition(), 10 ) then -- Switch Cargo from self.CargoClient to Client ... Each cargo can have only one client. So assigning the new client for the cargo is enough. @@ -5658,7 +5658,7 @@ self:T() self:T( 'self.CargoName = ' .. self.CargoName ) --self:T( 'self.CargoHostName = ' .. self.CargoHostName ) - --self.CargoSpawn:FromCarrier( Client:ClientGroup(), TargetZoneName, self.CargoHostName ) + --self.CargoSpawn:FromCarrier( Client:GetDCSGroup(), TargetZoneName, self.CargoHostName ) self:StatusUnLoaded() return Cargo @@ -5883,7 +5883,7 @@ end --- ClientGroup returns the Group of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 -- @return Group -function CLIENT:ClientGroup() +function CLIENT:GetDCSGroup() --self:T() -- local ClientData = Group.getByName( self.ClientName ) @@ -5955,7 +5955,7 @@ end function CLIENT:GetClientGroupID() self:T() - ClientGroup = self:ClientGroup() + ClientGroup = self:GetDCSGroup() if ClientGroup then if ClientGroup:isExist() then @@ -5972,7 +5972,7 @@ end function CLIENT:GetClientGroupName() self:T() - ClientGroup = self:ClientGroup() + ClientGroup = self:GetDCSGroup() if ClientGroup then if ClientGroup:isExist() then @@ -5992,7 +5992,7 @@ end function CLIENT:GetClientGroupUnit() self:T() - local ClientGroup = self:ClientGroup() + local ClientGroup = self:GetDCSGroup() if ClientGroup then if ClientGroup:isExist() then @@ -6010,7 +6010,7 @@ end function CLIENT:GetClientGroupDCSUnit() self:T() - local ClientGroup = self:ClientGroup() + local ClientGroup = self:GetDCSGroup() if ClientGroup then if ClientGroup:isExist() then @@ -8483,7 +8483,7 @@ function MISSION:ReportToAll() local AlivePlayers = '' for ClientID, Client in pairs( self._Clients ) do - if Client:ClientGroup() then + if Client:GetDCSGroup() then if Client:GetClientGroupDCSUnit() then if Client:GetClientGroupDCSUnit():getLife() > 0.0 then if AlivePlayers == '' then @@ -8716,7 +8716,7 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler") trace.i( "MISSIONSCHEDULER", "Client: " .. Client.ClientName ) - if Client:ClientGroup() then + if Client:GetDCSGroup() then -- There is at least one Client that is alive... So the Mission status is set to Ongoing. ClientsAlive = true diff --git a/Moose/Base.lua b/Moose/Base.lua index 3a1a56dc2..bc06b56de 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -13,15 +13,17 @@ _TraceClass = { --SPAWN = true, --STAGE = true, --ZONE = true, - --GROUP = true, + GROUP = true, --UNIT = true, - --CLIENT = true, + CLIENT = true, --CARGO = true, --CARGO_GROUP = true, --CARGO_PACKAGE = true, --CARGO_SLINGLOAD = true, --CARGO_ZONE = true, --CLEANUP = true, + MENU_SUB_GROUP = true, + MENU_COMMAND_GROUP = true, ESCORT = true, } @@ -247,13 +249,14 @@ function BASE:T( Arguments ) end local LineCurrent = DebugInfoCurrent.currentline - local LineFrom = DebugInfoFrom.currentline - + local LineFrom = 0 + if DebugInfoFrom then + LineFrom = DebugInfoFrom.currentline + end env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s\(%s\)" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) end end - -- Log an exception function BASE:E( Arguments ) @@ -270,3 +273,6 @@ function BASE:E( Arguments ) env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s\(%s\)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) end + + + diff --git a/Moose/Cargo.lua b/Moose/Cargo.lua index c243f17ad..812cacf7f 100644 --- a/Moose/Cargo.lua +++ b/Moose/Cargo.lua @@ -480,7 +480,7 @@ function CARGO_GROUP:Spawn( Client ) elseif self:IsStatusLoading() then local Client = self:IsLoadingToClient() - if Client and Client:ClientGroup() then + if Client and Client:GetDCSGroup() then SpawnCargo = false else local CargoGroup = Group.getByName( self.CargoName ) @@ -494,7 +494,7 @@ function CARGO_GROUP:Spawn( Client ) local ClientLoaded = self:IsLoadedInClient() -- Now test if another Client is alive (not this one), and it has the CARGO, then this cargo does not need to be initialized and spawned. if ClientLoaded and ClientLoaded ~= Client then - local ClientGroup = Client:ClientGroup() + local ClientGroup = Client:GetDCSGroup() if ClientLoaded:GetClientGroupDCSUnit() and ClientLoaded:GetClientGroupDCSUnit():isExist() then SpawnCargo = false else @@ -680,7 +680,7 @@ function CARGO_PACKAGE:Spawn( Client ) -- this needs to be checked thoroughly - local CargoClientGroup = self.CargoClient:ClientGroup() + local CargoClientGroup = self.CargoClient:GetDCSGroup() if not CargoClientGroup then if not self.CargoClientSpawn then self.CargoClientSpawn = SPAWN:New( self.CargoClient:GetClientGroupName() ):Limit( 1, 1 ) @@ -695,7 +695,7 @@ function CARGO_PACKAGE:Spawn( Client ) elseif self:IsStatusLoading() or self:IsStatusLoaded() then local CargoClientLoaded = self:IsLoadedInClient() - if CargoClientLoaded and CargoClientLoaded:ClientGroup() then + if CargoClientLoaded and CargoClientLoaded:GetDCSGroup() then SpawnCargo = false end @@ -720,7 +720,7 @@ self:T() local Near = false - if self.CargoClient and self.CargoClient:ClientGroup() then + if self.CargoClient and self.CargoClient:GetDCSGroup() then self:T( self.CargoClient.ClientName ) self:T( 'Client Exists.' ) @@ -746,8 +746,8 @@ self:T() local CarrierPosOnBoard = ClientUnit:getPoint() local CarrierPosMoveAway = ClientUnit:getPoint() - local CargoHostGroup = self.CargoClient:ClientGroup() - local CargoHostName = self.CargoClient:ClientGroup():getName() + local CargoHostGroup = self.CargoClient:GetDCSGroup() + local CargoHostName = self.CargoClient:GetDCSGroup():getName() local CargoHostUnits = CargoHostGroup:getUnits() local CargoPos = CargoHostUnits[1]:getPoint() @@ -830,7 +830,7 @@ self:T() local OnBoarded = false - if self.CargoClient and self.CargoClient:ClientGroup() then + if self.CargoClient and self.CargoClient:GetDCSGroup() then if routines.IsUnitInRadius( self.CargoClient:GetClientGroupDCSUnit(), self.CargoClient:ClientPosition(), 10 ) then -- Switch Cargo from self.CargoClient to Client ... Each cargo can have only one client. So assigning the new client for the cargo is enough. @@ -851,7 +851,7 @@ self:T() self:T( 'self.CargoName = ' .. self.CargoName ) --self:T( 'self.CargoHostName = ' .. self.CargoHostName ) - --self.CargoSpawn:FromCarrier( Client:ClientGroup(), TargetZoneName, self.CargoHostName ) + --self.CargoSpawn:FromCarrier( Client:GetDCSGroup(), TargetZoneName, self.CargoHostName ) self:StatusUnLoaded() return Cargo diff --git a/Moose/Client.lua b/Moose/Client.lua index 332bce256..ff1c58ad8 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -46,7 +46,7 @@ CLIENT = { -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) function CLIENT:New( ClientName, ClientBriefing ) local self = BASE:Inherit( self, BASE:New() ) - self:T() + self:T( ClientName, ClientBriefing ) self.ClientName = ClientName self:AddBriefing( ClientBriefing ) @@ -62,10 +62,22 @@ self:T() self._Menus = {} end ---- ClientGroup returns the Group of a Client. +--- Return the Group of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return Group -function CLIENT:ClientGroup() +-- @return #GROUP +function CLIENT:GetGroup() + + if not self.ClientGroup then + self.ClientGroup = GROUP:New( self:GetDCSGroup() ) + end + + return self.ClientGroup +end + +--- Return the DCSGroup of a Client. +-- This function is modified to deal with a couple of bugs in DCS 1.5.3 +-- @return DCSGroup +function CLIENT:GetDCSGroup() --self:T() -- local ClientData = Group.getByName( self.ClientName ) @@ -102,7 +114,7 @@ function CLIENT:ClientGroup() self:T( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) if tonumber(UnitData:getID()) == ClientUnitData.unitId then local ClientGroupTemplate = _Database.Groups[self.ClientName].Template - self.ClientGroupID = ClientGroupTemplate.groupId + self.ClientID = ClientGroupTemplate.groupId self.ClientGroupUnit = UnitData self:T( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) return ClientGroup @@ -127,7 +139,7 @@ function CLIENT:ClientGroup() end end - self.ClientGroupID = nil + self.ClientID = nil self.ClientGroupUnit = nil return nil @@ -135,46 +147,48 @@ end function CLIENT:GetClientGroupID() -self:T() - ClientGroup = self:ClientGroup() - - if ClientGroup then - if ClientGroup:isExist() then - return ClientGroup:getID() - else - return self.ClientGroupID - end - end - - return nil + if not self.ClientID then + if not self.ClientGroup then + self.ClientGroup = GROUP:New( self:GetDCSGroup() ) + end + if self.ClientGroup:IsAlive() then + self.ClientGroupID = self.ClientGroup:GetID() + else + self.ClientGroupID = self.ClientID + self.ClientGroup.GroupID = self.ClientID + end + end + + self:T( self.ClientGroupID ) + return self.ClientGroupID end function CLIENT:GetClientGroupName() -self:T() - ClientGroup = self:ClientGroup() - - if ClientGroup then - if ClientGroup:isExist() then - self:T( ClientGroup:getName() ) - return ClientGroup:getName() - else - self:T( self.ClientName ) - return self.ClientName - end - end - - return nil + if not self.ClientGroupName then + if not self.ClientGroup then + self.ClientGroup = GROUP:New( self:GetDCSGroup() ) + end + if self.ClientGroup:IsAlive() then + self.ClientGroupName = self.ClientGroup:GetName() + else + self.ClientGroupName = self.ClientName + self.ClientGroup.GroupName = self.ClientGroupName + end + end + + self:T( self.ClientGroupName ) + return self.ClientGroupName end --- Returns the Unit of the @{CLIENT}. -- @return Unit function CLIENT:GetClientGroupUnit() -self:T() + self:T() - local ClientGroup = self:ClientGroup() + local ClientGroup = self:GetDCSGroup() if ClientGroup then if ClientGroup:isExist() then @@ -192,7 +206,7 @@ end function CLIENT:GetClientGroupDCSUnit() self:T() - local ClientGroup = self:ClientGroup() + local ClientGroup = self:GetDCSGroup() if ClientGroup then if ClientGroup:isExist() then @@ -291,9 +305,9 @@ self:T() if not self.MenuMessages then if self:GetClientGroupID() then - self.MenuMessages = MENU_SUB_GROUP:New( self:GetClientGroupID(), 'Messages' ) - self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetClientGroupID(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) - self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetClientGroupID(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) + self.MenuMessages = MENU_SUB_GROUP:New( self:GetGroup(), 'Messages' ) + self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetGroup(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) + self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetGroup(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) end end @@ -307,7 +321,7 @@ self:T() self.Messages[MessageId].MessageTime = timer.getTime() self.Messages[MessageId].MessageDuration = MessageDuration if MessageInterval == nil then - self.Messages[MessageId].MessageInterval = 0 + self.Messages[MessageId].MessageInterval = 600 else self.Messages[MessageId].MessageInterval = MessageInterval end diff --git a/Moose/Escort.lua b/Moose/Escort.lua index a9fbd3722..13e6d3458 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -39,12 +39,112 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortClient = EscortClient self.EscortGroup = EscortGroup self.EscortName = EscortName + self.ReportTargets = true + + -- Escort Navigation + self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Escort" .. self.EscortName ) + self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + + -- Report Targets + self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Report Targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + + -- Attack Targets + self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Attack nearby targets", self.EscortMenu ) + self.EscortMenuAttackTargets = {} + self.Targets = {} + + -- Rules of Engagement + self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu ) + self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) + self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) + self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) + self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) - self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 10 ) + -- Reaction to Threats + self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu ) + self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) + self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + + + self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) end +function ESCORT._HoldPosition( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:HoldPosition( 300 ) + MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPosition" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ReportNearbyTargets( MenuParam ) + MenuParam.ParamSelf:T() + + MenuParam.ParamSelf.ReportTargets = MenuParam.ParamReportTargets + +end + +function ESCORT._AttackTarget( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:AttackUnit( MenuParam.ParamUnit ) + MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEHoldFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:HoldFire() + MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEReturnFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:ReturnFire() + MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEOpenFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:OpenFire() + MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEWeaponFree( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:WeaponFree() + MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionNoReaction( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionNoReaction() + MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionPassiveDefense( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionPassiveDefense() + MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionEvadeFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionEvadeFire() + MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionVertical( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionVertical() + MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + + function ESCORT:_ScanForTargets() self:T() + + self.Targets = {} if self.EscortGroup:IsAlive() then local EscortTargets = self.EscortGroup:GetDetectedTargets() @@ -85,12 +185,25 @@ function ESCORT:_ScanForTargets() local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) + if Distance <= 8 then - EscortTargetMessage = EscortTargetMessage .. " - " .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") " - EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" - if EscortTarget.visible then - EscortTargetMessage = EscortTargetMessage .. " visual contact" + + if EscortTarget.type then + EscortTargetMessage = EscortTargetMessage .. " - " .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at " + else + EscortTargetMessage = EscortTargetMessage .. " - Unknown target at " end + + EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" + + if EscortTarget.visible then + EscortTargetMessage = EscortTargetMessage .. ", visual" + end + + local TargetIndex = Distance*1000 + self.Targets[TargetIndex] = {} + self.Targets[TargetIndex].AttackMessage = EscortTargetMessage + self.Targets[TargetIndex].AttackUnit = EscortTargetUnit end end @@ -100,9 +213,41 @@ function ESCORT:_ScanForTargets() end end - if EscortTargetMessages ~= "" then - self.EscortClient:Message( EscortTargetMessages:gsub("\n$",""), 20, "/ESCORT.DetectedTargets", self.EscortName .. " reporting detected targets within 8 km range:" ) + if EscortTargetMessages ~= "" and self.ReportTargets == true then + self.EscortClient:Message( EscortTargetMessages:gsub("\n$",""), 20, "/ESCORT.DetectedTargets", self.EscortName .. " reporting detected targets within 8 km range:", 0 ) end + + self:T() + + self:T( { "Sorting Targets Table:", self.Targets } ) + table.sort( self.Targets ) + self:T( { "Sorted Targets Table:", self.Targets } ) + + for MenuIndex = 1, #self.EscortMenuAttackTargets do + self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } ) + self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove() + end + + local MenuIndex = 1 + for TargetID, TargetData in pairs( self.Targets ) do + self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) + if MenuIndex <= 10 then + self.EscortMenuAttackTargets[MenuIndex] = + MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), + self.Targets[TargetID].AttackMessage, + self.EscortMenuAttackNearbyTargets, + ESCORT._AttackTarget, + { ParamSelf = self, + ParamUnit = self.Targets[TargetID].AttackUnit + } + ) + self:T( { "New Menu:", self.EscortMenuAttackTargets[TargetID] } ) + MenuIndex = MenuIndex + 1 + else + break + end + end + else routines.removeFunction( self.ScanForTargetsFunction ) end diff --git a/Moose/Group.lua b/Moose/Group.lua index d1768fd21..dd75f356a 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -35,12 +35,16 @@ GROUPS = {} -- @return #GROUP self function GROUP:New( DCSGroup ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSGroup:getName() ) + self:T( DCSGroup ) self.DCSGroup = DCSGroup - self.GroupName = DCSGroup:getName() - self.GroupID = DCSGroup:getID() - self.Controller = DCSGroup:getController() + if self.DCSGroup and self.DCSGroup:isExist() then + self.GroupName = DCSGroup:getName() + self.GroupID = DCSGroup:getID() + self.Controller = DCSGroup:getController() + else + self:E( { "DCSGroup is nil or does not exist, cannot initialize GROUP!", self.DCSGroup } ) + end return self end @@ -111,6 +115,15 @@ function GROUP:Activate() return self:GetDCSGroup() end +--- Gets the ID of the GROUP. +-- @param self +-- @return #number The ID of the GROUP. +function GROUP:GetID() + self:T( self.GroupName ) + + return self.GroupID +end + --- Gets the name of the GROUP. -- @param self -- @return #string The name of the GROUP. @@ -253,6 +266,39 @@ self:T() end +--- Hold position at the current position of the first unit of the group. +-- @param self +-- @param #number Duration The maximum duration in seconds to hold the position. +-- @return #GROUP self +function GROUP:HoldPosition( Duration ) +trace.f( self.ClassName, { self.GroupName, Duration } ) + + local Controller = self:_GetController() + +-- pattern = enum AI.Task.OribtPattern, +-- point = Vec2, +-- point2 = Vec2, +-- speed = Distance, +-- altitude = Distance + + local GroupPoint = self:GetPoint() + --id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } + Controller:pushTask( { id = 'ControlledTask', + params = { task = { id = 'Orbit', + params = { pattern = AI.Task.OrbitPattern.CIRCLE, + point = GroupPoint, + speed = 0, + altitude = 30 + } + }, + stopCondition = { duration = Duration + } + } + } + ) + return self +end + --- Land the group at a Vec2Point. -- @param self -- @param #Vec2 Point The point where to land. @@ -272,6 +318,137 @@ trace.f( self.ClassName, { self.GroupName, Point, Duration } ) return self end +--- Attack the Unit. +-- @param self +-- @param #UNIT The unit. +-- @return #GROUP self +function GROUP:AttackUnit( AttackUnit ) + self:T( { self.GroupName, AttackUnit } ) + + local Controller = self:_GetController() + +-- AttackUnit = { +-- id = 'AttackUnit', +-- params = { +-- unitId = Unit.ID, +-- weaponType = number, +-- expend = enum AI.Task.WeaponExpend +-- attackQty = number, +-- direction = Azimuth, +-- attackQtyLimit = boolean, +-- groupAttack = boolean, +-- } +-- } + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + + Controller:pushTask( { id = 'AttackUnit', + params = { unitId = AttackUnit:GetID(), + expend = AI.Task.WeaponExpend.TWO, + groupAttack = true, + } + } + ) + return self +end + +--- Holding weapons. +-- @param self +-- @return #GROUP self +function GROUP:HoldFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPONS_HOLD ) + return self +end + +--- Return fire. +-- @param self +-- @return #GROUP self +function GROUP:ReturnFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) + return self +end + +--- Openfire. +-- @param self +-- @return #GROUP self +function GROUP:OpenFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + return self +end + +--- Weapon free. +-- @param self +-- @return #GROUP self +function GROUP:WeaponFree() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) + return self +end + +--- No evasion on enemy threats. +-- @param self +-- @return #GROUP self +function GROUP:EvasionNoReaction() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) + return self +end + +--- Evasion passive defense. +-- @param self +-- @return #GROUP self +function GROUP:EvasionPassiveDefense() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENSE ) + return self +end + +--- Evade fire. +-- @param self +-- @return #GROUP self +function GROUP:EvasionEvadeFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + return self +end + +--- Vertical manoeuvres. +-- @param self +-- @return #GROUP self +function GROUP:EvasionVertical() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) + return self +end + + --- Move the group to a Vec2 Point, wait for a defined duration and embark a group. -- @param self -- @param #Vec2 Point The point where to wait. diff --git a/Moose/Menu.lua b/Moose/Menu.lua index a8d980568..bd8e54b8a 100644 --- a/Moose/Menu.lua +++ b/Moose/Menu.lua @@ -76,7 +76,13 @@ MENU_SUB_GROUP = { ClassName = "MENU_SUB_GROUP" } -function MENU_SUB_GROUP:New( GroupID, MenuText, ParentMenu ) +--- Creates a new menu item for a group +-- @param self +-- @param MenuGroup The group owning the menu. +-- @param MenuText The text for the menu. +-- @param ParentMenu The parent menu. +-- @return #MENU_SUB_GROUP self +function MENU_SUB_GROUP:New( MenuGroup, MenuText, ParentMenu ) -- Arrange meta tables local MenuParentPath = nil @@ -86,7 +92,10 @@ function MENU_SUB_GROUP:New( GroupID, MenuText, ParentMenu ) local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self.MenuPath = missionCommands.addSubMenuForGroup( GroupID, MenuText, MenuParentPath ) + self:T( { MenuGroup, MenuText, ParentMenu } ) + + self.MenuGroup = MenuGroup + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath ) return self end @@ -96,7 +105,15 @@ MENU_COMMAND_GROUP = { ClassName = "MENU_COMMAND_GROUP" } -function MENU_COMMAND_GROUP:New( GroupID, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) +--- Creates a new radio command item for a group +-- @param self +-- @param MenuGroup The group owning the menu. +-- @param MenuText The text for the menu. +-- @param ParentMenu The parent menu. +-- @param CommandMenuFunction A function that is called when the menu key is pressed. +-- @param CommandMenuArgument An argument for the function. +-- @return #MENU_COMMAND_GROUP self +function MENU_COMMAND_GROUP:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) -- Arrange meta tables @@ -106,9 +123,18 @@ function MENU_COMMAND_GROUP:New( GroupID, MenuText, ParentMenu, CommandMenuFunct end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) + + self:T( { MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) - self.MenuPath = missionCommands.addCommandForGroup( GroupID, MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + self.MenuGroup = MenuGroup + self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) self.CommandMenuFunction = CommandMenuFunction self.CommandMenuArgument = CommandMenuArgument return self end + +function MENU_COMMAND_GROUP:Remove() + + missionCommands.removeItemForGroup( self.MenuGroup:GetID(), self.MenuPath ) + return nil +end diff --git a/Moose/Message.lua b/Moose/Message.lua index d17c07053..7c5f581f5 100644 --- a/Moose/Message.lua +++ b/Moose/Message.lua @@ -21,11 +21,12 @@ MESSAGE = { --- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. --- @param string MessageText is the text of the Message. --- @param string MessageCategory is a string expressing the Category of the Message. Messages are grouped on the display panel per Category to improve readability. --- @param number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. --- @param string MessageID is a string expressing the ID of the Message. --- @return MESSAGE +-- @param self +-- @param #string MessageText is the text of the Message. +-- @param #string MessageCategory is a string expressing the Category of the Message. Messages are grouped on the display panel per Category to improve readability. +-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. +-- @param #string MessageID is a string expressing the ID of the Message. +-- @return #MESSAGE -- @usage -- -- Create a series of new Messages. -- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". diff --git a/Moose/Mission.lua b/Moose/Mission.lua index 273b7755b..7e2eb696b 100644 --- a/Moose/Mission.lua +++ b/Moose/Mission.lua @@ -174,7 +174,7 @@ function MISSION:ReportToAll() local AlivePlayers = '' for ClientID, Client in pairs( self._Clients ) do - if Client:ClientGroup() then + if Client:GetDCSGroup() then if Client:GetClientGroupDCSUnit() then if Client:GetClientGroupDCSUnit():getLife() > 0.0 then if AlivePlayers == '' then @@ -407,7 +407,7 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler") trace.i( "MISSIONSCHEDULER", "Client: " .. Client.ClientName ) - if Client:ClientGroup() then + if Client:GetDCSGroup() then -- There is at least one Client that is alive... So the Mission status is set to Ongoing. ClientsAlive = true From 2e045f2cea981b75e28266ef39ddfcec0bcd8741 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 24 Mar 2016 12:20:24 +0100 Subject: [PATCH 03/14] Updated the Escort Class --- Moose/Escort.lua | 4 ++-- Moose/Group.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 13e6d3458..6f4ae664f 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -40,8 +40,8 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortGroup = EscortGroup self.EscortName = EscortName self.ReportTargets = true - - -- Escort Navigation + + -- Escort Navigation self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Escort" .. self.EscortName ) self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) diff --git a/Moose/Group.lua b/Moose/Group.lua index dd75f356a..fcd3c7900 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -360,7 +360,7 @@ function GROUP:HoldFire() local Controller = self:_GetController() - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPONS_HOLD ) + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) return self end From e7846e29789055dcc83388bebdea785427effe94 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 24 Mar 2016 12:21:01 +0100 Subject: [PATCH 04/14] trace off --- Moose/Base.lua | 10 +++++----- Moose/Escort.lua | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Moose/Base.lua b/Moose/Base.lua index bc06b56de..42f11d3d4 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -13,18 +13,18 @@ _TraceClass = { --SPAWN = true, --STAGE = true, --ZONE = true, - GROUP = true, + --GROUP = true, --UNIT = true, - CLIENT = true, + --CLIENT = true, --CARGO = true, --CARGO_GROUP = true, --CARGO_PACKAGE = true, --CARGO_SLINGLOAD = true, --CARGO_ZONE = true, --CLEANUP = true, - MENU_SUB_GROUP = true, - MENU_COMMAND_GROUP = true, - ESCORT = true, + --MENU_SUB_GROUP = true, + --MENU_COMMAND_GROUP = true, + --ESCORT = true, } --- The BASE Class diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 6f4ae664f..9f04348a5 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -181,7 +181,7 @@ function ESCORT:_ScanForTargets() -- EscortTargetLastVelocity } ) if EscortTarget.distance then - local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec() local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) From 4e87256c9adc2373020b5f66af13fd580e23d4da Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 24 Mar 2016 12:27:34 +0100 Subject: [PATCH 05/14] update to load embedded --- Embedded/Moose_Create_Embedded.bat | 1 + Embedded/Moose_Embedded.lua | 627 ++++++++++++++++++++++++++--- 2 files changed, 572 insertions(+), 56 deletions(-) diff --git a/Embedded/Moose_Create_Embedded.bat b/Embedded/Moose_Create_Embedded.bat index 0d28173c2..a47b82f5b 100644 --- a/Embedded/Moose_Create_Embedded.bat +++ b/Embedded/Moose_Create_Embedded.bat @@ -27,5 +27,6 @@ copy /b ..\Moose\Trace.lua ^ + ..\Moose\Spawn.lua ^ + ..\Moose\Movement.lua ^ + ..\Moose\Sead.lua ^ + + ..\Moose\Escort.lua ^ Moose_Embedded.lua /y \ No newline at end of file diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index cb2282790..03a00d5ff 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -709,7 +709,7 @@ routines.tostringBR = function(az, dist, alt, metric) dist = routines.utils.round(routines.utils.metersToNM(dist), 2) end - local s = string.format('%03d°', az) .. ' for ' .. dist + local s = string.format('%03d', az) .. ' for ' .. dist if alt then if metric then @@ -2880,6 +2880,9 @@ _TraceClass = { --CARGO_SLINGLOAD = true, --CARGO_ZONE = true, --CLEANUP = true, + --MENU_SUB_GROUP = true, + --MENU_COMMAND_GROUP = true, + --ESCORT = true, } --- The BASE Class @@ -3104,13 +3107,14 @@ function BASE:T( Arguments ) end local LineCurrent = DebugInfoCurrent.currentline - local LineFrom = DebugInfoFrom.currentline - + local LineFrom = 0 + if DebugInfoFrom then + LineFrom = DebugInfoFrom.currentline + end env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s\(%s\)" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) end end - -- Log an exception function BASE:E( Arguments ) @@ -3127,6 +3131,9 @@ function BASE:E( Arguments ) env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s\(%s\)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) end + + + --- Encapsulation of DCS World Menu system in a set of MENU classes. -- @module MENU @@ -3205,7 +3212,13 @@ MENU_SUB_GROUP = { ClassName = "MENU_SUB_GROUP" } -function MENU_SUB_GROUP:New( GroupID, MenuText, ParentMenu ) +--- Creates a new menu item for a group +-- @param self +-- @param MenuGroup The group owning the menu. +-- @param MenuText The text for the menu. +-- @param ParentMenu The parent menu. +-- @return #MENU_SUB_GROUP self +function MENU_SUB_GROUP:New( MenuGroup, MenuText, ParentMenu ) -- Arrange meta tables local MenuParentPath = nil @@ -3215,7 +3228,10 @@ function MENU_SUB_GROUP:New( GroupID, MenuText, ParentMenu ) local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self.MenuPath = missionCommands.addSubMenuForGroup( GroupID, MenuText, MenuParentPath ) + self:T( { MenuGroup, MenuText, ParentMenu } ) + + self.MenuGroup = MenuGroup + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath ) return self end @@ -3225,7 +3241,15 @@ MENU_COMMAND_GROUP = { ClassName = "MENU_COMMAND_GROUP" } -function MENU_COMMAND_GROUP:New( GroupID, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) +--- Creates a new radio command item for a group +-- @param self +-- @param MenuGroup The group owning the menu. +-- @param MenuText The text for the menu. +-- @param ParentMenu The parent menu. +-- @param CommandMenuFunction A function that is called when the menu key is pressed. +-- @param CommandMenuArgument An argument for the function. +-- @return #MENU_COMMAND_GROUP self +function MENU_COMMAND_GROUP:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) -- Arrange meta tables @@ -3235,12 +3259,21 @@ function MENU_COMMAND_GROUP:New( GroupID, MenuText, ParentMenu, CommandMenuFunct end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) + + self:T( { MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) - self.MenuPath = missionCommands.addCommandForGroup( GroupID, MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + self.MenuGroup = MenuGroup + self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) self.CommandMenuFunction = CommandMenuFunction self.CommandMenuArgument = CommandMenuArgument return self end + +function MENU_COMMAND_GROUP:Remove() + + missionCommands.removeItemForGroup( self.MenuGroup:GetID(), self.MenuPath ) + return nil +end --- A GROUP class abstraction of a DCSGroup class. -- The GROUP class will take an abstraction of the DCSGroup class, providing more methods that can be done with a GROUP. -- @@ -3278,12 +3311,16 @@ GROUPS = {} -- @return #GROUP self function GROUP:New( DCSGroup ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSGroup:getName() ) + self:T( DCSGroup ) self.DCSGroup = DCSGroup - self.GroupName = DCSGroup:getName() - self.GroupID = DCSGroup:getID() - self.Controller = DCSGroup:getController() + if self.DCSGroup and self.DCSGroup:isExist() then + self.GroupName = DCSGroup:getName() + self.GroupID = DCSGroup:getID() + self.Controller = DCSGroup:getController() + else + self:E( { "DCSGroup is nil or does not exist, cannot initialize GROUP!", self.DCSGroup } ) + end return self end @@ -3354,6 +3391,15 @@ function GROUP:Activate() return self:GetDCSGroup() end +--- Gets the ID of the GROUP. +-- @param self +-- @return #number The ID of the GROUP. +function GROUP:GetID() + self:T( self.GroupName ) + + return self.GroupID +end + --- Gets the name of the GROUP. -- @param self -- @return #string The name of the GROUP. @@ -3373,6 +3419,16 @@ function GROUP:GetPoint() return GroupPoint end +--- Gets the current Point of the GROUP in VEC3 format. +-- @return #Vec3 Current Vec3 position of the group. +function GROUP:GetPositionVec3() + self:T( self.GroupName ) + + local GroupPoint = self:GetUnit(1):GetPositionVec3() + self:T( GroupPoint ) + return GroupPoint +end + --- Destroy a GROUP -- Note that this destroy method also raises a destroy event at run-time. -- So all event listeners will catch the destroy event of this GROUP. @@ -3486,6 +3542,39 @@ self:T() end +--- Hold position at the current position of the first unit of the group. +-- @param self +-- @param #number Duration The maximum duration in seconds to hold the position. +-- @return #GROUP self +function GROUP:HoldPosition( Duration ) +trace.f( self.ClassName, { self.GroupName, Duration } ) + + local Controller = self:_GetController() + +-- pattern = enum AI.Task.OribtPattern, +-- point = Vec2, +-- point2 = Vec2, +-- speed = Distance, +-- altitude = Distance + + local GroupPoint = self:GetPoint() + --id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } + Controller:pushTask( { id = 'ControlledTask', + params = { task = { id = 'Orbit', + params = { pattern = AI.Task.OrbitPattern.CIRCLE, + point = GroupPoint, + speed = 0, + altitude = 30 + } + }, + stopCondition = { duration = Duration + } + } + } + ) + return self +end + --- Land the group at a Vec2Point. -- @param self -- @param #Vec2 Point The point where to land. @@ -3505,6 +3594,137 @@ trace.f( self.ClassName, { self.GroupName, Point, Duration } ) return self end +--- Attack the Unit. +-- @param self +-- @param #UNIT The unit. +-- @return #GROUP self +function GROUP:AttackUnit( AttackUnit ) + self:T( { self.GroupName, AttackUnit } ) + + local Controller = self:_GetController() + +-- AttackUnit = { +-- id = 'AttackUnit', +-- params = { +-- unitId = Unit.ID, +-- weaponType = number, +-- expend = enum AI.Task.WeaponExpend +-- attackQty = number, +-- direction = Azimuth, +-- attackQtyLimit = boolean, +-- groupAttack = boolean, +-- } +-- } + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + + Controller:pushTask( { id = 'AttackUnit', + params = { unitId = AttackUnit:GetID(), + expend = AI.Task.WeaponExpend.TWO, + groupAttack = true, + } + } + ) + return self +end + +--- Holding weapons. +-- @param self +-- @return #GROUP self +function GROUP:HoldFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + return self +end + +--- Return fire. +-- @param self +-- @return #GROUP self +function GROUP:ReturnFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) + return self +end + +--- Openfire. +-- @param self +-- @return #GROUP self +function GROUP:OpenFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + return self +end + +--- Weapon free. +-- @param self +-- @return #GROUP self +function GROUP:WeaponFree() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) + return self +end + +--- No evasion on enemy threats. +-- @param self +-- @return #GROUP self +function GROUP:EvasionNoReaction() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) + return self +end + +--- Evasion passive defense. +-- @param self +-- @return #GROUP self +function GROUP:EvasionPassiveDefense() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENSE ) + return self +end + +--- Evade fire. +-- @param self +-- @return #GROUP self +function GROUP:EvasionEvadeFire() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + return self +end + +--- Vertical manoeuvres. +-- @param self +-- @return #GROUP self +function GROUP:EvasionVertical() + self:T( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) + return self +end + + --- Move the group to a Vec2 Point, wait for a defined duration and embark a group. -- @param self -- @param #Vec2 Point The point where to wait. @@ -3684,7 +3904,21 @@ function GROUP:_GetController() return self.DCSGroup:getController() end ---- UNIT Classes + +function GROUP:GetDetectedTargets() + + return self:_GetController():getDetectedTargets() + +end + +function GROUP:IsTargetDetected( DCSObject ) + + local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + = self:_GetController():isTargetDetected( DCSObject ) + + return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + +end--- UNIT Classes -- @module UNIT Include.File( "Routines" ) @@ -3695,6 +3929,13 @@ Include.File( "Message" ) -- @type UNIT = { ClassName="UNIT", + CategoryName = { + [Unit.Category.AIRPLANE] = "Airplane", + [Unit.Category.HELICOPTER] = "Helicoper", + [Unit.Category.GROUND_UNIT] = "Ground Unit", + [Unit.Category.SHIP] = "Ship", + [Unit.Category.STRUCTURE] = "Structure", + } } function UNIT:New( DCSUnit ) @@ -3798,6 +4039,10 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) return false end +function UNIT:GetCategoryName() + return self.CategoryName[ self.DCSUnit:getDesc().category ] +end + --- ZONE Classes -- @module ZONE @@ -3869,6 +4114,7 @@ end --- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor. -- Administers the Spawning of new Groups within the DCSRTE and administers these new Groups within the DATABASE object(s). -- @module DATABASE +-- @author FlightControl Include.File( "Routines" ) Include.File( "Base" ) @@ -5864,7 +6110,7 @@ CLIENT = { -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) function CLIENT:New( ClientName, ClientBriefing ) local self = BASE:Inherit( self, BASE:New() ) - self:T() + self:T( ClientName, ClientBriefing ) self.ClientName = ClientName self:AddBriefing( ClientBriefing ) @@ -5880,9 +6126,21 @@ self:T() self._Menus = {} end ---- ClientGroup returns the Group of a Client. +--- Return the Group of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return Group +-- @return #GROUP +function CLIENT:GetGroup() + + if not self.ClientGroup then + self.ClientGroup = GROUP:New( self:GetDCSGroup() ) + end + + return self.ClientGroup +end + +--- Return the DCSGroup of a Client. +-- This function is modified to deal with a couple of bugs in DCS 1.5.3 +-- @return DCSGroup function CLIENT:GetDCSGroup() --self:T() @@ -5920,7 +6178,7 @@ function CLIENT:GetDCSGroup() self:T( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) if tonumber(UnitData:getID()) == ClientUnitData.unitId then local ClientGroupTemplate = _Database.Groups[self.ClientName].Template - self.ClientGroupID = ClientGroupTemplate.groupId + self.ClientID = ClientGroupTemplate.groupId self.ClientGroupUnit = UnitData self:T( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) return ClientGroup @@ -5945,7 +6203,7 @@ function CLIENT:GetDCSGroup() end end - self.ClientGroupID = nil + self.ClientID = nil self.ClientGroupUnit = nil return nil @@ -5953,44 +6211,46 @@ end function CLIENT:GetClientGroupID() -self:T() - ClientGroup = self:GetDCSGroup() - - if ClientGroup then - if ClientGroup:isExist() then - return ClientGroup:getID() - else - return self.ClientGroupID - end - end - - return nil + if not self.ClientID then + if not self.ClientGroup then + self.ClientGroup = GROUP:New( self:GetDCSGroup() ) + end + if self.ClientGroup:IsAlive() then + self.ClientGroupID = self.ClientGroup:GetID() + else + self.ClientGroupID = self.ClientID + self.ClientGroup.GroupID = self.ClientID + end + end + + self:T( self.ClientGroupID ) + return self.ClientGroupID end function CLIENT:GetClientGroupName() -self:T() - ClientGroup = self:GetDCSGroup() - - if ClientGroup then - if ClientGroup:isExist() then - self:T( ClientGroup:getName() ) - return ClientGroup:getName() - else - self:T( self.ClientName ) - return self.ClientName - end - end - - return nil + if not self.ClientGroupName then + if not self.ClientGroup then + self.ClientGroup = GROUP:New( self:GetDCSGroup() ) + end + if self.ClientGroup:IsAlive() then + self.ClientGroupName = self.ClientGroup:GetName() + else + self.ClientGroupName = self.ClientName + self.ClientGroup.GroupName = self.ClientGroupName + end + end + + self:T( self.ClientGroupName ) + return self.ClientGroupName end --- Returns the Unit of the @{CLIENT}. -- @return Unit function CLIENT:GetClientGroupUnit() -self:T() + self:T() local ClientGroup = self:GetDCSGroup() @@ -6109,9 +6369,9 @@ self:T() if not self.MenuMessages then if self:GetClientGroupID() then - self.MenuMessages = MENU_SUB_GROUP:New( self:GetClientGroupID(), 'Messages' ) - self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetClientGroupID(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) - self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetClientGroupID(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) + self.MenuMessages = MENU_SUB_GROUP:New( self:GetGroup(), 'Messages' ) + self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetGroup(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) + self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetGroup(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) end end @@ -6168,11 +6428,12 @@ MESSAGE = { --- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. --- @param string MessageText is the text of the Message. --- @param string MessageCategory is a string expressing the Category of the Message. Messages are grouped on the display panel per Category to improve readability. --- @param number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. --- @param string MessageID is a string expressing the ID of the Message. --- @return MESSAGE +-- @param self +-- @param #string MessageText is the text of the Message. +-- @param #string MessageCategory is a string expressing the Category of the Message. Messages are grouped on the display panel per Category to improve readability. +-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. +-- @param #string MessageID is a string expressing the ID of the Message. +-- @return #MESSAGE -- @usage -- -- Create a series of new Messages. -- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". @@ -10152,7 +10413,7 @@ end --- Get the index from a given group. -- The function will search the name of the group for a #, and will return the number behind the #-mark. -function SPAWN:_GetGroupIndexFromGroup( SpawnGroup ) +function SPAWN:GetSpawnIndexFromGroup( SpawnGroup ) self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) local IndexString = string.match( SpawnGroup:GetName(), "#.*$" ):sub( 2 ) @@ -10458,7 +10719,7 @@ function SPAWN:_OnLand( event ) self.Landed = true self:T( "self.Landed = true" ) if self.Landed and self.RepeatOnLanding then - local SpawnGroupIndex = self:_GetGroupIndexFromGroup( SpawnGroup ) + local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) self:T( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) self:ReSpawn( SpawnGroupIndex ) end @@ -10479,7 +10740,7 @@ function SPAWN:_OnLand( event ) if SpawnGroup then self:T( { "EngineShutDown event: " .. event.initiator:getName(), event } ) if self.Landed and self.RepeatOnEngineShutDown then - local SpawnGroupIndex = self:_GetGroupIndexFromGroup( SpawnGroup ) + local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) self:T( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) self:ReSpawn( SpawnGroupIndex ) end @@ -10805,3 +11066,257 @@ self:T( { event } ) end end end +--- Taking the lead of AI escorting your flight. +-- The ESCORT class allows you to interact with escoring AI on your flight and take the lead. +-- The following commands will be available: +-- +-- * Pop-up and Scan Area +-- * Re-Join Formation +-- * Hold Position in x km +-- * Report identified targets +-- * Perform tasks per identified target: Report vector to target, paint target, kill target +-- +-- @module ESCORT +-- @author FlightControl + +Include.File( "Routines" ) +Include.File( "Base" ) +Include.File( "Database" ) +Include.File( "Group" ) +Include.File( "Zone" ) + +--- ESCORT class +-- @type +-- +ESCORT = { + ClassName = "ESCORT", + EscortName = nil, -- The Escort Name + Targets = {}, -- The identified targets +} + +--- ESCORT class constructor for an AI group +-- @param self +-- @param #CLIENT EscortClient The client escorted by the EscortGroup. +-- @param #GROUP EscortGroup The group AI escorting the EscortClient. +-- @param #string EscortName Name of the escort. +-- @return #ESCORT self +function ESCORT:New( EscortClient, EscortGroup, EscortName ) + local self = BASE:Inherit( self, BASE:New() ) + self:T( { EscortClient, EscortGroup, EscortName } ) + + self.EscortClient = EscortClient + self.EscortGroup = EscortGroup + self.EscortName = EscortName + self.ReportTargets = true + + -- Escort Navigation + self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Escort" .. self.EscortName ) + self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + + -- Report Targets + self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Report Targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + + -- Attack Targets + self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Attack nearby targets", self.EscortMenu ) + self.EscortMenuAttackTargets = {} + self.Targets = {} + + -- Rules of Engagement + self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu ) + self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) + self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) + self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) + self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) + + -- Reaction to Threats + self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu ) + self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) + self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + + + self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) +end + +function ESCORT._HoldPosition( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:HoldPosition( 300 ) + MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPosition" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ReportNearbyTargets( MenuParam ) + MenuParam.ParamSelf:T() + + MenuParam.ParamSelf.ReportTargets = MenuParam.ParamReportTargets + +end + +function ESCORT._AttackTarget( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:AttackUnit( MenuParam.ParamUnit ) + MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEHoldFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:HoldFire() + MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEReturnFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:ReturnFire() + MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEOpenFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:OpenFire() + MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._ROEWeaponFree( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:WeaponFree() + MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionNoReaction( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionNoReaction() + MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionPassiveDefense( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionPassiveDefense() + MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionEvadeFire( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionEvadeFire() + MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +function ESCORT._EvasionVertical( MenuParam ) + + MenuParam.ParamSelf.EscortGroup:EvasionVertical() + MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + + +function ESCORT:_ScanForTargets() + self:T() + + self.Targets = {} + + if self.EscortGroup:IsAlive() then + local EscortTargets = self.EscortGroup:GetDetectedTargets() + + local EscortTargetMessages = "" + for EscortTargetID, EscortTarget in pairs( EscortTargets ) do + local EscortObject = EscortTarget.object + self:T( EscortObject ) + if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then + + local EscortTargetMessage = "" + + local EscortTargetUnit = UNIT:New( EscortObject ) + + local EscortTargetCategoryName = EscortTargetUnit:GetCategoryName() + local EscortTargetCategoryType = EscortTargetUnit:GetTypeName() + + + -- local EscortTargetIsDetected, + -- EscortTargetIsVisible, + -- EscortTargetLastTime, + -- EscortTargetKnowType, + -- EscortTargetKnowDistance, + -- EscortTargetLastPos, + -- EscortTargetLastVelocity + -- = self.EscortGroup:IsTargetDetected( EscortObject ) + -- + -- self:T( { EscortTargetIsDetected, + -- EscortTargetIsVisible, + -- EscortTargetLastTime, + -- EscortTargetKnowType, + -- EscortTargetKnowDistance, + -- EscortTargetLastPos, + -- EscortTargetLastVelocity } ) + + if EscortTarget.distance then + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec() + local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 + self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) + + if Distance <= 8 then + + if EscortTarget.type then + EscortTargetMessage = EscortTargetMessage .. " - " .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at " + else + EscortTargetMessage = EscortTargetMessage .. " - Unknown target at " + end + + EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" + + if EscortTarget.visible then + EscortTargetMessage = EscortTargetMessage .. ", visual" + end + + local TargetIndex = Distance*1000 + self.Targets[TargetIndex] = {} + self.Targets[TargetIndex].AttackMessage = EscortTargetMessage + self.Targets[TargetIndex].AttackUnit = EscortTargetUnit + end + end + + if EscortTargetMessage ~= "" then + EscortTargetMessages = EscortTargetMessages .. EscortTargetMessage .. "\n" + end + end + end + + if EscortTargetMessages ~= "" and self.ReportTargets == true then + self.EscortClient:Message( EscortTargetMessages:gsub("\n$",""), 20, "/ESCORT.DetectedTargets", self.EscortName .. " reporting detected targets within 8 km range:", 0 ) + end + + self:T() + + self:T( { "Sorting Targets Table:", self.Targets } ) + table.sort( self.Targets ) + self:T( { "Sorted Targets Table:", self.Targets } ) + + for MenuIndex = 1, #self.EscortMenuAttackTargets do + self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } ) + self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove() + end + + local MenuIndex = 1 + for TargetID, TargetData in pairs( self.Targets ) do + self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) + if MenuIndex <= 10 then + self.EscortMenuAttackTargets[MenuIndex] = + MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), + self.Targets[TargetID].AttackMessage, + self.EscortMenuAttackNearbyTargets, + ESCORT._AttackTarget, + { ParamSelf = self, + ParamUnit = self.Targets[TargetID].AttackUnit + } + ) + self:T( { "New Menu:", self.EscortMenuAttackTargets[TargetID] } ) + MenuIndex = MenuIndex + 1 + else + break + end + end + + else + routines.removeFunction( self.ScanForTargetsFunction ) + end +end From 9e9d3c9cc7abe7100afdf75266f7c2d5f6e85a36 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 24 Mar 2016 17:24:34 +0100 Subject: [PATCH 06/14] Fixed problems with the client --- Embedded/Moose_Embedded.lua | 145 ++++++++++++++++-------------------- Moose/Client.lua | 87 +++++++++------------- Moose/Escort.lua | 34 ++++----- Moose/Group.lua | 2 - Moose/Menu.lua | 22 +++--- 5 files changed, 128 insertions(+), 162 deletions(-) diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index 03a00d5ff..456824434 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -3214,11 +3214,11 @@ MENU_SUB_GROUP = { --- Creates a new menu item for a group -- @param self --- @param MenuGroup The group owning the menu. +-- @param CLIENT#CLIENT MenuClient The Client owning the menu. -- @param MenuText The text for the menu. -- @param ParentMenu The parent menu. -- @return #MENU_SUB_GROUP self -function MENU_SUB_GROUP:New( MenuGroup, MenuText, ParentMenu ) +function MENU_SUB_GROUP:New( MenuClient, MenuText, ParentMenu ) -- Arrange meta tables local MenuParentPath = nil @@ -3228,10 +3228,10 @@ function MENU_SUB_GROUP:New( MenuGroup, MenuText, ParentMenu ) local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuGroup, MenuText, ParentMenu } ) + self:T( { MenuClient, MenuText, ParentMenu } ) - self.MenuGroup = MenuGroup - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath ) + self.MenuClient = MenuClient + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) return self end @@ -3243,13 +3243,13 @@ MENU_COMMAND_GROUP = { --- Creates a new radio command item for a group -- @param self --- @param MenuGroup The group owning the menu. +-- @param CLIENT#CLIENT MenuClient The Client owning the menu. -- @param MenuText The text for the menu. -- @param ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. -- @param CommandMenuArgument An argument for the function. -- @return #MENU_COMMAND_GROUP self -function MENU_COMMAND_GROUP:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) +function MENU_COMMAND_GROUP:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) -- Arrange meta tables @@ -3260,10 +3260,10 @@ function MENU_COMMAND_GROUP:New( MenuGroup, MenuText, ParentMenu, CommandMenuFun local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) + self:T( { MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) - self.MenuGroup = MenuGroup - self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + self.MenuClient = MenuClient + self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) self.CommandMenuFunction = CommandMenuFunction self.CommandMenuArgument = CommandMenuArgument return self @@ -3271,13 +3271,11 @@ end function MENU_COMMAND_GROUP:Remove() - missionCommands.removeItemForGroup( self.MenuGroup:GetID(), self.MenuPath ) + missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) return nil end --- A GROUP class abstraction of a DCSGroup class. -- The GROUP class will take an abstraction of the DCSGroup class, providing more methods that can be done with a GROUP. --- --- -- @module GROUP -- @extends BASE#BASE @@ -6126,21 +6124,9 @@ self:T() self._Menus = {} end ---- Return the Group of a Client. --- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return #GROUP -function CLIENT:GetGroup() - - if not self.ClientGroup then - self.ClientGroup = GROUP:New( self:GetDCSGroup() ) - end - - return self.ClientGroup -end - --- Return the DCSGroup of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return DCSGroup +-- @return Group#Group function CLIENT:GetDCSGroup() --self:T() @@ -6203,7 +6189,7 @@ function CLIENT:GetDCSGroup() end end - self.ClientID = nil + self.ClientGroupID = nil self.ClientGroupUnit = nil return nil @@ -6212,15 +6198,13 @@ end function CLIENT:GetClientGroupID() - if not self.ClientID then - if not self.ClientGroup then - self.ClientGroup = GROUP:New( self:GetDCSGroup() ) - end - if self.ClientGroup:IsAlive() then - self.ClientGroupID = self.ClientGroup:GetID() + + if not self.ClientGroupID then + local ClientGroup = self:GetDCSGroup() + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupID = ClientGroup:getID() else self.ClientGroupID = self.ClientID - self.ClientGroup.GroupID = self.ClientID end end @@ -6232,14 +6216,11 @@ end function CLIENT:GetClientGroupName() if not self.ClientGroupName then - if not self.ClientGroup then - self.ClientGroup = GROUP:New( self:GetDCSGroup() ) - end - if self.ClientGroup:IsAlive() then - self.ClientGroupName = self.ClientGroup:GetName() + local ClientGroup = self:GetDCSGroup() + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupName = ClientGroup:getName() else - self.ClientGroupName = self.ClientName - self.ClientGroup.GroupName = self.ClientGroupName + self.ClientGroupName = self.ClientName end end @@ -6252,35 +6233,37 @@ end function CLIENT:GetClientGroupUnit() self:T() - local ClientGroup = self:GetDCSGroup() - - if ClientGroup then - if ClientGroup:isExist() then - return UNIT:New( ClientGroup:getUnit(1) ) + if not self.ClientGroupUnit then + local ClientGroup = self:GetDCSGroup() + + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupUnit = UNIT:New( ClientGroup:getUnit(1) ) else - return UNIT:New( self.ClientGroupUnit ) - end - end + self.ClientGroupUnit = UNIT:New( self.ClientGroupUnit ) + end + end - return nil + self:T( { self.ClientGroupUnit } ) + return self.ClientGroupUnit end --- Returns the DCSUnit of the @{CLIENT}. -- @return DCSUnit function CLIENT:GetClientGroupDCSUnit() -self:T() + self:T() - local ClientGroup = self:GetDCSGroup() + if not self.ClientGroupDCSUnit then + local ClientGroup = self:GetDCSGroup() + + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupDCSUnit = ClientGroup:getUnit(1) + else + self.ClientGroupDCSUnit = self.ClientGroupUnit + end + end - if ClientGroup then - if ClientGroup:isExist() then - return ClientGroup:getUnits()[1] - else - return self.ClientGroupUnit - end - end - - return nil + self:T( { self.ClientGroupDCSUnit } ) + return self.ClientGroupDCSUnit end function CLIENT:GetUnit() @@ -6369,9 +6352,9 @@ self:T() if not self.MenuMessages then if self:GetClientGroupID() then - self.MenuMessages = MENU_SUB_GROUP:New( self:GetGroup(), 'Messages' ) - self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetGroup(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) - self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetGroup(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) + self.MenuMessages = MENU_SUB_GROUP:New( self, 'Messages' ) + self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self, 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) + self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self,'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) end end @@ -11110,32 +11093,32 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.ReportTargets = true -- Escort Navigation - self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Escort" .. self.EscortName ) - self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient, "Escort" .. self.EscortName ) + self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) -- Report Targets - self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Report Targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Report Targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) -- Attack Targets - self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Attack nearby targets", self.EscortMenu ) + self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) self.EscortMenuAttackTargets = {} self.Targets = {} -- Rules of Engagement - self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu ) - self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) - self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) - self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) - self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) + self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient, "ROE", self.EscortMenu ) + self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) + self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) + self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) + self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) -- Reaction to Threats - self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu ) - self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) - self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) - self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) - self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient, "Evasion", self.EscortMenu ) + self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) + self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) @@ -11301,7 +11284,7 @@ function ESCORT:_ScanForTargets() self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) if MenuIndex <= 10 then self.EscortMenuAttackTargets[MenuIndex] = - MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), + MENU_COMMAND_GROUP:New( self.EscortClient, self.Targets[TargetID].AttackMessage, self.EscortMenuAttackNearbyTargets, ESCORT._AttackTarget, diff --git a/Moose/Client.lua b/Moose/Client.lua index ff1c58ad8..2a54792bc 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -62,21 +62,9 @@ self:T() self._Menus = {} end ---- Return the Group of a Client. --- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return #GROUP -function CLIENT:GetGroup() - - if not self.ClientGroup then - self.ClientGroup = GROUP:New( self:GetDCSGroup() ) - end - - return self.ClientGroup -end - --- Return the DCSGroup of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return DCSGroup +-- @return Group#Group function CLIENT:GetDCSGroup() --self:T() @@ -139,7 +127,7 @@ function CLIENT:GetDCSGroup() end end - self.ClientID = nil + self.ClientGroupID = nil self.ClientGroupUnit = nil return nil @@ -148,15 +136,13 @@ end function CLIENT:GetClientGroupID() - if not self.ClientID then - if not self.ClientGroup then - self.ClientGroup = GROUP:New( self:GetDCSGroup() ) - end - if self.ClientGroup:IsAlive() then - self.ClientGroupID = self.ClientGroup:GetID() + + if not self.ClientGroupID then + local ClientGroup = self:GetDCSGroup() + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupID = ClientGroup:getID() else self.ClientGroupID = self.ClientID - self.ClientGroup.GroupID = self.ClientID end end @@ -168,14 +154,11 @@ end function CLIENT:GetClientGroupName() if not self.ClientGroupName then - if not self.ClientGroup then - self.ClientGroup = GROUP:New( self:GetDCSGroup() ) - end - if self.ClientGroup:IsAlive() then - self.ClientGroupName = self.ClientGroup:GetName() + local ClientGroup = self:GetDCSGroup() + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupName = ClientGroup:getName() else - self.ClientGroupName = self.ClientName - self.ClientGroup.GroupName = self.ClientGroupName + self.ClientGroupName = self.ClientName end end @@ -188,35 +171,37 @@ end function CLIENT:GetClientGroupUnit() self:T() - local ClientGroup = self:GetDCSGroup() - - if ClientGroup then - if ClientGroup:isExist() then - return UNIT:New( ClientGroup:getUnit(1) ) + if not self.ClientGroupUnit then + local ClientGroup = self:GetDCSGroup() + + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupUnit = UNIT:New( ClientGroup:getUnit(1) ) else - return UNIT:New( self.ClientGroupUnit ) - end - end + self.ClientGroupUnit = UNIT:New( self.ClientGroupUnit ) + end + end - return nil + self:T( { self.ClientGroupUnit } ) + return self.ClientGroupUnit end --- Returns the DCSUnit of the @{CLIENT}. -- @return DCSUnit function CLIENT:GetClientGroupDCSUnit() -self:T() + self:T() - local ClientGroup = self:GetDCSGroup() + if not self.ClientGroupDCSUnit then + local ClientGroup = self:GetDCSGroup() + + if ClientGroup and ClientGroup:isExist() then + self.ClientGroupDCSUnit = ClientGroup:getUnit(1) + else + self.ClientGroupDCSUnit = self.ClientGroupUnit + end + end - if ClientGroup then - if ClientGroup:isExist() then - return ClientGroup:getUnits()[1] - else - return self.ClientGroupUnit - end - end - - return nil + self:T( { self.ClientGroupDCSUnit } ) + return self.ClientGroupDCSUnit end function CLIENT:GetUnit() @@ -305,9 +290,9 @@ self:T() if not self.MenuMessages then if self:GetClientGroupID() then - self.MenuMessages = MENU_SUB_GROUP:New( self:GetGroup(), 'Messages' ) - self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetGroup(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) - self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetGroup(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) + self.MenuMessages = MENU_SUB_GROUP:New( self, 'Messages' ) + self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self, 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) + self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self,'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) end end diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 9f04348a5..0f16d3c38 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -42,32 +42,32 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.ReportTargets = true -- Escort Navigation - self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Escort" .. self.EscortName ) - self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient, "Escort" .. self.EscortName ) + self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) -- Report Targets - self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Report Targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Report Targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) -- Attack Targets - self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Attack nearby targets", self.EscortMenu ) + self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) self.EscortMenuAttackTargets = {} self.Targets = {} -- Rules of Engagement - self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu ) - self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) - self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) - self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) - self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) + self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient, "ROE", self.EscortMenu ) + self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) + self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) + self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) + self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) -- Reaction to Threats - self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu ) - self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) - self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) - self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) - self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient, "Evasion", self.EscortMenu ) + self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) + self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) @@ -233,7 +233,7 @@ function ESCORT:_ScanForTargets() self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) if MenuIndex <= 10 then self.EscortMenuAttackTargets[MenuIndex] = - MENU_COMMAND_GROUP:New( self.EscortClient:GetGroup(), + MENU_COMMAND_GROUP:New( self.EscortClient, self.Targets[TargetID].AttackMessage, self.EscortMenuAttackNearbyTargets, ESCORT._AttackTarget, diff --git a/Moose/Group.lua b/Moose/Group.lua index fcd3c7900..6f3a72e0e 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -1,7 +1,5 @@ --- A GROUP class abstraction of a DCSGroup class. -- The GROUP class will take an abstraction of the DCSGroup class, providing more methods that can be done with a GROUP. --- --- -- @module GROUP -- @extends BASE#BASE diff --git a/Moose/Menu.lua b/Moose/Menu.lua index bd8e54b8a..a1dc369c3 100644 --- a/Moose/Menu.lua +++ b/Moose/Menu.lua @@ -78,11 +78,11 @@ MENU_SUB_GROUP = { --- Creates a new menu item for a group -- @param self --- @param MenuGroup The group owning the menu. +-- @param CLIENT#CLIENT MenuClient The Client owning the menu. -- @param MenuText The text for the menu. -- @param ParentMenu The parent menu. -- @return #MENU_SUB_GROUP self -function MENU_SUB_GROUP:New( MenuGroup, MenuText, ParentMenu ) +function MENU_SUB_GROUP:New( MenuClient, MenuText, ParentMenu ) -- Arrange meta tables local MenuParentPath = nil @@ -92,10 +92,10 @@ function MENU_SUB_GROUP:New( MenuGroup, MenuText, ParentMenu ) local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuGroup, MenuText, ParentMenu } ) + self:T( { MenuClient, MenuText, ParentMenu } ) - self.MenuGroup = MenuGroup - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath ) + self.MenuClient = MenuClient + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) return self end @@ -107,13 +107,13 @@ MENU_COMMAND_GROUP = { --- Creates a new radio command item for a group -- @param self --- @param MenuGroup The group owning the menu. +-- @param CLIENT#CLIENT MenuClient The Client owning the menu. -- @param MenuText The text for the menu. -- @param ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. -- @param CommandMenuArgument An argument for the function. -- @return #MENU_COMMAND_GROUP self -function MENU_COMMAND_GROUP:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) +function MENU_COMMAND_GROUP:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) -- Arrange meta tables @@ -124,10 +124,10 @@ function MENU_COMMAND_GROUP:New( MenuGroup, MenuText, ParentMenu, CommandMenuFun local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) + self:T( { MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) - self.MenuGroup = MenuGroup - self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroup:GetID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + self.MenuClient = MenuClient + self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) self.CommandMenuFunction = CommandMenuFunction self.CommandMenuArgument = CommandMenuArgument return self @@ -135,6 +135,6 @@ end function MENU_COMMAND_GROUP:Remove() - missionCommands.removeItemForGroup( self.MenuGroup:GetID(), self.MenuPath ) + missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) return nil end From 7abd07f54590e08996bce25351ad08d84f44d982 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 24 Mar 2016 18:09:22 +0100 Subject: [PATCH 07/14] Problem with Vec3 --- Embedded/Moose_Embedded.lua | 2 +- Moose/Escort.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index 456824434..19b65bdbd 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -11232,7 +11232,7 @@ function ESCORT:_ScanForTargets() -- EscortTargetLastVelocity } ) if EscortTarget.distance then - local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec() + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 0f16d3c38..b1e34d970 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -181,7 +181,7 @@ function ESCORT:_ScanForTargets() -- EscortTargetLastVelocity } ) if EscortTarget.distance then - local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec() + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() local Distance = routines.utils.get3DDist( EscortTargetUnitPositionVec3, EscortPositionVec3 ) / 1000 self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget.visible } ) From ca4d9f14645bd3337aae0521777dd0e37d50be2f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 25 Mar 2016 09:25:39 +0100 Subject: [PATCH 08/14] Fixed problem with Escort menus and could fine-tune the prototyping. --- Embedded/Moose_Embedded.lua | 223 ++++++++++++++++++++++-------------- Moose/Base.lua | 6 +- Moose/Client.lua | 44 +++---- Moose/Database.lua | 2 +- Moose/Escort.lua | 34 +++--- Moose/Group.lua | 4 +- Moose/Menu.lua | 114 +++++++++++++----- Moose/Sead.lua | 5 +- Moose/Spawn.lua | 3 +- Moose/Task.lua | 3 +- Moose/Unit.lua | 3 +- Moose/Zone.lua | 5 +- 12 files changed, 274 insertions(+), 172 deletions(-) diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index 19b65bdbd..c3a69c71b 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -2857,7 +2857,7 @@ end env.info(( 'Init: Scripts Loaded v1.1' )) --- BASE The base class for all the classes defined within MOOSE. --- @module BASE +-- @module Base -- @author Flightcontrol Include.File( "Routines" ) @@ -2880,8 +2880,8 @@ _TraceClass = { --CARGO_SLINGLOAD = true, --CARGO_ZONE = true, --CLEANUP = true, - --MENU_SUB_GROUP = true, - --MENU_COMMAND_GROUP = true, + --MENU_CLIENT = true, + --MENU_CLIENT_COMMAND = true, --ESCORT = true, } @@ -3135,13 +3135,14 @@ end --- Encapsulation of DCS World Menu system in a set of MENU classes. --- @module MENU +-- @module Menu Include.File( "Routines" ) Include.File( "Base" ) --- The MENU class --- @type +-- @type MENU +-- @extends Base#BASE MENU = { ClassName = "MENU", MenuPath = nil, @@ -3162,7 +3163,8 @@ function MENU:New( MenuText, MenuParentPath ) end --- The COMMANDMENU class --- @type +-- @type COMMANDMENU +-- @extends Menu#MENU COMMANDMENU = { ClassName = "COMMANDMENU", CommandMenuFunction = nil, @@ -3187,7 +3189,8 @@ function COMMANDMENU:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenu end --- The SUBMENU class --- @type +-- @type SUBMENU +-- @extends Menu#MENU SUBMENU = { ClassName = "SUBMENU" } @@ -3206,78 +3209,128 @@ function SUBMENU:New( MenuText, ParentMenu ) return Child end ---- The MENU_SUB_GROUP class --- @type -MENU_SUB_GROUP = { - ClassName = "MENU_SUB_GROUP" +-- This local variable is used to cache the menus registered under clients. +-- Menus don't dissapear when clients are destroyed and restarted. +-- So every menu for a client created must be tracked so that program logic accidentally does not create +-- the same menus twice during initialization logic. +-- These menu classes are handling this logic with this variable. +local _MENUCLIENTS = {} + +--- The MENU_CLIENT class +-- @type MENU_CLIENT +-- @extends Menu#MENU +MENU_CLIENT = { + ClassName = "MENU_CLIENT" } --- Creates a new menu item for a group -- @param self --- @param CLIENT#CLIENT MenuClient The Client owning the menu. --- @param MenuText The text for the menu. --- @param ParentMenu The parent menu. --- @return #MENU_SUB_GROUP self -function MENU_SUB_GROUP:New( MenuClient, MenuText, ParentMenu ) +-- @param Client#CLIENT MenuClient The Client owning the menu. +-- @param #string MenuText The text for the menu. +-- @param #table ParentMenu The parent menu. +-- @return #MENU_CLIENT self +function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu ) -- Arrange meta tables - local MenuParentPath = nil + local MenuParentPath = {} if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath + MenuParentPath = ParentMenu.MenuPath end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuClient, MenuText, ParentMenu } ) - self.MenuClient = MenuClient - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) + self.MenuClientGroupID = MenuClient:GetClientGroupID() + self.MenuParentPath = MenuParentPath + self.MenuText = MenuText + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } ) + + if not MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] then + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) + MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] = self.MenuPath + else + self.MenuPath = MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] + end + return self end ---- The MENU_COMMAND_GROUP class --- @type -MENU_COMMAND_GROUP = { - ClassName = "MENU_COMMAND_GROUP" + +--- The MENU_CLIENT_COMMAND class +-- @type MENU_CLIENT_COMMAND +-- @extends Menu#MENU +MENU_CLIENT_COMMAND = { + ClassName = "MENU_CLIENT_COMMAND" } --- Creates a new radio command item for a group -- @param self --- @param CLIENT#CLIENT MenuClient The Client owning the menu. +-- @param Client#CLIENT MenuClient The Client owning the menu. -- @param MenuText The text for the menu. -- @param ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. -- @param CommandMenuArgument An argument for the function. --- @return #MENU_COMMAND_GROUP self -function MENU_COMMAND_GROUP:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) +-- @return Menu#MENU_CLIENT_COMMAND self +function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) -- Arrange meta tables - local MenuParentPath = nil + local MenuParentPath = {} if ParentMenu ~= nil then MenuParentPath = ParentMenu.MenuPath end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) - self.MenuClient = MenuClient - self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + self.MenuClientGroupID = MenuClient:GetClientGroupID() + self.MenuParentPath = MenuParentPath + self.MenuText = MenuText + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } ) + + if not MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] then + self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] = self.MenuPath + else + self.MenuPath = MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] + end + self.CommandMenuFunction = CommandMenuFunction self.CommandMenuArgument = CommandMenuArgument return self end -function MENU_COMMAND_GROUP:Remove() +function MENU_CLIENT_COMMAND:Remove() + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then + MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil + end missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) return nil end --- A GROUP class abstraction of a DCSGroup class. -- The GROUP class will take an abstraction of the DCSGroup class, providing more methods that can be done with a GROUP. --- @module GROUP --- @extends BASE#BASE +-- @module Group Include.File( "Routines" ) Include.File( "Base" ) @@ -3286,6 +3339,7 @@ Include.File( "Unit" ) --- The GROUP class -- @type GROUP +-- @extends Base#BASE -- @field #Group DCSGroup The DCS group class. -- @field #string GroupName The name of the group. -- @field #number GroupID the ID of the group. @@ -3924,7 +3978,8 @@ Include.File( "Base" ) Include.File( "Message" ) --- The UNIT class --- @type +-- @type UNIT +-- @Extends Base#BASE UNIT = { ClassName="UNIT", CategoryName = { @@ -4042,14 +4097,15 @@ function UNIT:GetCategoryName() end --- ZONE Classes --- @module ZONE +-- @module Zone Include.File( "Routines" ) Include.File( "Base" ) Include.File( "Message" ) --- The ZONE class --- @type +-- @type ZONE +-- @Extends Base#BASE ZONE = { ClassName="ZONE", } @@ -4111,7 +4167,7 @@ end --- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor. -- Administers the Spawning of new Groups within the DCSRTE and administers these new Groups within the DATABASE object(s). --- @module DATABASE +-- @module Database -- @author FlightControl Include.File( "Routines" ) @@ -6061,7 +6117,8 @@ self:T() return Cargo end --- CLIENT Classes --- @module CLIENT +-- @module Client +-- @author FlightControl Include.File( "Routines" ) Include.File( "Base" ) @@ -6073,6 +6130,7 @@ Include.File( "Message" ) --- The CLIENT class -- @type CLIENT +-- @extends Base#BASE CLIENT = { ONBOARDSIDE = { NONE = 0, @@ -6233,18 +6291,13 @@ end function CLIENT:GetClientGroupUnit() self:T() - if not self.ClientGroupUnit then - local ClientGroup = self:GetDCSGroup() - - if ClientGroup and ClientGroup:isExist() then - self.ClientGroupUnit = UNIT:New( ClientGroup:getUnit(1) ) - else - self.ClientGroupUnit = UNIT:New( self.ClientGroupUnit ) - end - end + local ClientGroup = self:GetDCSGroup() - self:T( { self.ClientGroupUnit } ) - return self.ClientGroupUnit + if ClientGroup and ClientGroup:isExist() then + return UNIT:New( ClientGroup:getUnit(1) ) + else + return UNIT:New( self.ClientGroupUnit ) + end end --- Returns the DCSUnit of the @{CLIENT}. @@ -6252,18 +6305,13 @@ end function CLIENT:GetClientGroupDCSUnit() self:T() - if not self.ClientGroupDCSUnit then - local ClientGroup = self:GetDCSGroup() - - if ClientGroup and ClientGroup:isExist() then - self.ClientGroupDCSUnit = ClientGroup:getUnit(1) - else - self.ClientGroupDCSUnit = self.ClientGroupUnit - end + local ClientGroup = self:GetDCSGroup() + + if ClientGroup and ClientGroup:isExist() then + return ClientGroup:getUnit(1) + else + return self.ClientGroupUnit end - - self:T( { self.ClientGroupDCSUnit } ) - return self.ClientGroupDCSUnit end function CLIENT:GetUnit() @@ -6352,9 +6400,9 @@ self:T() if not self.MenuMessages then if self:GetClientGroupID() then - self.MenuMessages = MENU_SUB_GROUP:New( self, 'Messages' ) - self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self, 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) - self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self,'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) + self.MenuMessages = MENU_CLIENT:New( self, 'Messages' ) + self.MenuRouteMessageOn = MENU_CLIENT_COMMAND:New( self, 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) + self.MenuRouteMessageOff = MENU_CLIENT_COMMAND:New( self,'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) end end @@ -7432,7 +7480,8 @@ Include.File( "Client" ) Include.File( "Stage" ) --- The TASK class --- @type +-- @type TASK +-- @extends Base#BASE TASK = { -- Defines the different signal types with a Task. @@ -9632,7 +9681,7 @@ end -- This models AI that has succesfully returned to their airbase, to restart their combat activities. -- Check the @{#SPAWN.CleanUp} for further info. -- --- @module SPAWN +-- @module Spawn -- @author FlightControl Include.File( "Routines" ) @@ -9643,6 +9692,7 @@ Include.File( "Zone" ) --- SPAWN Class -- @type SPAWN +-- @extends Base#BASE -- @field ClassName SPAWN = { ClassName = "SPAWN", @@ -10914,7 +10964,7 @@ self:T( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGro end end --- Provides defensive behaviour to a set of SAM sites within a running Mission. --- @module SEAD +-- @module Sead -- @author to be searched on the forum -- @author (co) Flightcontrol (Modified and enriched with functionality) @@ -10925,7 +10975,8 @@ Include.File( "Client" ) Include.File( "Task" ) --- The SEAD class --- @type +-- @type SEAD +-- @extends Base#BASE SEAD = { ClassName = "SEAD", TargetSkill = { @@ -11093,32 +11144,32 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.ReportTargets = true -- Escort Navigation - self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient, "Escort" .. self.EscortName ) - self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + self.EscortMenu = MENU_CLIENT:New( self.EscortClient, "Escort" .. self.EscortName ) + self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) -- Report Targets - self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Report Targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report Targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) -- Attack Targets - self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) + self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) self.EscortMenuAttackTargets = {} self.Targets = {} -- Rules of Engagement - self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient, "ROE", self.EscortMenu ) - self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) - self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) - self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) - self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) + self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) + self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) + self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) + self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) + self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) -- Reaction to Threats - self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient, "Evasion", self.EscortMenu ) - self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) - self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) - self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) - self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) + self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) + self.EscortMenuEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) @@ -11284,7 +11335,7 @@ function ESCORT:_ScanForTargets() self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) if MenuIndex <= 10 then self.EscortMenuAttackTargets[MenuIndex] = - MENU_COMMAND_GROUP:New( self.EscortClient, + MENU_CLIENT_COMMAND:New( self.EscortClient, self.Targets[TargetID].AttackMessage, self.EscortMenuAttackNearbyTargets, ESCORT._AttackTarget, diff --git a/Moose/Base.lua b/Moose/Base.lua index 42f11d3d4..90314d5da 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -1,5 +1,5 @@ --- BASE The base class for all the classes defined within MOOSE. --- @module BASE +-- @module Base -- @author Flightcontrol Include.File( "Routines" ) @@ -22,8 +22,8 @@ _TraceClass = { --CARGO_SLINGLOAD = true, --CARGO_ZONE = true, --CLEANUP = true, - --MENU_SUB_GROUP = true, - --MENU_COMMAND_GROUP = true, + --MENU_CLIENT = true, + --MENU_CLIENT_COMMAND = true, --ESCORT = true, } diff --git a/Moose/Client.lua b/Moose/Client.lua index 2a54792bc..a9ce07add 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -1,5 +1,6 @@ --- CLIENT Classes --- @module CLIENT +-- @module Client +-- @author FlightControl Include.File( "Routines" ) Include.File( "Base" ) @@ -11,6 +12,7 @@ Include.File( "Message" ) --- The CLIENT class -- @type CLIENT +-- @extends Base#BASE CLIENT = { ONBOARDSIDE = { NONE = 0, @@ -171,18 +173,13 @@ end function CLIENT:GetClientGroupUnit() self:T() - if not self.ClientGroupUnit then - local ClientGroup = self:GetDCSGroup() - - if ClientGroup and ClientGroup:isExist() then - self.ClientGroupUnit = UNIT:New( ClientGroup:getUnit(1) ) - else - self.ClientGroupUnit = UNIT:New( self.ClientGroupUnit ) - end - end + local ClientGroup = self:GetDCSGroup() - self:T( { self.ClientGroupUnit } ) - return self.ClientGroupUnit + if ClientGroup and ClientGroup:isExist() then + return UNIT:New( ClientGroup:getUnit(1) ) + else + return UNIT:New( self.ClientGroupUnit ) + end end --- Returns the DCSUnit of the @{CLIENT}. @@ -190,18 +187,13 @@ end function CLIENT:GetClientGroupDCSUnit() self:T() - if not self.ClientGroupDCSUnit then - local ClientGroup = self:GetDCSGroup() - - if ClientGroup and ClientGroup:isExist() then - self.ClientGroupDCSUnit = ClientGroup:getUnit(1) - else - self.ClientGroupDCSUnit = self.ClientGroupUnit - end + local ClientGroup = self:GetDCSGroup() + + if ClientGroup and ClientGroup:isExist() then + return ClientGroup:getUnit(1) + else + return self.ClientGroupUnit end - - self:T( { self.ClientGroupDCSUnit } ) - return self.ClientGroupDCSUnit end function CLIENT:GetUnit() @@ -290,9 +282,9 @@ self:T() if not self.MenuMessages then if self:GetClientGroupID() then - self.MenuMessages = MENU_SUB_GROUP:New( self, 'Messages' ) - self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self, 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) - self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self,'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) + self.MenuMessages = MENU_CLIENT:New( self, 'Messages' ) + self.MenuRouteMessageOn = MENU_CLIENT_COMMAND:New( self, 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) + self.MenuRouteMessageOff = MENU_CLIENT_COMMAND:New( self,'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } ) end end diff --git a/Moose/Database.lua b/Moose/Database.lua index 27265637b..d6332868c 100644 --- a/Moose/Database.lua +++ b/Moose/Database.lua @@ -1,6 +1,6 @@ --- Administers the Initial Sets of the Mission Templates as defined within the Mission Editor. -- Administers the Spawning of new Groups within the DCSRTE and administers these new Groups within the DATABASE object(s). --- @module DATABASE +-- @module Database -- @author FlightControl Include.File( "Routines" ) diff --git a/Moose/Escort.lua b/Moose/Escort.lua index b1e34d970..bd63f11e9 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -42,32 +42,32 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.ReportTargets = true -- Escort Navigation - self.EscortMenu = MENU_SUB_GROUP:New( self.EscortClient, "Escort" .. self.EscortName ) - self.EscortMenuHoldPosition = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + self.EscortMenu = MENU_CLIENT:New( self.EscortClient, "Escort" .. self.EscortName ) + self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) -- Report Targets - self.EscortMenuReportNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Report Targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsOn = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_COMMAND_GROUP:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report Targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) -- Attack Targets - self.EscortMenuAttackNearbyTargets = MENU_SUB_GROUP:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) + self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) self.EscortMenuAttackTargets = {} self.Targets = {} -- Rules of Engagement - self.EscortMenuROE = MENU_SUB_GROUP:New( self.EscortClient, "ROE", self.EscortMenu ) - self.EscortMenuROEHoldFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) - self.EscortMenuROEReturnFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) - self.EscortMenuROEOpenFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) - self.EscortMenuROEWeaponFree = MENU_COMMAND_GROUP:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) + self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) + self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROEHoldFire, { ParamSelf = self, } ) + self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROEReturnFire, { ParamSelf = self, } ) + self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROEOpenFire, { ParamSelf = self, } ) + self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROEWeaponFree, { ParamSelf = self, } ) -- Reaction to Threats - self.EscortMenuEvasion = MENU_SUB_GROUP:New( self.EscortClient, "Evasion", self.EscortMenu ) - self.EscortMenuEvasionNoReaction = MENU_COMMAND_GROUP:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) - self.EscortMenuEvasionPassiveDefense = MENU_COMMAND_GROUP:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) - self.EscortMenuEvasionEvadeFire = MENU_COMMAND_GROUP:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) - self.EscortMenuEvasionVertical = MENU_COMMAND_GROUP:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) + self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) + self.EscortMenuEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) @@ -233,7 +233,7 @@ function ESCORT:_ScanForTargets() self:T( { "Adding menu:", TargetID, "for Unit", self.Targets[TargetID].AttackUnit } ) if MenuIndex <= 10 then self.EscortMenuAttackTargets[MenuIndex] = - MENU_COMMAND_GROUP:New( self.EscortClient, + MENU_CLIENT_COMMAND:New( self.EscortClient, self.Targets[TargetID].AttackMessage, self.EscortMenuAttackNearbyTargets, ESCORT._AttackTarget, diff --git a/Moose/Group.lua b/Moose/Group.lua index 6f3a72e0e..3da7de6f4 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -1,7 +1,6 @@ --- A GROUP class abstraction of a DCSGroup class. -- The GROUP class will take an abstraction of the DCSGroup class, providing more methods that can be done with a GROUP. --- @module GROUP --- @extends BASE#BASE +-- @module Group Include.File( "Routines" ) Include.File( "Base" ) @@ -10,6 +9,7 @@ Include.File( "Unit" ) --- The GROUP class -- @type GROUP +-- @extends Base#BASE -- @field #Group DCSGroup The DCS group class. -- @field #string GroupName The name of the group. -- @field #number GroupID the ID of the group. diff --git a/Moose/Menu.lua b/Moose/Menu.lua index a1dc369c3..9c10272bb 100644 --- a/Moose/Menu.lua +++ b/Moose/Menu.lua @@ -1,11 +1,12 @@ --- Encapsulation of DCS World Menu system in a set of MENU classes. --- @module MENU +-- @module Menu Include.File( "Routines" ) Include.File( "Base" ) --- The MENU class --- @type +-- @type MENU +-- @extends Base#BASE MENU = { ClassName = "MENU", MenuPath = nil, @@ -26,7 +27,8 @@ function MENU:New( MenuText, MenuParentPath ) end --- The COMMANDMENU class --- @type +-- @type COMMANDMENU +-- @extends Menu#MENU COMMANDMENU = { ClassName = "COMMANDMENU", CommandMenuFunction = nil, @@ -51,7 +53,8 @@ function COMMANDMENU:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenu end --- The SUBMENU class --- @type +-- @type SUBMENU +-- @extends Menu#MENU SUBMENU = { ClassName = "SUBMENU" } @@ -70,71 +73,122 @@ function SUBMENU:New( MenuText, ParentMenu ) return Child end ---- The MENU_SUB_GROUP class --- @type -MENU_SUB_GROUP = { - ClassName = "MENU_SUB_GROUP" +-- This local variable is used to cache the menus registered under clients. +-- Menus don't dissapear when clients are destroyed and restarted. +-- So every menu for a client created must be tracked so that program logic accidentally does not create +-- the same menus twice during initialization logic. +-- These menu classes are handling this logic with this variable. +local _MENUCLIENTS = {} + +--- The MENU_CLIENT class +-- @type MENU_CLIENT +-- @extends Menu#MENU +MENU_CLIENT = { + ClassName = "MENU_CLIENT" } --- Creates a new menu item for a group -- @param self --- @param CLIENT#CLIENT MenuClient The Client owning the menu. --- @param MenuText The text for the menu. --- @param ParentMenu The parent menu. --- @return #MENU_SUB_GROUP self -function MENU_SUB_GROUP:New( MenuClient, MenuText, ParentMenu ) +-- @param Client#CLIENT MenuClient The Client owning the menu. +-- @param #string MenuText The text for the menu. +-- @param #table ParentMenu The parent menu. +-- @return #MENU_CLIENT self +function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu ) -- Arrange meta tables - local MenuParentPath = nil + local MenuParentPath = {} if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath + MenuParentPath = ParentMenu.MenuPath end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuClient, MenuText, ParentMenu } ) - self.MenuClient = MenuClient - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) + self.MenuClientGroupID = MenuClient:GetClientGroupID() + self.MenuParentPath = MenuParentPath + self.MenuText = MenuText + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } ) + + if not MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] then + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) + MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] = self.MenuPath + else + self.MenuPath = MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] + end + return self end ---- The MENU_COMMAND_GROUP class --- @type -MENU_COMMAND_GROUP = { - ClassName = "MENU_COMMAND_GROUP" + +--- The MENU_CLIENT_COMMAND class +-- @type MENU_CLIENT_COMMAND +-- @extends Menu#MENU +MENU_CLIENT_COMMAND = { + ClassName = "MENU_CLIENT_COMMAND" } --- Creates a new radio command item for a group -- @param self --- @param CLIENT#CLIENT MenuClient The Client owning the menu. +-- @param Client#CLIENT MenuClient The Client owning the menu. -- @param MenuText The text for the menu. -- @param ParentMenu The parent menu. -- @param CommandMenuFunction A function that is called when the menu key is pressed. -- @param CommandMenuArgument An argument for the function. --- @return #MENU_COMMAND_GROUP self -function MENU_COMMAND_GROUP:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) +-- @return Menu#MENU_CLIENT_COMMAND self +function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument ) -- Arrange meta tables - local MenuParentPath = nil + local MenuParentPath = {} if ParentMenu ~= nil then MenuParentPath = ParentMenu.MenuPath end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) - self:T( { MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument } ) - self.MenuClient = MenuClient - self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + self.MenuClientGroupID = MenuClient:GetClientGroupID() + self.MenuParentPath = MenuParentPath + self.MenuText = MenuText + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } ) + + if not MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] then + self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument ) + MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] = self.MenuPath + else + self.MenuPath = MenuPath[table.concat(MenuParentPath) .. "/" .. MenuText] + end + self.CommandMenuFunction = CommandMenuFunction self.CommandMenuArgument = CommandMenuArgument return self end -function MENU_COMMAND_GROUP:Remove() +function MENU_CLIENT_COMMAND:Remove() + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then + MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil + end missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) return nil end diff --git a/Moose/Sead.lua b/Moose/Sead.lua index 8c22a1df6..0eb7a569f 100644 --- a/Moose/Sead.lua +++ b/Moose/Sead.lua @@ -1,5 +1,5 @@ --- Provides defensive behaviour to a set of SAM sites within a running Mission. --- @module SEAD +-- @module Sead -- @author to be searched on the forum -- @author (co) Flightcontrol (Modified and enriched with functionality) @@ -10,7 +10,8 @@ Include.File( "Client" ) Include.File( "Task" ) --- The SEAD class --- @type +-- @type SEAD +-- @extends Base#BASE SEAD = { ClassName = "SEAD", TargetSkill = { diff --git a/Moose/Spawn.lua b/Moose/Spawn.lua index 00d4b0d74..c88ee5a21 100644 --- a/Moose/Spawn.lua +++ b/Moose/Spawn.lua @@ -67,7 +67,7 @@ -- This models AI that has succesfully returned to their airbase, to restart their combat activities. -- Check the @{#SPAWN.CleanUp} for further info. -- --- @module SPAWN +-- @module Spawn -- @author FlightControl Include.File( "Routines" ) @@ -78,6 +78,7 @@ Include.File( "Zone" ) --- SPAWN Class -- @type SPAWN +-- @extends Base#BASE -- @field ClassName SPAWN = { ClassName = "SPAWN", diff --git a/Moose/Task.lua b/Moose/Task.lua index 4e45ad4f9..e75a03670 100644 --- a/Moose/Task.lua +++ b/Moose/Task.lua @@ -8,7 +8,8 @@ Include.File( "Client" ) Include.File( "Stage" ) --- The TASK class --- @type +-- @type TASK +-- @extends Base#BASE TASK = { -- Defines the different signal types with a Task. diff --git a/Moose/Unit.lua b/Moose/Unit.lua index 7af365ca5..a418dc71d 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -6,7 +6,8 @@ Include.File( "Base" ) Include.File( "Message" ) --- The UNIT class --- @type +-- @type UNIT +-- @Extends Base#BASE UNIT = { ClassName="UNIT", CategoryName = { diff --git a/Moose/Zone.lua b/Moose/Zone.lua index de42744b9..3496e0365 100644 --- a/Moose/Zone.lua +++ b/Moose/Zone.lua @@ -1,12 +1,13 @@ --- ZONE Classes --- @module ZONE +-- @module Zone Include.File( "Routines" ) Include.File( "Base" ) Include.File( "Message" ) --- The ZONE class --- @type +-- @type ZONE +-- @Extends Base#BASE ZONE = { ClassName="ZONE", } From 8eab8622c6c67d170fed21fb4b8b7ffde1098242 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 25 Mar 2016 14:36:48 +0100 Subject: [PATCH 09/14] Latest Updates --- DCS/{DCSTypes.lua => DCSTypes.doclua} | 6 +- DCS/land.doclua | 20 ++++ Embedded/Moose_Embedded.lua | 18 +-- Moose/Base.lua | 4 +- Moose/Client.lua | 43 ++++++- Moose/Escort.lua | 165 +++++++++++++++++++++++--- Moose/Group.lua | 155 +++++++++++++++++++----- Moose/Spawn.lua | 4 +- Moose/Unit.lua | 2 +- Moose/Zone.lua | 2 +- Test Missions/MOOSE_Spawn_Test.lua | 4 +- 11 files changed, 353 insertions(+), 70 deletions(-) rename DCS/{DCSTypes.lua => DCSTypes.doclua} (97%) create mode 100644 DCS/land.doclua diff --git a/DCS/DCSTypes.lua b/DCS/DCSTypes.doclua similarity index 97% rename from DCS/DCSTypes.lua rename to DCS/DCSTypes.doclua index 1bb654f73..6be092099 100644 --- a/DCS/DCSTypes.lua +++ b/DCS/DCSTypes.doclua @@ -1,3 +1,6 @@ +------------------------------------------------------------------------------- +--- @module DCSTypes + --- Time is given in seconds. -- @type Time @@ -228,4 +231,5 @@ AI = {} --#AI --- An angle type -- @type Angle -env.info( 'AI types created' ) \ No newline at end of file +env.info( 'AI types created' ) + diff --git a/DCS/land.doclua b/DCS/land.doclua new file mode 100644 index 000000000..3ee695bdf --- /dev/null +++ b/DCS/land.doclua @@ -0,0 +1,20 @@ +------------------------------------------------------------------------------- +-- @module 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 DCSTypes#Distance + +land = {} --#land \ No newline at end of file diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index c3a69c71b..c3cda1d51 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -3463,10 +3463,10 @@ end --- Gets the current Point of the GROUP in VEC2 format. -- @return #Vec2 Current x and Y position of the group. -function GROUP:GetPoint() +function GROUP:GetPointVec2() self:T( self.GroupName ) - local GroupPoint = self:GetUnit(1):GetPoint() + local GroupPoint = self:GetUnit(1):GetPointVec2() self:T( GroupPoint ) return GroupPoint end @@ -3609,7 +3609,7 @@ trace.f( self.ClassName, { self.GroupName, Duration } ) -- speed = Distance, -- altitude = Distance - local GroupPoint = self:GetPoint() + local GroupPoint = self:GetPointVec2() --id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } Controller:pushTask( { id = 'ControlledTask', params = { task = { id = 'Orbit', @@ -3857,7 +3857,7 @@ end function GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) self:T( Zone ) - local GroupPoint = self:GetPoint() + local GroupPoint = self:GetPointVec2() local PointFrom = {} PointFrom.x = GroupPoint.x @@ -3873,7 +3873,7 @@ function GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) if Randomize then ZonePoint = Zone:GetRandomPoint() else - ZonePoint = Zone:GetPoint() + ZonePoint = Zone:GetPointVec2() end PointTo.x = ZonePoint.x @@ -4051,7 +4051,7 @@ function UNIT:GetCallSign() end -function UNIT:GetPoint() +function UNIT:GetPointVec2() self:T( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p @@ -4128,7 +4128,7 @@ trace.f( self.ClassName, ZoneName ) return self end -function ZONE:GetPoint() +function ZONE:GetPointVec2() self:T( self.ZoneName ) local Zone = trigger.misc.getZone( self.ZoneName ) @@ -10152,7 +10152,7 @@ function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex ) if SpawnTemplate then - local UnitPoint = HostUnit:GetPoint() + local UnitPoint = HostUnit:GetPointVec2() --for PointID, Point in pairs( SpawnTemplate.route.points ) do --Point.x = UnitPoint.x --Point.y = UnitPoint.y @@ -10227,7 +10227,7 @@ function SPAWN:SpawnInZone( Zone, SpawnIndex ) if SpawnTemplate then - local ZonePoint = Zone:GetPoint() + local ZonePoint = Zone:GetPointVec2() SpawnTemplate.route.points = nil SpawnTemplate.route.points = {} diff --git a/Moose/Base.lua b/Moose/Base.lua index 90314d5da..76a4750a5 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -13,9 +13,9 @@ _TraceClass = { --SPAWN = true, --STAGE = true, --ZONE = true, - --GROUP = true, + GROUP = true, --UNIT = true, - --CLIENT = true, + CLIENT = true, --CARGO = true, --CARGO_GROUP = true, --CARGO_PACKAGE = true, diff --git a/Moose/Client.lua b/Moose/Client.lua index a9ce07add..81460fbcc 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -202,11 +202,32 @@ function CLIENT:GetUnit() return UNIT:New( self:GetClientGroupDCSUnit() ) end +--- Returns the Point of the @{CLIENT}. +-- @return DCSTypes#Vec2 +function CLIENT:GetPointVec2() + self:T() + + ClientGroupUnit = self:GetClientGroupDCSUnit() + + if ClientGroupUnit then + if ClientGroupUnit:isExist() then + local PointVec3 = ClientGroupUnit:getPoint() --DCSTypes#Vec3 + local PointVec2 = {} --DCSTypes#Vec2 + PointVec2.x = PointVec3.x + PointVec2.y = PointVec3.z + self:T( { PointVec2 } ) + return PointVec2 + end + end + + return nil +end + --- Returns the Position of the @{CLIENT}. --- @return Position +-- @return DCSTypes#Position function CLIENT:ClientPosition() ---self:T() + self:T() ClientGroupUnit = self:GetClientGroupDCSUnit() @@ -219,6 +240,24 @@ function CLIENT:ClientPosition() return nil end +--- Returns the altitude of the @{CLIENT}. +-- @return DCSTypes#Distance +function CLIENT:GetAltitude() + self:T() + + ClientGroupUnit = self:GetClientGroupDCSUnit() + + if ClientGroupUnit then + if ClientGroupUnit:isExist() then + local PointVec3 = ClientGroupUnit:getPoint() --DCSTypes#Vec3 + return PointVec3.y + end + end + + return nil +end + + --- Transport defines that the Client is a Transport. -- @return CLIENT function CLIENT:Transport() diff --git a/Moose/Escort.lua b/Moose/Escort.lua index bd63f11e9..0a8a57f6d 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -18,18 +18,27 @@ Include.File( "Group" ) Include.File( "Zone" ) --- ESCORT class --- @type --- +-- @type ESCORT +-- @extends Base#BASE +-- @field Client#CLIENT EscortClient +-- @field Group#GROUP EscortGroup +-- @field #string EscortName ESCORT = { ClassName = "ESCORT", EscortName = nil, -- The Escort Name + EscortClient = nil, + EscortGroup = nil, Targets = {}, -- The identified targets } +--- MENUPARAM type +-- @type MENUPARAM +-- @field #ESCORT ParamSelf + --- ESCORT class constructor for an AI group -- @param self --- @param #CLIENT EscortClient The client escorted by the EscortGroup. --- @param #GROUP EscortGroup The group AI escorting the EscortClient. +-- @param Client#CLIENT EscortClient The client escorted by the EscortGroup. +-- @param Group#GROUP EscortGroup The group AI escorting the EscortClient. -- @param #string EscortName Name of the escort. -- @return #ESCORT self function ESCORT:New( EscortClient, EscortGroup, EscortName ) @@ -40,15 +49,22 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortGroup = EscortGroup self.EscortName = EscortName self.ReportTargets = true + + self.EscortMenu = MENU_CLIENT:New( self.EscortClient, "Escort" .. self.EscortName ) -- Escort Navigation - self.EscortMenu = MENU_CLIENT:New( self.EscortClient, "Escort" .. self.EscortName ) - self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenu, ESCORT._HoldPosition, { ParamSelf = self } ) + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenuReportNavigation, ESCORT._HoldPosition, { ParamSelf = self } ) + self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) -- Report Targets - self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report Targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report Targets On", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report Targets Off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + + -- Scanning Targets + self.EscortMenuScanForTargets = MENU_CLIENT:New( self.EscortClient, "Scan targets", self.EscortMenu ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 30 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets30Seconds, { ParamSelf = self, ParamScanDuration = 30 } ) -- Attack Targets self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) @@ -69,16 +85,59 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) self.EscortMenuEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + -- Cancel current Task + self.EscortMenuCancelTask = MENU_CLIENT_COMMAND:New( self.EscortClient, "Cancel current task", self.EscortMenu, ESCORT._CancelCurrentTask, { ParamSelf = self, } ) + self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) end + +--- @param #MENUPARAM MenuParam function ESCORT._HoldPosition( MenuParam ) - MenuParam.ParamSelf.EscortGroup:HoldPosition( 300 ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + EscortGroup:PushTask( EscortGroup:HoldPosition( 300 ) ) MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPosition" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam +function ESCORT._HoldPositionNearBy( MenuParam ) + + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + --MenuParam.ParamSelf.EscortGroup:OrbitCircleAtVec2( MenuParam.ParamSelf.EscortClient:GetPointVec2(), 300, 30, 0 ) + + local PointFrom = {} + local GroupPoint = EscortGroup:GetPointVec2() + PointFrom = {} + PointFrom.x = GroupPoint.x + PointFrom.y = GroupPoint.y + PointFrom.speed = 250 + PointFrom.type = AI.Task.WaypointType.TURNING_POINT + PointFrom.alt = EscortClient:GetAltitude() + PointFrom.alt_type = AI.Task.AltitudeType.BARO + + local ClientPoint = MenuParam.ParamSelf.EscortClient:GetPointVec2() + local PointTo = {} + PointTo.x = ClientPoint.x + PointTo.y = ClientPoint.y + PointTo.speed = 250 + PointTo.type = AI.Task.WaypointType.TURNING_POINT + PointTo.alt = EscortClient:GetAltitude() + PointTo.alt_type = AI.Task.AltitudeType.BARO + PointTo.task = EscortGroup:OrbitCircleAtVec2( EscortClient:GetPointVec2(), 300, 30, 0 ) + + local Points = { PointFrom, PointTo } + + + EscortGroup:PushTask( EscortGroup:TaskMission( Points ) ) + MESSAGE:New( "Rejoining to your location. Please hold at your location.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPositionNearBy" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + function ESCORT._ReportNearbyTargets( MenuParam ) MenuParam.ParamSelf:T() @@ -86,58 +145,126 @@ function ESCORT._ReportNearbyTargets( MenuParam ) end +--- @param #MENUPARAM MenuParam +function ESCORT._ScanTargets30Seconds( MenuParam ) + MenuParam.ParamSelf:T() + + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + EscortGroup:PushTask( EscortGroup:OrbitCircle( 30, 200, 20 ) ) + MESSAGE:New( "Scanning targets for 30 seconds.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ScanTargets30Seconds" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +--- @param #MENUPARAM MenuParam +function ESCORT._ScanTargets60Seconds( MenuParam ) + MenuParam.ParamSelf:T() + + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + EscortGroup:PushTask( EscortGroup:OrbitCircle( 60, 200, 20 ) ) + MESSAGE:New( "Scanning targets for 60 seconds.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ScanTargets60Seconds" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +--- @param #MENUPARAM MenuParam function ESCORT._AttackTarget( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:AttackUnit( MenuParam.ParamUnit ) - MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackTarget" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._ROEHoldFire( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:HoldFire() - MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEHoldFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._ROEReturnFire( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:ReturnFire() - MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEReturnFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._ROEOpenFire( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:OpenFire() - MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEOpenFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._ROEWeaponFree( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:WeaponFree() - MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEWeaponFree" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._EvasionNoReaction( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:EvasionNoReaction() - MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionNoReaction" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._EvasionPassiveDefense( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:EvasionPassiveDefense() - MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionPassiveDefense" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._EvasionEvadeFire( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:EvasionEvadeFire() - MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionEvadeFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) end +--- @param #MENUPARAM MenuParam function ESCORT._EvasionVertical( MenuParam ) + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + MenuParam.ParamSelf.EscortGroup:EvasionVertical() - MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionVertical" ):ToClient( MenuParam.ParamSelf.EscortClient ) +end + +--- @param #MENUPARAM MenuParam +function ESCORT._CancelCurrentTask( MenuParam ) + + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + EscortGroup:PopCurrentTask() + MESSAGE:New( "Cancelling with current orders, continuing our mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/CancelCurrentTask" ):ToClient( MenuParam.ParamSelf.EscortClient ) end diff --git a/Moose/Group.lua b/Moose/Group.lua index 3da7de6f4..96c190cae 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -131,16 +131,26 @@ function GROUP:GetName() return self.GroupName end ---- Gets the current Point of the GROUP in VEC2 format. --- @return #Vec2 Current x and Y position of the group. -function GROUP:GetPoint() +--- Gets the current Point of the GROUP in VEC3 format. +-- @return #Vec3 Current x,y and z position of the group. +function GROUP:GetPointVec2() self:T( self.GroupName ) - local GroupPoint = self:GetUnit(1):GetPoint() + local GroupPoint = self:GetUnit(1):GetPointVec2() self:T( GroupPoint ) return GroupPoint end +--- Gets the current Point of the GROUP in VEC2 format. +-- @return #Vec2 Current x and y position of the group in the 2D plane. +function GROUP:GetPointVec2() + self:T( self.GroupName ) + + local GroupPoint = self:GetUnit(1):GetPointVec2() + self:T( GroupPoint ) + return GroupPoint +end + --- Gets the current Point of the GROUP in VEC3 format. -- @return #Vec3 Current Vec3 position of the group. function GROUP:GetPositionVec3() @@ -259,51 +269,118 @@ end -- @param self -- @return #number Maximum height found. function GROUP:GetMaxHeight() -self:T() + self:T() end ---- Hold position at the current position of the first unit of the group. --- @param self --- @param #number Duration The maximum duration in seconds to hold the position. --- @return #GROUP self -function GROUP:HoldPosition( Duration ) -trace.f( self.ClassName, { self.GroupName, Duration } ) +--- Popping current Task from the group. +-- @param #GROUP self +-- @return Group#GROUP self +function GROUP:PopCurrentTask() + self:T() local Controller = self:_GetController() + Controller:popTask() + + return self +end + + +--- Pushing Task on the queue from the group. +-- @param #GROUP self +-- @return Group#GROUP self +function GROUP:PushTask( DCSTask ) + self:T() + + local Controller = self:_GetController() + + Controller:pushTask( DCSTask ) + + return self +end + +--- Orbit at a specified position at a specified alititude during a specified duration with a specified speed. +-- @param #GROUP self +-- @param #Vec2 Point The point to hold the position. +-- @param #number Duration The maximum duration in seconds to hold the position. +-- @param #number Altitude The altitude to hold the position. +-- @param #number Speed The speed flying when holding the position. +-- @return #GROUP self +function GROUP:OrbitCircleAtVec2( Point, Duration, Altitude, Speed ) + self:T( { self.GroupName, Point, Duration, Altitude, Speed } ) + -- pattern = enum AI.Task.OribtPattern, -- point = Vec2, -- point2 = Vec2, -- speed = Distance, -- altitude = Distance - local GroupPoint = self:GetPoint() - --id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } - Controller:pushTask( { id = 'ControlledTask', - params = { task = { id = 'Orbit', - params = { pattern = AI.Task.OrbitPattern.CIRCLE, - point = GroupPoint, - speed = 0, - altitude = 30 - } - }, - stopCondition = { duration = Duration - } - } - } - ) - return self + local LandHeight = land.getHeight( Point ) + + self:T( { LandHeight } ) + + local AITask = { id = 'Orbit', + params = { pattern = AI.Task.OrbitPattern.CIRCLE, + point = Point, + speed = Speed, + altitude = Altitude + LandHeight + } + } + + +-- local AITask = { id = 'ControlledTask', +-- params = { task = { id = 'Orbit', +-- params = { pattern = AI.Task.OrbitPattern.CIRCLE, +-- point = Point, +-- speed = Speed, +-- altitude = Altitude + LandHeight +-- } +-- }, +-- stopCondition = { duration = Duration +-- } +-- } +-- } +-- ) + + return AITask end +--- Orbit at the current position of the first unit of the group at a specified alititude during a specified duration +-- @param #GROUP self +-- @param #number Duration The maximum duration in seconds to hold the position. +-- @param #number Altitude The altitude to hold the position. +-- @param #number Speed The speed flying when holding the position. +-- @return #GROUP self +function GROUP:OrbitCircle( Duration, Altitude, Speed ) + self:T( { self.GroupName, Duration, Altitude, Speed } ) + + local GroupPoint = self:GetPointVec2() + + return self:OrbitCircleAtVec2( GroupPoint, Duration, Altitude, Speed ) +end + + + +--- Hold position at the current position of the first unit of the group. +-- @param #GROUP self +-- @param #number Duration The maximum duration in seconds to hold the position. +-- @return #GROUP self +function GROUP:HoldPosition( Duration ) + self:T( { self.GroupName, Duration } ) + + return self:OrbitCircle( Duration, 30, 0 ) +end + + --- Land the group at a Vec2Point. -- @param self -- @param #Vec2 Point The point where to land. -- @param #number Duration The duration in seconds to stay on the ground. -- @return #GROUP self function GROUP:Land( Point, Duration ) -trace.f( self.ClassName, { self.GroupName, Point, Duration } ) + self:T( { self.GroupName, Point, Duration } ) local Controller = self:_GetController() @@ -498,12 +575,25 @@ trace.f( self.ClassName, { self.GroupName, Point, Radius } ) return self end +--- Return a Misson task to follow a given route. +-- @param self +-- @param #table GoPoints A table of Route Points. +-- @return #DCSTask +function GROUP:TaskMission( Points ) + self:T( Points ) + + local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } + + return MissionTask +end + + --- Make the group to follow a given route. -- @param self -- @param #table GoPoints A table of Route Points. -- @return #GROUP self function GROUP:Route( GoPoints ) -self:T( GoPoints ) + self:T( GoPoints ) local Points = routines.utils.deepCopy( GoPoints ) local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } @@ -527,7 +617,7 @@ end function GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) self:T( Zone ) - local GroupPoint = self:GetPoint() + local GroupPoint = self:GetPointVec2() local PointFrom = {} PointFrom.x = GroupPoint.x @@ -543,7 +633,7 @@ function GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) if Randomize then ZonePoint = Zone:GetRandomPoint() else - ZonePoint = Zone:GetPoint() + ZonePoint = Zone:GetPointVec2() end PointTo.x = ZonePoint.x @@ -621,6 +711,9 @@ self:T( { Begin, End } ) end --- Get the controller for the GROUP. +-- @function _GetController +-- @param #GROUP self +-- @return Controller#Controller function GROUP:_GetController() return self.DCSGroup:getController() diff --git a/Moose/Spawn.lua b/Moose/Spawn.lua index c88ee5a21..9cd980c77 100644 --- a/Moose/Spawn.lua +++ b/Moose/Spawn.lua @@ -538,7 +538,7 @@ function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex ) if SpawnTemplate then - local UnitPoint = HostUnit:GetPoint() + local UnitPoint = HostUnit:GetPointVec2() --for PointID, Point in pairs( SpawnTemplate.route.points ) do --Point.x = UnitPoint.x --Point.y = UnitPoint.y @@ -613,7 +613,7 @@ function SPAWN:SpawnInZone( Zone, SpawnIndex ) if SpawnTemplate then - local ZonePoint = Zone:GetPoint() + local ZonePoint = Zone:GetPointVec2() SpawnTemplate.route.points = nil SpawnTemplate.route.points = {} diff --git a/Moose/Unit.lua b/Moose/Unit.lua index a418dc71d..b83de9d14 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -79,7 +79,7 @@ function UNIT:GetCallSign() end -function UNIT:GetPoint() +function UNIT:GetPointVec2() self:T( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p diff --git a/Moose/Zone.lua b/Moose/Zone.lua index 3496e0365..8c710eacc 100644 --- a/Moose/Zone.lua +++ b/Moose/Zone.lua @@ -30,7 +30,7 @@ trace.f( self.ClassName, ZoneName ) return self end -function ZONE:GetPoint() +function ZONE:GetPointVec2() self:T( self.ZoneName ) local Zone = trigger.misc.getZone( self.ZoneName ) diff --git a/Test Missions/MOOSE_Spawn_Test.lua b/Test Missions/MOOSE_Spawn_Test.lua index 38306ef23..074aa5a9c 100644 --- a/Test Missions/MOOSE_Spawn_Test.lua +++ b/Test Missions/MOOSE_Spawn_Test.lua @@ -32,8 +32,8 @@ Group_Plane:Route( Route_Plane ) --Route_Helicopter[#Route_Helicopter].linkUnit = Group_Ship1:GetDCSUnit(1) --Route_Helicopter[#Route_Helicopter].helipadId = Group_Ship1:GetDCSUnit(1) ---Route_Helicopter[#Route_Helicopter].x = Group_Ship1:GetUnit(1):GetPoint().x ---Route_Helicopter[#Route_Helicopter].y = Group_Ship1:GetUnit(1):GetPoint().y +--Route_Helicopter[#Route_Helicopter].x = Group_Ship1:GetUnit(1):GetPointVec2().x +--Route_Helicopter[#Route_Helicopter].y = Group_Ship1:GetUnit(1):GetPointVec2().y --env.info( Route_Helicopter[#Route_Helicopter].type .. " on " .. Group_Ship1:GetUnit(1):GetID() ) --Group_Helicopter:Route( Route_Helicopter ) From 260f109e40313022e685f146f071ad1001a1328e Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 28 Mar 2016 22:54:31 +0200 Subject: [PATCH 10/14] Lots of changes done... Change trace prototypes. Change DCS class prototypes --- DCS/{Airbase.doclua => DCSAirbase.doclua} | 5 +- ...bject.doclua => DCSCoalitionObject.doclua} | 4 +- ...Controller.doclua => DCSController.doclua} | 3 +- DCS/{Group.doclua => DCSGroup.doclua} | 54 +- DCS/{Object.doclua => DCSObject.doclua} | 24 +- ...icObject.doclua => DCSStaticObject.doclua} | 6 +- DCS/DCSTask.doclua | 8 + DCS/{Time.doclua => DCSTime.doclua} | 0 DCS/{Unit.doclua => DCSUnit.doclua} | 38 +- DCS/{env.doclua => DCSenv.doclua} | 0 DCS/{land.doclua => DCSland.doclua} | 0 DCS/{timer.doclua => DCStimer.doclua} | 2 +- Embedded/Moose_Embedded.lua | 516 ++++++++-------- Moose/Base.lua | 106 +++- Moose/Cargo.lua | 114 ++-- Moose/CleanUp.lua | 18 +- Moose/Client.lua | 52 +- Moose/Database.lua | 14 +- Moose/DeployTask.lua | 30 +- Moose/DestroyBaseTask.lua | 6 +- Moose/DestroyGroupsTask.lua | 22 +- Moose/DestroyRadarsTask.lua | 17 +- Moose/DestroyUnitTypesTask.lua | 25 +- Moose/Escort.lua | 75 ++- Moose/GoHomeTask.lua | 21 +- Moose/Group.lua | 556 +++++++++++------- Moose/Message.lua | 42 +- Moose/Mission.lua | 75 +-- Moose/Movement.lua | 22 +- Moose/NoTask.lua | 18 +- Moose/PickupTask.lua | 14 +- Moose/RouteTask.lua | 22 +- Moose/Routines.lua | 110 ++-- Moose/Sead.lua | 8 +- Moose/Spawn.lua | 102 ++-- Moose/Stage.lua | 84 +-- Moose/Task.lua | 75 ++- Moose/Unit.lua | 22 +- Moose/Zone.lua | 14 +- {Moose => Trash}/Trace.lua | 0 40 files changed, 1251 insertions(+), 1073 deletions(-) rename DCS/{Airbase.doclua => DCSAirbase.doclua} (96%) rename DCS/{CoalitionObject.doclua => DCSCoalitionObject.doclua} (87%) rename DCS/{Controller.doclua => DCSController.doclua} (99%) rename DCS/{Group.doclua => DCSGroup.doclua} (68%) rename DCS/{Object.doclua => DCSObject.doclua} (85%) rename DCS/{StaticObject.doclua => DCSStaticObject.doclua} (93%) create mode 100644 DCS/DCSTask.doclua rename DCS/{Time.doclua => DCSTime.doclua} (100%) rename DCS/{Unit.doclua => DCSUnit.doclua} (94%) rename DCS/{env.doclua => DCSenv.doclua} (100%) rename DCS/{land.doclua => DCSland.doclua} (100%) rename DCS/{timer.doclua => DCStimer.doclua} (98%) rename {Moose => Trash}/Trace.lua (100%) diff --git a/DCS/Airbase.doclua b/DCS/DCSAirbase.doclua similarity index 96% rename from DCS/Airbase.doclua rename to DCS/DCSAirbase.doclua index 679a09981..85ed697df 100644 --- a/DCS/Airbase.doclua +++ b/DCS/DCSAirbase.doclua @@ -1,9 +1,10 @@ ------------------------------------------------------------------------------- --- @module Airbase --- @extends CoalitionObject#CoalitionObject +-- @module DCSAirbase + --- Represents airbases: airdromes, helipads and ships with flying decks or landing pads. -- @type Airbase +-- @extends DCSCoalitionObject#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. diff --git a/DCS/CoalitionObject.doclua b/DCS/DCSCoalitionObject.doclua similarity index 87% rename from DCS/CoalitionObject.doclua rename to DCS/DCSCoalitionObject.doclua index ee189fd77..14ba57abf 100644 --- a/DCS/CoalitionObject.doclua +++ b/DCS/DCSCoalitionObject.doclua @@ -1,8 +1,8 @@ ------------------------------------------------------------------------------- --- @module CoalitionObject --- @extends Object#Object +-- @module DCSCoalitionObject --- @type CoalitionObject +-- @extends DCSObject#Object --- Returns coalition of the object. -- @function [parent=#CoalitionObject] getCoalition diff --git a/DCS/Controller.doclua b/DCS/DCSController.doclua similarity index 99% rename from DCS/Controller.doclua rename to DCS/DCSController.doclua index 0f434cd30..602e97d5d 100644 --- a/DCS/Controller.doclua +++ b/DCS/DCSController.doclua @@ -1,6 +1,5 @@ ------------------------------------------------------------------------------- --- @module Controller --- TODO Add Task templates +-- @module 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/DCS/Group.doclua b/DCS/DCSGroup.doclua similarity index 68% rename from DCS/Group.doclua rename to DCS/DCSGroup.doclua index 4aeb17653..a3d0edf5d 100644 --- a/DCS/Group.doclua +++ b/DCS/DCSGroup.doclua @@ -1,6 +1,5 @@ ------------------------------------------------------------------------------- --- @module Group - +-- @module DCSGroup --- Represents group of Units. -- @type Group @@ -17,66 +16,67 @@ -- Static Functions --- Returns group by the name assigned to the group in Mission Editor. --- @function [parent=#Airbase] getByName +-- @function [parent=#Group] getByName -- @param #string name -- @return #Group -- Member Functions --- returns true if the group exist or false otherwise. --- @function [parent=#Airbase] isExist --- @param self +-- @function [parent=#Group] isExist +-- @param #Group self -- @return #boolean --- Destroys the group and all of its units. --- @function [parent=#Airbase] destroy --- @param self +-- @function [parent=#Group] destroy +-- @param #Group self --- Returns category of the group. --- @function [parent=#Airbase] getCategory --- @param self +-- @function [parent=#Group] getCategory +-- @param #Group self -- @return #Group.Category --TODO check coalition.side --- Returns coalition of the group. --- @function [parent=#Airbase] getCoalition --- @param self +-- @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=#Airbase] getName --- @param self +-- @function [parent=#Group] getName +-- @param #Group self -- @return #string --- Returns the group identifier. --- @function [parent=#Airbase] getID --- @param self +-- @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=#Airbase] getUnit --- @param self +-- @function [parent=#Group] getUnit +-- @param #Group self -- @param #number unitNumber --- @return Unit#Unit +-- @return DCSUnit#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=#Airbase] getSize --- @param self +-- @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=#Airbase] getInitialSize --- @param self +-- @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=#Airbase] getUnits --- @param self --- @return #list array of Units +-- @function [parent=#Group] getUnits +-- @param #Group self +-- @return #list array of Units --- Returns controller of the group. --- @function [parent=#Airbase] getController --- @param self +-- @function [parent=#Group] getController +-- @param #Group self -- @return Controller#Controller Group = {} --#Group + diff --git a/DCS/Object.doclua b/DCS/DCSObject.doclua similarity index 85% rename from DCS/Object.doclua rename to DCS/DCSObject.doclua index fcd3c2416..281e2781a 100644 --- a/DCS/Object.doclua +++ b/DCS/DCSObject.doclua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module Object +-- @module DCSObject --- @type Object -- @field #Object.Category Category @@ -18,55 +18,55 @@ -- @field #Box3 box bounding box of collision geometry --- @function [parent=#Object] isExist --- @param self +-- @param #Object self -- @return #boolean --- @function [parent=#Object] destroy --- @param self +-- @param #Object self --- @function [parent=#Object] getCategory --- @param self +-- @param #Object self -- @return #Object.Category --- Returns type name of the Object. -- @function [parent=#Object] getTypeName --- @param self +-- @param #Object self -- @return #string --- Returns object descriptor. -- @function [parent=#Object] getDesc --- @param self +-- @param #Object self -- @return #Object.Desc --- Returns true if the object belongs to the category. -- @function [parent=#Object] hasAttribute --- @param self +-- @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 self +-- @param #Object self -- @return #string --- Returns object coordinates for current time. -- @function [parent=#Object] getPoint --- @param self +-- @param #Object self -- @return #Vec3 --- Returns object position for current time. -- @function [parent=#Object] getPosition --- @param self +-- @param #Object self -- @return #Position3 --- Returns the unit's velocity vector. -- @function [parent=#Object] getVelocity --- @param self +-- @param #Object self -- @return #Vec3 --- Returns true if the unit is in air. -- @function [parent=#Object] inAir --- @param self +-- @param #Object self -- @return #boolean Object = {} --#Object diff --git a/DCS/StaticObject.doclua b/DCS/DCSStaticObject.doclua similarity index 93% rename from DCS/StaticObject.doclua rename to DCS/DCSStaticObject.doclua index 2aa818548..e8e76964f 100644 --- a/DCS/StaticObject.doclua +++ b/DCS/DCSStaticObject.doclua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module StaticObject +-- @module DCSStaticObject ------------------------------------------------------------------------------- @@ -22,12 +22,12 @@ --- returns identifier of the static object. -- @function [parent=#StaticObject] getID --- @param self +-- @param #StaticObject self -- @return #StaticObject.ID --- Returns descriptor of the StaticObject. -- @function [parent=#StaticObject] getDesc --- @param self +-- @param #StaticObject self -- @return #StaticObject.Desc diff --git a/DCS/DCSTask.doclua b/DCS/DCSTask.doclua new file mode 100644 index 000000000..3d57efca1 --- /dev/null +++ b/DCS/DCSTask.doclua @@ -0,0 +1,8 @@ + +--- @type DCSTask +-- @field #string id +-- @field #DCSTask.param param + +--- @type DCSTask.param + +env.info( "DCSTask defined" ) diff --git a/DCS/Time.doclua b/DCS/DCSTime.doclua similarity index 100% rename from DCS/Time.doclua rename to DCS/DCSTime.doclua diff --git a/DCS/Unit.doclua b/DCS/DCSUnit.doclua similarity index 94% rename from DCS/Unit.doclua rename to DCS/DCSUnit.doclua index 1e420182e..d94e301d7 100644 --- a/DCS/Unit.doclua +++ b/DCS/DCSUnit.doclua @@ -1,8 +1,8 @@ ------------------------------------------------------------------------------- --- @module Unit --- @extends CoalitionObject#CoalitionObject +-- @module DCSUnit --- @type Unit +-- @extends DCSCoalitionObject#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 @@ -151,68 +151,68 @@ --- Returns if the unit is activated. -- @function [parent=#Unit] isActive --- @param self +-- @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 self +-- @param #Unit self -- @return #string --- returns the unit's unique identifier. -- @function [parent=#Unit] getID --- @param self +-- @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 self +-- @param #Unit self -- @return #number --- Returns controller of the unit if it exist and nil otherwise -- @function [parent=#Unit] getController --- @param self +-- @param #Unit self -- @return #Controller --- Returns the unit's group if it exist and nil otherwise -- @function [parent=#Unit] getGroup --- @param self --- @return Group#Group +-- @param #Unit self +-- @return DCSGroup#Group --- Returns the unit's callsign - the localized string. -- @function [parent=#Unit] getCallsign --- @param self +-- @param #Unit self -- @return #string --- Returns the unit's health. Dead units has health <= 1.0 -- @function [parent=#Unit] getLife --- @param self +-- @param #Unit self -- @return #number --- returns the unit's initial health. -- @function [parent=#Unit] getLife0 --- @param self +-- @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 self +-- @param #Unit self -- @return #number --- Returns the unit ammunition. -- @function [parent=#Unit] getAmmo --- @param self +-- @param #Unit self -- @return #Unit.Ammo --- Returns the unit sensors. -- @function [parent=#Unit] getSensors --- @param self +-- @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 self +-- @param #Unit self -- @param #Unit.SensorType sensorType (= nil) Sensor type. -- @param ... Additional parameters. -- @return #boolean @@ -229,13 +229,13 @@ -- 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 self +-- @param #Unit self -- @return #boolean, Object#Object --- Returns unit descriptor. Descriptor type depends on unit category. -- @function [parent=#Unit] getDesc --- @param self --- @return Unit#Unit.Desc +-- @param #Unit self +-- @return #Unit.Desc Unit = {} --#Unit diff --git a/DCS/env.doclua b/DCS/DCSenv.doclua similarity index 100% rename from DCS/env.doclua rename to DCS/DCSenv.doclua diff --git a/DCS/land.doclua b/DCS/DCSland.doclua similarity index 100% rename from DCS/land.doclua rename to DCS/DCSland.doclua diff --git a/DCS/timer.doclua b/DCS/DCStimer.doclua similarity index 98% rename from DCS/timer.doclua rename to DCS/DCStimer.doclua index 56127eb4a..2d0f4a16c 100644 --- a/DCS/timer.doclua +++ b/DCS/DCStimer.doclua @@ -1,5 +1,5 @@ ------------------------------------------------------------------------------- --- @module timer +-- @module DCStimer --- @type timer diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index c3cda1d51..721e46db9 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -3363,7 +3363,7 @@ GROUPS = {} -- @return #GROUP self function GROUP:New( DCSGroup ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSGroup ) + self:F( DCSGroup ) self.DCSGroup = DCSGroup if self.DCSGroup and self.DCSGroup:isExist() then @@ -3384,7 +3384,7 @@ end -- @return #GROUP self function GROUP:NewFromName( GroupName ) local self = BASE:Inherit( self, BASE:New() ) - self:T( GroupName ) + self:F( GroupName ) self.DCSGroup = Group.getByName( GroupName ) if self.DCSGroup then @@ -3402,7 +3402,7 @@ end -- @return #GROUP self function GROUP:NewFromDCSUnit( DCSUnit ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSUnit ) + self:F( DCSUnit ) self.DCSGroup = DCSUnit:getGroup() if self.DCSGroup then @@ -3418,7 +3418,7 @@ end -- @param self -- @return #Group The DCSGroup. function GROUP:GetDCSGroup() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) self.DCSGroup = Group.getByName( self.GroupName ) return self.DCSGroup end @@ -3430,7 +3430,7 @@ end -- @param #number UnitNumber The unit index to be returned from the GROUP. -- @return #Unit The DCS Unit. function GROUP:GetDCSUnit( UnitNumber ) - self:T( { self.GroupName, UnitNumber } ) + self:F( { self.GroupName, UnitNumber } ) return self.DCSGroup:getUnit( UnitNumber ) end @@ -3438,7 +3438,7 @@ end --- Activates a GROUP. -- @param self function GROUP:Activate() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) trigger.action.activateGroup( self:GetDCSGroup() ) return self:GetDCSGroup() end @@ -3447,7 +3447,7 @@ end -- @param self -- @return #number The ID of the GROUP. function GROUP:GetID() - self:T( self.GroupName ) + self:F( self.GroupName ) return self.GroupID end @@ -3456,7 +3456,7 @@ end -- @param self -- @return #string The name of the GROUP. function GROUP:GetName() - self:T( self.GroupName ) + self:F( self.GroupName ) return self.GroupName end @@ -3464,7 +3464,7 @@ end --- Gets the current Point of the GROUP in VEC2 format. -- @return #Vec2 Current x and Y position of the group. function GROUP:GetPointVec2() - self:T( self.GroupName ) + self:F( self.GroupName ) local GroupPoint = self:GetUnit(1):GetPointVec2() self:T( GroupPoint ) @@ -3474,7 +3474,7 @@ end --- Gets the current Point of the GROUP in VEC3 format. -- @return #Vec3 Current Vec3 position of the group. function GROUP:GetPositionVec3() - self:T( self.GroupName ) + self:F( self.GroupName ) local GroupPoint = self:GetUnit(1):GetPositionVec3() self:T( GroupPoint ) @@ -3486,7 +3486,7 @@ end -- So all event listeners will catch the destroy event of this GROUP. -- @param self function GROUP:Destroy() - self:T( self.GroupName ) + self:F( self.GroupName ) for Index, UnitData in pairs( self.DCSGroup:getUnits() ) do self:CreateEventCrash( timer.getTime(), UnitData ) @@ -3502,7 +3502,7 @@ end -- @param #number UnitNumber The number of the Unit to be returned. -- @return #Unit The DCS Unit. function GROUP:GetUnit( UnitNumber ) - self:T( { self.GroupName, UnitNumber } ) + self:F( { self.GroupName, UnitNumber } ) return UNIT:New( self.DCSGroup:getUnit( UnitNumber ) ) end @@ -3511,7 +3511,7 @@ end -- @param self -- @return #boolean Air category evaluation result. function GROUP:IsAir() -self:T() + self:F() local IsAirResult = self.DCSGroup:getCategory() == Group.Category.AIRPLANE or self.DCSGroup:getCategory() == Group.Category.HELICOPTER @@ -3524,7 +3524,7 @@ end -- @param self -- @return #boolean Alive result. function GROUP:IsAlive() -self:T() + self:F() local IsAliveResult = self.DCSGroup and self.DCSGroup:isExist() @@ -3537,7 +3537,7 @@ end -- @param self -- @return #boolean All units on the ground result. function GROUP:AllOnGround() -self:T() + self:F() local AllOnGroundResult = true @@ -3556,7 +3556,7 @@ end -- @param self -- @return #number Maximum velocity found. function GROUP:GetMaxVelocity() - self:T() + self:F() local MaxVelocity = 0 @@ -3579,7 +3579,7 @@ end -- @param self -- @return #number Minimum height found. function GROUP:GetMinHeight() - self:T() + self:F() end @@ -3589,7 +3589,7 @@ end -- @param self -- @return #number Maximum height found. function GROUP:GetMaxHeight() -self:T() + self:F() end @@ -3598,7 +3598,7 @@ end -- @param self -- @param #number Duration The maximum duration in seconds to hold the position. -- @return #GROUP self -function GROUP:HoldPosition( Duration ) +function GROUP:TaskHoldPosition( Duration ) trace.f( self.ClassName, { self.GroupName, Duration } ) local Controller = self:_GetController() @@ -3651,7 +3651,7 @@ end -- @param #UNIT The unit. -- @return #GROUP self function GROUP:AttackUnit( AttackUnit ) - self:T( { self.GroupName, AttackUnit } ) + self:F( { self.GroupName, AttackUnit } ) local Controller = self:_GetController() @@ -3684,7 +3684,7 @@ end -- @param self -- @return #GROUP self function GROUP:HoldFire() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3696,7 +3696,7 @@ end -- @param self -- @return #GROUP self function GROUP:ReturnFire() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3708,7 +3708,7 @@ end -- @param self -- @return #GROUP self function GROUP:OpenFire() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3720,7 +3720,7 @@ end -- @param self -- @return #GROUP self function GROUP:WeaponFree() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3732,7 +3732,7 @@ end -- @param self -- @return #GROUP self function GROUP:EvasionNoReaction() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3744,7 +3744,7 @@ end -- @param self -- @return #GROUP self function GROUP:EvasionPassiveDefense() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3756,7 +3756,7 @@ end -- @param self -- @return #GROUP self function GROUP:EvasionEvadeFire() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3768,7 +3768,7 @@ end -- @param self -- @return #GROUP self function GROUP:EvasionVertical() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3833,7 +3833,7 @@ end -- @param #table GoPoints A table of Route Points. -- @return #GROUP self function GROUP:Route( GoPoints ) -self:T( GoPoints ) + self:F( GoPoints ) local Points = routines.utils.deepCopy( GoPoints ) local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } @@ -3855,7 +3855,7 @@ end -- @param #number Speed The speed. -- @param BASE#FORMATION Formation The formation string. function GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) - self:T( Zone ) + self:F( Zone ) local GroupPoint = self:GetPointVec2() @@ -3908,7 +3908,7 @@ end -- @param #boolean Randomize Randomization of the route, when true. -- @param #number Radius When randomization is on, the randomization is within the radius. function GROUP:CopyRoute( Begin, End, Randomize, Radius ) -self:T( { Begin, End } ) + self:F( { Begin, End } ) local Points = {} @@ -3993,7 +3993,7 @@ UNIT = { function UNIT:New( DCSUnit ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSUnit:getName() ) + self:F( DCSUnit:getName() ) self.DCSUnit = DCSUnit self.UnitName = DCSUnit:getName() @@ -4003,39 +4003,39 @@ function UNIT:New( DCSUnit ) end function UNIT:IsAlive() - self:T( self.UnitName ) + self:F( self.UnitName ) return ( self.DCSUnit and self.DCSUnit:isExist() ) end function UNIT:GetDCSUnit() - self:T( self.DCSUnit ) + self:F( self.DCSUnit ) return self.DCSUnit end function UNIT:GetID() - self:T( self.UnitID ) + self:F( self.UnitID ) return self.UnitID end function UNIT:GetName() - self:T( self.UnitName ) + self:F( self.UnitName ) return self.UnitName end function UNIT:GetTypeName() - self:T( self.UnitName ) + self:F( self.UnitName ) return self.DCSUnit:getTypeName() end function UNIT:GetPrefix() - self:T( self.UnitName ) + self:F( self.UnitName ) local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) self:T( UnitPrefix ) @@ -4045,14 +4045,14 @@ end function UNIT:GetCallSign() - self:T( self.UnitName ) + self:F( self.UnitName ) return self.DCSUnit:getCallsign() end function UNIT:GetPointVec2() - self:T( self.UnitName ) + self:F( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p @@ -4066,7 +4066,7 @@ end function UNIT:GetPositionVec3() - self:T( self.UnitName ) + self:F( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p @@ -4075,7 +4075,7 @@ function UNIT:GetPositionVec3() end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) - self:T( { self.UnitName, AwaitUnit.UnitName, Radius } ) + self:F( { self.UnitName, AwaitUnit.UnitName, Radius } ) local UnitPos = self:GetPositionVec3() local AwaitUnitPos = AwaitUnit:GetPositionVec3() @@ -4129,7 +4129,7 @@ trace.f( self.ClassName, ZoneName ) end function ZONE:GetPointVec2() - self:T( self.ZoneName ) + self:F( self.ZoneName ) local Zone = trigger.misc.getZone( self.ZoneName ) local Point = { x = Zone.point.x, y = Zone.point.z } @@ -4326,7 +4326,7 @@ end --- Set a status to a Group within the Database, this to check crossing events for example. function DATABASE:SetStatusGroup( GroupName, Status ) - self:T( Status ) + self:F( Status ) self.Groups[GroupName].Status = Status end @@ -4334,7 +4334,7 @@ end --- Get a status to a Group within the Database, this to check crossing events for example. function DATABASE:GetStatusGroup( GroupName ) - self:T( Status ) + self:F( Status ) if self.Groups[GroupName] then return self.Groups[GroupName].Status @@ -4487,7 +4487,7 @@ end --- Follows new players entering Clients within the DCSRTE. function DATABASE:_FollowPlayers() - self:T( "_FollowPlayers" ) + self:F( "_FollowPlayers" ) local ClientUnit = 0 local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) } @@ -4510,7 +4510,7 @@ end --- Add a new player entering a Unit. function DATABASE:_AddPlayerFromUnit( UnitData ) - self:T( UnitData ) + self:F( UnitData ) if UnitData:isExist() then local UnitName = UnitData:getName() @@ -4588,7 +4588,7 @@ end --- Registers Scores the players completing a Mission Task. function DATABASE:_AddMissionTaskScore( PlayerUnit, MissionName, Score ) - self:T( { PlayerUnit, MissionName, Score } ) + self:F( { PlayerUnit, MissionName, Score } ) local PlayerName = PlayerUnit:getPlayerName() @@ -4614,7 +4614,7 @@ end --- Registers Mission Scores for possible multiple players that contributed in the Mission. function DATABASE:_AddMissionScore( MissionName, Score ) - self:T( { PlayerUnit, MissionName, Score } ) + self:F( { PlayerUnit, MissionName, Score } ) for PlayerName, PlayerData in pairs( self.Players ) do @@ -4635,7 +4635,7 @@ end function DATABASE:OnHit( event ) - self:T( { event } ) + self:F( { event } ) local InitUnit = nil local InitUnitName = "" @@ -5139,7 +5139,7 @@ CARGO_ZONE = { } function CARGO_ZONE:New( CargoZoneName, CargoHostName ) local self = BASE:Inherit( self, BASE:New() ) -self:T( { CargoZoneName, CargoHostName } ) + self:F( { CargoZoneName, CargoHostName } ) self.CargoZoneName = CargoZoneName self.CargoZone = trigger.misc.getZone( CargoZoneName ) @@ -5155,7 +5155,7 @@ self:T( { CargoZoneName, CargoHostName } ) end function CARGO_ZONE:Spawn() - self:T( self.CargoHostName ) + self:F( self.CargoHostName ) if self.CargoHostSpawn then local CargoHostGroup = self.CargoHostSpawn:GetGroupFromIndex() @@ -5173,7 +5173,7 @@ function CARGO_ZONE:Spawn() end function CARGO_ZONE:GetHostUnit() - self:T( self ) + self:F( self ) if self.CargoHostName then @@ -5193,7 +5193,7 @@ function CARGO_ZONE:GetHostUnit() end function CARGO_ZONE:ReportCargosToClient( Client, CargoType ) -self:T() + self:F() local SignalUnit = self:GetHostUnit() @@ -5222,7 +5222,7 @@ self:T() end function CARGO_ZONE:Signal() -self:T() + self:F() local Signalled = false @@ -5276,7 +5276,7 @@ self:T() end function CARGO_ZONE:WhiteSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.WHITE @@ -5285,7 +5285,7 @@ self:T() end function CARGO_ZONE:BlueSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.BLUE @@ -5294,7 +5294,7 @@ self:T() end function CARGO_ZONE:RedSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.RED @@ -5303,7 +5303,7 @@ self:T() end function CARGO_ZONE:OrangeSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.ORANGE @@ -5312,7 +5312,7 @@ self:T() end function CARGO_ZONE:GreenSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.GREEN @@ -5322,7 +5322,7 @@ end function CARGO_ZONE:WhiteFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.WHITE @@ -5331,7 +5331,7 @@ self:T() end function CARGO_ZONE:RedFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.RED @@ -5340,7 +5340,7 @@ self:T() end function CARGO_ZONE:GreenFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.GREEN @@ -5349,7 +5349,7 @@ self:T() end function CARGO_ZONE:YellowFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.YELLOW @@ -5359,7 +5359,7 @@ end function CARGO_ZONE:GetCargoHostUnit() - self:T( self ) + self:F( self ) if self.CargoHostSpawn then local CargoHostGroup = self.CargoHostSpawn:GetGroupFromIndex(1) @@ -5375,7 +5375,7 @@ function CARGO_ZONE:GetCargoHostUnit() end function CARGO_ZONE:GetCargoZoneName() -self:T() + self:F() return self.CargoZoneName end @@ -5393,7 +5393,7 @@ CARGO = { --- Add Cargo to the mission... Cargo functionality needs to be reworked a bit, so this is still under construction. I need to make a CARGO Class... function CARGO:New( CargoType, CargoName, CargoWeight ) local self = BASE:Inherit( self, BASE:New() ) -self:T( { CargoType, CargoName, CargoWeight } ) + self:F( { CargoType, CargoName, CargoWeight } ) self.CargoType = CargoType @@ -5406,14 +5406,14 @@ self:T( { CargoType, CargoName, CargoWeight } ) end function CARGO:Spawn( Client ) - self:T() + self:F() return self end function CARGO:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = true @@ -5423,7 +5423,7 @@ end function CARGO:IsLoadingToClient() -self:T() + self:F() if self:IsStatusLoading() then return self.CargoClient @@ -5435,7 +5435,7 @@ end function CARGO:IsLoadedInClient() -self:T() + self:F() if self:IsStatusLoaded() then return self.CargoClient @@ -5447,7 +5447,7 @@ end function CARGO:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:StatusUnLoaded() @@ -5455,7 +5455,7 @@ self:T() end function CARGO:OnBoard( Client, LandingZone ) -self:T() + self:F() local Valid = true @@ -5466,7 +5466,7 @@ self:T() end function CARGO:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = true @@ -5474,7 +5474,7 @@ self:T() end function CARGO:Load( Client ) -self:T() + self:F() self:StatusLoaded( Client ) @@ -5482,18 +5482,18 @@ self:T() end function CARGO:IsLandingRequired() -self:T() + self:F() return true end function CARGO:IsSlingLoad() -self:T() + self:F() return false end function CARGO:StatusNone() -self:T() + self:F() self.CargoClient = nil self.CargoStatus = CARGO.STATUS.NONE @@ -5502,7 +5502,7 @@ self:T() end function CARGO:StatusLoading( Client ) -self:T() + self:F() self.CargoClient = Client self.CargoStatus = CARGO.STATUS.LOADING @@ -5512,7 +5512,7 @@ self:T() end function CARGO:StatusLoaded( Client ) -self:T() + self:F() self.CargoClient = Client self.CargoStatus = CARGO.STATUS.LOADED @@ -5522,7 +5522,7 @@ self:T() end function CARGO:StatusUnLoaded() -self:T() + self:F() self.CargoClient = nil self.CargoStatus = CARGO.STATUS.UNLOADED @@ -5532,25 +5532,25 @@ end function CARGO:IsStatusNone() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.NONE end function CARGO:IsStatusLoading() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.LOADING end function CARGO:IsStatusLoaded() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.LOADED end function CARGO:IsStatusUnLoaded() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.UNLOADED end @@ -5562,7 +5562,7 @@ CARGO_GROUP = { function CARGO_GROUP:New( CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - self:T( { CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone } ) + self:F( { CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone } ) self.CargoSpawn = SPAWN:NewWithAlias( CargoGroupTemplate, CargoName ) self.CargoZone = CargoZone @@ -5574,7 +5574,7 @@ function CARGO_GROUP:New( CargoType, CargoName, CargoWeight, CargoGroupTemplate, end function CARGO_GROUP:Spawn( Client ) - self:T( { Client } ) + self:F( { Client } ) local SpawnCargo = true @@ -5635,7 +5635,7 @@ function CARGO_GROUP:Spawn( Client ) end function CARGO_GROUP:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -5652,7 +5652,7 @@ end function CARGO_GROUP:OnBoard( Client, LandingZone, OnBoardSide ) -self:T() + self:F() local Valid = true @@ -5731,7 +5731,7 @@ end function CARGO_GROUP:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = false @@ -5747,7 +5747,7 @@ end function CARGO_GROUP:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:T( 'self.CargoName = ' .. self.CargoName ) @@ -5770,8 +5770,7 @@ CARGO_PACKAGE = { function CARGO_PACKAGE:New( CargoType, CargoName, CargoWeight, CargoClient ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - - self:T( { CargoType, CargoName, CargoWeight, CargoClient } ) + self:F( { CargoType, CargoName, CargoWeight, CargoClient } ) self.CargoClient = CargoClient @@ -5783,7 +5782,7 @@ end function CARGO_PACKAGE:Spawn( Client ) - self:T( { self, Client } ) + self:F( { self, Client } ) -- this needs to be checked thoroughly @@ -5823,7 +5822,7 @@ end function CARGO_PACKAGE:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -5842,7 +5841,7 @@ end function CARGO_PACKAGE:OnBoard( Client, LandingZone, OnBoardSide ) -self:T() + self:F() local Valid = true @@ -5933,7 +5932,7 @@ end function CARGO_PACKAGE:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = false @@ -5953,7 +5952,7 @@ end function CARGO_PACKAGE:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:T( 'self.CargoName = ' .. self.CargoName ) --self:T( 'self.CargoHostName = ' .. self.CargoHostName ) @@ -5972,8 +5971,7 @@ CARGO_SLINGLOAD = { function CARGO_SLINGLOAD:New( CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - - self:T( { CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID } ) + self:F( { CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID } ) self.CargoHostName = CargoHostName @@ -5994,19 +5992,19 @@ end function CARGO_SLINGLOAD:IsLandingRequired() -self:T() + self:F() return false end function CARGO_SLINGLOAD:IsSlingLoad() -self:T() + self:F() return true end function CARGO_SLINGLOAD:Spawn( Client ) - self:T( { self, Client } ) + self:F( { self, Client } ) local Zone = trigger.misc.getZone( self.CargoZone ) @@ -6056,7 +6054,7 @@ end function CARGO_SLINGLOAD:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -6065,7 +6063,7 @@ end function CARGO_SLINGLOAD:IsInLandingZone( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -6081,7 +6079,7 @@ end function CARGO_SLINGLOAD:OnBoard( Client, LandingZone, OnBoardSide ) -self:T() + self:F() local Valid = true @@ -6091,7 +6089,7 @@ end function CARGO_SLINGLOAD:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = false @@ -6107,7 +6105,7 @@ end function CARGO_SLINGLOAD:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:T( 'self.CargoName = ' .. self.CargoName ) self:T( 'self.CargoGroupName = ' .. self.CargoGroupName ) @@ -6166,7 +6164,7 @@ CLIENT = { -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) function CLIENT:New( ClientName, ClientBriefing ) local self = BASE:Inherit( self, BASE:New() ) - self:T( ClientName, ClientBriefing ) + self:F( ClientName, ClientBriefing ) self.ClientName = ClientName self:AddBriefing( ClientBriefing ) @@ -6178,7 +6176,7 @@ end --- Resets a CLIENT. -- @param string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. function CLIENT:Reset( ClientName ) -self:T() + self:F() self._Menus = {} end @@ -6289,7 +6287,7 @@ end --- Returns the Unit of the @{CLIENT}. -- @return Unit function CLIENT:GetClientGroupUnit() - self:T() + self:F() local ClientGroup = self:GetDCSGroup() @@ -6303,7 +6301,7 @@ end --- Returns the DCSUnit of the @{CLIENT}. -- @return DCSUnit function CLIENT:GetClientGroupDCSUnit() - self:T() + self:F() local ClientGroup = self:GetDCSGroup() @@ -6315,7 +6313,7 @@ function CLIENT:GetClientGroupDCSUnit() end function CLIENT:GetUnit() - self:T() + self:F() return UNIT:New( self:GetClientGroupDCSUnit() ) end @@ -6340,7 +6338,7 @@ end --- Transport defines that the Client is a Transport. -- @return CLIENT function CLIENT:Transport() -self:T() + self:F() self.ClientTransport = true return self @@ -6350,7 +6348,7 @@ end -- @param string ClientBriefing is the text defining the Mission briefing. -- @return CLIENT function CLIENT:AddBriefing( ClientBriefing ) -self:T() + self:F() self.ClientBriefing = ClientBriefing return self end @@ -6358,14 +6356,14 @@ end --- IsTransport returns if a Client is a transport. -- @return bool function CLIENT:IsTransport() -self:T() + self:F() return self.ClientTransport end --- ShowCargo shows the @{CARGO} within the CLIENT to the Player. -- The @{CARGO} is shown throught the MESSAGE system of DCS World. function CLIENT:ShowCargo() -self:T() + self:F() local CargoMsg = "" @@ -6396,7 +6394,7 @@ end -- @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 when the CLIENT is in the air. function CLIENT:Message( Message, MessageDuration, MessageId, MessageCategory, MessageInterval ) -self:T() + self:F() if not self.MenuMessages then if self:GetClientGroupID() then @@ -6477,7 +6475,7 @@ MESSAGE = { -- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ) function MESSAGE:New( MessageText, MessageCategory, MessageDuration, MessageID ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { MessageText, MessageCategory, MessageDuration, MessageID } ) + self:F( { MessageText, MessageCategory, MessageDuration, MessageID } ) -- When no messagecategory is given, we don't show it as a title... if MessageCategory and MessageCategory ~= "" then @@ -6517,7 +6515,7 @@ end -- MessageClient1:ToClient( ClientGroup ) -- MessageClient2:ToClient( ClientGroup ) function MESSAGE:ToClient( Client ) - self:T( Client ) + self:F( Client ) if Client and Client:GetClientGroupID() then @@ -6540,7 +6538,7 @@ end -- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- MessageBLUE:ToBlue() function MESSAGE:ToBlue() - self:T() + self:F() self:ToCoalition( coalition.side.BLUE ) @@ -6558,7 +6556,7 @@ end -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- MessageRED:ToRed() function MESSAGE:ToRed( ) - self:T() + self:F() self:ToCoalition( coalition.side.RED ) @@ -6577,7 +6575,7 @@ end -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- MessageRED:ToCoalition( coalition.side.RED ) function MESSAGE:ToCoalition( CoalitionSide ) - self:T( CoalitionSide ) + self:F( CoalitionSide ) if CoalitionSide then trace.i(self.ClassName, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) @@ -6598,7 +6596,7 @@ end -- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) -- MessageAll:ToAll() function MESSAGE:ToAll() - self:T() + self:F() self:ToCoalition( coalition.side.RED ) self:ToCoalition( coalition.side.BLUE ) @@ -6617,7 +6615,7 @@ MESSAGEQUEUE = { function MESSAGEQUEUE:New( RefreshInterval ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { RefreshInterval } ) + self:F( { RefreshInterval } ) self.RefreshInterval = RefreshInterval @@ -6710,7 +6708,7 @@ STAGE = { function STAGE:New() local self = BASE:Inherit( self, BASE:New() ) - self:T() + self:F() return self end @@ -6742,14 +6740,14 @@ STAGEBRIEF = { function STAGEBRIEF:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGEBRIEF:Execute( Mission, Client, Task ) local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) - self:T() + self:F() Mission:ShowBriefing( Client ) self.StageBriefingTime = timer.getTime() return Valid @@ -6779,13 +6777,13 @@ STAGESTART = { function STAGESTART:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGESTART:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) if Task.TaskBriefing then Client:Message( Task.TaskBriefing, 30, Mission.Name .. "/Stage", "Mission Command: Tasking" ) @@ -6797,7 +6795,7 @@ self:T() end function STAGESTART:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) if timer.getTime() - self.StageStartTime <= self.StageStartDuration then @@ -6817,13 +6815,13 @@ STAGE_CARGO_LOAD = { function STAGE_CARGO_LOAD:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGE_CARGO_LOAD:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) for LoadCargoID, LoadCargo in pairs( Task.Cargos.LoadCargos ) do @@ -6838,7 +6836,7 @@ self:T() end function STAGE_CARGO_LOAD:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) return 1 @@ -6851,13 +6849,13 @@ STAGE_CARGO_INIT = { function STAGE_CARGO_INIT:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGE_CARGO_INIT:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) for InitLandingZoneID, InitLandingZone in pairs( Task.LandingZones.LandingZones ) do @@ -6877,7 +6875,7 @@ end function STAGE_CARGO_INIT:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) return 1 @@ -6894,7 +6892,7 @@ STAGEROUTE = { function STAGEROUTE:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' self.MessageSwitch = true return self @@ -6902,7 +6900,7 @@ end function STAGEROUTE:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) local RouteMessage = "Fly to " @@ -6920,7 +6918,7 @@ self:T() end function STAGEROUTE:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) -- check if the Client is in the landing zone @@ -6955,13 +6953,13 @@ STAGELANDING = { function STAGELANDING:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGELANDING:Execute( Mission, Client, Task ) -self:T() + self:F() Client:Message( "We have arrived at the landing zone.", self.MSG.TIME, Mission.Name .. "/StageArrived", "Co-Pilot: Arrived", 10 ) @@ -7013,7 +7011,7 @@ self:T() end function STAGELANDING:Validate( Mission, Client, Task ) -self:T() + self:F() Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.LandingZones.LandingZoneNames ) if Task.CurrentLandingZoneName then @@ -7057,13 +7055,13 @@ STAGELANDED = { function STAGELANDED:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGELANDED:Execute( Mission, Client, Task ) -self:T() + self:F() if Task.IsLandingRequired then Client:Message( 'We have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType .. '.', @@ -7079,7 +7077,7 @@ end function STAGELANDED:Validate( Mission, Client, Task ) -self:T() + self:F() if not routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName ) then self:T( "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." ) @@ -7112,20 +7110,20 @@ STAGEUNLOAD = { function STAGEUNLOAD:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGEUNLOAD:Execute( Mission, Client, Task ) -self:T() + self:F() Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', self.MSG.TIME, Mission.Name .. "/StageUnLoad", "Co-Pilot: Unload" ) Task:RemoveCargoMenus( Client ) end function STAGEUNLOAD:Executing( Mission, Client, Task ) -self:T() + self:F() env.info( 'STAGEUNLOAD:Executing() Task.Cargo.CargoName = ' .. Task.Cargo.CargoName ) local TargetZoneName @@ -7145,7 +7143,7 @@ self:T() end function STAGEUNLOAD:Validate( Mission, Client, Task ) -self:T() + self:F() env.info( 'STAGEUNLOAD:Validate()' ) if routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName ) then @@ -7184,13 +7182,13 @@ STAGELOAD = { function STAGELOAD:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGELOAD:Execute( Mission, Client, Task ) -self:T() + self:F() if not Task.IsSlingLoad then Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', @@ -7205,7 +7203,7 @@ self:T() end function STAGELOAD:Executing( Mission, Client, Task ) -self:T() + self:F() -- If the Cargo is ready to be loaded, load it into the Client. @@ -7257,7 +7255,7 @@ self:T() end function STAGELOAD:Validate( Mission, Client, Task ) -self:T() + self:F() self:T( "Task.CurrentLandingZoneName = " .. Task.CurrentLandingZoneName ) @@ -7316,18 +7314,18 @@ STAGEDONE = { function STAGEDONE:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'AI' return self end function STAGEDONE:Execute( Mission, Client, Task ) -self:T() + self:F() end function STAGEDONE:Validate( Mission, Client, Task ) -self:T() + self:F() Task:Done() @@ -7342,20 +7340,20 @@ STAGEARRIVE = { function STAGEARRIVE:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGEARRIVE:Execute( Mission, Client, Task ) -self:T() + self:F() Client:Message( 'We have arrived at ' .. Task.CurrentLandingZoneName .. ".", self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Arrived" ) end function STAGEARRIVE:Validate( Mission, Client, Task ) -self:T() + self:F() Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.LandingZones ) if ( Task.CurrentLandingZoneID ) then @@ -7376,7 +7374,7 @@ STAGEGROUPSDESTROYED = { function STAGEGROUPSDESTROYED:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'AI' return self end @@ -7388,7 +7386,7 @@ end --end function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task ) -self:T() + self:F() if Task.MissionTask:IsGoalReached() then return 1 @@ -7398,7 +7396,7 @@ self:T() end function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task ) -self:T() + self:F() self:T( { Task.ClassName, Task.Destroyed } ) --env.info( 'Event Table Task = ' .. tostring(Task) ) @@ -7998,7 +7996,7 @@ DESTROYBASETASK = { -- @return DESTROYBASETASK function DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupPrefixes, DestroyPercentage ) local self = BASE:Inherit( self, TASK:New() ) - self:T() + self:F() self.Name = 'Destroy' self.Destroyed = 0 @@ -8020,7 +8018,7 @@ end --- Handle the S_EVENT_DEAD events to validate the destruction of units for the task monitoring. -- @param event Event structure of DCS world. function DESTROYBASETASK:EventDead( event ) - self:T( { 'EventDead', event } ) + self:F( { 'EventDead', event } ) if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then local DestroyUnit = event.initiator @@ -8051,7 +8049,7 @@ end -- @param DestroyGroup Group structure describing the group to be evaluated. -- @param DestroyUnit Unit structure describing the Unit to be evaluated. function DESTROYBASETASK:ReportGoalProgress( DestroyGroup, DestroyUnit ) -self:T() + self:F() return 0 end @@ -8235,7 +8233,7 @@ PICKUPTASK = { -- @param number OnBoardSide Reflects from which side the cargo Group will be on-boarded on the Carrier. function PICKUPTASK:New( CargoType, OnBoardSide ) local self = BASE:Inherit( self, TASK:New() ) - self:T() + self:F() -- self holds the inherited instance of the PICKUPTASK Class to the BASE class. @@ -8257,7 +8255,7 @@ function PICKUPTASK:New( CargoType, OnBoardSide ) end function PICKUPTASK:FromZone( LandingZone ) -self:T() + self:F() self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone @@ -8266,7 +8264,7 @@ self:T() end function PICKUPTASK:InitCargo( InitCargos ) -self:T( { InitCargos } ) + self:F( { InitCargos } ) if type( InitCargos ) == "table" then self.Cargos.InitCargos = InitCargos @@ -8278,7 +8276,7 @@ self:T( { InitCargos } ) end function PICKUPTASK:LoadCargo( LoadCargos ) -self:T( { LoadCargos } ) + self:F( { LoadCargos } ) if type( LoadCargos ) == "table" then self.Cargos.LoadCargos = LoadCargos @@ -8290,7 +8288,7 @@ self:T( { LoadCargos } ) end function PICKUPTASK:AddCargoMenus( Client, Cargos, TransportRadius ) -self:T() + self:F() for CargoID, Cargo in pairs( Cargos ) do @@ -8337,7 +8335,7 @@ self:T() end function PICKUPTASK:RemoveCargoMenus( Client ) -self:T() + self:F() for MenuID, MenuData in pairs( Client._Menus ) do for SubMenuID, SubMenuData in pairs( MenuData.PickupSubMenus ) do @@ -8364,7 +8362,7 @@ end function PICKUPTASK:HasFailed( ClientDead ) -self:T() + self:F() local TaskHasFailed = self.TaskFailed return TaskHasFailed @@ -8390,7 +8388,7 @@ DEPLOYTASK = { -- @return #DEPLOYTASK The created DeployTask function DEPLOYTASK:New( CargoType ) local self = BASE:Inherit( self, TASK:New() ) - self:T() + self:F() local Valid = true @@ -8407,7 +8405,7 @@ function DEPLOYTASK:New( CargoType ) end function DEPLOYTASK:ToZone( LandingZone ) -self:T() + self:F() self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone @@ -8417,7 +8415,7 @@ end function DEPLOYTASK:InitCargo( InitCargos ) -self:T( { InitCargos } ) + self:F( { InitCargos } ) if type( InitCargos ) == "table" then self.Cargos.InitCargos = InitCargos @@ -8430,7 +8428,7 @@ end function DEPLOYTASK:LoadCargo( LoadCargos ) -self:T( { LoadCargos } ) + self:F( { LoadCargos } ) if type( LoadCargos ) == "table" then self.Cargos.LoadCargos = LoadCargos @@ -8445,7 +8443,7 @@ end --- When the cargo is unloaded, it will move to the target zone name. -- @param string TargetZoneName Name of the Zone to where the Cargo should move after unloading. function DEPLOYTASK:SetCargoTargetZoneName( TargetZoneName ) -self:T() + self:F() local Valid = true @@ -8460,7 +8458,7 @@ self:T() end function DEPLOYTASK:AddCargoMenus( Client, Cargos, TransportRadius ) -self:T() + self:F() local ClientGroupID = Client:GetClientGroupID() @@ -8507,7 +8505,7 @@ self:T() end function DEPLOYTASK:RemoveCargoMenus( Client ) -self:T() + self:F() local ClientGroupID = Client:GetClientGroupID() trace.i( self.ClassName, ClientGroupID ) @@ -8635,7 +8633,7 @@ MISSION = { function MISSION:Meta() local self = BASE:Inherit( self, BASE:New() ) - self:T() + self:F() return self end @@ -8681,13 +8679,13 @@ end --- Returns if a Mission has completed. -- @return bool function MISSION:IsCompleted() - self:T() + self:F() return self.MissionStatus == "ACCOMPLISHED" end --- Set a Mission to completed. function MISSION:Completed() - self:T() + self:F() self.MissionStatus = "ACCOMPLISHED" self:StatusToClients() end @@ -8695,13 +8693,13 @@ end --- Returns if a Mission is ongoing. -- treturn bool function MISSION:IsOngoing() - self:T() + self:F() return self.MissionStatus == "ONGOING" end --- Set a Mission to ongoing. function MISSION:Ongoing() - self:T() + self:F() self.MissionStatus = "ONGOING" --self:StatusToClients() end @@ -8709,13 +8707,13 @@ end --- Returns if a Mission is pending. -- treturn bool function MISSION:IsPending() - self:T() + self:F() return self.MissionStatus == "PENDING" end --- Set a Mission to pending. function MISSION:Pending() - self:T() + self:F() self.MissionStatus = "PENDING" self:StatusToClients() end @@ -8723,20 +8721,20 @@ end --- Returns if a Mission has failed. -- treturn bool function MISSION:IsFailed() - self:T() + self:F() return self.MissionStatus == "FAILED" end --- Set a Mission to failed. function MISSION:Failed() - self:T() + self:F() self.MissionStatus = "FAILED" self:StatusToClients() end --- Send the status of the MISSION to all Clients. function MISSION:StatusToClients() - self:T() + self:F() if self.MissionReportFlash then for ClientID, Client in pairs( self._Clients ) do Client:Message( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. '! ( ' .. self.MissionPriority .. ' mission ) ', 10, self.Name .. '/Status', "Mission Command: Mission Status") @@ -8746,7 +8744,7 @@ end --- Handles the reporting. After certain time intervals, a MISSION report MESSAGE will be shown to All Players. function MISSION:ReportTrigger() - self:T() + self:F() if self.MissionReportShow == true then self.MissionReportShow = false @@ -8772,7 +8770,7 @@ end --- Report the status of all MISSIONs to all active Clients. function MISSION:ReportToAll() - self:T() + self:F() local AlivePlayers = '' for ClientID, Client in pairs( self._Clients ) do @@ -8834,7 +8832,7 @@ end -- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Transport Troops', 'Operational', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.', 'NATO' ) -- Mission:AddGoalFunction( DeployPatriotTroopsGoal ) function MISSION:AddGoalFunction( GoalFunction ) - self:T() + self:F() self.GoalFunction = GoalFunction end @@ -8842,7 +8840,7 @@ end -- @param CLIENT Client to show briefing to. -- @return CLIENT function MISSION:ShowBriefing( Client ) - self:T( { Client.ClientName } ) + self:F( { Client.ClientName } ) if not Client.ClientBriefingShown then Client.ClientBriefingShown = true @@ -8867,7 +8865,7 @@ end -- Mission:AddClient( CLIENT:New( 'US UH-1H*HOT-Deploy Troops 2', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) -- Mission:AddClient( CLIENT:New( 'US UH-1H*RAMP-Deploy Troops 4', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) function MISSION:AddClient( Client ) - self:T( { Client } ) + self:F( { Client } ) local Valid = true @@ -8886,7 +8884,7 @@ end -- -- Seach for Client "Bomber" within the Mission. -- local BomberClient = Mission:FindClient( "Bomber" ) function MISSION:FindClient( ClientName ) - self:T( { self._Clients[ClientName] } ) + self:F( { self._Clients[ClientName] } ) return self._Clients[ClientName] end @@ -8917,7 +8915,7 @@ end -- Mission:AddTask( DeployTask, 2 ) function MISSION:AddTask( Task, TaskNumber ) - self:T() + self:F() self._Tasks[TaskNumber] = Task self._Tasks[TaskNumber]:EnableEvents() @@ -8934,7 +8932,7 @@ function MISSION:AddTask( Task, TaskNumber ) -- Task2 = Mission:GetTask( 2 ) function MISSION:GetTask( TaskNumber ) - self:T() + self:F() local Valid = true @@ -8958,7 +8956,7 @@ end -- Tasks = Mission:GetTasks() -- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) function MISSION:GetTasks() - self:T() + self:F() return self._Tasks end @@ -9330,7 +9328,7 @@ CLEANUP = { -- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 ) -- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 ) function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { ZoneNames, TimeInterval } ) + self:F( { ZoneNames, TimeInterval } ) if type( ZoneNames ) == 'table' then self.ZoneNames = ZoneNames @@ -9359,7 +9357,7 @@ end --- Destroys a group from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName ) - self:T( { GroupObject, CleanUpGroupName } ) + self:F( { GroupObject, CleanUpGroupName } ) if GroupObject then -- and GroupObject:isExist() then --MESSAGE:New( "Destroy Group " .. CleanUpGroupName, CleanUpGroupName, 1, CleanUpGroupName ):ToAll() @@ -9371,7 +9369,7 @@ end --- Destroys a unit from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName ) - self:T( { CleanUpUnit, CleanUpUnitName } ) + self:F( { CleanUpUnit, CleanUpUnitName } ) if CleanUpUnit then --MESSAGE:New( "Destroy " .. CleanUpUnitName, CleanUpUnitName, 1, CleanUpUnitName ):ToAll() @@ -9398,7 +9396,7 @@ end --- Destroys a missile from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyMissile( MissileObject ) - self:T( { MissileObject } ) + self:F( { MissileObject } ) if MissileObject and MissileObject:isExist() then MissileObject:destroy() @@ -9409,7 +9407,7 @@ end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see CLEANUP function CLEANUP:_EventCrash( event ) - self:T( { event } ) + self:F( { event } ) --MESSAGE:New( "Crash ", "Crash", 10, "Crash" ):ToAll() -- self:T("before getGroup") @@ -9439,7 +9437,7 @@ end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see CLEANUP function CLEANUP:_EventShot( event ) - self:T( { event } ) + self:F( { event } ) local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired local _groupname = _grp:getName() -- return the name of the group @@ -9463,7 +9461,7 @@ end --- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit. function CLEANUP:_EventHitCleanUp( event ) - self:T( { event } ) + self:F( { event } ) local CleanUpUnit = event.initiator -- the Unit if CleanUpUnit and CleanUpUnit:isExist() and Object.getCategory(CleanUpUnit) == Object.Category.UNIT then @@ -9497,7 +9495,7 @@ function CLEANUP:_EventHitCleanUp( event ) end function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName ) - self:T( { CleanUpUnit, CleanUpUnitName } ) + self:F( { CleanUpUnit, CleanUpUnitName } ) self.CleanUpList[CleanUpUnitName] = {} self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit @@ -9546,7 +9544,7 @@ CleanUpSurfaceTypeText = { --- At the defined time interval, CleanUp the Groups within the CleanUpList. function CLEANUP:_Scheduler() - self:T( "CleanUp Scheduler" ) + self:F( "CleanUp Scheduler" ) for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do @@ -9710,7 +9708,7 @@ SPAWN = { -- @usage local Plane = SPAWN:New( "Plane" ) -- Creates a new local variable that can initiate new planes with the name "Plane#ddd" using the template "Plane" as defined within the ME. function SPAWN:New( SpawnTemplatePrefix ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { SpawnTemplatePrefix } ) + self:F( { SpawnTemplatePrefix } ) local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) if TemplateGroup then @@ -9752,7 +9750,7 @@ end -- @usage local PlaneWithAlias = SPAWN:NewWithAlias( "Plane", "Bomber" ) -- Creates a new local variable that can instantiate new planes with the name "Bomber#ddd" using the template "Plane" as defined within the ME. function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { SpawnTemplatePrefix, SpawnAliasPrefix } ) + self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } ) local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) if TemplateGroup then @@ -9801,7 +9799,7 @@ end -- -- There will be maximum 24 groups spawned during the whole mission lifetime. -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Limit( 2, 24 ) function SPAWN:Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) - self:T( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) + self:F( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) self.SpawnMaxUnitsAlive = SpawnMaxUnitsAlive -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. self.SpawnMaxGroups = SpawnMaxGroups -- The maximum amount of groups that can be spawned. @@ -9829,7 +9827,7 @@ end -- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):RandomizeRoute( 2, 2, 2000 ) function SPAWN:RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius ) - self:T( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius } ) + self:F( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius } ) self.SpawnRandomizeRoute = true self.SpawnRandomizeRouteStartPoint = SpawnStartPoint @@ -9864,7 +9862,7 @@ end -- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):Limit( 12, 150 ):Schedule( 200, 0.4 ):RandomizeTemplate( Spawn_US_Platoon ):RandomizeRoute( 3, 3, 2000 ) -- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):Limit( 12, 150 ):Schedule( 200, 0.4 ):RandomizeTemplate( Spawn_US_Platoon ):RandomizeRoute( 3, 3, 2000 ) function SPAWN:RandomizeTemplate( SpawnTemplatePrefixTable ) - self:T( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) + self:F( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) self.SpawnTemplatePrefixTable = SpawnTemplatePrefixTable self.SpawnRandomizeTemplate = true @@ -9892,7 +9890,7 @@ end -- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically. -- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():RandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown() function SPAWN:Repeat() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self.SpawnRepeat = true self.RepeatOnEngineShutDown = false @@ -9911,7 +9909,7 @@ end -- @see Repeat function SPAWN:RepeatOnLanding() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self:Repeat() self.RepeatOnEngineShutDown = false @@ -9923,7 +9921,7 @@ end --- Same as the @{#SPAWN.Repeat) method, but now the Group will respawn after its engines have shut down. -- @return SPAWN function SPAWN:RepeatOnEngineShutDown() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self:Repeat() self.RepeatOnEngineShutDown = true @@ -9940,7 +9938,7 @@ end -- @return #SPAWN self -- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive. function SPAWN:CleanUp( SpawnCleanUpInterval ) - self:T( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) + self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) self.SpawnCleanUpInterval = SpawnCleanUpInterval self.SpawnCleanUpTimeStamps = {} @@ -9963,7 +9961,7 @@ end -- -- Define an array of Groups. -- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):Limit( 2, 24 ):Visible( 90, "Diamond", 10, 100, 50 ) function SPAWN:Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) - self:T( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) + self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) self.SpawnVisible = true -- When the first Spawn executes, all the Groups need to be made visible before start. @@ -10011,7 +10009,7 @@ end -- @param self -- @return GROUP#GROUP The group that was spawned. You can use this group for further actions. function SPAWN:Spawn() - self:T( { self.SpawnTemplatePrefix, self.SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) return self:SpawnWithIndex( self.SpawnIndex + 1 ) end @@ -10022,7 +10020,7 @@ end -- @param #string SpawnIndex The index of the group to be spawned. -- @return GROUP#GROUP The group that was spawned. You can use this group for further actions. function SPAWN:ReSpawn( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) if not SpawnIndex then SpawnIndex = 1 @@ -10040,7 +10038,7 @@ end -- Uses @{DATABASE} global object defined in MOOSE. -- @return GROUP#GROUP The group that was spawned. You can use this group for further actions. function SPAWN:SpawnWithIndex( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups } ) if self:_GetSpawnIndex( SpawnIndex ) then @@ -10080,7 +10078,7 @@ end -- -- Between these two values, a random amount of seconds will be choosen for each new spawn of the helicopters. -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation ) - self:T( { SpawnTime, SpawnTimeVariation } ) + self:F( { SpawnTime, SpawnTimeVariation } ) self.SpawnCurrentTimer = 0 -- The internal timer counter to trigger a scheduled spawning of SpawnTemplatePrefix. self.SpawnSetTimer = 0 -- The internal timer value when a scheduled spawning of SpawnTemplatePrefix occurs. @@ -10104,7 +10102,7 @@ end --- Will start the spawning scheduler. -- Note: This function is called automatically when @{#SPAWN.Scheduled} is called. function SPAWN:SpawnScheduleStart() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) --local ClientUnit = #AlivePlayerUnits() @@ -10121,7 +10119,7 @@ end --- Will stop the scheduled spawning scheduler. function SPAWN:SpawnScheduleStop() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self.SpawnIsScheduled = false end @@ -10137,7 +10135,7 @@ end -- @return GROUP#GROUP that was spawned. -- @return #nil Nothing was spawned. function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, HostUnit, OuterRadius, InnerRadius, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, HostUnit, OuterRadius, InnerRadius, SpawnIndex } ) if HostUnit and HostUnit:IsAlive() then -- and HostUnit:getUnit(1):inAir() == false then @@ -10212,7 +10210,7 @@ end -- @return GROUP#GROUP that was spawned. -- @return #nil when nothing was spawned. function SPAWN:SpawnInZone( Zone, SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, Zone, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, Zone, SpawnIndex } ) if Zone then @@ -10266,7 +10264,7 @@ end -- This will be similar to the uncontrolled flag setting in the ME. -- @return #SPAWN self function SPAWN:UnControlled() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self.SpawnUnControlled = true @@ -10284,7 +10282,7 @@ end -- @param #number SpawnIndex Is the number of the Group that is to be spawned. -- @return string SpawnGroupName function SPAWN:SpawnGroupName( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) local SpawnPrefix = self.SpawnTemplatePrefix if self.SpawnAliasPrefix then @@ -10308,7 +10306,7 @@ end -- @return GROUP#GROUP, #number The group found, the new index where the group was found. -- @return #nil, #nil When no group is found, #nil is returned. function SPAWN:GetFirstAliveGroup( SpawnCursor ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) for SpawnIndex = 1, self.SpawnCount do local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) @@ -10328,7 +10326,7 @@ end -- @return GROUP#GROUP, #number The group found, the new index where the group was found. -- @return #nil, #nil When no group is found, #nil is returned. function SPAWN:GetNextAliveGroup( SpawnCursor ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) SpawnCursor = SpawnCursor + 1 for SpawnIndex = SpawnCursor, self.SpawnCount do @@ -10344,7 +10342,7 @@ end --- Find the last alive group during runtime. function SPAWN:GetLastAliveGroup() - self:T( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) + self:F( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) self.SpawnIndex = self:_GetLastIndex() for SpawnIndex = self.SpawnIndex, 1, -1 do @@ -10368,7 +10366,7 @@ end -- @param #number SpawnIndex The index of the group to return. -- @return GROUP#GROUP function SPAWN:GetGroupFromIndex( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) if SpawnIndex then local SpawnGroup = self.SpawnGroups[SpawnIndex].Group @@ -10387,7 +10385,7 @@ end -- @return #string The prefix -- @return #nil Nothing found function SPAWN:_GetGroupIndexFromDCSUnit( DCSUnit ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) if DCSUnit and DCSUnit:getName() then local IndexString = string.match( DCSUnit:getName(), "#.*-" ):sub( 2, -2 ) @@ -10411,7 +10409,7 @@ end -- @return #string The prefix -- @return #nil Nothing found function SPAWN:_GetPrefixFromDCSUnit( DCSUnit ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) if DCSUnit and DCSUnit:getName() then local SpawnPrefix = string.match( DCSUnit:getName(), ".*#" ) @@ -10427,7 +10425,7 @@ end --- Return the group within the SpawnGroups collection with input a DCSUnit. function SPAWN:_GetGroupFromDCSUnit( DCSUnit ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) if DCSUnit then local SpawnPrefix = self:_GetPrefixFromDCSUnit( DCSUnit ) @@ -10447,7 +10445,7 @@ end --- Get the index from a given group. -- The function will search the name of the group for a #, and will return the number behind the #-mark. function SPAWN:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) local IndexString = string.match( SpawnGroup:GetName(), "#.*$" ):sub( 2 ) local Index = tonumber( IndexString ) @@ -10459,14 +10457,14 @@ end --- Return the last maximum index that can be used. function SPAWN:_GetLastIndex() - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) return self.SpawnMaxGroups end --- Initalize the SpawnGroups collection. function SPAWN:_InitializeSpawnGroups( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) if not self.SpawnGroups[SpawnIndex] then self.SpawnGroups[SpawnIndex] = {} @@ -10513,7 +10511,7 @@ end --- Gets the CountryID of the Group with the given SpawnPrefix function SPAWN:_GetGroupCountryID( SpawnPrefix ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) local TemplateGroup = Group.getByName( SpawnPrefix ) @@ -10528,7 +10526,7 @@ end --- Gets the Group Template from the ME environment definition. -- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE. function SPAWN:_GetTemplate( SpawnTemplatePrefix ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) local SpawnTemplate = nil @@ -10548,7 +10546,7 @@ end --- Prepares the new Group Template. function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) @@ -10581,7 +10579,7 @@ end -- @param #number SpawnIndex The index of the group to be spawned. -- @return #SPAWN function SPAWN:_RandomizeRoute( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) if self.SpawnRandomizeRoute then local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate @@ -10602,7 +10600,7 @@ end function SPAWN:_RandomizeTemplate( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) if self.SpawnRandomizeTemplate then self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ] @@ -10621,7 +10619,7 @@ function SPAWN:_RandomizeTemplate( SpawnIndex ) end function SPAWN:_TranslateRotate( SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) -- Translate local TranslatedX = SpawnX @@ -10665,7 +10663,7 @@ end --- Get the next index of the groups to be spawned. This function is complicated, as it is used at several spaces. function SPAWN:_GetSpawnIndex( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then @@ -10784,7 +10782,7 @@ end --- This function is called automatically by the Spawning scheduler. -- It is the internal worker method SPAWNing new Groups on the defined time intervals. function SPAWN:_Scheduler() -self:T( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) + self:F( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) if self.SpawnInit or self.SpawnCurrentTimer == self.SpawnSetTimer then -- Validate if there are still groups left in the batch... @@ -10802,7 +10800,7 @@ self:T( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.Sp end function SPAWN:_SpawnCleanUpScheduler() - self:T( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) + self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) local SpawnCursor local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup( SpawnCursor ) @@ -10856,7 +10854,7 @@ MOVEMENT = { function MOVEMENT:New( MovePrefixes, MoveMaximum ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { MovePrefixes, MoveMaximum } ) + self:F( { MovePrefixes, MoveMaximum } ) if type( MovePrefixes ) == 'table' then self.MovePrefixes = MovePrefixes @@ -10881,21 +10879,21 @@ end --- Call this function to start the MOVEMENT scheduling. function MOVEMENT:ScheduleStart() -self:T() + self:F() self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 ) end --- Call this function to stop the MOVEMENT scheduling. -- @todo need to implement it ... Forgot. function MOVEMENT:ScheduleStop() -self:T() + self:F() end --- Captures the birth events when new Units were spawned. -- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. function MOVEMENT:OnBirth( event ) -self:T( { event } ) + self:F( { event } ) if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then @@ -10921,7 +10919,7 @@ end --- Captures the Dead or Crash events when Units crash or are destroyed. -- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. function MOVEMENT:OnDeadOrCrash( event ) -self:T( { event } ) + self:F( { event } ) if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then local MovementUnit = event.initiator @@ -10939,7 +10937,7 @@ end --- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true. function MOVEMENT:_Scheduler() -self:T( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) + self:F( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) if self.AliveUnits > 0 then local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits @@ -10999,7 +10997,7 @@ SEAD = { -- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) function SEAD:New( SEADGroupPrefixes ) local self = BASE:Inherit( self, BASE:New() ) - self:T( SEADGroupPrefixes ) + self:F( SEADGroupPrefixes ) if type( SEADGroupPrefixes ) == 'table' then for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix @@ -11016,7 +11014,7 @@ end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see SEAD function SEAD:EventShot( event ) -self:T( { event } ) + self:F( { event } ) local SEADUnit = event.initiator local SEADUnitName = SEADUnit:getName() @@ -11136,7 +11134,7 @@ ESCORT = { -- @return #ESCORT self function ESCORT:New( EscortClient, EscortGroup, EscortName ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { EscortClient, EscortGroup, EscortName } ) + self:F( { EscortClient, EscortGroup, EscortName } ) self.EscortClient = EscortClient self.EscortGroup = EscortGroup @@ -11177,8 +11175,8 @@ end function ESCORT._HoldPosition( MenuParam ) - MenuParam.ParamSelf.EscortGroup:HoldPosition( 300 ) - MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPosition" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MenuParam.ParamSelf.EscortGroup:TaskHoldPosition( 300 ) + MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/TaskHoldPosition" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._ReportNearbyTargets( MenuParam ) @@ -11244,7 +11242,7 @@ end function ESCORT:_ScanForTargets() - self:T() + self:F() self.Targets = {} diff --git a/Moose/Base.lua b/Moose/Base.lua index 76a4750a5..a01b9e2ee 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -4,8 +4,9 @@ Include.File( "Routines" ) -_TraceOn = true -_TraceClass = { +local _TraceOn = true +local _TraceLevel = 1 +local _TraceClass = { --DATABASE = true, --SEAD = true, --DESTROYBASETASK = true, @@ -51,7 +52,6 @@ FORMATION = { -- @return #BASE -- @usage -- function TASK:New() --- trace.f(self.ClassName) -- -- local self = BASE:Inherit( self, BASE:New() ) -- @@ -100,8 +100,31 @@ function BASE:Inherited( Child ) return Parent end +--- Get the ClassName + ClassID of the class instance. +-- The ClassName + ClassID is formatted as '%s#%09d'. +-- @param #BASE self +-- @return #string The ClassName + ClassID of the class instance. +function BASE:GetClassNameAndID() + return string.format( '%s#%09d', self:GetClassName(), self:GetClassID() ) +end + +--- Get the ClassName of the class instance. +-- @param #BASE self +-- @return #string The ClassName of the class instance. +function BASE:GetClassName() + return self.ClassName +end + +--- Get the ClassID of the class instance. +-- @param #BASE self +-- @return #string The ClassID of the class instance. +function BASE:GetClassID() + return self.ClassID +end + + function BASE:AddEvent( Event, EventFunction ) -trace.f( self.ClassName, Event ) + self:F( Event ) self.Events[#self.Events+1] = {} self.Events[#self.Events].Event = Event @@ -113,22 +136,20 @@ end function BASE:EnableEvents() -trace.f( self.ClassName ) + self:F( #self.Events ) - trace.i( self.ClassName, #self.Events ) for EventID, Event in pairs( self.Events ) do Event.Self = self Event.EventEnabled = true end - --env.info( 'EnableEvent Table Task = ' .. tostring(self) ) self.Events.Handler = world.addEventHandler( self ) return self end function BASE:DisableEvents() -trace.f( self.ClassName ) - + self:F() + world.removeEventHandler( self ) for EventID, Event in pairs( self.Events ) do Event.Self = nil @@ -139,7 +160,7 @@ trace.f( self.ClassName ) end -BaseEventCodes = { +local BaseEventCodes = { "S_EVENT_SHOT", "S_EVENT_HIT", "S_EVENT_TAKEOFF", @@ -179,7 +200,7 @@ BaseEventCodes = { function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace ) -trace.f( self.ClassName, { EventTime, Initiator, IniUnitName, place, subplace } ) + self:F( { EventTime, Initiator, IniUnitName, place, subplace } ) local Event = { id = world.event.S_EVENT_BIRTH, @@ -194,7 +215,7 @@ trace.f( self.ClassName, { EventTime, Initiator, IniUnitName, place, subplace } end function BASE:CreateEventCrash( EventTime, Initiator ) -trace.f( self.ClassName, { EventTime, Initiator } ) + self:F( { EventTime, Initiator } ) local Event = { id = world.event.S_EVENT_CRASH, @@ -206,7 +227,6 @@ trace.f( self.ClassName, { EventTime, Initiator } ) end function BASE:onEvent(event) ---trace.f(self.ClassName, event ) --env.info( 'onEvent Table self = ' .. tostring(self) ) if self then @@ -223,7 +243,7 @@ function BASE:onEvent(event) if event.target and event.target:isExist() then event.TgtUnitName = event.target:getName() end - trace.i( self.ClassName, { BaseEventCodes[event.id], event } ) + self:T( { BaseEventCodes[event.id], event } ) EventObject.EventFunction( self, event ) end end @@ -236,6 +256,44 @@ end -- Trace section -- Log a trace (only shown when trace is on) + +function BASE:F( Arguments ) + + if _TraceOn and _TraceClass[self.ClassName] then + + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + local Function = "function" + if DebugInfoCurrent.name then + Function = DebugInfoCurrent.name + end + + local LineCurrent = DebugInfoCurrent.currentline + local LineFrom = 0 + if DebugInfoFrom then + LineFrom = DebugInfoFrom.currentline + end + env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s\(%s\)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) + end +end + +function BASE:F2( Arguments ) + + if _TraceLevel >= 2 then + self:F( Arguments ) + end + +end + +function BASE:F3( Arguments ) + + if _TraceLevel >= 3 then + self:F( Arguments ) + end + +end + function BASE:T( Arguments ) if _TraceOn and _TraceClass[self.ClassName] then @@ -253,10 +311,28 @@ function BASE:T( Arguments ) if DebugInfoFrom then LineFrom = DebugInfoFrom.currentline end - env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s\(%s\)" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) + env.info( string.format( "%6d\(%6d\)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) end end +function BASE:T2( Arguments ) + + if _TraceLevel >= 2 then + self:T( Arguments ) + end + +end + +function BASE:T3( Arguments ) + + if _TraceLevel >= 3 then + self:T( Arguments ) + end + +end + + + -- Log an exception function BASE:E( Arguments ) diff --git a/Moose/Cargo.lua b/Moose/Cargo.lua index 812cacf7f..3d843e7a8 100644 --- a/Moose/Cargo.lua +++ b/Moose/Cargo.lua @@ -32,7 +32,7 @@ CARGO_ZONE = { } function CARGO_ZONE:New( CargoZoneName, CargoHostName ) local self = BASE:Inherit( self, BASE:New() ) -self:T( { CargoZoneName, CargoHostName } ) + self:F( { CargoZoneName, CargoHostName } ) self.CargoZoneName = CargoZoneName self.CargoZone = trigger.misc.getZone( CargoZoneName ) @@ -48,7 +48,7 @@ self:T( { CargoZoneName, CargoHostName } ) end function CARGO_ZONE:Spawn() - self:T( self.CargoHostName ) + self:F( self.CargoHostName ) if self.CargoHostSpawn then local CargoHostGroup = self.CargoHostSpawn:GetGroupFromIndex() @@ -66,7 +66,7 @@ function CARGO_ZONE:Spawn() end function CARGO_ZONE:GetHostUnit() - self:T( self ) + self:F( self ) if self.CargoHostName then @@ -86,7 +86,7 @@ function CARGO_ZONE:GetHostUnit() end function CARGO_ZONE:ReportCargosToClient( Client, CargoType ) -self:T() + self:F() local SignalUnit = self:GetHostUnit() @@ -115,7 +115,7 @@ self:T() end function CARGO_ZONE:Signal() -self:T() + self:F() local Signalled = false @@ -169,7 +169,7 @@ self:T() end function CARGO_ZONE:WhiteSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.WHITE @@ -178,7 +178,7 @@ self:T() end function CARGO_ZONE:BlueSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.BLUE @@ -187,7 +187,7 @@ self:T() end function CARGO_ZONE:RedSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.RED @@ -196,7 +196,7 @@ self:T() end function CARGO_ZONE:OrangeSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.ORANGE @@ -205,7 +205,7 @@ self:T() end function CARGO_ZONE:GreenSmoke() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.GREEN @@ -215,7 +215,7 @@ end function CARGO_ZONE:WhiteFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.WHITE @@ -224,7 +224,7 @@ self:T() end function CARGO_ZONE:RedFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.RED @@ -233,7 +233,7 @@ self:T() end function CARGO_ZONE:GreenFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.GREEN @@ -242,7 +242,7 @@ self:T() end function CARGO_ZONE:YellowFlare() -self:T() + self:F() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.YELLOW @@ -252,7 +252,7 @@ end function CARGO_ZONE:GetCargoHostUnit() - self:T( self ) + self:F( self ) if self.CargoHostSpawn then local CargoHostGroup = self.CargoHostSpawn:GetGroupFromIndex(1) @@ -268,7 +268,7 @@ function CARGO_ZONE:GetCargoHostUnit() end function CARGO_ZONE:GetCargoZoneName() -self:T() + self:F() return self.CargoZoneName end @@ -286,7 +286,7 @@ CARGO = { --- Add Cargo to the mission... Cargo functionality needs to be reworked a bit, so this is still under construction. I need to make a CARGO Class... function CARGO:New( CargoType, CargoName, CargoWeight ) local self = BASE:Inherit( self, BASE:New() ) -self:T( { CargoType, CargoName, CargoWeight } ) + self:F( { CargoType, CargoName, CargoWeight } ) self.CargoType = CargoType @@ -299,14 +299,14 @@ self:T( { CargoType, CargoName, CargoWeight } ) end function CARGO:Spawn( Client ) - self:T() + self:F() return self end function CARGO:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = true @@ -316,7 +316,7 @@ end function CARGO:IsLoadingToClient() -self:T() + self:F() if self:IsStatusLoading() then return self.CargoClient @@ -328,7 +328,7 @@ end function CARGO:IsLoadedInClient() -self:T() + self:F() if self:IsStatusLoaded() then return self.CargoClient @@ -340,7 +340,7 @@ end function CARGO:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:StatusUnLoaded() @@ -348,7 +348,7 @@ self:T() end function CARGO:OnBoard( Client, LandingZone ) -self:T() + self:F() local Valid = true @@ -359,7 +359,7 @@ self:T() end function CARGO:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = true @@ -367,7 +367,7 @@ self:T() end function CARGO:Load( Client ) -self:T() + self:F() self:StatusLoaded( Client ) @@ -375,18 +375,18 @@ self:T() end function CARGO:IsLandingRequired() -self:T() + self:F() return true end function CARGO:IsSlingLoad() -self:T() + self:F() return false end function CARGO:StatusNone() -self:T() + self:F() self.CargoClient = nil self.CargoStatus = CARGO.STATUS.NONE @@ -395,7 +395,7 @@ self:T() end function CARGO:StatusLoading( Client ) -self:T() + self:F() self.CargoClient = Client self.CargoStatus = CARGO.STATUS.LOADING @@ -405,7 +405,7 @@ self:T() end function CARGO:StatusLoaded( Client ) -self:T() + self:F() self.CargoClient = Client self.CargoStatus = CARGO.STATUS.LOADED @@ -415,7 +415,7 @@ self:T() end function CARGO:StatusUnLoaded() -self:T() + self:F() self.CargoClient = nil self.CargoStatus = CARGO.STATUS.UNLOADED @@ -425,25 +425,25 @@ end function CARGO:IsStatusNone() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.NONE end function CARGO:IsStatusLoading() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.LOADING end function CARGO:IsStatusLoaded() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.LOADED end function CARGO:IsStatusUnLoaded() -self:T() + self:F() return self.CargoStatus == CARGO.STATUS.UNLOADED end @@ -455,7 +455,7 @@ CARGO_GROUP = { function CARGO_GROUP:New( CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - self:T( { CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone } ) + self:F( { CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone } ) self.CargoSpawn = SPAWN:NewWithAlias( CargoGroupTemplate, CargoName ) self.CargoZone = CargoZone @@ -467,7 +467,7 @@ function CARGO_GROUP:New( CargoType, CargoName, CargoWeight, CargoGroupTemplate, end function CARGO_GROUP:Spawn( Client ) - self:T( { Client } ) + self:F( { Client } ) local SpawnCargo = true @@ -528,7 +528,7 @@ function CARGO_GROUP:Spawn( Client ) end function CARGO_GROUP:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -545,7 +545,7 @@ end function CARGO_GROUP:OnBoard( Client, LandingZone, OnBoardSide ) -self:T() + self:F() local Valid = true @@ -624,7 +624,7 @@ end function CARGO_GROUP:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = false @@ -640,7 +640,7 @@ end function CARGO_GROUP:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:T( 'self.CargoName = ' .. self.CargoName ) @@ -663,8 +663,7 @@ CARGO_PACKAGE = { function CARGO_PACKAGE:New( CargoType, CargoName, CargoWeight, CargoClient ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - - self:T( { CargoType, CargoName, CargoWeight, CargoClient } ) + self:F( { CargoType, CargoName, CargoWeight, CargoClient } ) self.CargoClient = CargoClient @@ -676,7 +675,7 @@ end function CARGO_PACKAGE:Spawn( Client ) - self:T( { self, Client } ) + self:F( { self, Client } ) -- this needs to be checked thoroughly @@ -716,7 +715,7 @@ end function CARGO_PACKAGE:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -735,7 +734,7 @@ end function CARGO_PACKAGE:OnBoard( Client, LandingZone, OnBoardSide ) -self:T() + self:F() local Valid = true @@ -826,7 +825,7 @@ end function CARGO_PACKAGE:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = false @@ -846,7 +845,7 @@ end function CARGO_PACKAGE:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:T( 'self.CargoName = ' .. self.CargoName ) --self:T( 'self.CargoHostName = ' .. self.CargoHostName ) @@ -865,8 +864,7 @@ CARGO_SLINGLOAD = { function CARGO_SLINGLOAD:New( CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - - self:T( { CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID } ) + self:F( { CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID } ) self.CargoHostName = CargoHostName @@ -887,19 +885,19 @@ end function CARGO_SLINGLOAD:IsLandingRequired() -self:T() + self:F() return false end function CARGO_SLINGLOAD:IsSlingLoad() -self:T() + self:F() return true end function CARGO_SLINGLOAD:Spawn( Client ) - self:T( { self, Client } ) + self:F( { self, Client } ) local Zone = trigger.misc.getZone( self.CargoZone ) @@ -949,7 +947,7 @@ end function CARGO_SLINGLOAD:IsNear( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -958,7 +956,7 @@ end function CARGO_SLINGLOAD:IsInLandingZone( Client, LandingZone ) -self:T() + self:F() local Near = false @@ -974,7 +972,7 @@ end function CARGO_SLINGLOAD:OnBoard( Client, LandingZone, OnBoardSide ) -self:T() + self:F() local Valid = true @@ -984,7 +982,7 @@ end function CARGO_SLINGLOAD:OnBoarded( Client, LandingZone ) -self:T() + self:F() local OnBoarded = false @@ -1000,7 +998,7 @@ end function CARGO_SLINGLOAD:UnLoad( Client, TargetZoneName ) -self:T() + self:F() self:T( 'self.CargoName = ' .. self.CargoName ) self:T( 'self.CargoGroupName = ' .. self.CargoGroupName ) diff --git a/Moose/CleanUp.lua b/Moose/CleanUp.lua index 41d8e1485..a08858e60 100644 --- a/Moose/CleanUp.lua +++ b/Moose/CleanUp.lua @@ -28,7 +28,7 @@ CLEANUP = { -- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 ) -- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 ) function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { ZoneNames, TimeInterval } ) + self:F( { ZoneNames, TimeInterval } ) if type( ZoneNames ) == 'table' then self.ZoneNames = ZoneNames @@ -57,7 +57,7 @@ end --- Destroys a group from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName ) - self:T( { GroupObject, CleanUpGroupName } ) + self:F( { GroupObject, CleanUpGroupName } ) if GroupObject then -- and GroupObject:isExist() then --MESSAGE:New( "Destroy Group " .. CleanUpGroupName, CleanUpGroupName, 1, CleanUpGroupName ):ToAll() @@ -69,7 +69,7 @@ end --- Destroys a unit from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName ) - self:T( { CleanUpUnit, CleanUpUnitName } ) + self:F( { CleanUpUnit, CleanUpUnitName } ) if CleanUpUnit then --MESSAGE:New( "Destroy " .. CleanUpUnitName, CleanUpUnitName, 1, CleanUpUnitName ):ToAll() @@ -96,7 +96,7 @@ end --- Destroys a missile from the simulator, but checks first if it is still existing! -- @see CLEANUP function CLEANUP:_DestroyMissile( MissileObject ) - self:T( { MissileObject } ) + self:F( { MissileObject } ) if MissileObject and MissileObject:isExist() then MissileObject:destroy() @@ -107,7 +107,7 @@ end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see CLEANUP function CLEANUP:_EventCrash( event ) - self:T( { event } ) + self:F( { event } ) --MESSAGE:New( "Crash ", "Crash", 10, "Crash" ):ToAll() -- self:T("before getGroup") @@ -137,7 +137,7 @@ end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see CLEANUP function CLEANUP:_EventShot( event ) - self:T( { event } ) + self:F( { event } ) local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired local _groupname = _grp:getName() -- return the name of the group @@ -161,7 +161,7 @@ end --- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit. function CLEANUP:_EventHitCleanUp( event ) - self:T( { event } ) + self:F( { event } ) local CleanUpUnit = event.initiator -- the Unit if CleanUpUnit and CleanUpUnit:isExist() and Object.getCategory(CleanUpUnit) == Object.Category.UNIT then @@ -195,7 +195,7 @@ function CLEANUP:_EventHitCleanUp( event ) end function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName ) - self:T( { CleanUpUnit, CleanUpUnitName } ) + self:F( { CleanUpUnit, CleanUpUnitName } ) self.CleanUpList[CleanUpUnitName] = {} self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit @@ -244,7 +244,7 @@ CleanUpSurfaceTypeText = { --- At the defined time interval, CleanUp the Groups within the CleanUpList. function CLEANUP:_Scheduler() - self:T( "CleanUp Scheduler" ) + self:F( "CleanUp Scheduler" ) for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do diff --git a/Moose/Client.lua b/Moose/Client.lua index 81460fbcc..1f671531a 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -48,7 +48,7 @@ CLIENT = { -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) function CLIENT:New( ClientName, ClientBriefing ) local self = BASE:Inherit( self, BASE:New() ) - self:T( ClientName, ClientBriefing ) + self:F( ClientName, ClientBriefing ) self.ClientName = ClientName self:AddBriefing( ClientBriefing ) @@ -60,7 +60,7 @@ end --- Resets a CLIENT. -- @param string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. function CLIENT:Reset( ClientName ) -self:T() + self:F() self._Menus = {} end @@ -68,7 +68,7 @@ end -- This function is modified to deal with a couple of bugs in DCS 1.5.3 -- @return Group#Group function CLIENT:GetDCSGroup() ---self:T() + self:F3() -- local ClientData = Group.getByName( self.ClientName ) -- if ClientData and ClientData:isExist() then @@ -80,33 +80,33 @@ function CLIENT:GetDCSGroup() local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - --self:T( { "CoalitionData:", CoalitionData } ) + self:T3( { "CoalitionData:", CoalitionData } ) for UnitId, UnitData in pairs( CoalitionData ) do - --self:T( { "UnitData:", UnitData } ) + self:T3( { "UnitData:", UnitData } ) if UnitData and UnitData:isExist() then local ClientGroup = Group.getByName( self.ClientName ) if ClientGroup then - self:T( "ClientGroup = " .. self.ClientName ) + self:T3( "ClientGroup = " .. self.ClientName ) if ClientGroup:isExist() then if ClientGroup:getID() == UnitData:getGroup():getID() then - self:T( "Normal logic" ) - self:T( self.ClientName .. " : group found!" ) + self:T3( "Normal logic" ) + self:T3( self.ClientName .. " : group found!" ) return ClientGroup end else -- Now we need to resolve the bugs in DCS 1.5 ... -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) - self:T( "Bug 1.5 logic" ) + self:T3( "Bug 1.5 logic" ) local ClientUnits = _Database.Groups[self.ClientName].Units - self:T( { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } ) + self:T3( { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } ) for ClientUnitID, ClientUnitData in pairs( ClientUnits ) do - self:T( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) + self:T3( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) if tonumber(UnitData:getID()) == ClientUnitData.unitId then local ClientGroupTemplate = _Database.Groups[self.ClientName].Template self.ClientID = ClientGroupTemplate.groupId self.ClientGroupUnit = UnitData - self:T( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) + self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) return ClientGroup end end @@ -121,10 +121,10 @@ function CLIENT:GetDCSGroup() -- For non player clients local ClientGroup = Group.getByName( self.ClientName ) if ClientGroup then - self:T( "ClientGroup = " .. self.ClientName ) + self:T3( "ClientGroup = " .. self.ClientName ) if ClientGroup:isExist() then - self:T( "Normal logic" ) - self:T( self.ClientName .. " : group found!" ) + self:T3( "Normal logic" ) + self:T3( self.ClientName .. " : group found!" ) return ClientGroup end end @@ -171,7 +171,7 @@ end --- Returns the Unit of the @{CLIENT}. -- @return Unit function CLIENT:GetClientGroupUnit() - self:T() + self:F() local ClientGroup = self:GetDCSGroup() @@ -185,7 +185,7 @@ end --- Returns the DCSUnit of the @{CLIENT}. -- @return DCSUnit function CLIENT:GetClientGroupDCSUnit() - self:T() + self:F2() local ClientGroup = self:GetDCSGroup() @@ -197,7 +197,7 @@ function CLIENT:GetClientGroupDCSUnit() end function CLIENT:GetUnit() - self:T() + self:F() return UNIT:New( self:GetClientGroupDCSUnit() ) end @@ -205,7 +205,7 @@ end --- Returns the Point of the @{CLIENT}. -- @return DCSTypes#Vec2 function CLIENT:GetPointVec2() - self:T() + self:F() ClientGroupUnit = self:GetClientGroupDCSUnit() @@ -227,7 +227,7 @@ end --- Returns the Position of the @{CLIENT}. -- @return DCSTypes#Position function CLIENT:ClientPosition() - self:T() + self:F() ClientGroupUnit = self:GetClientGroupDCSUnit() @@ -243,7 +243,7 @@ end --- Returns the altitude of the @{CLIENT}. -- @return DCSTypes#Distance function CLIENT:GetAltitude() - self:T() + self:F() ClientGroupUnit = self:GetClientGroupDCSUnit() @@ -261,7 +261,7 @@ end --- Transport defines that the Client is a Transport. -- @return CLIENT function CLIENT:Transport() -self:T() + self:F() self.ClientTransport = true return self @@ -271,7 +271,7 @@ end -- @param string ClientBriefing is the text defining the Mission briefing. -- @return CLIENT function CLIENT:AddBriefing( ClientBriefing ) -self:T() + self:F() self.ClientBriefing = ClientBriefing return self end @@ -279,14 +279,14 @@ end --- IsTransport returns if a Client is a transport. -- @return bool function CLIENT:IsTransport() -self:T() + self:F() return self.ClientTransport end --- ShowCargo shows the @{CARGO} within the CLIENT to the Player. -- The @{CARGO} is shown throught the MESSAGE system of DCS World. function CLIENT:ShowCargo() -self:T() + self:F() local CargoMsg = "" @@ -317,7 +317,7 @@ end -- @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 when the CLIENT is in the air. function CLIENT:Message( Message, MessageDuration, MessageId, MessageCategory, MessageInterval ) -self:T() + self:F() if not self.MenuMessages then if self:GetClientGroupID() then diff --git a/Moose/Database.lua b/Moose/Database.lua index d6332868c..46923d2ba 100644 --- a/Moose/Database.lua +++ b/Moose/Database.lua @@ -159,7 +159,7 @@ end --- Set a status to a Group within the Database, this to check crossing events for example. function DATABASE:SetStatusGroup( GroupName, Status ) - self:T( Status ) + self:F( Status ) self.Groups[GroupName].Status = Status end @@ -167,7 +167,7 @@ end --- Get a status to a Group within the Database, this to check crossing events for example. function DATABASE:GetStatusGroup( GroupName ) - self:T( Status ) + self:F( Status ) if self.Groups[GroupName] then return self.Groups[GroupName].Status @@ -320,7 +320,7 @@ end --- Follows new players entering Clients within the DCSRTE. function DATABASE:_FollowPlayers() - self:T( "_FollowPlayers" ) + self:F( "_FollowPlayers" ) local ClientUnit = 0 local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) } @@ -343,7 +343,7 @@ end --- Add a new player entering a Unit. function DATABASE:_AddPlayerFromUnit( UnitData ) - self:T( UnitData ) + self:F( UnitData ) if UnitData:isExist() then local UnitName = UnitData:getName() @@ -421,7 +421,7 @@ end --- Registers Scores the players completing a Mission Task. function DATABASE:_AddMissionTaskScore( PlayerUnit, MissionName, Score ) - self:T( { PlayerUnit, MissionName, Score } ) + self:F( { PlayerUnit, MissionName, Score } ) local PlayerName = PlayerUnit:getPlayerName() @@ -447,7 +447,7 @@ end --- Registers Mission Scores for possible multiple players that contributed in the Mission. function DATABASE:_AddMissionScore( MissionName, Score ) - self:T( { PlayerUnit, MissionName, Score } ) + self:F( { PlayerUnit, MissionName, Score } ) for PlayerName, PlayerData in pairs( self.Players ) do @@ -468,7 +468,7 @@ end function DATABASE:OnHit( event ) - self:T( { event } ) + self:F( { event } ) local InitUnit = nil local InitUnitName = "" diff --git a/Moose/DeployTask.lua b/Moose/DeployTask.lua index 39c148a01..4bd0cf65c 100644 --- a/Moose/DeployTask.lua +++ b/Moose/DeployTask.lua @@ -18,7 +18,7 @@ DEPLOYTASK = { -- @return #DEPLOYTASK The created DeployTask function DEPLOYTASK:New( CargoType ) local self = BASE:Inherit( self, TASK:New() ) - self:T() + self:F() local Valid = true @@ -35,7 +35,7 @@ function DEPLOYTASK:New( CargoType ) end function DEPLOYTASK:ToZone( LandingZone ) -self:T() + self:F() self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone @@ -45,7 +45,7 @@ end function DEPLOYTASK:InitCargo( InitCargos ) -self:T( { InitCargos } ) + self:F( { InitCargos } ) if type( InitCargos ) == "table" then self.Cargos.InitCargos = InitCargos @@ -58,7 +58,7 @@ end function DEPLOYTASK:LoadCargo( LoadCargos ) -self:T( { LoadCargos } ) + self:F( { LoadCargos } ) if type( LoadCargos ) == "table" then self.Cargos.LoadCargos = LoadCargos @@ -73,7 +73,7 @@ end --- When the cargo is unloaded, it will move to the target zone name. -- @param string TargetZoneName Name of the Zone to where the Cargo should move after unloading. function DEPLOYTASK:SetCargoTargetZoneName( TargetZoneName ) -self:T() + self:F() local Valid = true @@ -88,15 +88,15 @@ self:T() end function DEPLOYTASK:AddCargoMenus( Client, Cargos, TransportRadius ) -self:T() + self:F() local ClientGroupID = Client:GetClientGroupID() - trace.i( self.ClassName, ClientGroupID ) + self:T( ClientGroupID ) for CargoID, Cargo in pairs( Cargos ) do - trace.i( self.ClassName, { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo.CargoWeight } ) + self:T( { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo.CargoWeight } ) if Cargo:IsStatusLoaded() and Client == Cargo:IsLoadedInClient() then @@ -110,7 +110,7 @@ self:T() self.TEXT[1] .. " " .. Cargo.CargoType, nil ) - trace.i( self.ClassName, 'Added DeployMenu ' .. self.TEXT[1] ) + self:T( 'Added DeployMenu ' .. self.TEXT[1] ) end if Client._Menus[Cargo.CargoType].DeploySubMenus == nil then @@ -118,7 +118,7 @@ self:T() end if Client._Menus[Cargo.CargoType].DeployMenu == nil then - trace.i( self.ClassName, 'deploymenu is nil' ) + self:T( 'deploymenu is nil' ) end Client._Menus[Cargo.CargoType].DeploySubMenus[ #Client._Menus[Cargo.CargoType].DeploySubMenus + 1 ] = missionCommands.addCommandForGroup( @@ -128,29 +128,29 @@ self:T() self.MenuAction, { ReferenceTask = self, CargoTask = Cargo } ) - trace.i( self.ClassName, 'Added DeploySubMenu ' .. Cargo.CargoType .. ":" .. Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )" ) + self:T( 'Added DeploySubMenu ' .. Cargo.CargoType .. ":" .. Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )" ) end end end function DEPLOYTASK:RemoveCargoMenus( Client ) -self:T() + self:F() local ClientGroupID = Client:GetClientGroupID() - trace.i( self.ClassName, ClientGroupID ) + self:T( ClientGroupID ) for MenuID, MenuData in pairs( Client._Menus ) do if MenuData.DeploySubMenus ~= nil then for SubMenuID, SubMenuData in pairs( MenuData.DeploySubMenus ) do missionCommands.removeItemForGroup( ClientGroupID, SubMenuData ) - trace.i( self.ClassName, "Removed DeploySubMenu " ) + self:T( "Removed DeploySubMenu " ) SubMenuData = nil end end if MenuData.DeployMenu then missionCommands.removeItemForGroup( ClientGroupID, MenuData.DeployMenu ) - trace.i( self.ClassName, "Removed DeployMenu " ) + self:T( "Removed DeployMenu " ) MenuData.DeployMenu = nil end end diff --git a/Moose/DestroyBaseTask.lua b/Moose/DestroyBaseTask.lua index adcb14603..6d73b0036 100644 --- a/Moose/DestroyBaseTask.lua +++ b/Moose/DestroyBaseTask.lua @@ -23,7 +23,7 @@ DESTROYBASETASK = { -- @return DESTROYBASETASK function DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupPrefixes, DestroyPercentage ) local self = BASE:Inherit( self, TASK:New() ) - self:T() + self:F() self.Name = 'Destroy' self.Destroyed = 0 @@ -45,7 +45,7 @@ end --- Handle the S_EVENT_DEAD events to validate the destruction of units for the task monitoring. -- @param event Event structure of DCS world. function DESTROYBASETASK:EventDead( event ) - self:T( { 'EventDead', event } ) + self:F( { 'EventDead', event } ) if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then local DestroyUnit = event.initiator @@ -76,7 +76,7 @@ end -- @param DestroyGroup Group structure describing the group to be evaluated. -- @param DestroyUnit Unit structure describing the Unit to be evaluated. function DESTROYBASETASK:ReportGoalProgress( DestroyGroup, DestroyUnit ) -self:T() + self:F() return 0 end diff --git a/Moose/DestroyGroupsTask.lua b/Moose/DestroyGroupsTask.lua index 61541d71b..44ab501ff 100644 --- a/Moose/DestroyGroupsTask.lua +++ b/Moose/DestroyGroupsTask.lua @@ -17,27 +17,25 @@ DESTROYGROUPSTASK = { -- @param ?number DestroyPercentage defines the %-tage that needs to be destroyed to achieve mission success. eg. If in the Group there are 10 units, then a value of 75 would require 8 units to be destroyed from the Group to complete the @{TASK}. ---@return DESTROYGROUPSTASK function DESTROYGROUPSTASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupNames, DestroyPercentage ) -trace.f(self.ClassName) - - -- Inheritance - local Child = BASE:Inherit( self, DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupNames, DestroyPercentage ) ) - - Child.Name = 'Destroy Groups' - Child.GoalVerb = "Destroy " .. DestroyGroupType + local self = BASE:Inherit( self, DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupNames, DestroyPercentage ) ) + self:F() + + self.Name = 'Destroy Groups' + self.GoalVerb = "Destroy " .. DestroyGroupType - Child.AddEvent( Child, world.event.S_EVENT_DEAD, Child.EventDead ) - Child.AddEvent( Child, world.event.S_EVENT_CRASH, Child.EventDead ) + self:AddEvent( world.event.S_EVENT_DEAD, self.EventDead ) + self:AddEvent( world.event.S_EVENT_CRASH, self.EventDead ) --Child.AddEvent( Child, world.event.S_EVENT_PILOT_DEAD, Child.EventDead ) - return Child + return self end --- Report Goal Progress. -- @param Group DestroyGroup Group structure describing the group to be evaluated. -- @param Unit DestroyUnit Unit structure describing the Unit to be evaluated. function DESTROYGROUPSTASK:ReportGoalProgress( DestroyGroup, DestroyUnit ) -trace.f(self.ClassName) - trace.i( self.ClassName, DestroyGroup:getSize() ) + self:F( { DestroyGroup, DestroyUnit } ) + self:T( DestroyGroup:getSize() ) local DestroyCount = 0 if DestroyGroup then diff --git a/Moose/DestroyRadarsTask.lua b/Moose/DestroyRadarsTask.lua index 113230531..be28006d8 100644 --- a/Moose/DestroyRadarsTask.lua +++ b/Moose/DestroyRadarsTask.lua @@ -14,29 +14,26 @@ DESTROYRADARSTASK = { -- @param table{string,...} DestroyGroupNames Table of string containing the group names of which the radars are be destroyed. -- @return DESTROYRADARSTASK function DESTROYRADARSTASK:New( DestroyGroupNames ) -trace.f(self.ClassName) - - -- Inheritance - local Child = BASE:Inherit( self, DESTROYGROUPSTASK:New( 'radar installations', 'radars', DestroyGroupNames ) ) - - Child.Name = 'Destroy Radars' + local self = BASE:Inherit( self, DESTROYGROUPSTASK:New( 'radar installations', 'radars', DestroyGroupNames ) ) + self:F() + self.Name = 'Destroy Radars' - Child.AddEvent( Child, world.event.S_EVENT_DEAD, Child.EventDead ) + self:AddEvent( world.event.S_EVENT_DEAD, self.EventDead ) - return Child + return self end --- Report Goal Progress. -- @param Group DestroyGroup Group structure describing the group to be evaluated. -- @param Unit DestroyUnit Unit structure describing the Unit to be evaluated. function DESTROYRADARSTASK:ReportGoalProgress( DestroyGroup, DestroyUnit ) -trace.f(self.ClassName) + self:F( { DestroyGroup, DestroyUnit } ) local DestroyCount = 0 if DestroyUnit and DestroyUnit:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) then if DestroyUnit and DestroyUnit:getLife() <= 1.0 then - trace.i( self.ClassName, 'Destroyed a radar' ) + self:T( 'Destroyed a radar' ) DestroyCount = 1 end end diff --git a/Moose/DestroyUnitTypesTask.lua b/Moose/DestroyUnitTypesTask.lua index 3dee60e2b..17e5af1bf 100644 --- a/Moose/DestroyUnitTypesTask.lua +++ b/Moose/DestroyUnitTypesTask.lua @@ -17,33 +17,28 @@ DESTROYUNITTYPESTASK = { -- @param string DestroyUnitTypes Table of string containing the type names of the units to achieve mission success. -- @return DESTROYUNITTYPESTASK function DESTROYUNITTYPESTASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupNames, DestroyUnitTypes ) -trace.f(self.ClassName) - - -- Inheritance - local Child = BASE:Inherit( self, DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupNames ) ) - + local self = BASE:Inherit( self, DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupNames ) ) + self:F( { DestroyGroupType, DestroyUnitType, DestroyGroupNames, DestroyUnitTypes } ) + if type(DestroyUnitTypes) == 'table' then - Child.DestroyUnitTypes = DestroyUnitTypes + self.DestroyUnitTypes = DestroyUnitTypes else - Child.DestroyUnitTypes = { DestroyUnitTypes } + self.DestroyUnitTypes = { DestroyUnitTypes } end - Child.Name = 'Destroy Unit Types' - Child.GoalVerb = "Destroy " .. DestroyGroupType + self.Name = 'Destroy Unit Types' + self.GoalVerb = "Destroy " .. DestroyGroupType - --env.info( 'New Types Child = ' .. tostring(Child) ) - --env.info( 'New Types self = ' .. tostring(self) ) + self:AddEvent( world.event.S_EVENT_DEAD, self.EventDead ) - Child.AddEvent( Child, world.event.S_EVENT_DEAD, Child.EventDead ) - - return Child + return self end --- Report Goal Progress. -- @param Group DestroyGroup Group structure describing the group to be evaluated. -- @param Unit DestroyUnit Unit structure describing the Unit to be evaluated. function DESTROYUNITTYPESTASK:ReportGoalProgress( DestroyGroup, DestroyUnit ) -trace.f(self.ClassName) + self:F( { DestroyGroup, DestroyUnit } ) local DestroyCount = 0 for UnitTypeID, UnitType in pairs( self.DestroyUnitTypes ) do diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 0a8a57f6d..5f4c77ccc 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -43,7 +43,7 @@ ESCORT = { -- @return #ESCORT self function ESCORT:New( EscortClient, EscortGroup, EscortName ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { EscortClient, EscortGroup, EscortName } ) + self:F( { EscortClient, EscortGroup, EscortName } ) self.EscortClient = EscortClient self.EscortGroup = EscortGroup @@ -99,8 +99,8 @@ function ESCORT._HoldPosition( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - EscortGroup:PushTask( EscortGroup:HoldPosition( 300 ) ) - MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPosition" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:PushTask( EscortGroup:TaskHoldPosition( 300 ) ) + MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/TaskHoldPosition" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -109,7 +109,7 @@ function ESCORT._HoldPositionNearBy( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - --MenuParam.ParamSelf.EscortGroup:OrbitCircleAtVec2( MenuParam.ParamSelf.EscortClient:GetPointVec2(), 300, 30, 0 ) + --MenuParam.ParamSelf.EscortGroup:TaskOrbitCircleAtVec2( MenuParam.ParamSelf.EscortClient:GetPointVec2(), 300, 30, 0 ) local PointFrom = {} local GroupPoint = EscortGroup:GetPointVec2() @@ -129,13 +129,13 @@ function ESCORT._HoldPositionNearBy( MenuParam ) PointTo.type = AI.Task.WaypointType.TURNING_POINT PointTo.alt = EscortClient:GetAltitude() PointTo.alt_type = AI.Task.AltitudeType.BARO - PointTo.task = EscortGroup:OrbitCircleAtVec2( EscortClient:GetPointVec2(), 300, 30, 0 ) + PointTo.task = EscortGroup:TaskOrbitCircleAtVec2( EscortClient:GetPointVec2(), 300, 30, 0 ) local Points = { PointFrom, PointTo } EscortGroup:PushTask( EscortGroup:TaskMission( Points ) ) - MESSAGE:New( "Rejoining to your location. Please hold at your location.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPositionNearBy" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Rejoining to your location. Please hold at your location.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPositionNearBy" ):ToClient( EscortClient ) end function ESCORT._ReportNearbyTargets( MenuParam ) @@ -152,8 +152,13 @@ function ESCORT._ScanTargets30Seconds( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - EscortGroup:PushTask( EscortGroup:OrbitCircle( 30, 200, 20 ) ) - MESSAGE:New( "Scanning targets for 30 seconds.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ScanTargets30Seconds" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:PushTask( + EscortGroup:TaskControlled( + EscortGroup:TaskOrbitCircle( 200, 20 ), + EscortGroup:TaskCondition( nil, nil, nil, nil, 30, nil ) + ) + ) + MESSAGE:New( "Scanning targets for 30 seconds.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ScanTargets30Seconds" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -163,8 +168,13 @@ function ESCORT._ScanTargets60Seconds( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - EscortGroup:PushTask( EscortGroup:OrbitCircle( 60, 200, 20 ) ) - MESSAGE:New( "Scanning targets for 60 seconds.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ScanTargets60Seconds" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:PushTask( + EscortGroup:TaskControlled( + EscortGroup:TaskOrbitCircle( 200, 20 ), + EscortGroup:TaskCondition( nil, nil, nil, nil, 60, nil ) + ) + ) + MESSAGE:New( "Scanning targets for 60 seconds.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ScanTargets60Seconds" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -172,9 +182,12 @@ function ESCORT._AttackTarget( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - - MenuParam.ParamSelf.EscortGroup:AttackUnit( MenuParam.ParamUnit ) - MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackTarget" ):ToClient( MenuParam.ParamSelf.EscortClient ) + local AttackUnit = MenuParam.ParamUnit + + EscortGroup:OpenFire() + EscortGroup:EvasionVertical() + EscortGroup:PushTask( EscortGroup:TaskAttackUnit( AttackUnit ) ) + MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackTarget" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -183,8 +196,8 @@ function ESCORT._ROEHoldFire( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:HoldFire() - MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEHoldFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:HoldFire() + MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEHoldFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -193,8 +206,8 @@ function ESCORT._ROEReturnFire( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:ReturnFire() - MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEReturnFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:ReturnFire() + MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEReturnFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -203,8 +216,8 @@ function ESCORT._ROEOpenFire( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:OpenFire() - MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEOpenFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:OpenFire() + MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEOpenFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -213,8 +226,8 @@ function ESCORT._ROEWeaponFree( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:WeaponFree() - MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEWeaponFree" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:WeaponFree() + MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEWeaponFree" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -223,8 +236,8 @@ function ESCORT._EvasionNoReaction( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:EvasionNoReaction() - MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionNoReaction" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:EvasionNoReaction() + MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionNoReaction" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -233,8 +246,8 @@ function ESCORT._EvasionPassiveDefense( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:EvasionPassiveDefense() - MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionPassiveDefense" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:EvasionPassiveDefense() + MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionPassiveDefense" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -243,8 +256,8 @@ function ESCORT._EvasionEvadeFire( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:EvasionEvadeFire() - MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionEvadeFire" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:EvasionEvadeFire() + MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionEvadeFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -253,8 +266,8 @@ function ESCORT._EvasionVertical( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient - MenuParam.ParamSelf.EscortGroup:EvasionVertical() - MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionVertical" ):ToClient( MenuParam.ParamSelf.EscortClient ) + EscortGroup:EvasionVertical() + MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionVertical" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam @@ -264,12 +277,12 @@ function ESCORT._CancelCurrentTask( MenuParam ) local EscortClient = MenuParam.ParamSelf.EscortClient EscortGroup:PopCurrentTask() - MESSAGE:New( "Cancelling with current orders, continuing our mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/CancelCurrentTask" ):ToClient( MenuParam.ParamSelf.EscortClient ) + MESSAGE:New( "Cancelling with current orders, continuing our mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/CancelCurrentTask" ):ToClient( EscortClient ) end function ESCORT:_ScanForTargets() - self:T() + self:F() self.Targets = {} diff --git a/Moose/GoHomeTask.lua b/Moose/GoHomeTask.lua index 7bb3da7ad..4f302f5a1 100644 --- a/Moose/GoHomeTask.lua +++ b/Moose/GoHomeTask.lua @@ -13,26 +13,23 @@ GOHOMETASK = { -- @param table{string,...}|string LandingZones Table of Landing Zone names where Home(s) are located. -- @return GOHOMETASK function GOHOMETASK:New( LandingZones ) -trace.f(self.ClassName) - - -- Child holds the inherited instance of the PICKUPTASK Class to the BASE class. - local Child = BASE:Inherit( self, TASK:New() ) - + local self = BASE:Inherit( self, TASK:New() ) + self:F( { LandingZones } ) local Valid = true Valid = routines.ValidateZone( LandingZones, "LandingZones", Valid ) if Valid then - Child.Name = 'Fly Home' - Child.TaskBriefing = "Task: Fly back to your home base. Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to your home base." + self.Name = 'Fly Home' + self.TaskBriefing = "Task: Fly back to your home base. Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to your home base." if type( LandingZones ) == "table" then - Child.LandingZones = LandingZones + self.LandingZones = LandingZones else - Child.LandingZones = { LandingZones } + self.LandingZones = { LandingZones } end - Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGEARRIVE:New(), STAGEDONE:New() } - Child.SetStage( Child, 1 ) + self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGEARRIVE:New(), STAGEDONE:New() } + self.SetStage( self, 1 ) end - return Child + return self end diff --git a/Moose/Group.lua b/Moose/Group.lua index 96c190cae..ede103434 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -10,7 +10,7 @@ Include.File( "Unit" ) --- The GROUP class -- @type GROUP -- @extends Base#BASE --- @field #Group DCSGroup The DCS group class. +-- @field DCSGroup#Group DCSGroup The DCS group class. -- @field #string GroupName The name of the group. -- @field #number GroupID the ID of the group. -- @field #table Controller The controller of the group. @@ -19,21 +19,22 @@ GROUP = { GroupName = "", GroupID = 0, Controller = nil, + DCSGroup = nil, } --- A DCSGroup --- @type Group +-- @type DCSGroup -- @field id_ The ID of the group in DCS GROUPS = {} --- Create a new GROUP from a DCSGroup -- @param self --- @param #Group DCSGroup The DCS Group +-- @param DCSGroup#Group DCSGroup The DCS Group -- @return #GROUP self function GROUP:New( DCSGroup ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSGroup ) + self:F( DCSGroup ) self.DCSGroup = DCSGroup if self.DCSGroup and self.DCSGroup:isExist() then @@ -54,7 +55,7 @@ end -- @return #GROUP self function GROUP:NewFromName( GroupName ) local self = BASE:Inherit( self, BASE:New() ) - self:T( GroupName ) + self:F( GroupName ) self.DCSGroup = Group.getByName( GroupName ) if self.DCSGroup then @@ -72,7 +73,7 @@ end -- @return #GROUP self function GROUP:NewFromDCSUnit( DCSUnit ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSUnit ) + self:F( DCSUnit ) self.DCSGroup = DCSUnit:getGroup() if self.DCSGroup then @@ -88,7 +89,7 @@ end -- @param self -- @return #Group The DCSGroup. function GROUP:GetDCSGroup() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) self.DCSGroup = Group.getByName( self.GroupName ) return self.DCSGroup end @@ -100,7 +101,7 @@ end -- @param #number UnitNumber The unit index to be returned from the GROUP. -- @return #Unit The DCS Unit. function GROUP:GetDCSUnit( UnitNumber ) - self:T( { self.GroupName, UnitNumber } ) + self:F( { self.GroupName, UnitNumber } ) return self.DCSGroup:getUnit( UnitNumber ) end @@ -108,7 +109,7 @@ end --- Activates a GROUP. -- @param self function GROUP:Activate() - self:T( { self.GroupName } ) + self:F( { self.GroupName } ) trigger.action.activateGroup( self:GetDCSGroup() ) return self:GetDCSGroup() end @@ -117,7 +118,7 @@ end -- @param self -- @return #number The ID of the GROUP. function GROUP:GetID() - self:T( self.GroupName ) + self:F( self.GroupName ) return self.GroupID end @@ -126,15 +127,35 @@ end -- @param self -- @return #string The name of the GROUP. function GROUP:GetName() - self:T( self.GroupName ) + self:F( self.GroupName ) return self.GroupName end +--- Gets the type name of the group. +-- @param #GROUP self +-- @return #string The type name of the group. +function GROUP:GetTypeName() + self:F( self.GroupName ) + + return self.DCSGroup:getUnit(1):getTypeName() +end + +--- Gets the callsign of the fist unit of the group. +-- @param #GROUP self +-- @return #string The callsign of the first unit of the group. +function GROUP:GetCallsign() + self:F( self.GroupName ) + + return self.DCSGroup:getUnit(1):getCallsign() +end + + + --- Gets the current Point of the GROUP in VEC3 format. -- @return #Vec3 Current x,y and z position of the group. function GROUP:GetPointVec2() - self:T( self.GroupName ) + self:F( self.GroupName ) local GroupPoint = self:GetUnit(1):GetPointVec2() self:T( GroupPoint ) @@ -144,7 +165,7 @@ end --- Gets the current Point of the GROUP in VEC2 format. -- @return #Vec2 Current x and y position of the group in the 2D plane. function GROUP:GetPointVec2() - self:T( self.GroupName ) + self:F( self.GroupName ) local GroupPoint = self:GetUnit(1):GetPointVec2() self:T( GroupPoint ) @@ -154,7 +175,7 @@ end --- Gets the current Point of the GROUP in VEC3 format. -- @return #Vec3 Current Vec3 position of the group. function GROUP:GetPositionVec3() - self:T( self.GroupName ) + self:F( self.GroupName ) local GroupPoint = self:GetUnit(1):GetPositionVec3() self:T( GroupPoint ) @@ -166,7 +187,7 @@ end -- So all event listeners will catch the destroy event of this GROUP. -- @param self function GROUP:Destroy() - self:T( self.GroupName ) + self:F( self.GroupName ) for Index, UnitData in pairs( self.DCSGroup:getUnits() ) do self:CreateEventCrash( timer.getTime(), UnitData ) @@ -182,7 +203,7 @@ end -- @param #number UnitNumber The number of the Unit to be returned. -- @return #Unit The DCS Unit. function GROUP:GetUnit( UnitNumber ) - self:T( { self.GroupName, UnitNumber } ) + self:F( { self.GroupName, UnitNumber } ) return UNIT:New( self.DCSGroup:getUnit( UnitNumber ) ) end @@ -191,7 +212,7 @@ end -- @param self -- @return #boolean Air category evaluation result. function GROUP:IsAir() -self:T() + self:F() local IsAirResult = self.DCSGroup:getCategory() == Group.Category.AIRPLANE or self.DCSGroup:getCategory() == Group.Category.HELICOPTER @@ -204,7 +225,7 @@ end -- @param self -- @return #boolean Alive result. function GROUP:IsAlive() -self:T() + self:F() local IsAliveResult = self.DCSGroup and self.DCSGroup:isExist() @@ -217,7 +238,7 @@ end -- @param self -- @return #boolean All units on the ground result. function GROUP:AllOnGround() -self:T() + self:F() local AllOnGroundResult = true @@ -233,10 +254,10 @@ end --- Returns the current maximum velocity of the group. -- Each unit within the group gets evaluated, and the maximum velocity (= the unit which is going the fastest) is returned. --- @param self +-- @param #GROUP self -- @return #number Maximum velocity found. function GROUP:GetMaxVelocity() - self:T() + self:F() local MaxVelocity = 0 @@ -259,7 +280,7 @@ end -- @param self -- @return #number Minimum height found. function GROUP:GetMinHeight() - self:T() + self:F() end @@ -269,16 +290,17 @@ end -- @param self -- @return #number Maximum height found. function GROUP:GetMaxHeight() - self:T() + self:F() end +-- Tasks --- Popping current Task from the group. -- @param #GROUP self -- @return Group#GROUP self function GROUP:PopCurrentTask() - self:T() + self:F() local Controller = self:_GetController() @@ -292,7 +314,7 @@ end -- @param #GROUP self -- @return Group#GROUP self function GROUP:PushTask( DCSTask ) - self:T() + self:F() local Controller = self:_GetController() @@ -301,15 +323,60 @@ function GROUP:PushTask( DCSTask ) return self end +--- Return a condition section for a controlled task +-- @param #GROUP self +-- @param #Time time +-- @param #string userFlag +-- @param #boolean userFlagValue +-- @param #string condition +-- @param #Time duration +-- @param #number lastWayPoint +-- return #DCSTask +function GROUP:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint ) + self:F( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } ) + + local DCSStopCondition = {} + DCSStopCondition.time = time + DCSStopCondition.userFlag = userFlag + DCSStopCondition.userFlagValue = userFlagValue + DCSStopCondition.condition = condition + DCSStopCondition.duration = duration + DCSStopCondition.lastWayPoint = lastWayPoint + + self:T( { DCSStopCondition } ) + return DCSStopCondition +end + +--- Return a Controlled Task taking a Task and a TaskCondition +-- @param #GROUP self +-- @param #DCSTask DCSTask +-- @param #DCSStopCondition DCSStopCondition +-- @return #DCSTask +function GROUP:TaskControlled( DCSTask, DCSStopCondition ) + self:F( { DCSTask, DCSStopCondition } ) + + local DCSTaskControlled + + DCSTaskControlled = { + id = 'ControlledTask', + params = { + task = DCSTask, + stopCondition = DCSStopCondition, + } + } + + self:T( { DCSTaskControlled } ) + return DCSTaskControlled +end + --- Orbit at a specified position at a specified alititude during a specified duration with a specified speed. -- @param #GROUP self -- @param #Vec2 Point The point to hold the position. --- @param #number Duration The maximum duration in seconds to hold the position. -- @param #number Altitude The altitude to hold the position. -- @param #number Speed The speed flying when holding the position. -- @return #GROUP self -function GROUP:OrbitCircleAtVec2( Point, Duration, Altitude, Speed ) - self:T( { self.GroupName, Point, Duration, Altitude, Speed } ) +function GROUP:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) + self:F( { self.GroupName, Point, Altitude, Speed } ) -- pattern = enum AI.Task.OribtPattern, -- point = Vec2, @@ -321,7 +388,7 @@ function GROUP:OrbitCircleAtVec2( Point, Duration, Altitude, Speed ) self:T( { LandHeight } ) - local AITask = { id = 'Orbit', + local DCSTask = { id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.CIRCLE, point = Point, speed = Speed, @@ -344,21 +411,20 @@ function GROUP:OrbitCircleAtVec2( Point, Duration, Altitude, Speed ) -- } -- ) - return AITask + return DCSTask end ---- Orbit at the current position of the first unit of the group at a specified alititude during a specified duration +--- Orbit at the current position of the first unit of the group at a specified alititude -- @param #GROUP self --- @param #number Duration The maximum duration in seconds to hold the position. -- @param #number Altitude The altitude to hold the position. -- @param #number Speed The speed flying when holding the position. -- @return #GROUP self -function GROUP:OrbitCircle( Duration, Altitude, Speed ) - self:T( { self.GroupName, Duration, Altitude, Speed } ) +function GROUP:TaskOrbitCircle( Altitude, Speed ) + self:F( { self.GroupName, Altitude, Speed } ) local GroupPoint = self:GetPointVec2() - return self:OrbitCircleAtVec2( GroupPoint, Duration, Altitude, Speed ) + return self:TaskOrbitCircleAtVec2( GroupPoint, Altitude, Speed ) end @@ -367,41 +433,57 @@ end -- @param #GROUP self -- @param #number Duration The maximum duration in seconds to hold the position. -- @return #GROUP self -function GROUP:HoldPosition( Duration ) - self:T( { self.GroupName, Duration } ) +function GROUP:TaskHoldPosition() + self:F( { self.GroupName } ) - return self:OrbitCircle( Duration, 30, 0 ) + return self:TaskOrbitCircle( 30, 10 ) end --- Land the group at a Vec2Point. --- @param self +-- @param #GROUP self -- @param #Vec2 Point The point where to land. -- @param #number Duration The duration in seconds to stay on the ground. -- @return #GROUP self -function GROUP:Land( Point, Duration ) - self:T( { self.GroupName, Point, Duration } ) +function GROUP:TaskLandAtVec2( Point, Duration ) + self:F( { self.GroupName, Point, Duration } ) - local Controller = self:_GetController() - + local DCSTask + if Duration and Duration > 0 then - Controller:pushTask( { id = 'Land', params = { point = Point, durationFlag = true, duration = Duration } } ) + DCSTask = { id = 'Land', params = { point = Point, durationFlag = true, duration = Duration } } else - Controller:pushTask( { id = 'Land', params = { point = Point, durationFlag = false } } ) + DCSTask = { id = 'Land', params = { point = Point, durationFlag = false } } end - return self + self:T( DCSTask ) + return DCSTask end ---- Attack the Unit. --- @param self --- @param #UNIT The unit. +--- Land the group at a @{Zone#ZONE). +-- @param #GROUP self +-- @param Zone#ZONE Zone The zone where to land. +-- @param #number Duration The duration in seconds to stay on the ground. -- @return #GROUP self -function GROUP:AttackUnit( AttackUnit ) - self:T( { self.GroupName, AttackUnit } ) +function GROUP:TaskLandAtZone( Zone, Duration ) + self:F( { self.GroupName, Zone, Duration } ) - local Controller = self:_GetController() + local Point = Zone:GetPointVec2() + local DCSTask = self:TaskLandAtVec2( Point, Duration ) + + self:T( DCSTask ) + return DCSTask +end + + +--- Attack the Unit. +-- @param #GROUP self +-- @param Unit#UNIT The unit. +-- @return #DCSTask The DCS task structure. +function GROUP:TaskAttackUnit( AttackUnit ) + self:F( { self.GroupName, AttackUnit } ) + -- AttackUnit = { -- id = 'AttackUnit', -- params = { @@ -413,187 +495,88 @@ function GROUP:AttackUnit( AttackUnit ) -- attackQtyLimit = boolean, -- groupAttack = boolean, -- } --- } - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - - Controller:pushTask( { id = 'AttackUnit', - params = { unitId = AttackUnit:GetID(), - expend = AI.Task.WeaponExpend.TWO, - groupAttack = true, - } +-- } + + local DCSTask + DCSTask = { id = 'AttackUnit', + params = { unitId = AttackUnit:GetID(), + expend = AI.Task.WeaponExpend.TWO, + groupAttack = true, } - ) - return self -end - ---- Holding weapons. --- @param self --- @return #GROUP self -function GROUP:HoldFire() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() + } - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + self:T( { DCSTask } ) return self end ---- Return fire. --- @param self --- @return #GROUP self -function GROUP:ReturnFire() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) - return self -end - ---- Openfire. --- @param self --- @return #GROUP self -function GROUP:OpenFire() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - return self -end - ---- Weapon free. --- @param self --- @return #GROUP self -function GROUP:WeaponFree() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) - return self -end - ---- No evasion on enemy threats. --- @param self --- @return #GROUP self -function GROUP:EvasionNoReaction() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) - return self -end - ---- Evasion passive defense. --- @param self --- @return #GROUP self -function GROUP:EvasionPassiveDefense() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENSE ) - return self -end - ---- Evade fire. --- @param self --- @return #GROUP self -function GROUP:EvasionEvadeFire() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - return self -end - ---- Vertical manoeuvres. --- @param self --- @return #GROUP self -function GROUP:EvasionVertical() - self:T( { self.GroupName } ) - - local Controller = self:_GetController() - - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - return self -end --- Move the group to a Vec2 Point, wait for a defined duration and embark a group. --- @param self +-- @param #GROUP self -- @param #Vec2 Point The point where to wait. -- @param #number Duration The duration in seconds to wait. --- @param EmbarkingGroup The group to be embarked. --- @return #GROUP self -function GROUP:Embarking( Point, Duration, EmbarkingGroup ) -trace.f( self.ClassName, { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } ) +-- @param #GROUP EmbarkingGroup The group to be embarked. +-- @return #DCSTask The DCS task structure +function GROUP:TaskEmbarkingAtVec2( Point, Duration, EmbarkingGroup ) + self:F( { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } ) - local Controller = self:_GetController() + local DCSTask + DCSTask = { id = 'Embarking', + params = { x = Point.x, + y = Point.y, + duration = Duration, + groupsForEmbarking = { EmbarkingGroup.GroupID }, + durationFlag = true, + distributionFlag = false, + distribution = {}, + } + } - trace.i( self.ClassName, EmbarkingGroup.GroupID ) - trace.i( self.ClassName, EmbarkingGroup.DCSGroup:getID() ) - trace.i( self.ClassName, EmbarkingGroup.DCSGroup.id ) - - Controller:pushTask( { id = 'Embarking', - params = { x = Point.x, - y = Point.y, - duration = Duration, - groupsForEmbarking = { EmbarkingGroup.GroupID }, - durationFlag = true, - distributionFlag = false, - distribution = {}, - } - } - ) - - return self + self:T( { DCSTask } ) + return DCSTask end --- Move to a defined Vec2 Point, and embark to a group when arrived within a defined Radius. --- @param self +-- @param #GROUP self -- @param #Vec2 Point The point where to wait. -- @param #number Radius The radius of the embarking zone around the Point. --- @return #GROUP self -function GROUP:EmbarkToTransport( Point, Radius ) -trace.f( self.ClassName, { self.GroupName, Point, Radius } ) +-- @return #DCSTask The DCS task structure. +function GROUP:TaskEmbarkToTransportAtVec2( Point, Radius ) + self:F( { self.GroupName, Point, Radius } ) - local Controller = self:_GetController() - - Controller:pushTask( { id = 'EmbarkToTransport', - params = { x = Point.x, - y = Point.y, - zoneRadius = Radius, - } - } - ) + local DCSTask --#DCSTask + DCSTask = { id = 'EmbarkToTransport', + params = { x = Point.x, + y = Point.y, + zoneRadius = Radius, + } + } - return self + self:T( { DCSTask } ) + return DCSTask end --- Return a Misson task to follow a given route. --- @param self +-- @param #GROUP self -- @param #table GoPoints A table of Route Points. -- @return #DCSTask function GROUP:TaskMission( Points ) - self:T( Points ) + self:F( Points ) - local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } + local DCSTask + DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } - return MissionTask + self:T( { DCSTask } ) + return DCSTask end --- Make the group to follow a given route. --- @param self +-- @param #GROUP self -- @param #table GoPoints A table of Route Points. -- @return #GROUP self function GROUP:Route( GoPoints ) - self:T( GoPoints ) + self:F( GoPoints ) local Points = routines.utils.deepCopy( GoPoints ) local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } @@ -609,13 +592,13 @@ end -- The group final destination point can be randomized. -- A speed can be given in km/h. -- A given formation can be given. --- @param self --- @param ZONE#ZONE Zone The zone where to route to. +-- @param #GROUP self +-- @param 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 GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) - self:T( Zone ) +-- @param Base#FORMATION Formation The formation string. +function GROUP:TaskRouteToZone( Zone, Randomize, Speed, Formation ) + self:F( Zone ) local GroupPoint = self:GetPointVec2() @@ -661,14 +644,14 @@ function GROUP:RouteToZone( Zone, Randomize, Speed, Formation ) return self end ---- Return the route of a group. --- @param self +--- Return the route of a group by using the @{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. -- @param #boolean Randomize Randomization of the route, when true. -- @param #number Radius When randomization is on, the randomization is within the radius. function GROUP:CopyRoute( Begin, End, Randomize, Radius ) -self:T( { Begin, End } ) + self:F( { Begin, End } ) local Points = {} @@ -733,4 +716,161 @@ function GROUP:IsTargetDetected( DCSObject ) return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity -end \ No newline at end of file +end + +-- Options + +--- Holding weapons. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:HoldFire() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + return self +end + +--- Return fire. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:ReturnFire() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) + return self +end + +--- Openfire. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:OpenFire() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + return self +end + +--- Weapon free. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:WeaponFree() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) + return self +end + +--- No evasion on enemy threats. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:EvasionNoReaction() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) + return self +end + +--- Evasion passive defense. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:EvasionPassiveDefense() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENSE ) + return self +end + +--- Evade fire. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:EvasionEvadeFire() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + return self +end + +--- Vertical manoeuvres. +-- @param #GROUP self +-- @return #GROUP self +function GROUP:EvasionVertical() + self:F( { self.GroupName } ) + + local Controller = self:_GetController() + + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) + return self +end + +-- Message APIs + +--- Returns a message for a coalition or a client. +-- @param #GROUP self +-- @param #string Message The message text +-- @param #Duration Duration The duration of the message. +-- @return Message#MESSAGE +function GROUP:Message( Message, Duration ) + self:F( { Message, Duration } ) + + return MESSAGE:New( Message, self:GetCallsign() .. "(" .. self:GetTypeName() .. ")", Duration, self:GetClassNameAndID() ) +end + +--- Send a message to all coalitions. +-- 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 #GROUP self +-- @param #string Message The message text +-- @param #Duration Duration The duration of the message. +function GROUP:MessageToAll( Message, Duration ) + self:F( { Message, Duration } ) + + self:Message( Message, Duration ):ToAll() +end + +--- Send a message to the red coalition. +-- 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 #GROUP self +-- @param #string Message The message text +-- @param #Duration Duration The duration of the message. +function GROUP:MessageToRed( Message, Duration ) + self:F( { Message, Duration } ) + + self:Message( Message, Duration ):ToRed() +end + +--- Send a message to the blue coalition. +-- 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 #GROUP self +-- @param #string Message The message text +-- @param #Duration Duration The duration of the message. +function GROUP:MessageToBlue( Message, Duration ) + self:F( { Message, Duration } ) + + self:Message( Message, Duration ):ToBlue() +end + +--- Send a message to a client. +-- 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 #GROUP self +-- @param #string Message The message text +-- @param #Duration Duration The duration of the message. +-- @param Client#CLIENT Client The client object receiving the message. +function GROUP:MessageToClient( Message, Duration, Client ) + self:F( { Message, Duration } ) + + self:Message( Message, Duration ):ToClient( Client ) +end + diff --git a/Moose/Message.lua b/Moose/Message.lua index 7c5f581f5..556ae6484 100644 --- a/Moose/Message.lua +++ b/Moose/Message.lua @@ -6,13 +6,12 @@ -- Messages are sent to Clients with MESSAGE:@{ToClient}(). -- Messages are sent to Coalitions with MESSAGE:@{ToCoalition}(). -- Messages are sent to All Players with MESSAGE:@{ToAll}(). --- @module MESSAGE +-- @module Message -Include.File( "Trace" ) Include.File( "Base" ) --- The MESSAGE class --- @type +-- @type MESSAGE MESSAGE = { ClassName = "MESSAGE", MessageCategory = 0, @@ -39,7 +38,7 @@ MESSAGE = { -- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ) function MESSAGE:New( MessageText, MessageCategory, MessageDuration, MessageID ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { MessageText, MessageCategory, MessageDuration, MessageID } ) + self:F( { MessageText, MessageCategory, MessageDuration, MessageID } ) -- When no messagecategory is given, we don't show it as a title... if MessageCategory and MessageCategory ~= "" then @@ -61,8 +60,9 @@ function MESSAGE:New( MessageText, MessageCategory, MessageDuration, MessageID ) 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". --- @param CLIENT Client is the Group of the Client. --- @return MESSAGE +-- @param #MESSAGE self +-- @param Client#CLIENT Client is the Group of the Client. +-- @return #MESSAGE -- @usage -- -- Send the 2 messages created with the @{New} method to the Client Group. -- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1. @@ -79,20 +79,21 @@ end -- MessageClient1:ToClient( ClientGroup ) -- MessageClient2:ToClient( ClientGroup ) function MESSAGE:ToClient( Client ) - self:T( Client ) + self:F( Client ) if Client and Client:GetClientGroupID() then local ClientGroupID = Client:GetClientGroupID() - trace.i( self.ClassName, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) + 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 ) end return self end ---- Sends a MESSAGE to the Blue coalition. --- @return MESSAGE +--- Sends a MESSAGE to the Blue coalition. +-- @param #MESSAGE self +-- @return #MESSAGE -- @usage -- -- Send a message created with the @{New} method to the BLUE coalition. -- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() @@ -102,7 +103,7 @@ end -- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- MessageBLUE:ToBlue() function MESSAGE:ToBlue() - self:T() + self:F() self:ToCoalition( coalition.side.BLUE ) @@ -110,7 +111,8 @@ function MESSAGE:ToBlue() end --- Sends a MESSAGE to the Red Coalition. --- @return MESSAGE +-- @param #MESSAGE self +-- @return #MESSAGE -- @usage -- -- Send a message created with the @{New} method to the RED coalition. -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() @@ -120,7 +122,7 @@ end -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- MessageRED:ToRed() function MESSAGE:ToRed( ) - self:T() + self:F() self:ToCoalition( coalition.side.RED ) @@ -128,8 +130,9 @@ function MESSAGE:ToRed( ) end --- Sends a MESSAGE to a Coalition. +-- @param #MESSAGE self -- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. --- @return MESSAGE +-- @return #MESSAGE -- @usage -- -- Send a message created with the @{New} method to the RED coalition. -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) @@ -139,10 +142,10 @@ end -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- MessageRED:ToCoalition( coalition.side.RED ) function MESSAGE:ToCoalition( CoalitionSide ) - self:T( CoalitionSide ) + self:F( CoalitionSide ) if CoalitionSide then - trace.i(self.ClassName, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) + self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) end @@ -150,7 +153,8 @@ function MESSAGE:ToCoalition( CoalitionSide ) end --- Sends a MESSAGE to all players. --- @return MESSAGE +-- @param #MESSAGE self +-- @return #MESSAGE -- @usage -- -- Send a message created to all players. -- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() @@ -160,7 +164,7 @@ end -- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) -- MessageAll:ToAll() function MESSAGE:ToAll() - self:T() + self:F() self:ToCoalition( coalition.side.RED ) self:ToCoalition( coalition.side.BLUE ) @@ -179,7 +183,7 @@ MESSAGEQUEUE = { function MESSAGEQUEUE:New( RefreshInterval ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { RefreshInterval } ) + self:F( { RefreshInterval } ) self.RefreshInterval = RefreshInterval diff --git a/Moose/Mission.lua b/Moose/Mission.lua index 7e2eb696b..1c8f713ca 100644 --- a/Moose/Mission.lua +++ b/Moose/Mission.lua @@ -33,7 +33,7 @@ MISSION = { function MISSION:Meta() local self = BASE:Inherit( self, BASE:New() ) - self:T() + self:F() return self end @@ -79,13 +79,13 @@ end --- Returns if a Mission has completed. -- @return bool function MISSION:IsCompleted() - self:T() + self:F() return self.MissionStatus == "ACCOMPLISHED" end --- Set a Mission to completed. function MISSION:Completed() - self:T() + self:F() self.MissionStatus = "ACCOMPLISHED" self:StatusToClients() end @@ -93,13 +93,13 @@ end --- Returns if a Mission is ongoing. -- treturn bool function MISSION:IsOngoing() - self:T() + self:F() return self.MissionStatus == "ONGOING" end --- Set a Mission to ongoing. function MISSION:Ongoing() - self:T() + self:F() self.MissionStatus = "ONGOING" --self:StatusToClients() end @@ -107,13 +107,13 @@ end --- Returns if a Mission is pending. -- treturn bool function MISSION:IsPending() - self:T() + self:F() return self.MissionStatus == "PENDING" end --- Set a Mission to pending. function MISSION:Pending() - self:T() + self:F() self.MissionStatus = "PENDING" self:StatusToClients() end @@ -121,20 +121,20 @@ end --- Returns if a Mission has failed. -- treturn bool function MISSION:IsFailed() - self:T() + self:F() return self.MissionStatus == "FAILED" end --- Set a Mission to failed. function MISSION:Failed() - self:T() + self:F() self.MissionStatus = "FAILED" self:StatusToClients() end --- Send the status of the MISSION to all Clients. function MISSION:StatusToClients() - self:T() + self:F() if self.MissionReportFlash then for ClientID, Client in pairs( self._Clients ) do Client:Message( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. '! ( ' .. self.MissionPriority .. ' mission ) ', 10, self.Name .. '/Status', "Mission Command: Mission Status") @@ -144,33 +144,28 @@ end --- Handles the reporting. After certain time intervals, a MISSION report MESSAGE will be shown to All Players. function MISSION:ReportTrigger() - self:T() + self:F() if self.MissionReportShow == true then self.MissionReportShow = false -trace.r( "MISSION", "1", { true } ) return true else if self.MissionReportFlash == true then if timer.getTime() >= self.MissionReportTrigger then self.MissionReportTrigger = timer.getTime() + self.MissionTimeInterval -trace.r( "MISSION", "2", { true } ) return true else -trace.r( "MISSION", "3", { false } ) return false end else -trace.r( "MISSION", "4", { false } ) return false end end -trace.e() end --- Report the status of all MISSIONs to all active Clients. function MISSION:ReportToAll() - self:T() + self:F() local AlivePlayers = '' for ClientID, Client in pairs( self._Clients ) do @@ -232,7 +227,7 @@ end -- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Transport Troops', 'Operational', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.', 'NATO' ) -- Mission:AddGoalFunction( DeployPatriotTroopsGoal ) function MISSION:AddGoalFunction( GoalFunction ) - self:T() + self:F() self.GoalFunction = GoalFunction end @@ -240,7 +235,7 @@ end -- @param CLIENT Client to show briefing to. -- @return CLIENT function MISSION:ShowBriefing( Client ) - self:T( { Client.ClientName } ) + self:F( { Client.ClientName } ) if not Client.ClientBriefingShown then Client.ClientBriefingShown = true @@ -265,7 +260,7 @@ end -- Mission:AddClient( CLIENT:New( 'US UH-1H*HOT-Deploy Troops 2', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) -- Mission:AddClient( CLIENT:New( 'US UH-1H*RAMP-Deploy Troops 4', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) function MISSION:AddClient( Client ) - self:T( { Client } ) + self:F( { Client } ) local Valid = true @@ -273,7 +268,6 @@ function MISSION:AddClient( Client ) self._Clients[Client.ClientName] = Client end -trace.r( self.ClassName, "" ) return Client end @@ -284,7 +278,7 @@ end -- -- Seach for Client "Bomber" within the Mission. -- local BomberClient = Mission:FindClient( "Bomber" ) function MISSION:FindClient( ClientName ) - self:T( { self._Clients[ClientName] } ) + self:F( { self._Clients[ClientName] } ) return self._Clients[ClientName] end @@ -315,7 +309,7 @@ end -- Mission:AddTask( DeployTask, 2 ) function MISSION:AddTask( Task, TaskNumber ) - self:T() + self:F() self._Tasks[TaskNumber] = Task self._Tasks[TaskNumber]:EnableEvents() @@ -332,7 +326,7 @@ function MISSION:AddTask( Task, TaskNumber ) -- Task2 = Mission:GetTask( 2 ) function MISSION:GetTask( TaskNumber ) - self:T() + self:F() local Valid = true @@ -356,7 +350,7 @@ end -- Tasks = Mission:GetTasks() -- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) function MISSION:GetTasks() - self:T() + self:F() return self._Tasks end @@ -391,13 +385,10 @@ MISSIONSCHEDULER = { --- This is the main MISSIONSCHEDULER Scheduler function. It is considered internal and is automatically created when the Mission.lua file is included. function MISSIONSCHEDULER.Scheduler() -trace.scheduled("MISSIONSCHEDULER","Scheduler") -- loop through the missions in the TransportTasks for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - trace.i( "MISSIONSCHEDULER", MissionName ) - if not Mission:IsCompleted() then -- This flag will monitor if for this mission, there are clients alive. If this flag is still false at the end of the loop, the mission status will be set to Pending (if not Failed or Completed). @@ -405,8 +396,6 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler") for ClientID, Client in pairs( Mission._Clients ) do - trace.i( "MISSIONSCHEDULER", "Client: " .. Client.ClientName ) - if Client:GetDCSGroup() then -- There is at least one Client that is alive... So the Mission status is set to Ongoing. @@ -470,7 +459,6 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler") end if Task:IsDone() then - trace.i( "MISSIONSCHEDULER", "Task " .. Task.Name .. " is Done." ) --env.info( 'Scheduler: Mission '.. Mission.Name .. ' Task ' .. Task.Name .. ' Stage ' .. Task.Stage.Name .. ' done. TaskComplete = ' .. string.format ( "%s", TaskComplete and "true" or "false" ) ) TaskComplete = true -- when a task is not yet completed, a mission cannot be completed @@ -546,29 +534,22 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler") if Mission:ReportTrigger() then Mission:ReportToAll() end - end - -trace.e() end --- Start the MISSIONSCHEDULER. function MISSIONSCHEDULER.Start() -trace.f("MISSIONSCHEDULER") if MISSIONSCHEDULER ~= nil then MISSIONSCHEDULER.SchedulerId = routines.scheduleFunction( MISSIONSCHEDULER.Scheduler, { }, 0, 2 ) end -trace.e() end --- Stop the MISSIONSCHEDULER. function MISSIONSCHEDULER.Stop() -trace.f("MISSIONSCHEDULER") if MISSIONSCHEDULER.SchedulerId then routines.removeFunction(MISSIONSCHEDULER.SchedulerId) MISSIONSCHEDULER.SchedulerId = nil end -trace.e() end --- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. @@ -582,13 +563,11 @@ end -- 'Russia' ) -- MISSIONSCHEDULER:AddMission( Mission ) function MISSIONSCHEDULER.AddMission( Mission ) -trace.f("MISSIONSCHEDULER") MISSIONSCHEDULER.Missions[Mission.Name] = Mission MISSIONSCHEDULER.MissionCount = MISSIONSCHEDULER.MissionCount + 1 -- Add an overall AI Client for the AI tasks... This AI Client will facilitate the Events in the background for each Task. --MissionAdd:AddClient( CLIENT:New( 'AI' ) ) -trace.r( "MISSIONSCHEDULER", "" ) return Mission end @@ -605,10 +584,8 @@ end -- -- Now remove the Mission. -- MISSIONSCHEDULER:RemoveMission( 'Russia Transport Troops SA-6' ) function MISSIONSCHEDULER.RemoveMission( MissionName ) -trace.f("MISSIONSCHEDULER") MISSIONSCHEDULER.Missions[MissionName] = nil MISSIONSCHEDULER.MissionCount = MISSIONSCHEDULER.MissionCount - 1 -trace.e() end --- Find a MISSION within the MISSIONSCHEDULER. @@ -625,24 +602,19 @@ end -- -- Now find the Mission. -- MissionFind = MISSIONSCHEDULER:FindMission( 'Russia Transport Troops SA-6' ) function MISSIONSCHEDULER.FindMission( MissionName ) -trace.f("MISSIONSCHEDULER") -trace.r( "MISSIONSCHEDULER", "" ) return MISSIONSCHEDULER.Missions[MissionName] end -- Internal function used by the MISSIONSCHEDULER menu. function MISSIONSCHEDULER.ReportMissionsShow( ) -trace.menu("MISSIONSCHEDULER","ReportMissionsShow") for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do Mission.MissionReportShow = true Mission.MissionReportFlash = false end -trace.e() end -- Internal function used by the MISSIONSCHEDULER menu. function MISSIONSCHEDULER.ReportMissionsFlash( TimeInterval ) -trace.menu("MISSIONSCHEDULER","ReportMissionsFlash") local Count = 0 for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do Mission.MissionReportShow = false @@ -652,49 +624,40 @@ trace.menu("MISSIONSCHEDULER","ReportMissionsFlash") env.info( "TimeInterval = " .. Mission.MissionTimeInterval ) Count = Count + 1 end -trace.e() end -- Internal function used by the MISSIONSCHEDULER menu. function MISSIONSCHEDULER.ReportMissionsHide( Prm ) -trace.menu("MISSIONSCHEDULER","ReportMissionsHide") for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do Mission.MissionReportShow = false Mission.MissionReportFlash = false end -trace.e() end --- Enables a MENU option in the communications menu under F10 to control the status of the active missions. -- This function should be called only once when starting the MISSIONSCHEDULER. function MISSIONSCHEDULER.ReportMenu() -trace.f("MISSIONSCHEDULER") local ReportMenu = SUBMENU:New( 'Status' ) local ReportMenuShow = COMMANDMENU:New( 'Show Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsShow, 0 ) local ReportMenuFlash = COMMANDMENU:New('Flash Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsFlash, 120 ) local ReportMenuHide = COMMANDMENU:New( 'Hide Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsHide, 0 ) -trace.e() end --- Show the remaining mission time. function MISSIONSCHEDULER:TimeShow() -trace.f("MISSIONSCHEDULER") self.TimeIntervalCount = self.TimeIntervalCount + 1 if self.TimeIntervalCount >= self.TimeTriggerShow then local TimeMsg = string.format("%00d", ( self.TimeSeconds / 60 ) - ( timer.getTime() / 60 )) .. ' minutes left until mission reload.' MESSAGE:New( TimeMsg, "Mission time", self.TimeShow, '/TimeMsg' ):ToAll() self.TimeIntervalCount = 0 end -trace.e() end function MISSIONSCHEDULER:Time( TimeSeconds, TimeIntervalShow, TimeShow ) -trace.f("MISSIONSCHEDULER") self.TimeIntervalCount = 0 self.TimeSeconds = TimeSeconds self.TimeIntervalShow = TimeIntervalShow self.TimeShow = TimeShow -trace.e() end diff --git a/Moose/Movement.lua b/Moose/Movement.lua index e13b590cd..727b4f36e 100644 --- a/Moose/Movement.lua +++ b/Moose/Movement.lua @@ -23,7 +23,7 @@ MOVEMENT = { function MOVEMENT:New( MovePrefixes, MoveMaximum ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { MovePrefixes, MoveMaximum } ) + self:F( { MovePrefixes, MoveMaximum } ) if type( MovePrefixes ) == 'table' then self.MovePrefixes = MovePrefixes @@ -35,34 +35,34 @@ function MOVEMENT:New( MovePrefixes, MoveMaximum ) self.AliveUnits = 0 -- Contains the counter how many units are currently alive self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not. - self.AddEvent( self, world.event.S_EVENT_BIRTH, self.OnBirth ) - self.AddEvent( self, world.event.S_EVENT_DEAD, self.OnDeadOrCrash ) - self.AddEvent( self, world.event.S_EVENT_CRASH, self.OnDeadOrCrash ) + self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth ) + self:AddEvent( world.event.S_EVENT_DEAD, self.OnDeadOrCrash ) + self:AddEvent( world.event.S_EVENT_CRASH, self.OnDeadOrCrash ) - self.EnableEvents( self ) + self:EnableEvents() - self.ScheduleStart( self ) + self:ScheduleStart() return self end --- Call this function to start the MOVEMENT scheduling. function MOVEMENT:ScheduleStart() -self:T() + self:F() self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 ) end --- Call this function to stop the MOVEMENT scheduling. -- @todo need to implement it ... Forgot. function MOVEMENT:ScheduleStop() -self:T() + self:F() end --- Captures the birth events when new Units were spawned. -- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. function MOVEMENT:OnBirth( event ) -self:T( { event } ) + self:F( { event } ) if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then @@ -88,7 +88,7 @@ end --- Captures the Dead or Crash events when Units crash or are destroyed. -- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. function MOVEMENT:OnDeadOrCrash( event ) -self:T( { event } ) + self:F( { event } ) if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then local MovementUnit = event.initiator @@ -106,7 +106,7 @@ end --- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true. function MOVEMENT:_Scheduler() -self:T( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) + self:F( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) if self.AliveUnits > 0 then local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits diff --git a/Moose/NoTask.lua b/Moose/NoTask.lua index 0e46fbf5b..016ba955e 100644 --- a/Moose/NoTask.lua +++ b/Moose/NoTask.lua @@ -11,19 +11,17 @@ NOTASK = { --- Creates a new NOTASK. function NOTASK:New() -trace.f(self.ClassName) - - -- Child holds the inherited instance of the PICKUPTASK Class to the BASE class. - local Child = BASE:Inherit( self, TASK:New() ) - + local self = BASE:Inherit( self, TASK:New() ) + self:F() + local Valid = true if Valid then - Child.Name = 'Nothing' - Child.TaskBriefing = "Task: Execute your mission." - Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEDONE:New() } - Child.SetStage( Child, 1 ) + self.Name = 'Nothing' + self.TaskBriefing = "Task: Execute your mission." + self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEDONE:New() } + self.SetStage( self, 1 ) end - return Child + return self end diff --git a/Moose/PickupTask.lua b/Moose/PickupTask.lua index 7cca54e5b..f93a634f6 100644 --- a/Moose/PickupTask.lua +++ b/Moose/PickupTask.lua @@ -19,7 +19,7 @@ PICKUPTASK = { -- @param number OnBoardSide Reflects from which side the cargo Group will be on-boarded on the Carrier. function PICKUPTASK:New( CargoType, OnBoardSide ) local self = BASE:Inherit( self, TASK:New() ) - self:T() + self:F() -- self holds the inherited instance of the PICKUPTASK Class to the BASE class. @@ -41,7 +41,7 @@ function PICKUPTASK:New( CargoType, OnBoardSide ) end function PICKUPTASK:FromZone( LandingZone ) -self:T() + self:F() self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone @@ -50,7 +50,7 @@ self:T() end function PICKUPTASK:InitCargo( InitCargos ) -self:T( { InitCargos } ) + self:F( { InitCargos } ) if type( InitCargos ) == "table" then self.Cargos.InitCargos = InitCargos @@ -62,7 +62,7 @@ self:T( { InitCargos } ) end function PICKUPTASK:LoadCargo( LoadCargos ) -self:T( { LoadCargos } ) + self:F( { LoadCargos } ) if type( LoadCargos ) == "table" then self.Cargos.LoadCargos = LoadCargos @@ -74,7 +74,7 @@ self:T( { LoadCargos } ) end function PICKUPTASK:AddCargoMenus( Client, Cargos, TransportRadius ) -self:T() + self:F() for CargoID, Cargo in pairs( Cargos ) do @@ -121,7 +121,7 @@ self:T() end function PICKUPTASK:RemoveCargoMenus( Client ) -self:T() + self:F() for MenuID, MenuData in pairs( Client._Menus ) do for SubMenuID, SubMenuData in pairs( MenuData.PickupSubMenus ) do @@ -148,7 +148,7 @@ end function PICKUPTASK:HasFailed( ClientDead ) -self:T() + self:F() local TaskHasFailed = self.TaskFailed return TaskHasFailed diff --git a/Moose/RouteTask.lua b/Moose/RouteTask.lua index ab1bacd17..0c39ef425 100644 --- a/Moose/RouteTask.lua +++ b/Moose/RouteTask.lua @@ -13,31 +13,29 @@ ROUTETASK = { -- @param string TaskBriefing (optional) Defines a text describing the briefing of the task. -- @return ROUTETASK function ROUTETASK:New( LandingZones, TaskBriefing ) -trace.f(self.ClassName, { LandingZones, TaskBriefing } ) - - -- Child holds the inherited instance of the PICKUPTASK Class to the BASE class. - local Child = BASE:Inherit( self, TASK:New() ) + local self = BASE:Inherit( self, TASK:New() ) + self:F( { LandingZones, TaskBriefing } ) local Valid = true Valid = routines.ValidateZone( LandingZones, "LandingZones", Valid ) if Valid then - Child.Name = 'Route To Zone' + self.Name = 'Route To Zone' if TaskBriefing then - Child.TaskBriefing = TaskBriefing .. " Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the target objective." + self.TaskBriefing = TaskBriefing .. " Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the target objective." else - Child.TaskBriefing = "Task: Fly to specified zone(s). Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the target objective." + self.TaskBriefing = "Task: Fly to specified zone(s). Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the target objective." end if type( LandingZones ) == "table" then - Child.LandingZones = LandingZones + self.LandingZones = LandingZones else - Child.LandingZones = { LandingZones } + self.LandingZones = { LandingZones } end - Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGEARRIVE:New(), STAGEDONE:New() } - Child.SetStage( Child, 1 ) + self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGEARRIVE:New(), STAGEDONE:New() } + self.SetStage( self, 1 ) end - return Child + return self end diff --git a/Moose/Routines.lua b/Moose/Routines.lua index d8a61bde6..f6be076c0 100644 --- a/Moose/Routines.lua +++ b/Moose/Routines.lua @@ -2,7 +2,7 @@ -- @module routines -- @author Flightcontrol -Include.File( "Trace" ) +--Include.File( "Trace" ) --Include.File( "Message" ) @@ -1455,7 +1455,7 @@ end function routines.IsPartOfGroupInZones( CargoGroup, LandingZones ) -trace.f() +--trace.f() local CurrentZoneID = nil @@ -1471,14 +1471,14 @@ trace.f() end end -trace.r( "", "", { CurrentZoneID } ) +--trace.r( "", "", { CurrentZoneID } ) return CurrentZoneID end function routines.IsUnitInZones( TransportUnit, LandingZones ) -trace.f("", "routines.IsUnitInZones" ) +--trace.f("", "routines.IsUnitInZones" ) local TransportZoneResult = nil local TransportZonePos = nil @@ -1506,19 +1506,19 @@ trace.f("", "routines.IsUnitInZones" ) end end if TransportZoneResult then - trace.i( "routines", "TransportZone:" .. TransportZoneResult ) + --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) else - trace.i( "routines", "TransportZone:nil logic" ) + --trace.i( "routines", "TransportZone:nil logic" ) end return TransportZoneResult else - trace.i( "routines", "TransportZone:nil hard" ) + --trace.i( "routines", "TransportZone:nil hard" ) return nil end end function routines.IsStaticInZones( TransportStatic, LandingZones ) -trace.f() +--trace.f() local TransportZoneResult = nil local TransportZonePos = nil @@ -1545,13 +1545,13 @@ trace.f() end end -trace.r( "", "", { TransportZoneResult } ) +--trace.r( "", "", { TransportZoneResult } ) return TransportZoneResult end function routines.IsUnitInRadius( CargoUnit, ReferencePosition, Radius ) -trace.f() +--trace.f() local Valid = true @@ -1568,7 +1568,7 @@ trace.f() end function routines.IsPartOfGroupInRadius( CargoGroup, ReferencePosition, Radius ) -trace.f() +--trace.f() local Valid = true @@ -1594,7 +1594,7 @@ end function routines.ValidateString( Variable, VariableName, Valid ) -trace.f() +--trace.f() if type( Variable ) == "string" then if Variable == "" then @@ -1606,12 +1606,12 @@ trace.f() Valid = false end -trace.r( "", "", { Valid } ) +--trace.r( "", "", { Valid } ) return Valid end function routines.ValidateNumber( Variable, VariableName, Valid ) -trace.f() +--trace.f() if type( Variable ) == "number" then else @@ -1619,25 +1619,25 @@ trace.f() Valid = false end -trace.r( "", "", { Valid } ) +--trace.r( "", "", { Valid } ) return Valid end function routines.ValidateGroup( Variable, VariableName, Valid ) -trace.f() +--trace.f() if Variable == nil then error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) Valid = false end -trace.r( "", "", { Valid } ) +--trace.r( "", "", { Valid } ) return Valid end function routines.ValidateZone( LandingZones, VariableName, Valid ) -trace.f() +--trace.f() if LandingZones == nil then error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) @@ -1659,12 +1659,12 @@ trace.f() end end -trace.r( "", "", { Valid } ) +--trace.r( "", "", { Valid } ) return Valid end function routines.ValidateEnumeration( Variable, VariableName, Enum, Valid ) -trace.f() +--trace.f() local ValidVariable = false @@ -1681,7 +1681,7 @@ trace.f() Valid = false end -trace.r( "", "", { Valid } ) +--trace.r( "", "", { Valid } ) return Valid end @@ -1859,7 +1859,7 @@ routines.ground.patrol = function(gpData, pType, form, speed) end function routines.GetUnitHeight( CheckUnit ) -trace.f( "routines" ) +--trace.f( "routines" ) local UnitPoint = CheckUnit:getPoint() local UnitPosition = { x = UnitPoint.x, y = UnitPoint.z } @@ -1869,7 +1869,7 @@ trace.f( "routines" ) --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - trace.f( "routines", "Unit Height = " .. UnitHeight - LandHeight ) + --trace.f( "routines", "Unit Height = " .. UnitHeight - LandHeight ) return UnitHeight - LandHeight @@ -1886,7 +1886,7 @@ Su34Menus = 0 function Su34AttackCarlVinson(groupName) -trace.menu("", "Su34AttackCarlVinson") +--trace.menu("", "Su34AttackCarlVinson") local groupSu34 = Group.getByName( groupName ) local controllerSu34 = groupSu34.getController(groupSu34) local groupCarlVinson = Group.getByName("US Carl Vinson #001") @@ -1900,7 +1900,7 @@ trace.menu("", "Su34AttackCarlVinson") end function Su34AttackWest(groupName) -trace.f("","Su34AttackWest") +--trace.f("","Su34AttackWest") local groupSu34 = Group.getByName( groupName ) local controllerSu34 = groupSu34.getController(groupSu34) local groupShipWest1 = Group.getByName("US Ship West #001") @@ -1918,7 +1918,7 @@ trace.f("","Su34AttackWest") end function Su34AttackNorth(groupName) -trace.menu("","Su34AttackNorth") +--trace.menu("","Su34AttackNorth") local groupSu34 = Group.getByName( groupName ) local controllerSu34 = groupSu34.getController(groupSu34) local groupShipNorth1 = Group.getByName("US Ship North #001") @@ -1940,7 +1940,7 @@ trace.menu("","Su34AttackNorth") end function Su34Orbit(groupName) -trace.menu("","Su34Orbit") +--trace.menu("","Su34Orbit") local groupSu34 = Group.getByName( groupName ) local controllerSu34 = groupSu34:getController() controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) @@ -1951,7 +1951,7 @@ trace.menu("","Su34Orbit") end function Su34TakeOff(groupName) -trace.menu("","Su34TakeOff") +--trace.menu("","Su34TakeOff") local groupSu34 = Group.getByName( groupName ) local controllerSu34 = groupSu34:getController() controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) @@ -1961,7 +1961,7 @@ trace.menu("","Su34TakeOff") end function Su34Hold(groupName) -trace.menu("","Su34Hold") +--trace.menu("","Su34Hold") local groupSu34 = Group.getByName( groupName ) local controllerSu34 = groupSu34:getController() controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) @@ -1971,19 +1971,19 @@ trace.menu("","Su34Hold") end function Su34RTB(groupName) -trace.menu("","Su34RTB") +--trace.menu("","Su34RTB") Su34Status.status[groupName] = 6 MessageToRed( string.format('%s: ',groupName) .. 'Return to Krasnodar. ', 10, 'RedStatus' .. groupName ) end function Su34Destroyed(groupName) -trace.menu("","Su34Destroyed") +--trace.menu("","Su34Destroyed") Su34Status.status[groupName] = 7 MessageToRed( string.format('%s: ',groupName) .. 'Destroyed. ', 30, 'RedStatus' .. groupName ) end function GroupAlive( groupName ) -trace.menu("","GroupAlive") +--trace.menu("","GroupAlive") local groupTest = Group.getByName( groupName ) local groupExists = false @@ -1992,17 +1992,17 @@ trace.menu("","GroupAlive") groupExists = groupTest:isExist() end - trace.r( "", "", { groupExists } ) + --trace.r( "", "", { groupExists } ) return groupExists end function Su34IsDead() -trace.f() +--trace.f() end function Su34OverviewStatus() -trace.menu("","Su34OverviewStatus") +--trace.menu("","Su34OverviewStatus") local msg = "" local currentStatus = 0 local Exists = false @@ -2053,25 +2053,25 @@ end function UpdateBoardMsg() -trace.f() +--trace.f() Su34OverviewStatus() MessageToRed( boardMsgRed.statusMsg, 15, 'RedStatus' ) end function MusicReset( flg ) -trace.f() +--trace.f() trigger.action.setUserFlag(95,flg) end function PlaneActivate(groupNameFormat, flg) -trace.f() +--trace.f() local groupName = groupNameFormat .. string.format("#%03d", trigger.misc.getUserFlag(flg)) --trigger.action.outText(groupName,10) trigger.action.activateGroup(Group.getByName(groupName)) end function Su34Menu(groupName) -trace.f() +--trace.f() --env.info(( 'Su34Menu(' .. groupName .. ')' )) local groupSu34 = Group.getByName( groupName ) @@ -2144,7 +2144,7 @@ end --- Obsolete function, but kept to rework in framework. function ChooseInfantry ( TeleportPrefixTable, TeleportMax ) -trace.f("Spawn") +--trace.f("Spawn") --env.info(( 'ChooseInfantry: ' )) TeleportPrefixTableCount = #TeleportPrefixTable @@ -2229,7 +2229,7 @@ end SpawnedInfantry = 0 function LandCarrier ( CarrierGroup, LandingZonePrefix ) -trace.f() +--trace.f() --env.info(( 'LandCarrier: ' )) --env.info(( 'LandCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) --env.info(( 'LandCarrier: LandingZone = ' .. LandingZonePrefix )) @@ -2248,7 +2248,7 @@ end EscortCount = 0 function EscortCarrier ( CarrierGroup, EscortPrefix, EscortLastWayPoint, EscortEngagementDistanceMax, EscortTargetTypes ) -trace.f() +--trace.f() --env.info(( 'EscortCarrier: ' )) --env.info(( 'EscortCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) --env.info(( 'EscortCarrier: EscortPrefix = ' .. EscortPrefix )) @@ -2314,7 +2314,7 @@ trace.f() end function SendMessageToCarrier( CarrierGroup, CarrierMessage ) -trace.f() +--trace.f() if CarrierGroup ~= nil then MessageToGroup( CarrierGroup, CarrierMessage, 30, 'Carrier/' .. CarrierGroup:getName() ) @@ -2323,7 +2323,7 @@ trace.f() end function MessageToGroup( MsgGroup, MsgText, MsgTime, MsgName ) -trace.f() +--trace.f() if type(MsgGroup) == 'string' then --env.info( 'MessageToGroup: Converted MsgGroup string "' .. MsgGroup .. '" into a Group structure.' ) @@ -2342,7 +2342,7 @@ trace.f() end function MessageToUnit( UnitName, MsgText, MsgTime, MsgName ) -trace.f() +--trace.f() if UnitName ~= nil then local MsgTable = {} @@ -2355,25 +2355,25 @@ trace.f() end function MessageToAll( MsgText, MsgTime, MsgName ) -trace.f() +--trace.f() MESSAGE:New( MsgText, "Message", MsgTime, MsgName ):ToCoalition( coalition.side.RED ):ToCoalition( coalition.side.BLUE ) end function MessageToRed( MsgText, MsgTime, MsgName ) -trace.f() +--trace.f() MESSAGE:New( MsgText, "To Red Coalition", MsgTime, MsgName ):ToCoalition( coalition.side.RED ) end function MessageToBlue( MsgText, MsgTime, MsgName ) -trace.f() +--trace.f() MESSAGE:New( MsgText, "To Blue Coalition", MsgTime, MsgName ):ToCoalition( coalition.side.RED ) end function getCarrierHeight( CarrierGroup ) -trace.f() +--trace.f() if CarrierGroup ~= nil then if table.getn(CarrierGroup:getUnits()) == 1 then @@ -2398,7 +2398,7 @@ trace.f() end function GetUnitHeight( CheckUnit ) -trace.f() +--trace.f() local UnitPoint = CheckUnit:getPoint() local UnitPosition = { x = CurrentPoint.x, y = CurrentPoint.z } @@ -2420,7 +2420,7 @@ _MusicTable.FileCnt = 0 function MusicRegister( SndRef, SndFile, SndTime ) -trace.f() +--trace.f() env.info(( 'MusicRegister: SndRef = ' .. SndRef )) env.info(( 'MusicRegister: SndFile = ' .. SndFile )) @@ -2441,7 +2441,7 @@ trace.f() end function MusicToPlayer( SndRef, PlayerName, SndContinue ) -trace.f() +--trace.f() --env.info(( 'MusicToPlayer: SndRef = ' .. SndRef )) @@ -2464,7 +2464,7 @@ trace.f() end function MusicToGroup( SndRef, SndGroup, SndContinue ) -trace.f() +--trace.f() --env.info(( 'MusicToGroup: SndRef = ' .. SndRef )) @@ -2507,7 +2507,7 @@ trace.f() end function MusicCanStart(PlayerName) -trace.f() +--trace.f() --env.info(( 'MusicCanStart:' )) @@ -2549,7 +2549,7 @@ trace.f() end function MusicScheduler() -trace.scheduled("", "MusicScheduler") +--trace.scheduled("", "MusicScheduler") --env.info(( 'MusicScheduler:' )) if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then diff --git a/Moose/Sead.lua b/Moose/Sead.lua index 0eb7a569f..78d8f0d37 100644 --- a/Moose/Sead.lua +++ b/Moose/Sead.lua @@ -34,7 +34,7 @@ SEAD = { -- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) function SEAD:New( SEADGroupPrefixes ) local self = BASE:Inherit( self, BASE:New() ) - self:T( SEADGroupPrefixes ) + self:F( SEADGroupPrefixes ) if type( SEADGroupPrefixes ) == 'table' then for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix @@ -42,8 +42,8 @@ function SEAD:New( SEADGroupPrefixes ) else self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes end - self.AddEvent( self, world.event.S_EVENT_SHOT, self.EventShot ) - self.EnableEvents( self ) + self:AddEvent( world.event.S_EVENT_SHOT, self.EventShot ) + self:EnableEvents() return self end @@ -51,7 +51,7 @@ end --- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. -- @see SEAD function SEAD:EventShot( event ) -self:T( { event } ) + self:F( { event } ) local SEADUnit = event.initiator local SEADUnitName = SEADUnit:getName() diff --git a/Moose/Spawn.lua b/Moose/Spawn.lua index 9cd980c77..920975962 100644 --- a/Moose/Spawn.lua +++ b/Moose/Spawn.lua @@ -96,7 +96,7 @@ SPAWN = { -- @usage local Plane = SPAWN:New( "Plane" ) -- Creates a new local variable that can initiate new planes with the name "Plane#ddd" using the template "Plane" as defined within the ME. function SPAWN:New( SpawnTemplatePrefix ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { SpawnTemplatePrefix } ) + self:F( { SpawnTemplatePrefix } ) local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) if TemplateGroup then @@ -118,11 +118,11 @@ function SPAWN:New( SpawnTemplatePrefix ) error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) end - self.AddEvent( self, world.event.S_EVENT_BIRTH, self._OnBirth ) - self.AddEvent( self, world.event.S_EVENT_DEAD, self._OnDeadOrCrash ) - self.AddEvent( self, world.event.S_EVENT_CRASH, self._OnDeadOrCrash ) + self:AddEvent( world.event.S_EVENT_BIRTH, self._OnBirth ) + self:AddEvent( world.event.S_EVENT_DEAD, self._OnDeadOrCrash ) + self:AddEvent( world.event.S_EVENT_CRASH, self._OnDeadOrCrash ) - self.EnableEvents( self ) + self:EnableEvents() return self end @@ -138,7 +138,7 @@ end -- @usage local PlaneWithAlias = SPAWN:NewWithAlias( "Plane", "Bomber" ) -- Creates a new local variable that can instantiate new planes with the name "Bomber#ddd" using the template "Plane" as defined within the ME. function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) local self = BASE:Inherit( self, BASE:New() ) - self:T( { SpawnTemplatePrefix, SpawnAliasPrefix } ) + self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } ) local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) if TemplateGroup then @@ -161,11 +161,11 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) end - self.AddEvent( self, world.event.S_EVENT_BIRTH, self._OnBirth ) - self.AddEvent( self, world.event.S_EVENT_DEAD, self._OnDeadOrCrash ) - self.AddEvent( self, world.event.S_EVENT_CRASH, self._OnDeadOrCrash ) + self:AddEvent( world.event.S_EVENT_BIRTH, self._OnBirth ) + self:AddEvent( world.event.S_EVENT_DEAD, self._OnDeadOrCrash ) + self:AddEvent( world.event.S_EVENT_CRASH, self._OnDeadOrCrash ) - self.EnableEvents( self ) + self:EnableEvents() return self end @@ -187,7 +187,7 @@ end -- -- There will be maximum 24 groups spawned during the whole mission lifetime. -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Limit( 2, 24 ) function SPAWN:Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) - self:T( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) + self:F( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) self.SpawnMaxUnitsAlive = SpawnMaxUnitsAlive -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. self.SpawnMaxGroups = SpawnMaxGroups -- The maximum amount of groups that can be spawned. @@ -215,7 +215,7 @@ end -- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):RandomizeRoute( 2, 2, 2000 ) function SPAWN:RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius ) - self:T( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius } ) + self:F( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius } ) self.SpawnRandomizeRoute = true self.SpawnRandomizeRouteStartPoint = SpawnStartPoint @@ -250,7 +250,7 @@ end -- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):Limit( 12, 150 ):Schedule( 200, 0.4 ):RandomizeTemplate( Spawn_US_Platoon ):RandomizeRoute( 3, 3, 2000 ) -- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):Limit( 12, 150 ):Schedule( 200, 0.4 ):RandomizeTemplate( Spawn_US_Platoon ):RandomizeRoute( 3, 3, 2000 ) function SPAWN:RandomizeTemplate( SpawnTemplatePrefixTable ) - self:T( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) + self:F( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) self.SpawnTemplatePrefixTable = SpawnTemplatePrefixTable self.SpawnRandomizeTemplate = true @@ -278,7 +278,7 @@ end -- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically. -- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():RandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown() function SPAWN:Repeat() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self.SpawnRepeat = true self.RepeatOnEngineShutDown = false @@ -297,7 +297,7 @@ end -- @see Repeat function SPAWN:RepeatOnLanding() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self:Repeat() self.RepeatOnEngineShutDown = false @@ -309,7 +309,7 @@ end --- Same as the @{#SPAWN.Repeat) method, but now the Group will respawn after its engines have shut down. -- @return SPAWN function SPAWN:RepeatOnEngineShutDown() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self:Repeat() self.RepeatOnEngineShutDown = true @@ -326,7 +326,7 @@ end -- @return #SPAWN self -- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive. function SPAWN:CleanUp( SpawnCleanUpInterval ) - self:T( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) + self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) self.SpawnCleanUpInterval = SpawnCleanUpInterval self.SpawnCleanUpTimeStamps = {} @@ -349,7 +349,7 @@ end -- -- Define an array of Groups. -- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):Limit( 2, 24 ):Visible( 90, "Diamond", 10, 100, 50 ) function SPAWN:Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) - self:T( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) + self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) self.SpawnVisible = true -- When the first Spawn executes, all the Groups need to be made visible before start. @@ -397,7 +397,7 @@ end -- @param self -- @return GROUP#GROUP The group that was spawned. You can use this group for further actions. function SPAWN:Spawn() - self:T( { self.SpawnTemplatePrefix, self.SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) return self:SpawnWithIndex( self.SpawnIndex + 1 ) end @@ -408,7 +408,7 @@ end -- @param #string SpawnIndex The index of the group to be spawned. -- @return GROUP#GROUP The group that was spawned. You can use this group for further actions. function SPAWN:ReSpawn( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) if not SpawnIndex then SpawnIndex = 1 @@ -426,7 +426,7 @@ end -- Uses @{DATABASE} global object defined in MOOSE. -- @return GROUP#GROUP The group that was spawned. You can use this group for further actions. function SPAWN:SpawnWithIndex( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups } ) if self:_GetSpawnIndex( SpawnIndex ) then @@ -466,7 +466,7 @@ end -- -- Between these two values, a random amount of seconds will be choosen for each new spawn of the helicopters. -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation ) - self:T( { SpawnTime, SpawnTimeVariation } ) + self:F( { SpawnTime, SpawnTimeVariation } ) self.SpawnCurrentTimer = 0 -- The internal timer counter to trigger a scheduled spawning of SpawnTemplatePrefix. self.SpawnSetTimer = 0 -- The internal timer value when a scheduled spawning of SpawnTemplatePrefix occurs. @@ -490,7 +490,7 @@ end --- Will start the spawning scheduler. -- Note: This function is called automatically when @{#SPAWN.Scheduled} is called. function SPAWN:SpawnScheduleStart() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) --local ClientUnit = #AlivePlayerUnits() @@ -507,7 +507,7 @@ end --- Will stop the scheduled spawning scheduler. function SPAWN:SpawnScheduleStop() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self.SpawnIsScheduled = false end @@ -516,14 +516,14 @@ 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 self --- @param #UNIT HostUnit The air or ground unit dropping or unloading the group. +-- @param Unit#UNIT HostUnit The air or ground unit dropping or unloading the group. -- @param #number OuterRadius The outer radius in meters where the new group will be spawned. -- @param #number InnerRadius The inner radius in meters where the new group will NOT be spawned. -- @param #number SpawnIndex (Optional) The index which group to spawn within the given zone. --- @return GROUP#GROUP that was spawned. +-- @return Group#GROUP that was spawned. -- @return #nil Nothing was spawned. function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, HostUnit, OuterRadius, InnerRadius, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, HostUnit, OuterRadius, InnerRadius, SpawnIndex } ) if HostUnit and HostUnit:IsAlive() then -- and HostUnit:getUnit(1):inAir() == false then @@ -566,14 +566,14 @@ function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex ) SpawnTemplate.units[UnitID].x = UnitPoint.x SpawnTemplate.units[UnitID].y = UnitPoint.y else - local CirclePos = routines.getRandPointInCircle( UnitPoint, InnerRadius+1, InnerRadius ) + local CirclePos = routines.getRandPointInCircle( UnitPoint, OuterRadius, InnerRadius ) SpawnTemplate.units[UnitID].x = CirclePos.x SpawnTemplate.units[UnitID].y = CirclePos.y end self:T( 'SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) end - local SpawnPos = routines.getRandPointInCircle( UnitPoint, InnerRadius+1, InnerRadius ) + local SpawnPos = routines.getRandPointInCircle( UnitPoint, OuterRadius, InnerRadius ) local Point = {} Point.type = "Turning Point" Point.x = SpawnPos.x @@ -598,7 +598,7 @@ end -- @return GROUP#GROUP that was spawned. -- @return #nil when nothing was spawned. function SPAWN:SpawnInZone( Zone, SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, Zone, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, Zone, SpawnIndex } ) if Zone then @@ -652,7 +652,7 @@ end -- This will be similar to the uncontrolled flag setting in the ME. -- @return #SPAWN self function SPAWN:UnControlled() - self:T( { self.SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix } ) self.SpawnUnControlled = true @@ -670,7 +670,7 @@ end -- @param #number SpawnIndex Is the number of the Group that is to be spawned. -- @return string SpawnGroupName function SPAWN:SpawnGroupName( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) local SpawnPrefix = self.SpawnTemplatePrefix if self.SpawnAliasPrefix then @@ -694,7 +694,7 @@ end -- @return GROUP#GROUP, #number The group found, the new index where the group was found. -- @return #nil, #nil When no group is found, #nil is returned. function SPAWN:GetFirstAliveGroup( SpawnCursor ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) for SpawnIndex = 1, self.SpawnCount do local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) @@ -714,7 +714,7 @@ end -- @return GROUP#GROUP, #number The group found, the new index where the group was found. -- @return #nil, #nil When no group is found, #nil is returned. function SPAWN:GetNextAliveGroup( SpawnCursor ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnCursor } ) SpawnCursor = SpawnCursor + 1 for SpawnIndex = SpawnCursor, self.SpawnCount do @@ -730,7 +730,7 @@ end --- Find the last alive group during runtime. function SPAWN:GetLastAliveGroup() - self:T( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) + self:F( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) self.SpawnIndex = self:_GetLastIndex() for SpawnIndex = self.SpawnIndex, 1, -1 do @@ -754,7 +754,7 @@ end -- @param #number SpawnIndex The index of the group to return. -- @return GROUP#GROUP function SPAWN:GetGroupFromIndex( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) if SpawnIndex then local SpawnGroup = self.SpawnGroups[SpawnIndex].Group @@ -773,7 +773,7 @@ end -- @return #string The prefix -- @return #nil Nothing found function SPAWN:_GetGroupIndexFromDCSUnit( DCSUnit ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) if DCSUnit and DCSUnit:getName() then local IndexString = string.match( DCSUnit:getName(), "#.*-" ):sub( 2, -2 ) @@ -797,7 +797,7 @@ end -- @return #string The prefix -- @return #nil Nothing found function SPAWN:_GetPrefixFromDCSUnit( DCSUnit ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) if DCSUnit and DCSUnit:getName() then local SpawnPrefix = string.match( DCSUnit:getName(), ".*#" ) @@ -813,7 +813,7 @@ end --- Return the group within the SpawnGroups collection with input a DCSUnit. function SPAWN:_GetGroupFromDCSUnit( DCSUnit ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) if DCSUnit then local SpawnPrefix = self:_GetPrefixFromDCSUnit( DCSUnit ) @@ -833,7 +833,7 @@ end --- Get the index from a given group. -- The function will search the name of the group for a #, and will return the number behind the #-mark. function SPAWN:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) local IndexString = string.match( SpawnGroup:GetName(), "#.*$" ):sub( 2 ) local Index = tonumber( IndexString ) @@ -845,14 +845,14 @@ end --- Return the last maximum index that can be used. function SPAWN:_GetLastIndex() - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) return self.SpawnMaxGroups end --- Initalize the SpawnGroups collection. function SPAWN:_InitializeSpawnGroups( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) if not self.SpawnGroups[SpawnIndex] then self.SpawnGroups[SpawnIndex] = {} @@ -899,7 +899,7 @@ end --- Gets the CountryID of the Group with the given SpawnPrefix function SPAWN:_GetGroupCountryID( SpawnPrefix ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) local TemplateGroup = Group.getByName( SpawnPrefix ) @@ -914,7 +914,7 @@ end --- Gets the Group Template from the ME environment definition. -- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE. function SPAWN:_GetTemplate( SpawnTemplatePrefix ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) local SpawnTemplate = nil @@ -934,7 +934,7 @@ end --- Prepares the new Group Template. function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) @@ -967,7 +967,7 @@ end -- @param #number SpawnIndex The index of the group to be spawned. -- @return #SPAWN function SPAWN:_RandomizeRoute( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) if self.SpawnRandomizeRoute then local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate @@ -988,7 +988,7 @@ end function SPAWN:_RandomizeTemplate( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) if self.SpawnRandomizeTemplate then self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ] @@ -1007,7 +1007,7 @@ function SPAWN:_RandomizeTemplate( SpawnIndex ) end function SPAWN:_TranslateRotate( SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) -- Translate local TranslatedX = SpawnX @@ -1051,7 +1051,7 @@ end --- Get the next index of the groups to be spawned. This function is complicated, as it is used at several spaces. function SPAWN:_GetSpawnIndex( SpawnIndex ) - self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then @@ -1170,7 +1170,7 @@ end --- This function is called automatically by the Spawning scheduler. -- It is the internal worker method SPAWNing new Groups on the defined time intervals. function SPAWN:_Scheduler() -self:T( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) + self:F( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) if self.SpawnInit or self.SpawnCurrentTimer == self.SpawnSetTimer then -- Validate if there are still groups left in the batch... @@ -1188,7 +1188,7 @@ self:T( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.Sp end function SPAWN:_SpawnCleanUpScheduler() - self:T( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) + self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) local SpawnCursor local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup( SpawnCursor ) diff --git a/Moose/Stage.lua b/Moose/Stage.lua index cfd4c00a3..11301093f 100644 --- a/Moose/Stage.lua +++ b/Moose/Stage.lua @@ -29,7 +29,7 @@ STAGE = { function STAGE:New() local self = BASE:Inherit( self, BASE:New() ) - self:T() + self:F() return self end @@ -61,14 +61,14 @@ STAGEBRIEF = { function STAGEBRIEF:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGEBRIEF:Execute( Mission, Client, Task ) local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) - self:T() + self:F() Mission:ShowBriefing( Client ) self.StageBriefingTime = timer.getTime() return Valid @@ -98,13 +98,13 @@ STAGESTART = { function STAGESTART:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGESTART:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) if Task.TaskBriefing then Client:Message( Task.TaskBriefing, 30, Mission.Name .. "/Stage", "Mission Command: Tasking" ) @@ -116,7 +116,7 @@ self:T() end function STAGESTART:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) if timer.getTime() - self.StageStartTime <= self.StageStartDuration then @@ -136,13 +136,13 @@ STAGE_CARGO_LOAD = { function STAGE_CARGO_LOAD:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGE_CARGO_LOAD:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) for LoadCargoID, LoadCargo in pairs( Task.Cargos.LoadCargos ) do @@ -157,7 +157,7 @@ self:T() end function STAGE_CARGO_LOAD:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) return 1 @@ -170,13 +170,13 @@ STAGE_CARGO_INIT = { function STAGE_CARGO_INIT:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGE_CARGO_INIT:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) for InitLandingZoneID, InitLandingZone in pairs( Task.LandingZones.LandingZones ) do @@ -196,7 +196,7 @@ end function STAGE_CARGO_INIT:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) return 1 @@ -213,7 +213,7 @@ STAGEROUTE = { function STAGEROUTE:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' self.MessageSwitch = true return self @@ -221,7 +221,7 @@ end function STAGEROUTE:Execute( Mission, Client, Task ) -self:T() + self:F() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) local RouteMessage = "Fly to " @@ -239,7 +239,7 @@ self:T() end function STAGEROUTE:Validate( Mission, Client, Task ) -self:T() + self:F() local Valid = STAGE:Validate( Mission, Client, Task ) -- check if the Client is in the landing zone @@ -274,13 +274,13 @@ STAGELANDING = { function STAGELANDING:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGELANDING:Execute( Mission, Client, Task ) -self:T() + self:F() Client:Message( "We have arrived at the landing zone.", self.MSG.TIME, Mission.Name .. "/StageArrived", "Co-Pilot: Arrived", 10 ) @@ -332,7 +332,7 @@ self:T() end function STAGELANDING:Validate( Mission, Client, Task ) -self:T() + self:F() Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.LandingZones.LandingZoneNames ) if Task.CurrentLandingZoneName then @@ -376,13 +376,13 @@ STAGELANDED = { function STAGELANDED:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGELANDED:Execute( Mission, Client, Task ) -self:T() + self:F() if Task.IsLandingRequired then Client:Message( 'We have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType .. '.', @@ -398,7 +398,7 @@ end function STAGELANDED:Validate( Mission, Client, Task ) -self:T() + self:F() if not routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName ) then self:T( "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." ) @@ -431,20 +431,20 @@ STAGEUNLOAD = { function STAGEUNLOAD:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGEUNLOAD:Execute( Mission, Client, Task ) -self:T() + self:F() Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', self.MSG.TIME, Mission.Name .. "/StageUnLoad", "Co-Pilot: Unload" ) Task:RemoveCargoMenus( Client ) end function STAGEUNLOAD:Executing( Mission, Client, Task ) -self:T() + self:F() env.info( 'STAGEUNLOAD:Executing() Task.Cargo.CargoName = ' .. Task.Cargo.CargoName ) local TargetZoneName @@ -464,7 +464,7 @@ self:T() end function STAGEUNLOAD:Validate( Mission, Client, Task ) -self:T() + self:F() env.info( 'STAGEUNLOAD:Validate()' ) if routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.CurrentLandingZoneName ) then @@ -503,13 +503,13 @@ STAGELOAD = { function STAGELOAD:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGELOAD:Execute( Mission, Client, Task ) -self:T() + self:F() if not Task.IsSlingLoad then Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', @@ -524,13 +524,13 @@ self:T() end function STAGELOAD:Executing( Mission, Client, Task ) -self:T() + self:F() -- If the Cargo is ready to be loaded, load it into the Client. if not Task.IsSlingLoad then - trace.i(self.ClassName, Task.Cargo.CargoName) + self:T( Task.Cargo.CargoName) if Task.Cargo:OnBoarded( Client, Task.CurrentCargoZone ) then @@ -553,12 +553,12 @@ self:T() if Cargo:IsSlingLoad() then local CargoStatic = StaticObject.getByName( Cargo.CargoStaticName ) if CargoStatic then - trace.i(self.ClassName, "Cargo is found in the DCS simulator.") + self:T( "Cargo is found in the DCS simulator.") local CargoStaticPosition = CargoStatic:getPosition().p - trace.i(self.ClassName, "Cargo Position x = " .. CargoStaticPosition.x .. ", y = " .. CargoStaticPosition.y .. ", z = " .. CargoStaticPosition.z ) + self:T( "Cargo Position x = " .. CargoStaticPosition.x .. ", y = " .. CargoStaticPosition.y .. ", z = " .. CargoStaticPosition.z ) local CargoStaticHeight = routines.GetUnitHeight( CargoStatic ) if CargoStaticHeight > 5 then - trace.i(self.ClassName, "Cargo is airborne.") + self:T( "Cargo is airborne.") Cargo:StatusLoaded() Task.Cargo = Cargo Client:Message( 'The Cargo has been successfully hooked onto the helicopter and is now being sling loaded. Fly outside the landing zone.', @@ -576,7 +576,7 @@ self:T() end function STAGELOAD:Validate( Mission, Client, Task ) -self:T() + self:F() self:T( "Task.CurrentLandingZoneName = " .. Task.CurrentLandingZoneName ) @@ -635,18 +635,18 @@ STAGEDONE = { function STAGEDONE:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'AI' return self end function STAGEDONE:Execute( Mission, Client, Task ) -self:T() + self:F() end function STAGEDONE:Validate( Mission, Client, Task ) -self:T() + self:F() Task:Done() @@ -661,20 +661,20 @@ STAGEARRIVE = { function STAGEARRIVE:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'CLIENT' return self end function STAGEARRIVE:Execute( Mission, Client, Task ) -self:T() + self:F() Client:Message( 'We have arrived at ' .. Task.CurrentLandingZoneName .. ".", self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Arrived" ) end function STAGEARRIVE:Validate( Mission, Client, Task ) -self:T() + self:F() Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:GetClientGroupDCSUnit(), Task.LandingZones ) if ( Task.CurrentLandingZoneID ) then @@ -695,7 +695,7 @@ STAGEGROUPSDESTROYED = { function STAGEGROUPSDESTROYED:New() local self = BASE:Inherit( self, STAGE:New() ) - self:T() + self:F() self.StageType = 'AI' return self end @@ -707,7 +707,7 @@ end --end function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task ) -self:T() + self:F() if Task.MissionTask:IsGoalReached() then return 1 @@ -717,7 +717,7 @@ self:T() end function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task ) -self:T() + self:F() self:T( { Task.ClassName, Task.Destroyed } ) --env.info( 'Event Table Task = ' .. tostring(Task) ) diff --git a/Moose/Task.lua b/Moose/Task.lua index e75a03670..3481963a2 100644 --- a/Moose/Task.lua +++ b/Moose/Task.lua @@ -48,10 +48,9 @@ TASK = { --- Instantiates a new TASK Base. Should never be used. Interface Class. -- @return TASK function TASK:New() -trace.f(self.ClassName) - local self = BASE:Inherit( self, BASE:New() ) - + self:F() + -- assign Task default values during construction self.TaskBriefing = "Task: No Task." self.Time = timer.getTime() @@ -61,14 +60,14 @@ trace.f(self.ClassName) end function TASK:SetStage( StageSequenceIncrement ) -trace.f(self.ClassName, { StageSequenceIncrement } ) + self:F( { StageSequenceIncrement } ) local Valid = false if StageSequenceIncrement ~= 0 then self.ActiveStage = self.ActiveStage + StageSequenceIncrement if 1 <= self.ActiveStage and self.ActiveStage <= #self.Stages then self.Stage = self.Stages[self.ActiveStage] - trace.i( self.ClassName, { self.Stage.Name } ) + self:T( { self.Stage.Name } ) self.Frequency = self.Stage.Frequency Valid = true else @@ -81,7 +80,7 @@ trace.f(self.ClassName, { StageSequenceIncrement } ) end function TASK:Init() -trace.f(self.ClassName) + self:F() self.ActiveStage = 0 self:SetStage(1) self.TaskDone = false @@ -92,7 +91,7 @@ end --- Get progress of a TASK. -- @return string GoalsText function TASK:GetGoalProgress() -trace.f(self.ClassName) + self:F() local GoalsText = "" for GoalVerb, GoalVerbData in pairs( self.GoalTasks ) do @@ -116,7 +115,7 @@ end -- @param MISSION Mission Group structure describing the Mission. -- @param CLIENT Client Group structure describing the Client. function TASK:ShowGoalProgress( Mission, Client ) -trace.f(self.ClassName) + self:F() local GoalsText = "" for GoalVerb, GoalVerbData in pairs( self.GoalTasks ) do @@ -138,32 +137,32 @@ end --- Sets a TASK to status Done. function TASK:Done() -trace.f(self.ClassName) + self:F() self.TaskDone = true end --- Returns if a TASK is done. -- @return bool function TASK:IsDone() - trace.i( self.ClassName, self.TaskDone ) + self:F( self.TaskDone ) return self.TaskDone end --- Sets a TASK to status failed. function TASK:Failed() -trace.f(self.ClassName) + self:F() self.TaskFailed = true end --- Returns if a TASk has failed. -- @return bool function TASK:IsFailed() - trace.i( self.ClassName, self.TaskFailed ) + self:F( self.TaskFailed ) return self.TaskFailed end function TASK:Reset( Mission, Client ) -trace.f(self.ClassName) + self:F() self.ExecuteStage = _TransportExecuteStage.NONE end @@ -177,7 +176,7 @@ end -- @param ?string GoalVerb is the name of the Goal of the TASK. -- @return bool function TASK:Goal( GoalVerb ) -trace.f(self.ClassName) + self:F() if not GoalVerb then GoalVerb = self.GoalVerb end @@ -192,7 +191,7 @@ end -- @param number GoalTotal is the number of times the GoalVerb needs to be achieved. -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. function TASK:SetGoalTotal( GoalTotal, GoalVerb ) -trace.f(self.ClassName, { GoalTotal, GoalVerb } ) + self:F( { GoalTotal, GoalVerb } ) if not GoalVerb then GoalVerb = self.GoalVerb @@ -207,7 +206,7 @@ end --- Gets the total of Goals to be achieved within the TASK of the GoalVerb. -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. function TASK:GetGoalTotal( GoalVerb ) -trace.f(self.ClassName) + self:F() if not GoalVerb then GoalVerb = self.GoalVerb end @@ -223,7 +222,7 @@ end -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. -- @return TASK function TASK:SetGoalCount( GoalCount, GoalVerb ) -trace.f(self.ClassName) + self:F() if not GoalVerb then GoalVerb = self.GoalVerb end @@ -238,7 +237,7 @@ end -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. -- @return TASK function TASK:IncreaseGoalCount( GoalCountIncrease, GoalVerb ) -trace.f(self.ClassName) + self:F() if not GoalVerb then GoalVerb = self.GoalVerb end @@ -252,7 +251,7 @@ end -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. -- @return TASK function TASK:GetGoalCount( GoalVerb ) -trace.f(self.ClassName) + self:F() if not GoalVerb then GoalVerb = self.GoalVerb end @@ -267,7 +266,7 @@ end -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. -- @return TASK function TASK:GetGoalPercentage( GoalVerb ) -trace.f(self.ClassName) + self:F() if not GoalVerb then GoalVerb = self.GoalVerb end @@ -285,10 +284,10 @@ function TASK:IsGoalReached( ) local GoalReached = true for GoalVerb, Goals in pairs( self.GoalTasks ) do - trace.i( self.ClassName, { "GoalVerb", GoalVerb } ) + self:T( { "GoalVerb", GoalVerb } ) if self:Goal( GoalVerb ) then local GoalToDo = self:GetGoalTotal( GoalVerb ) - self:GetGoalCount( GoalVerb ) - trace.i( self.ClassName, "GoalToDo = " .. GoalToDo ) + self:T( "GoalToDo = " .. GoalToDo ) if GoalToDo <= 0 then else GoalReached = false @@ -299,7 +298,7 @@ function TASK:IsGoalReached( ) end end - trace.i( self.ClassName, GoalReached ) + self:T( GoalReached ) return GoalReached end @@ -308,7 +307,7 @@ end -- @param string GoalTask is a text describing the Goal of the TASK to be achieved. -- @param number GoalIncrease is a number by which the Goal achievement is increasing. function TASK:AddGoalCompletion( GoalVerb, GoalTask, GoalIncrease ) -trace.f( self.ClassName, { GoalVerb, GoalTask, GoalIncrease } ) + self:F( { GoalVerb, GoalTask, GoalIncrease } ) if self:Goal( GoalVerb ) then self.GoalTasks[GoalVerb].Goals[#self.GoalTasks[GoalVerb].Goals+1] = GoalTask @@ -321,7 +320,7 @@ end -- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used. -- @return string Goals function TASK:GetGoalCompletion( GoalVerb ) -trace.f( self.ClassName, { GoalVerb } ) + self:F( { GoalVerb } ) if self:Goal( GoalVerb ) then local Goals = "" @@ -331,14 +330,12 @@ trace.f( self.ClassName, { GoalVerb } ) end function TASK.MenuAction( Parameter ) -trace.menu("TASK","MenuAction") - trace.l( "TASK", "MenuAction" ) Parameter.ReferenceTask.ExecuteStage = _TransportExecuteStage.EXECUTING Parameter.ReferenceTask.Cargo = Parameter.CargoTask end function TASK:StageExecute() -trace.f(self.ClassName) + self:F() local Execute = false @@ -357,7 +354,7 @@ end --- Work function to set signal events within a TASK. function TASK:AddSignal( SignalUnitNames, SignalType, SignalColor, SignalHeight ) -trace.f(self.ClassName) + self:F() local Valid = true @@ -388,7 +385,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddSmokeRed( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.RED, SignalHeight ) end @@ -396,7 +393,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddSmokeGreen( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.GREEN, SignalHeight ) end @@ -404,7 +401,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddSmokeBlue( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.BLUE, SignalHeight ) end @@ -412,7 +409,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddSmokeWhite( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.WHITE, SignalHeight ) end @@ -420,7 +417,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddSmokeOrange( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.ORANGE, SignalHeight ) end @@ -428,7 +425,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddFlareRed( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.RED, SignalHeight ) end @@ -436,7 +433,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddFlareGreen( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.GREEN, SignalHeight ) end @@ -444,7 +441,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddFlareBlue( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.BLUE, SignalHeight ) end @@ -452,7 +449,7 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddFlareWhite( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.WHITE, SignalHeight ) end @@ -460,6 +457,6 @@ end -- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone. -- @param number SignalHeight Altitude that the Signal should be fired... function TASK:AddFlareOrange( SignalUnitNames, SignalHeight ) -trace.f(self.ClassName) + self:F() self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.ORANGE, SignalHeight ) end diff --git a/Moose/Unit.lua b/Moose/Unit.lua index b83de9d14..18b410ae9 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -21,7 +21,7 @@ UNIT = { function UNIT:New( DCSUnit ) local self = BASE:Inherit( self, BASE:New() ) - self:T( DCSUnit:getName() ) + self:F( DCSUnit:getName() ) self.DCSUnit = DCSUnit self.UnitName = DCSUnit:getName() @@ -31,39 +31,39 @@ function UNIT:New( DCSUnit ) end function UNIT:IsAlive() - self:T( self.UnitName ) + self:F( self.UnitName ) return ( self.DCSUnit and self.DCSUnit:isExist() ) end function UNIT:GetDCSUnit() - self:T( self.DCSUnit ) + self:F( self.DCSUnit ) return self.DCSUnit end function UNIT:GetID() - self:T( self.UnitID ) + self:F( self.UnitID ) return self.UnitID end function UNIT:GetName() - self:T( self.UnitName ) + self:F( self.UnitName ) return self.UnitName end function UNIT:GetTypeName() - self:T( self.UnitName ) + self:F( self.UnitName ) return self.DCSUnit:getTypeName() end function UNIT:GetPrefix() - self:T( self.UnitName ) + self:F( self.UnitName ) local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) self:T( UnitPrefix ) @@ -73,14 +73,14 @@ end function UNIT:GetCallSign() - self:T( self.UnitName ) + self:F( self.UnitName ) return self.DCSUnit:getCallsign() end function UNIT:GetPointVec2() - self:T( self.UnitName ) + self:F( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p @@ -94,7 +94,7 @@ end function UNIT:GetPositionVec3() - self:T( self.UnitName ) + self:F( self.UnitName ) local UnitPos = self.DCSUnit:getPosition().p @@ -103,7 +103,7 @@ function UNIT:GetPositionVec3() end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) - self:T( { self.UnitName, AwaitUnit.UnitName, Radius } ) + self:F( { self.UnitName, AwaitUnit.UnitName, Radius } ) local UnitPos = self:GetPositionVec3() local AwaitUnitPos = AwaitUnit:GetPositionVec3() diff --git a/Moose/Zone.lua b/Moose/Zone.lua index 8c710eacc..760a15fd6 100644 --- a/Moose/Zone.lua +++ b/Moose/Zone.lua @@ -13,9 +13,8 @@ ZONE = { } function ZONE:New( ZoneName ) -trace.f( self.ClassName, ZoneName ) - local self = BASE:Inherit( self, BASE:New() ) + self:F( ZoneName ) local Zone = trigger.misc.getZone( ZoneName ) @@ -31,7 +30,7 @@ trace.f( self.ClassName, ZoneName ) end function ZONE:GetPointVec2() - self:T( self.ZoneName ) + self:F( self.ZoneName ) local Zone = trigger.misc.getZone( self.ZoneName ) local Point = { x = Zone.point.x, y = Zone.point.z } @@ -42,7 +41,7 @@ function ZONE:GetPointVec2() end function ZONE:GetRandomPoint() -trace.f( self.ClassName, self.ZoneName ) + self:F( self.ZoneName ) local Point = {} @@ -51,18 +50,17 @@ trace.f( self.ClassName, self.ZoneName ) Point.x = Zone.point.x + math.random( Zone.radius * -1, Zone.radius ) Point.y = Zone.point.z + math.random( Zone.radius * -1, Zone.radius ) - trace.i( self.ClassName, { Zone } ) - trace.i( self.ClassName, { Point } ) + self:T( { Zone, Point } ) return Point end function ZONE:GetRadius() -trace.f( self.ClassName, self.ZoneName ) + self:F( self.ZoneName ) local Zone = trigger.misc.getZone( self.ZoneName ) - trace.i( self.ClassName, { Zone } ) + self:T( { Zone } ) return Zone.radius end diff --git a/Moose/Trace.lua b/Trash/Trace.lua similarity index 100% rename from Moose/Trace.lua rename to Trash/Trace.lua From 6834a5f6eaee0afabcde2e8449e4bcd15a6dd10e Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 29 Mar 2016 09:37:32 +0200 Subject: [PATCH 11/14] Completed a first version of an escort follow function!!! And made a test mission for it. --- Loaders/MOOSE-Template.miz | Bin 0 -> 86575 bytes Moose/Base.lua | 2 +- Moose/Client.lua | 9 ++- Moose/Escort.lua | 75 +++++++++++++++++- Moose/Group.lua | 39 ++++++++- Moose/Unit.lua | 2 +- .../lua/MOOSE_Escort_Test_Follow.lua | 19 +++++ Test Missions/{ => lua}/MOOSE_Pickup_Test.lua | 0 Test Missions/{ => lua}/MOOSE_Spawn_Test.lua | 0 .../miz/MOOSE_Escort_Test_Follow.miz | Bin 0 -> 39292 bytes Test Missions/{ => miz}/MOOSE_Pickup_Test.miz | Bin Test Missions/{ => miz}/MOOSE_Spawn_Test.miz | Bin 12 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 Loaders/MOOSE-Template.miz create mode 100644 Test Missions/lua/MOOSE_Escort_Test_Follow.lua rename Test Missions/{ => lua}/MOOSE_Pickup_Test.lua (100%) rename Test Missions/{ => lua}/MOOSE_Spawn_Test.lua (100%) create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow.miz rename Test Missions/{ => miz}/MOOSE_Pickup_Test.miz (100%) rename Test Missions/{ => miz}/MOOSE_Spawn_Test.miz (100%) diff --git a/Loaders/MOOSE-Template.miz b/Loaders/MOOSE-Template.miz new file mode 100644 index 0000000000000000000000000000000000000000..108e949f105d14dc08b0130f795a99079fd5be7d GIT binary patch literal 86575 zcmaI6b8u$Svo@MZ@+O%WZ)_VATNB&1ZQFJ-v2EM7ZQJG~x$`^U{px<_+*|jL-qqD> zuX>){UA=bqs+N-k0|$bDf6+Qe&Dhdwf7}-bR?k}ZtKUvJ*81FEbHE%cw~S@W;F}g@!C-D0gwEP zin;b^83ckC33$0e+i96-yD?w$mW{me9B;F&x$N%R|9D>gP_QNUMm_8haP0iMRaqbn zGKTj0H|fDW_A_%hnV)cEE5~{0J4PRzigsN}iWo=|;&Y>aIVq%C>V|w=tcX+_A zS<7^V8=QX62(9p5%!z~}W)2`w2hAslMV>hoa5|MibK>ax3of70U(WIHkmvTw#Y#?h zz6RjI4q(t46f2Njo~Q|n^dbY8zF|PlU914-zrr7PwMBIQnw@)li(MwRJrLsh&qn1A zd$5AB+B4wNlw@r7l8$^&-5tG2n;!Cs2#B(9#@ga;`DO#MzBc-ELK7cV-5pP4MGL0v zU-BK99?)|F!yd3ro?F>QOeK1l_$xYl+^Sy-`|Mv14}}I)xz1%*&U2ZdPrT$zEtHwZ zmTZK9P;FmXK3);@J@6*>?7EOS`ki}M_Ns002U4jfyTnXv8sLdD7;h%WH&3)58wV5q zAG24R!4>!9+I-GQi51hI_BBL5pVT_Ju*NRhA@Jdq~mfymF2NU(@aSO>0qDHGyTo%l+)L$lEu9ch4*Q|Y- z9B^>@3Y_Pbt$$1O;B@ZxxU4Y&X6wT{Z~DyPe@mWR1My>OIAwNg7>AVHRAE8CoA5gw zh97+9Q}(+A1Xp(D4e)Yw%y&KuRg&g?H9S5gtnAj-;k<2bWJq4HT_aBbf(?3T zB{Dg%G}M<5176u;#FKl{Zx47NkxW0|jN72f+nwqy-8b4E3D*>R3KIhHBfyc}=E&ae zPgi_DM)gwjpD^Hn)ss6CSDAbi5 zD2-@J;fd>;`&?&lXNcJtBzh|sYmPmP&V6J_pc@MQW{2r4Ibvcj+3$@_iQGr;fj<_b z{J4-#!V1uaCfPQ;v@NjXq1=cJ8~Jv=OZa=b&)t%f-6?ItQattL-~lbAI4J5W@Q6{f z<61icuIVImi$mjZfWM{BM7#D;Ik$brqB4P**k^s7i$>4LSe+CMLig^^?E1K0)F2oY5%-?XCwOr71-kr4I zj9ht@zE)$x*XZN$hBRDFTxX-g1;cccJEyr8DzqHsXN0&lP3s`~z)xU%{4A+YsAoC9#os@<)G1N!)h^rc`)jhbMrePWCL`J=v>VE+?Bj$E8e`K0($T zHYI$Ju2i-r!P4AlT>Soy9q zw%>=V@<>)jH#fk;Jp#0=Q}T4nnLf{Tg(q}7%K^HpgXwlD>vzpHj+f&&=Ie1PDzCSr z1iFtS`E3Rl*v=;E>wXf-?a*B1pCCde66BDr7sv-8azQz|zOgkh@)H0%hv)8LCkXio z>0^LwF8U@{uuiQ5pnGo{@EY=_g0(^{UEbxoAxy_ZB#PhOH*==*4fRoW_r~>9RC1{j zjM@&0naH+BQ#;Fem_!42d31SDGe_<6`O1Xe{|tKL1R40c{IfW?XS(~Pog04TiCyc2 zH5O^bvka*5WATOxS5#;aS~9zH^2AJB>J7olv(R<2i0=wE;AtX(<5T80g2^a^xNonQ z?%gaPceE#t6EH&Fal?U5Xy}0@^Viwr&!wSJj9bs`Z`&^K?_E*`ynUq%N6Y^_09`{H zMDD6ydH3k?57ZKjX^MTr$t1FbhzJtl%-AtKOI$nVC7-o}>6QD4W1(1fzQLbNqMa$~ zC!dQM!D)e##pYp;YVUGXG?%6KnUf=`pS(;LGm~_`m}I}dXC?L5RD*rs`* zH>2mCxqDy|qSDrqyPl_TPRgrF=OKZ>sr>GKv8yC=3S)*ocHIWd4gNl_N+v`}*5QmC z#br!+_6bZwDz?F2cZ4KVWc%d;8{(twD5xhrrbmgYrw!R~V#h=e zSOV~8MfkPTj1<1X_-fFVD1s=+o<1q}0ck&-gHu+(__KccbJl>Ir|8|!+XpNi+Yeiv zs9BkUG&|<`J8Q&L;nN)ZJhlNBIY7<@!57sziZe!MsEsk^0U&1zVlt@Pd)Bp4+0?L= zk|2wJph_iD^V@pdsE3>YdJkB1aIL!Dk1I; zH6%+nJtTOUtFTy)svN>WyhhCFIsFhOW16&gs}*j1)%aPkgS|ulPC3Q++FEcF_8%y_ zyU*hfU{OF`1+S0Ko$p)vMv_g)pym@hs$R?%O9aUH3lgQDZC>7eQPZD_-zBUJJl$iZLdD@Zn2C>Vh`qR0Ip7h>c1+U zzekd~PR+oXC@n!!v$fraV44w@B4vhMd{XND+u3>q`)qmCB_g^o1)bf;4V4zZC9iC9 zOaQqafs~|ZXXZrT1wN0#{&0aN7rl3EyO;z7n?&-MD+YI>_I-Pnl}6RI6MKn4G~3t{ zp_~;Dp%5sAdAu%2g$hboo1({xu&gjn8mN--m5khX?_%X%>~r7|as+o-cjQ6FOPiR$ ziePEYVJDtg#$Lzvbn@l63m0d>hE~Hq&YPe>hf~@#)L$TV&D1lf5CL*fKE+1(yZA&S z+k*2%6(L*)gUh2>lt*=Fe5tj|v4}($;A*|6gba~J5fKuFB9+(NEvIG@= zx6;=Aw~@PNlmAt-enoP>RkPwmX+n|S@b9g;Yo!x3YdK!5n9OGO$ogg+kbI*mxTcz` zkw{+tm2$HWvJ&Q2JxiEi*^J7nUwCK59+7l%Ri1?g${Z`2ASTxC{7UAD+AkjD2()sA zTD1nl9AX)4fg;uCSm}Qg$p_Y~wynm{5P(z7vpU1`io^hOf{SL_0f+#fFahw0AdRAr zQ-zgUTK5$)w4zxoX(ZC8nzHZH=+29eJk#>PypFblW;OO8^OlGO_?8Gqkd}x6=L)NyUpI4NSQ!qSiWqTCMZNPRPb2&fHhdhgrc0GdEVZHWX zoyWR$dqt6Ww13sdl90;TTdloNd!6__;UP6Hs;S8e7;J<8+QY!)zF+Uqs)ft?B(Y|s zyMe1Z+r}}q701kI3039ejm;IIn+RdG8K|G^uk4`#Q_3?Fu2j@OsTK=Fja4-=3)ESu z>+B|iFandkz_>*z^L`ArXg^zxUsvuQ(AcpYB$k%W%=~DAOALikGXuRlL&wvO3Z>;} z<>yDRv+_Sv=!=YR{3mL+2H>gr#2bsW8>b}@p_j!JK`OIAKzJe#`QKH~haR_vUGZt7 zFr40X!O;a`w;LD7ZT^*Or3s9&G-9y5N?Jf1&6@KlzhtCqNkw%@#yiNF9HsG(-bz~N zFsd^aA?(j8?{YH9u;TP#+4ju62(QMcu28T2rhcnii-mcH4DfebM3ck_l9N#9YUP1D z5!dEGDYSvP;gAdMjFp6TLw7SkXT8?`AteEt1~xY_!R&j9Kf#vP!{{l;ZRYJ8DGWs% zlR>J0I-fx*sf5kfbB-rlo>8dgQ3pE&&x_VVt%gH!+7D~D?6#r_o>B!-TJ~Z=0&F}5 z{q)01S7k_B}a%AUtP(F<9WA4MY^F{K0J z;!+=hJX}59D|clyMYoK2SKItGeKb1TOgQd9Or4!XK=unb|E#+^`=Hc4^Mc zHJuM9qqqM0gqWXum;J`#&jlrCK-{wMP}yE80X`D4&~~sM35IDjL>Kq5MrQ6?7qV=y-o>k6 zClleR_)CL?G9PI^6g^eF8FaJo^()H#mINnk2%+`U^xdM&g*T6(aXQy< z#@Tx0U5_Dcxd*w8xIhTwK2VKFk+mHAl;8>r@G0UEzP?kUR={x(!^V>n_zAxzUqx6( z9_~keY&TUJKT^}|Qqw_9e@DqvTFf)6t$p6qh++SUvT5++*1|Y_g5HH4TSNe7B0XL` zs6~BBDxLc@&}ys?0jk;myKeWiWM@jHNR~{alN65EkbfCL(#VWao<0HJkbwYTsKYLb zeug%S8Cw{uwrvR9JV7QAf7q()oKTd#+A-pAcF?$j9e*F@luUZW)hM`&c4ZPNKAW98 zV&*W5dg=;c7T<-Pspn~oebcX$^!8~HrSx(UMFenTuEbPtd#)I&6N{*)_J6@7P?`I3 zJ3dUi%QC34jx*X=HQYpB!-}tfL+A6im2wL^U?;4~j7IeDEz#bl zq3>1o04RwNl3OsUW=*8({*XV9AjcW)2gte+5lE^w5_exB z))|x98@FY7VRs%AteU{XX7}KzI%2OPSX1gl@}pAeLCPPKppRoe_2ye8NkOT;t%mM4 znI6xYVGrZoA5SlkrMll~URDwNBJly@Th=F49iET&^{Z&H=*-zA)%O)4(To#ujCY;< zt7Sr>)8nr__|9UsBHpbydZQy7j?NN44!aXn(*N|Rz(QJldNYMGqON)|iS-L!qS1%| z?1K9<-4`(t26ja(0}Tlw6=!qeN+j0bwQts4v^@!41b`q7-Bk#3MT+zG9k64X_x$Wb z$n)m){BHq^ERo&Uv4wP6{QE#U^*G`Qaa}86A~>jKc~D}uaFHGsjoQIliVM@cIwA2K zYz^1-`tAGL<(G~-F?8iBOIZvkkXH94P91hJ4dG%IQ9OX%&~pAg7=qP0PwQ49%vhE* zq6{HdGT{Ve(tN;a188e>c_nZ#Tli}+<$;+-SfyvlT_S94s4*`BIZDZnUQtQZ99w~* zxezWtj{sU!+KO^MPic$QXiI>92(-K%Ff6)!F5OH_ag3< zjI)hBp{_X$0tmx}C@iSbT65+>9;L75G>_O^b0)YnBb6b#HkLkqAlpw9rW^aVs1@y9^$&pqh_Pzy9%>d)iOb&SwZUCQa?2%U9Dx~nYDZ) zWe5~}MWe%nqoBXy7Tik?qIv4J<}#b|nXPxoaY+8m6IiDI7?>ql(P^@6 zCJ_7Kr|ydiQ5t|Jy2(^z3@?i40Om_f6Oh?v8>?kBJKBDIvG~xUMHq$S8XP(MZ zg0{mJC&)9kd9hMd>mpWD58_{zbP%iMw~gCYrwrMRr8|lU082lTOH#RhZ$8(oa7%Zw zI*ZF9nkRvtgu=@A;*-|NW&}`N#)JM{7Qo8+72Ur=;Byy``otKGlGSU$Hle8S{!OnM*oiP?fLR6_#9ZDyLW>VW`z2QEC)K6tzW#Z*1_- zdy)a9!mFQwY~o`IJTt<^3|=*m>ghEke)%P-Kd8?lw55+I?C%pJqwyBTLoI8mi&*@z zFoO-P&08Rbt60X+uj`);!-I#UT4PqcB(FknAxStzOo#LV1Np#t)W7p=Z7vsJ%JU2$ zXvPiQ_muLv@uJiQ#;tn68?M0NQ8SnItZGu{0_a`n!kGIq$Ak&e*uevS>m;S=@B!it zIg}L19gmE`_0kuY7-quMG!Mw|<-N@Z zZ5zvK_aQ$}2hbuxsE`0P*rt|P=eUL4lu{X#O9?>om5=O7;Z^md0AmdYA@^ak@5CZ_ zSZNM1?CAsdrdh#gnrM|TCLpOY~xs` z8e?ni35FFkl`_Q9-^^O_99p3h!8_R`>By5$2&>~kAd5fOZ-DWBMRe#%qEuQeVMJPp zQ=94V2chK)BcwSqZpu|#L?@@|F+yjf>5tF?sAHZ0O0b49z#A!n!rt28481-yUvmj$ ze_p!H!AYsAO@p0QR(|5)gTyyqFieAaT5Vu2Sd2e5^;zy;HvArVTFHR z%mUA#Z`Yz4q<6KW+jM=s>oCt1a}*-pRWtq2Zfz7(I?#T}_bJ1i<;AAHEr|`I4f=Y3 z!%bX24mGH2%;Ap8^yeN>;}feNla!34huT%nr$s=`Ck1|T=P6GDImThC^w6dku#0Nj z4~P$y>~6~KX2-Wqbg&034K?Uo--jaj@e6CNJp6`0mK`IfhwF`7;fB;(rl*3Iqcz)l z*3;rDr#7c`pj#cL-FR+1BSW8e-7=7mXlmSj-Xv;QtMT6K@j&0E^n9_wvPp#4hIN(` zT=~M%ej;nrYo@>+H55%+kV5OghAelaFKbByYm(PgPhc$5w{`use_zcEJNl0GCr_P$ z(MGzUCRWO`w8g*)(GEKnF@dw8MqUOO-ok>BwOdU_DDp>1J@{fQ@=#b=EK1N=*@2`_ z0ZTp13x>)pP7E73J&Ht@F|Yogvf+?p^EcZk|8%hvPUTa^{GHgs^nIQ+SL<*}@XUa< zq>d{GoYJKJ^z0F!9P?c4i+}~TUfoYaFmbYc@ax_To0Z7=9ucI$XPT7%4`%}IC&Tho z;dWEy5t4e6;79{detXYQW5_~xJ|7n{j^NxRG_IDwp-l8ydc)vloB@V}=noX(j{ine z=zPo0v_9~xD~o*0#TaOejzs6L@x!s! zZoErB-J=IpSdpT%AE0P9UigwvN-6-a0AE-Mgp#Y9jDKcNfO$p?UdK81V>F#Sr)4^P z`mJ%#xs$Zwo79cQ2&nTB&%$qOii6>~s*g<)Tn*)M(i?$GTjqAix&u+Cb!b-c_gl8D z0iCbPe4XoV=k;8Ll=;wW9(hW`HJIzZKFa8h+!}E%C~`e3ff37$0jXRbbK$5oPJaiXU(ILXZkdwSq5s(p-15Z zAW}=TNdycm<a(oNYh*SzYc*?WxzsKTo<~cRiQ}yL_&X*lai=T9O+jgkz{^2+nnQU$hDz+ zZoan=MSGD+>L95h^ex^fqT$x`MhJ@dG}k)Q1{lxJjYZ$M_5}zK)z%dVp{%lD7WL_q ziQvJZ7Dm5-rsn3y(nrOz$n&t2MSbY=Lj3Veiw#uSrYpv>X7LsqT=E6+cG9UIKueMC z0#Pcirr5*0^lJZNk7Bq)SgSHc&vE`0Rj(q0-Q}Tp*QX#m*2<`X>f{eN3`Q1BpuA{- zb?t*u*h#Z-U>+xyd;39Ybsnj?A=NZ?1IbpJ{T{T{^y}i!pM=qePje&#KPMeZK>EZi zCxU;c+Q4zohn6Q=S+Fd0cP)L~yFi%aMX*3XP=MjZXwP?4SURAS%n+kK+sFl_Ir^G% zI~2u|5b;B2Unep@lp(m4x{V>7j5;d~BrH2g)XK;!@*{?xLG-K}>bjc*x2BC?GQAhmF zo25Q}1*X7ZHNMsaGI8kK4(Z7FHZ8Eo`ffzEe5G&<=eW$GRoc-{NO zdYzEU57)D{MRdiJ12kHSY1Bbls{w;5=TfT@Spq6lTb0&&v2)8SjaTv85i-ss+rwGs z4u_P4`m~*{-1)MFs0fitVhkXAppX?ji+8#j`?^~N)|Wb@VGCrD*H1Ff6D=m1Hv3GY zK@l0Jqn7uq?N=VRzqc_T#TP3B)89qgw?l|Q}$W0`Q@xflLT13k)sr0x66?7)@ ztd;Tn7kbX@&o+W%f)(RUz3|R$(NwNa{R*?8^$KSaAx@y;SPmhMDBm((|7$2=`;%Vo zzYRxB+EP{;{TqrH`X}iB#OfD=4ZV=Ch=8(`61|bRq0_%f34I55$uTLqvB?=pnsTLD z<=ygQ1&{zUQuN$XR|{h=2@87%d6OSv!HP2G7GehWE}eA>G;(DL3Gg;egk`9tcOgMb zfTCi*Xy*RBM)sak5+;^ya60XZ+=`00^pyO#oZ>i8R}OTL|4yv1|0k*GKSKTg1mk}a zv(~p$Fm|+cb}%%akfwo>pq-|tm5@>Xf2ifA{$ti@=pb(5qtjXTkB-6^8($AQ%QiXR zFVgKIM*3fDOzQL{%<|%p6?jarJpX#&GD^xaN;l>-VoO0q-T#wZq#euuB)9WcwQB|n z0wSyn0s{SyoU6Wrv6-#2qp{=Frlf5KKQLsk%NJm9rNl}iQ$N}tsZ^fStguv_KQ3sJ zDHZJRQ06KB<@poQ0fXF}nAG&C-U!~*q?Nlu_AnAVPj2H`>;_W_v)A`j2 z)`I2fOy~5~sw%0!-8S!QG*>D*s7+~{MVgA*qUOn!&CjOF=rwhdpOl#_UX#*D%B)@O z417}c8teHt7j&%6#h2vXYoyyOF2~f4hWpih`&0Qmo1}l9Tio3uBzxA9rwlrpmui|x zHY+GDxMeFT$9=EH)N5L&&swMR3%w7mMZX8$Qf6|J(Yv|s*c7W+pDH#dK9*(qjvsE` zh-2N|yhAzgJsdM)9khiq&f8vOv`(Bh(XG=Ngn3NMg8Pw~r z;%mJ5w(G(E^1S&v*xm}J z$lMIe`|uyr{qM<=t~~7u4*>%5{x609GvZ`x_n*9VoKll?+!sOY{!ndY&j9x8ukarF z)%_}CS)&c=3RRL=5~F3lGZSG!XxLu-dTERU;Ss?oaZs}<^?bj3GHe$$2@%hm@#W(C zIJwO9@qH#j8=-03?0o(j?>W(h(GZBGy{9FGsJ_b=+^ZF=ZecF4iVn)vMMv~^$eA2N zNh?;VMRbVF6jUHvy}Vnd6)b2waR6+(I}Ir*sj-&&BnN-U!m?=^eC-8)f%m%CjHl*F zq@_{JhAZ+)DwauwI=B&%(kvnnETb)}l_DRW!YnriF?vm>x*M#6>P}|$GlsF(ahO9h z)%WB22MM2It7KdCl@J)rM{^oo$N4aog5TnBw@75^oAru0zmQp;x#JQ7EvKPwsS5Pd zGy|4Oy?(6mCeuRnNtk(1Vh#1{@c5-I8l7ho8?aV61|?BWfG_<1YgCgqs5reGZvVSe zU{q}I*SB}T#5uN{;q(y%aZ4`C@GnBm)I3Bek_Ok4ksU zml!XD%mS*|L??i{;M#fh*9^(TIUtfN6P7eZIR1q$^a)vElvHRDkV+fmS@7f2LOepx z#?5}aqDUbObYhhR++O+~f}*RrQUB=yX2Gf{H;U>rv&GN?NTken_iK7Qur||_2~@b6#qqTr$Gk9l}B_V5j1QmOS)h9sxx3o z&A&(>fSVfT3yQpn14Z%=1hCQ6OR<`T5ip=tXR({)sZ(X_vhyNBT^xH5PwmE!D9K?$ znRO?UMJCOs$===K%%u%)*3^0uDcoevN}U5VXQP)>3ItBv!~W_x^zOTal+)UJVH}@d^1BOi zxCH;!+LxU(i{}RaCh6dW-vYByv1|BPR_Q*=iS-d3l9nTssoW=p6Vrd^FC}AB z`=-IW&Zo2R#vlEV0#Cwiv7v(Uc8CO07t;=!Swe^OTse)caI>WGlo+-^c>*Z=LTupX zhyA6yfE1G+B3?*7*^Cp0RgPuF#8oYw5n?ZdV9NvwrSc#+2CPlm^v+O(hbM^R7eQIC zCAB+7eOR@^t^jP*P0Q!h$}* zY-82wKBWM9!m-XtPo}iAJ^r)=YBdLPJ?I(L0sq+=sq=Nj&R?Ag?f!2D_O3snqDXNb z9B64QgZMPtKWfQ=r*;fDS{DjU%8w7v*;#9}FBNv`E$xr8{o02!dcTID|8ASP@*f}O`A1=#H4tC>t)c47(=6Qd;8DWzzy$fnA+5x0 z+GTT*ci-u(`nCK^jD_|klD7%-)BgE!^qXNv!^~6Fzal4f(uB6I2@w4@Bpcv-rNy2* zHuIlJ#_d~=Hl_qq3R8Q47w%=k{^E7!*Fn=UFPSFEEiu|SpZ`%=FAkjZLH~<9;lBcw z~b6uEQszPZ)@G+7;8DRJ<&GM z4^H9O+DTAGkNme2Szd)dq&<z3UBjaaqIT1L=hqaBu%YQI{aC(=H`VCU5j5E z!_jyD%QV$UsJp9G&_YdLN>h{0H2qhu<<%#W*vndM69iO}NjRpe#)y`L5`7K56 z+*Ih{$n>kSnLAqXQq)V24Pa(lza7WIbN02M=|M0PK&Q4EH@&j zOy__N7ad>gG%zPts2fzkUC;EKkL^3`;(%&wug{p0;{JS05tFbloh&m9S~yB3b4M($ zay;UbX;ZvMk^K1nqZY#Vnt^BGig!WlWk4siu9~>E!KHwxa!2sjrK;G?TBoaC` zGUBno-c50iW)jr?O)fE3>k2NEgddzi2g_U`F6J{-#;Q26JUbC_#9W>fO;nMPBqopo8%kqfB7zK|z^pSZ zhT3Uj4LIdPX2B67WJ&$@$%z|1p8=MqUO-a=v>%5&y02D{mR9EZ_$l__)0`Ik_UDKF z@xt}7Oi#Te?t=z0Epm%! zsL0fbPL_*`peUKn5|rZOVTbsrHpYe~Z+a5H<*Lv#uOI*B%;lbf8&o4Mq3276J`j$29M6&fE(N- z$Dm22_`>uji**@1iDwuH`f88Wz|qEr4#P8J2*^J)OyLyEMSC`TA)2Zl5Y+qLOWAwC zS9y5CUsk!lMsO!Sm5YQ(q(LdyBPmDHes7=KyF{bZn2qO6p(Pr#mclmfCwJn=Y17^d z40;o`^Z6O18z8cTt}E7GyNtCL@E4gZNBai&nF8!Dn4t=aUGk#Gt9k3Ly``<({sR8i zgpCIE1m%eG4tV_qtU@V1+%zzIf9;XzDoE4bxfpEb5Ly?0aR<+^qa04EErSiL0q3mX zHdo>`f2Tn{iYJKl$a$ssfu%f?-yk{HbBps%Pr}9}OUR~l%qc;p98jQ2Q;p-bfy;yL zstV5KYN|&*sll?&^>D{PpMTdGc;g!f4f&kJAduf@=>Jz@0D;g>>vQ?_IppQveYF1A zXk5h$70iH*NK=rA@y}01q8uga7fEgMxQ~yj_6$68z&(7$4O9gTNv}xUU_pA!;zjlF z!lRM-h^X_%Sx&NHSEV&y7QoKZTD_eJox5mK*~O%dp1M6jO>H5*+sA9&h6MR`Waaet zn&-sCL?1p8Q`TWS?($oGmYVZmXBMnTqW+>cZmf_ewjC^{zAPO*mwJbMc4$hHxRTf9 zvHaXjJ#(Ua&AcWjHfFP34JM)g>=*5WKV`L@v=3*z5T*9f<+g&4a5 zW^=T@T`DQMI!Apr&6hpr*BR!I-!zTpzxM$%5sBrM58~VbS0ha<;uk5O4{y}M!(Cu+ zI`Be0z9e)`0a@Z0xvQ=Lr5H|_k_^gBKJITsk~M)9`4}~PzP#x{6Ny^8r^RbW4;in& z|Kh|1$K)+&1DEsU$8O^c-I9v&$qpJoMKPBs9UqV9*Z6n!0QTc;*rHTFt>Phw%#z?G zR)GYE^1#CE{IWmyjRe7G~0c zrwZhYJ~WFEUXRg58&Oo^9T*9M-a%@OMe$AnlG$_@7F^JO5=ir-kq>CI=OH(O5Dg&6 zTX!Fb)}5G2EP2+vnm>|WP@RuAOKp_#`CA0SaIDMh*V!R}9Bn%ig>WnPRko*_xH%0dYqahC<7 zn4?1|qs%eO4+|+e-7#Zs0ocr+2@&|o5UIW+84;4TU?byFAkL*GSbY@(yG_lT9BenE%>2DIvqH*M7 zTD=sNhpcpPC)fq&D8~aW^&RdS3C$Mb@hNIU>U(w?*y^&}3ef6D^;m3HK z?>m#TUg!EtJ70Cm7)di7qUY04J#>Sw`rUr7wdk^hJA$SCb4{N;YQTt-G5oZRUn4k5 zW<7SHOFKq}%Ynixi2$)nD0~0HD6peMl*Zpd2T$C*wcIx590+4-4p@PNtgPtp| z6NWBkBzcXVbcbhFCPGO{vJV%Ek?`U@0YBpyvetYhd?&`LY#P+1FP!(w+4591_6oRC zoJ5v<=X(11%DePA3+?pmMYYiaXVb?E3N#>EZge%!&k)|brF*3aJLLp(fS#lGJ7tj% zF4U|=DAzD-oLJ;4AoR=rb8i!n?=C&(wes^?d0tzZctwpEKtkykW`M=D5B38v~}Hrqz0p=s3}zl>guUu)7tv? zvfcM~mptA;%HGXBhiuLsdUF>HL;;QqxpOVhQh>#n0HmcD;QxcfWyCx)_0vrrC<`s6 z@}g3-vv%f6^|>w6W15MymY{7cxOsMwU2OwAyhB*AgXk4(oy*&Ryb@riol^!^RnQWz zmu@f(0q)bBjs;Q^jtATyK|K!!3ZxtNcOs!3F@)d~^t7f(M8S!c)!Glf(t%gLmT1x* zgTAR`Hi659LTBKimI8*@S)e@$)xmPFy&;jdK{0;x?(ktYg6?HA)K{~H3n2odRT+?T zec@D?={aIpSP%{<@cxlSFV+a@xIY6VNdhpW-V#(3d_ijm>-95X>LFVZsI*_E3--y7 zsTcRjik6QBETutoM1NXoAJmtIC|YW2f|56xD&JeeVTn*4HFc_FfaeOV6#G}#r3r(9 z9@Gp-Vyy+qhwarD{)T%%#ad!FC%nVc>_SLW8JWMMp*Hrkw;=Up3Kc{+g+ z{iT)2Aw}+Vjv8k53z>d^=!=4#5$E999Ad531WF$^00>_o;05m!UE&@^YIO?J zCym`$sEU+Yp;QNc%0HA(D8OHE>%j<0ZSQ=9Pn!!xhBc{df*6$=DW7g4$Nn0>>kF;Y zPQTIT_;)|+TKyYVv1#KpyKXdUo=Wsu#T7I!O6ZsZF4SucL`V6060${tvro7}+uj-6 z{tp`D!~}h_UI-|Q3ohB68zZzib(Um2uWY>#HI7Cms(3|ddn--;sXz>3XU-^IfGzsOifRq!ERZ%=LhlOX?ln2 zy{5`~*T~KK`*fk7N}K`}3y$m&{I6qC1DHC^+o0~7#TOp$oey(tshT6jTrPqAWSr&J z8?}^8YKLUn`)hT`Eh^{~+R7HxOO*DRym+Kg$Ez#8<b z0W#Qy?vc5Vdbv^DGDaa}lIV=?9;fZAcu|Q1EAItl6pN#KdbO~Ze)x$rIGcU2U@ekE zx*VtHCqGjaYkQD;H|fCDZ)IuBe6D+qZWHipDy}lN*g{1!Pj2C;bN!WO_R-Y_sH>A9 zTCY0}v^!^`K0;fq!^Un`RJ_uH4=U>6bLt2t99p7O7*L_WQuP~9UXLZL#9Qbw7XrlZ zju;yyNBg0(Ip_h8C*~IGiIp!Z#u;bis+J8u1;ZL(0o$GsSIS)ZyrF}ODE#s zXVfQ7HT!j!f*M0AJ+4+u1eRM1<&bRrBU+eQhapX7N^gp3a7y-;hQR!6H(_lw_*oqX z&K2k_RBH5#bj=#s+*(nI1ZVGY_s@HBUnk8kusR9%RbXkeJh3stAIe^48G&@E0>4=r z$w@i@iF24C@$1m&RD#V$#QPyl02p-FsEQj2Ej*s^-ai8z?Or_H$=t59i#84_=HtJv za94yAR(YP=%!N87E@`;&Qmu(oO`-iwwJ1ZLB4JTS#L0YTONo4V0D;?Lgq%Ocsz~5*F%Kw+50_t@UuM9 zyV-v_@>PzjnRqfSbEBH`KdlYbyDra|$|Y2FDa?IRug;3SyQ0kY#q zNlKtcO+mM=jg9FhI}!-;cN%(g0Yt9uln7L>I^^7d9j?E|l7??OC@L@TR+<~@XI#cD z{PS7>33P)Pu<%DL>9dP}CBlk!P22PNEawEULbkLOtjUGMp5b!fqZ~=sev?WrPrV`v zc}=E4JOf=BgYf3YqjZ{z@v(`uHk0 z4j#pVinLqZTBD!O%1UOs$s5vJ0{PPuI)FG#b`El3)$8g zet@~wiBg0RvOxi3{QJe_loTT7Y5UPD=e;K4%_FxGY81G4~|_K)iwrpAFd9y$coIzDtNT0e~~T1f!IdxiN98&=a2 zAc-~3ajwJdNCm%PpX57yhVvIB$r}1iImwJtW}yYTtPc{d4%R0rXX;mOOvJSJRKgus z{UFS*!-soIxYFbJC+dSGfHELj7@TlypU@g)uL=|n7)tZr&Xe`J6aqW)6!m?Sj7JYNkF#0ikQM6mI!L?AHZ1Y?Ev|?MtpNM ztsqX1d6ABTa8jgVbjJhqSg;Vn#JE)18I}VJ@mg>h*$aGaV{Zz57GK;c#fWFb=%54_ z1+#+Or7j!~t4`3=SGI&Aif+er0Bid7GL@5nEZ=rf0x{NkIGoNxe~`x*uVIbVAp0&O zn5nfCmNywk`hp={~5uEWK+9Ky|EJ%aoZz41f|X3YiSS5J(b3 zoDo78&EqTuiPV=#beRIsx>GuHy*IPCAV-yg3MeCsE}|?-29b8Z*B#pMw{{(-oxpYq zj{|+hpjvblEkX`DN`y9o+cDs483rPe-HTQ*NyZ>X_(>{6Of7`}I=oFxM!VexyNI1t zFnMpA8w$WuIF)DI;q7f!&YK-F94m$dsZ~9gY!7@=GzJqJxgzJ^6>^0B`><9-ZLvZ*ombD4dhf-3kX3+zb<yf?I0`sAvR^ zPmtV}$0MT)(H|y7a_1(^MnktbEs449vtURARJC53Uoew@i0(SNz4}%xRT#12d7I6` ztm&Z4I42y_%!BAeREhV^=Zn^1IXnr>j=wh|ceu;27IpL3zm zE{B4W1K7IRPB!CgFp6mRsDnGg6VRAR5@m<@VYZaez0AbFb27m zCq%}D6Prlu*J_%J5*2$O1j zVix>hBZF`#XW==VUzRh1stlR#C*Tk&@zp*6&Q?&ZxLztWjKk|Rsch|*%=Q)i7*$sH zN93<964v}kaD5bAIL($hL1oUUs;)le@6=X^*UbGjR%c~XsywtE9?A^IYj!vwz&#S? zXIRaYx93Djyt*#R9Sa2xuxQ0md>5(JZ^mr>P}apY`t|(*V3$fw9)pX&jz!`Z)UW2C z8Mg^Q6T-1>mHrFSG7HfzWQZwwZDnPpgcsVQF{p1xvzTTt@lrH+hjEH>&lH{28~x!Z*?xEs=ie)a6C1-gXs!8#!e0@($6T}JN$#@ zYf*3?qPA$llq@hT1rd+@b!(7$L0#sV%&efH#G495K!ok{zs{tmw#%U zZ&Kr|{i$)jh{l;!;e0lYgDc+S^bmKNuz+=8D$Ll9mRiR{Disu_*r9ZU)KFuI1fl2y zJck@8xj!SpMcbv@1Qsv`s7_`bTm)o;+e_cVTPrTU4cG-T^J9TbJ za#YM61Txil3CaU8NN?_8mX;v}tKTElQp0kbchU62 zHRw4^y9u~CYqwEVVVGtE*zsz(8c-#EV|$*}=z`^d^V`3d$5qt)8?h#E69vk!ysXA) zepG~6;Z(6Bs5?k=y*DM`sWeWcUKdNfL19B+k1sJzvwUOA#z8?;iW(g%ozMIZ=2MDp!jR4VGbt0y*eLU-nv z7vQQ64(n}RM9rA;#30A>0*vio0#4*~Zs4D{F=UKtr$SrV)@iKdSbdDVuS0Im1BhY% z0|CtQod{?yvw7tS!sz$|^03H2Fx}p>?wb|)3GZE@hn^w!Q>O)fGr!U@D2-74E`atM zWG2`~KwML)S^!ylRGu`JoPUFhHtdYn#KaR32 zj1zp=n2Y0p6iGqZuyV`MafQwdu~#DqOQNDsV|?wwAR5z`ETVdN z4;(%E@Ev1s9Zj-}a1i05n4P>^>ne!^X|XbFO40k(Ev5%^O+nYgQhKdgZ0e|{v^{>6 zY?PLnX9pZNyrb@{W*wjd&cVMno!kB1JQIBL~iysb$=-xxP&R3h~*qfRvDnunjuw~*{(S67*oR;+50k_!XhEY;C= zEuXLCGRdRc1Pxm(f z)j*t5Z@kXtePEX1NsOKl+W7#2+Ta}_bEiy@hYnH*d$M|Jmh3W1U-CVAyZ>%y3+`K9 zrm2v;^GN}kOXOz}IFp4U<+3BSRyqWqdcl`yd7P!`MGjgGP<43#gPTYU>_qzvT}>|e z3mhFJ%8Xqkk%_F<4AxKDRo6@1sU-YHY5h4 zNgjWUoERt;an(C+N*E38CIl$N(FrsS5RS*>eY`v$bC1&)GP zRD_fu*oR?#6X&%Bx}@%0X;8d)B3XE$^PnX%PyBqWh}2)Im2yxgO9ILp>8B(zvLkQ- z#$+O-aHt>^s++S2t{;Nk{{mda)znYo0sH?DBoKuUmIlhp@NY^;@Q%I=bKVJP*J~(8 z?hx)ljf%JsztC@*%d5VSuM1zsaB+&qwft}`{>}>-ym4>0TkiQ+ht%`#a@+3xx`k+9 zIK|vbql=nApNesC{TtOX_7+YY@~$-**f2-oRT+wB+%@tu(tG@Lv?m=Ai6=6LzDSU) zD7MnXq4*b8uhG026rC)MiRL zSNxZVDF}I2c1iX`RA>nzE8-}qEkSbutXU;B>*UzKPCSMlgXd6c1{DtQCsefmA|r4i z-TO_AvnSB)Y*13ZJ0NAMGZHL+QzMc!?xRicG)vMsjtXQYZxgQD;3mwsyDHf+A?q(isd~31LpDbRB9K zD`$VQk8F6goMeM7zlp*1P6r5wixoq4C|WXbG^q;>GyfTG?QybxHMP`+@}XqK>m4mm zY5$T@wCnhMq)!82F$VWjJHaz*6fM9EyvW3Ll39<^VlqBeLXA+cjDR2OYCXj^fK0U~ z&lm~v2nI`)7f$ZFjhFn5ho^$6TJj|hx8x#SgBmR-s6OrCpQD#B4!dnuA zWwwTOvtcDlD@FufmUqrGcp;TcYaM@n7zr|>VQ_w@YW+V9$%bAZvo4WsmJ4GkMHn@9 zD8t591e9%6y{WG}cA=a3?o+k+7yo%h1vBm`YV-5{S8n(e?yDwLDDUlX*&McwsV2 zdp1*pnLWX#%S@7^mP+5Yv%fRvUHQ@NE7l0MRLkN2=mV0pF zUY(Z}5OQK8Xugd`qcnIAx7wTRsBJt7?;vIcUb<1~*ZJk^6oUv1QgDv>)Xbt`^8wCs zCt}eU<5}LP=DQDYXdOXxtv6AcUB)56z_`PMY=r48udZx1A0E_Bb2aHXPBdTtbi{B? zR1g2iMTF$71mLWLK&Yb&2*@=G#p*lF?$qcfK8pN7I(83UWP_hzo87p9P+#j7ut%(T zN4pI$dpWA#8TC%^QUAHoCq*m%+mZB%zaRL^Xvaj7@lJphTMGyk67<6ld6ON^!OQ6= zAV1{tv9n`poE`m?3g@(=Mg9kJf5U8r;0Bk~gC@vygs<+<+qCdNGlpaU*hnrfO~uGu zi0bQ$TEPY$USyX&Axn2;C|K49>>lN3R9;OcVTui4=Jzj#=-=qASKezgVW7K{d zV%i9$oz-Y?l~B+|c=?z@DrXS}aa3VHFaS-Q%X9cbSP-Le4nV{3JRZdb-+1*8_KM@Q zFRTNUWm>5LI+9TF_n*q(G0MPM4gYz7vg=a>a(}y05zIL1?GWQ%W7ON$vvw!Nj=>1A zqCY5n(GVYp^qe9+>geVR>k&n>t4HLa7Mxq@>zf@zIsN!ku{@b#`J4ec1t;+3cp4(e zj(l>yjDF8{tZNv6UEo3pI^ZH5eV}75jK?G(g}~r*7m%j4RQF3LM(H1&fmS;oO`?A} z#WxuVVZHPEf4FYNiZA5*2uno0?$s<~qkQXC4&EXV2@3p1yXUg1F5Sjlvb$f`Dt)nQ zYKDGTuxjeU>bk$E*MdfagTday`B#uLcZ%&*2$^#nX*%1}#Z|Dr14n+D)!L-dDI1Re z_jI}V+%F{7to_VU!8dl~5wuif%69$f$LCUFj5S}|j9biGV1YZ|-^P|u>HNyI=SsJ) zJBA19?sV0)fi1NW@aOi@6B&M5iA_;5J3HU#F-yIw`J88U<(faABK!J#P+wb(eIuJ) z_G#?r)op)noIUmW*0tcjAvIRkCi9*gdo$r1s(L9|;JBLg;9GsXBy|Ta;<$(ynWy9R&G|vV3#`;9CIOVQ-Xn&f6-| zKb8bGL9O`EhGZ3aO;#XNFjmXeo%Jh-IuK=WtjS)iGhB}8`3ZV0mhQ5%XN**h?41jp zbV1yYPo1VRR1!d#$tUvXsewa!^^da9Xer&!55lb2zrefE+X-AI%3Hx^m|doCDE!Wj z=q`E9D2FRW`2JM)!nzN=ImyH{g?G`mx714wG_DOQ$4v<{-bpQFpsWkm?wN1vTu%7w}xnZyUjCm%R_Y#pgH*w(63F*{;xA;hiEgm^?Y~@i?tfYz^Q4C?=a2s~j8>oO9Mq*$D zFfbSc>=Slh*+_8kDc5O7s#hDQIp`_~w?Q0v^sS&n}cc#hmyTokBd#B6c{_1toeWj5+3u zCzviCGh5V57T?TVQPM%WGiKC62L5TLi`i$3sm7xm<%`Y}-$);QV?9(eQB1SheMQl7 zXDd0c!meGjk?~Doj;+PWq1rH13PdDP_mx#GX(Sa@kq+P?{VS+Pwjv~R`3^Ix zM=M_n%sOK2&A!s8g+FqJWt(XAW7#*F)u^Ja_Le9?Bcr2#fyKlIl{0*S7i8}#cxmg= zPIrT~M}TS=fM{47h8PuynfeZ8I&2WGO*n1v-3YE>AND-L!47X3Op3oWf_4r26vs@$ z;|NeOanu&SuDwd(dS+k(m2>Wl>R3^^hbN3r*nxCp+3-vum7F3PX66*t@YI}|fmd=0 znU7UVj{L&PQ<+_r93iDYogpEj`xuTU(O=|J*5Ss|Ow3rCQ)YQwZe z%OhmJFZ54D;jOB50RUAiPiDLt)u4!11|FaQ+YbJrp8-Zzw8&Db(?Woe~d59vV$<+chFIphtGmx$GFps*( ziu}aDo_6JL9eqp22^*y0S%L!tehn>Y25Vj3py-O+5gPL>0((mpHg`c7MsrQ0ZJz2= zm6U?&3ss@Cv4ZJR1IB)MtOyLB4H}<1jyvAniRlg+k$xivbrzv7 z5IB`wpkIu?mM%SU@6?5fUHRNS@FfuTjzVBsG^k_JG6mKP>!A)h=mYgXw&?{`(PR)Q z#m=b!JF_0+R0)*@;%u0u*U`42!z5J|0-ZJvhpdcFsVd@oA=FQhdTz3sfiPQ&xxZe- z5JFcdKBjaa3IB;6F6s%fNWOGYUDW!JRt;g}IZi3{_5{yIL9NqLsQi6tpmZ?}zM2Lr zAYER55(P@AzNMK%)22!L3bU^tDW3f_xPY3TSlq%eI2JTdt`^I zM%5Uh6$U5{D)*tkaad&O2-gcfS91DKc|c!}6(D<;6JMSwrRo>s=qVia1kO`FHn+q{ zFw366d5_i3WDl~kRF_QlIBOZoN_1WrLnU~Sr61#A#Mkhgpv)qK?k0OET;lw$Sm9YE z+vUv-);FeV;|n+KNmb2njp$^?r#BhAoR#b}^B$+mG4(vI>S6OH?8hiO6hKGbS9_a7 zvGSaZ3iF8YSUy8e&mrLle_s|}OM1bR8pA+`Dc`Dpwl$Fyt(r zj_D~tl!SC5CfW0F@S*8O&K^v%k_M)@mcu9-Z>HnBmLk4w#l(K5N_K*^PO!YH&64?B ztuSGu*@xDvJk97;$0gEH;%4PgCP-&uDEANeRAWx7Jq#fqygz`K%pdWC!k2V3cmFhWpChL>@Y}S}Mt!8C0r=Qa# z+7X{eQ5Fkh>ON{|l4@#h8}y)?@QMmNB@q@aN^M(4)iJHU@Y)gX4maOtaF=P=!+vOX z0(xpX3$H2MIE74AJ@`qw$zjQ(K^BjTW{1*D8EIJ$((CIGW6%>Jgj%o59;h7sgMZTt zsgUgx6uE9xjqtt-E#G(K<7CQ%#=5V(??l4DExl-6euA;W*kn%#yOLBkKs~aiMciXs zx=%eic=XeZ(lEh)RibT?@Yf;T*B{*%8y(56e6g{7TJVPaaNb7oX(TT^hBa|f z*AdS@8izN@5k(bKBMs`@jgrX$JST4_<#eIWl0L}m6@{2>1=~h{#7V9m3xzSJCGT1k zr%Oz}0u3WySQKD93r2RdWC{pH45MWfWwMmU03|ndZcC>-l^HTTRW{xofjo=?3Gr-Y zWfiHltL^4du|K9`S39Q@^tQW{)$PSuHy(Bm_xo<@$8ZG6-Tj09-r4Kz!+!ACI{LlM zKhW&mKCK4h(r`J^GIc7Qig)Se@Np`}Rm-{E-25S551Jh#->62YQE(tKAl1P|M&x&b)s;@r z6!@rW)H0SVyE@$rlJ`+wc*Yan2yED3Uv(56UBzP{VzpurL4E)LW(avougy|=?SJ9` zH2nP{<4;%jw8PJB&Dxi3&Ds}LCTovWCUNqSqC&tveXfFi!yD0$)G2#uR$SFg(hUdn zt1A|yqE@pYM5SuM+_jm?uT_?RF;n>$|5KHd?4vI>o~gda4QSlIt`!@rw7kFi`$6yM=&ZN5b=E)H>>c!H5ud*+ zXgEzW0On7z_&Q?oav`yR9s@l>v-#qxY9ck~`d_>f@z=(UUB zQ`Zwg~OJ6d&X=1eT=e?adblr zZ&g@-77*j$wcM>Y`i(-3=~ICfo#SDec7CLbKXzH|UsjSj@-L&)W_7sIM0Kj@3n!;v8OKoY)+lV7m$o(FF#vWac|16bgw@&#E=HHmjnO4_*_PZ_z_@*vN7?I9 zc-i{jFFT@u2ju}cmxD9R$535s1ctrF?&t(mh*!c)13A|?g*=`5?1z;X!$zlc8(5PE z)wI!tz-dD|DIi9$A*{2y;%RCq8$dVjOU}(&3@S`SI8gT=oCAOm#7*U(-_q_`GNGHt!$_>twxlE1Qsd~|vgo5QDdJ_AU4_tt|3}_X z02EA5{IS%?Qf15LqpXs!#%rX5Tv^Nj@Gt|Dr2V$!sa*b^t8y|ud?uOVOGW!xuIpPO zvo!2yq`PFc%}X_$QGP9Y(X5-7VBF&W5)^~A1%C9jb*c?P%lez0c-*D^5@a7n7>0{9 z)*SR%)43wd6Y8Q$9cTsSwj+z+w&!*cU0dz&w4e%i+c9VKDp7i3x zhiDA9_k%3Lhb)D>U1S0id~~g8aq}uo^JqJ{2=Vq+D>#lu$iRavx`=O&DVT*y+zoH7 z2-)b&)@YZV0xhiTK~uT(d9ZK7#V_#p_T>3XY$wAATp)$ban;QPkJIZG+^wiY?)6)A zNUW&`4S>pgbZV?=S5;}sw~GURof61$zFVU*UW4B%yB}re?xgA1Tm_;$)t;)Rl#mbr zP}D>MZm!}{WLH5>`K1D$Do(JDQ#FdX8{~-%erj0@wU8%G%tl@|PlIJ)JN;_0&X^VR z;Mtg~)}LeqYR%i^#dCVuR=`Jl2n&RCJjex;L}IDZHJ0-Sg7u$skZrt zp>8lXv~o1fJDlbiPft0ZzQl;C9#T9kL-n9CF@w$4!EEDdp@CJS0nF{Uim_EA?V9%b z;YC@jgZ$&m$GK9SZm{JU#@O1Ej4@~1#-5O@t?y>VNW@1J-GRtUmdUBu$CyV1+B_C@ z6}hTaoST)FNNJzHoY8JiLq?}7%{IT!QbwdrN^DXz)b^mfe4x!mxHcj0Y6LBHYoq*Z zj^wPfrDV$xL!}JFItX5ub8AG0#FdwjrlDel@=GcX?cC-vhsLUYw`%*8+qzq0s`5t3 zD^=b0m6nmoK{wf{7~6&=saWJnE4tWpo`S#g=>@UCgp7^Ek|em>gqxt=hq4(NZy-9GJ%q zC~_J7`;1b8AM$3$>Vb9%qYUyBl&UF18Xr`- zdunHo!a|)o5F53HVZ(vn-%$jQ_wkq?CY%F7t3c?_?7|pBUBy|LP@Dx`Kw8zFLMM|` z)z;bB7yPiYHne%z5!JTqDw$wlcEcro;N+Izkec%<16asD4|mN02#$zq1DBF!l%l8{l3$bJW(IjbFDWTwdP^f zZvW`0_olzT7u~RO4T-PeL$NMYoj$=2%18K9AYSdf>w6vkEXTpeH{m!9AVQ5MWWl!7 z5c+B~iJpj3K=m0&g-ux=Rmh$`=AMf%2sDVUz?-z(nMIENw&OEz?ImI0qO#3z6bCOt zeziJ0l)+#Hi1L+i;zV&wDpZt}M$w`iT6KIS3-r#au{Lg$OO7J;iv^F;p|R~;JMt4d z3zN|Q8~>CYf86W}`(c)NU{4nVY{tIzL;~}4>%yJ-#kzEkI9_MyLe1wnmePG4kD}a@ z{_m4$QU$-M_WymJ+LvN63)b&ZGCYhfI`A))!5=thmb#y_%tEp*ktj~cFKIN?6@nUB zDg2zFn4Hs9F(S7ucPIT^@TKC;w5LRV;(^xZ?6X04i66v@*-J@=NM6idPI5#tLro44 zeA)t6GN81*HlLRRd|d!K10BnoKL4&@8K|X=CZ5pS%oMz!vv#(w=}dg@>;8HS5&Px(d!zz z|2w_`cZ9J@n}P0TIXXmDVn`V`BuOmt23$|9r%PsFXqX4l^|-j}1~?_czC&09bj)v6 zzoct+opF8qRHgWfI@m0Qq@o;qAjs}Hsl}#f;XK#E-jTOoM=?LmuPH1dVzto0 zr{+jqQO!(Drt;OT!RZT4B;XOrF%}89WWkYvsl9xy3Pnb&%+27lPaCEYpfI~TV`lU= zL875mGqguue?ypM#lLBzL@yqgxFajISuhQQ85JdS?}Q;M-&R_(r*&Tm^Ej1}pZYRg z^)i7o)z4O#Pe*gKeF|1JwJ3zMmD=8NXaJF#t*GuhAse%m&{M<)pD<=CE8|78raAtN z<=YkZ?4`B3VeKq4l`6L0v@Isg+@BO~yam>blO~eiJmsDvRkM_DSGh!kWyx?Og2fKt z)>g@#meH<6c*RMVw)2W|$56e17N7cHPnVXLU;K$&RiNv$!EF0$$)?%(30vf9gqXlh zC8FD_y{H7qk=*vId=uB$caD2+ZO2$N(q^$qk;;8K0=|+n39}S;*Blawo2<81l&wPq z{={ngwWQTp7cr@K9iz2L;DNENP*pd;%p~=IMmof)T591@+?%$?zubCI6;~(;y_7Te z#nqy3NRha0utufc&>&KAd@kK!>IvS5BaA?S1_PNY-DbP}!~5%Vud)f@aHkvp`w_&*#(DM;_u#<-HWYNdf?y6G$aAEIN@2DRf zUqt~tnHvm7VVEpp+;NhS5cwi1P4Iu;B9U{{B(F3n+qryH264!K)C284|)t zaV1dDJ!0up3-xU$gVAJ2($ESThxRiBXU8C+`-vWDl(2~;(R&xm%UiwU9+Iq`nMC4I zzqe&2Z1stme{XhD<{k>xw!$I%;o}F^sdt=w~ANzZD!kfeWcL!F= zyS;52@8-_7Th(Uo@XdZX<*ba2(hqu@zq_PR&e6{H-kY6$r|pziB6f49-`jI45NvpN z<{^=#pKb2%?)LWVD*8v8`-i;9gOVl?BEoM zJcsV^#K&FD5bY&*@Jx>^nnckshePA@NR-RskD}Z~mR{3izeWX&vviEnb*=;uI!DQF zK?jf^k46{tEoY-=rjsYIHp8EKMuLHer)_OaSEedp>FVynJj_QIFSO$TLa+>wuWu7A zElliC8sZEHt1c@35h&wJQ7?F`%BR8LG4}~5vkCexXjbFfVzML>1chE@F)$T_Z^8F^ zu$LmXZo>g4JEydI;xPT&XfP=vF`-390NY-jzqoPMyOou7@1e;D0|?bY_-@!Jlib`j)N3^BY}7&u7`yW!45@g7Q2Y#m@IR^Fq`+BC0bb=spwimR5r)%Y(1#TeKTYK z6M#nmDoe0B;Gi4JJDZ}@&?uSMlJgEE`aorctxC#y%1}k#iB@a?<#ybAfp?~!87k>uJo_Qps+}k6ajn=`*GxqV* z>Zws{evni87uQD_ox3?5K&4SDVmP;}G>>kksPb8~Er-9ZRvX-kNYfM1LC-U(<+A>JVPZ8}5aIm-*h=D1@F_hvX)6L9Q!C9NHTX8-QW2s6C$KtQ`ksMW5pnMEfn`q9Cf+IJu zro)1p=`hNb5gRnr40`l-|5#q#&}nbCOG(GQ-~0QoU%SaWVqxK?Z65ZH-nxnX|F4hH zjotLa{_A&rSOvKmTVh4%rX6hW?E7<|^UgMV2gmOY`=!j??V}?ItSlCUhsRZ!{c=N& z_xFDntEWA&5Z$SyTVUNkD3JqZNr|iP#4_ycb#Hq|5Lx2S-ka^cK9TtDpepz6yW_3> z_a!DC?DYQLKNL{M;%`{NRse_vtW$;@Bc!Q(6(q0 zr-@YUpH5a!H(Yj|tetLrI%(vS^MjEXb&b=Fmz|Ra80F&Uiuf5PaS?}NS=B(mcz7m$ ztp4)XzyAF5UspO00%9x+>fDzr;?K{N84m#*aBe5DI&T+A@czr|<<*y)|905hJy`C= zS#U&QT!US>BN@g?4v*3-udFr%q6eIM)fDkb8v1w@DiSMOsfQw*ykurU>kITjRPd@T z@)bo5ig!|+L~NFmrr2axi{>w;E4UjBZ7QHB#wn&g_~w*NvB)SQV?@gdm>eg!6}kA+ z_z@#z9Uz8itec)cErRgD3M|dIE+1EA-0s?|0sxVWH}zsU#(F~rMN^5H69=aYAA6PT z9!vHL16NVGp$W!ETG`~FMP3^x-ie1Xe=`g73g$1s-h~*5Dtr+J&d_pxDa+-8DuUFY z8S39;=mZfn^(O4{f(7e@)nR=g_rF)oiM!g!+1qFN;#WvRqxIl_vYAz_#d46t_>+pm@+8 z7E2}W8&5&ne$&Iqu78Gu3Ro2bjRKKe>tNbWdKrYYH5jzgWONtgSLsb6*0xb1lf?=# zP1^3z7c2E%b~(9LOA&cOrA`#^ILe$RoY-tRWuXp8&uvBLlgn)(*3!dR@O}tMu)9an zzSapE$*2*uJ%wJwa=cXHg(#s4m_lsv*HBGr$a7nl3c97DrGyprLb7}P+C@H2BGaT& zDH%O`B%tgvvPCN{VXtY|m=AF+1?(q-aGXy@ zbgGmJ_HP~q@4?myAjE2r-{nPg4Yookh$sL8&f(MntbNuBC8nLII(eY@hLZ!-AV z`4%M7XLMVLHsm;E$g>?Rp^mcn85?BK@{L8xRu}yt>6k9_H8>Dn-q4`tFpT>#2)y!+ zmPFEV3oA2D^gsq75@2&Rq{~rxX$yP$DUv={up1Is>9RHIr&ETt%TB1@C5{4l*y`;U zmS=YlRPl_Gd3j$iv3z+TN;(&l58^vd>7;a=rI&E1HcBt! zK@biG@lX`QBl2My<#@A-aFC~hXjKk!M@=hkVzCU79t5-o6b1mz>WHx`85ZSKM7vNy zo33DsA4(R)P@n*OHt1WiR-hnWpMemNC(ep;F+{#)kH{=DHi_!aQz{%hVyx3Q9vf;Fg;V29GrPW# zJ}s>8HW(i~`RM(KE*d6n{Y_L@xv-PLO4gcD46bB~L9V_ZX@<{v|GW>8+*uGAM#ApJr)tj7E>B0}KcRd7gH$Xiik8ip_G#H#&`f$zy(hUd6GD9X z>N&mzqYxREEwSF3{x*)hspIg&BL|(@IZ9N!IOQ9GMKX3I9)xO7E!LXFtI+~dd9vzJ z;@a1;Mwu&^S(G~S-KQEfkmmY=HLB}E=fxM$oH$pI@D77e@z zE_WVfb-{-S{prTS7Rj|2O$n_wmwRF@uYN1CRYmrcqdU;;y6Wjify_1yeTl`_)H!SE zYfV{8f6iI|J?E@B#P;jVZstX(Cz##l8>G;#EaP~pc^#g zWg4F6u8-70kx!>y zn7Bg*q2~^dTD6P){ZHyWC zR3Cryq+wF@6{00pnc6o8HD8msj;4E2wru2)AR1Vj`Jd8b^B;lg&PCAwT=qHWH=!b=n4Nl5+bnxv(U$ zQc5lrYAWZwsezdvg$0Lw%%POEr{*Qr@f^&4dBvSo;XL?L(9pz-)dU#GVsW6i9wVT= z1NsBL^bVsOn}1PfmKwzaDaGl_%}R+$s7@H4BzZ6{yLIAIJ&d&wb?1>HIFO|Puy6SL z#0!hl8|Rf{SDs37XYFcBGG^|iIAUZAp5>F{h*Aks$&)mt9_OdV`PKY17H z0qxuYWSuOmrQ9}4-3nYKxMW#(?7XvdN3C&>IRups%;B!*C=_% zb%Hk(y_jcdsGR4d4S`;C^b^`VA;HJ@>D1LIL5H~rYvWc-G$%C1x%(&>)6-f zfDe^y(J^%#yp~MJ$8B)uu8KPj#j40GUF^hj3T07d&f7xcHpUexpEMgYXcjq6OsAF$ zmitBq1X9f`OC&AMIREAN_7lsezFEkXX7F)E(K5k$KB*>o$q|_HGkO-u(zhz0IIo-l zm?-3B_iT%30ZBqct0LHfyw$SMX+wj^C9c!FKPZMWn79 z$GJM8SJzp?QJw}_7~^5L&Ll5kh}Snsmf=Q#KEQ_n29!GjZ-FGrYY)u$rj8YaIia%FUgQD-U^G*_1bsUa1Po{y6_|N@+Ax>A^^j!ZMY?O-drCVqNh!R zi_Cm>^bDNP>=|&ODesBqJGfj%i^>^hzQCS84iQDJ;vZb9())3wSebHI6;jv_%* zkI^IqJRD8PizJKk$;iX!?Oc@L!fa_v%ss@SUh7g;)WVqXWSXh8Zg2bWV5hg&hj!0b z@@;=-dvpKbxPPeES)ge+F|2=C@=SdfLg-%N=6iJzN13>a$+=ePe4ai63hH_U^6UBp z^8LM1w{hVzlVP#hX)>x93QCq3Nou}iz zCcq-Ksy_t$KE5QB44ppFUBW+DtrIA=9w#_h&2-|!uR|2?ka~moWWEH5G|24=J2r8Eb0; z(+LYkr2xrE)fxXqDCYXSXj5bwYtorw^=y6(zFB!NvJQua8obGMVR!9m<)6_N58 zZ~;|r3#OE_*XR|$IKl3_qQ?@RM)+);UeSY;QFr ziny2zBLH+ji@%mfTccA}w$>^i0=v=0b&E`61dwb@_prCwKRXtG{|?W8 zb%MM|$AUFO^M(z3p8c1V6?!BrU`+Kq2(L4TkS^${c@&Y6DxXnSSX5)?e3^0fwr_49 zZtnEwuE2Vql)Ah>H7LB|luj48Vz-Ily-~6c6M9>yTAIc#sDOCKEk0sN(%qNo%a#Kb{ zr+(6EamizjjuDFO#rM0BM{sZ16^#STfrg|7ueje`#@tMpLQ}{ ztttS~Ya!<|9F@+m5S~Ju-}ie5LfYQ$?`+kxgjS!hXo?nR2O;^U8FJV^es{=6cojqT zg>XNP8-U@P=7po{syIQTJ-EoCM=*nsycRgV^|A8$us?+%dvMh_#P{dLe^C-$!^Rn$ z_B}$C^a>xqd9m$__he$e^V|V z^p1|U|LC7>^VO1b(o~lhBA`k4I!sA=K-f>Pl=(k1Le;}WS`cpgczqd9gJG{Vx>LdUJ_QCkfzHpeA=?mdXg zsDVy3%Hg#=M;X^EcA>%$6;je#yKK_Man-amebIEQwkzP(^6C=o&z&xDhb7dXz_+8~ zK%jKxuhUG^i9}Rz`Jv-Q&v$WbfEauX&nNDlOEnbUE8*D>nqFFQ(eJXSp`~I;J)~^( zbLGGk0K(7+!`s#HwE9Q$bd4#07!Kn}{#g_Sp~fN^{gh`$k?xXvxVRN&>eak}?{dzp z1ddbv(2G_EvhIb3zAU@g_?}_RFnSjqJ5p|D8!W(N*`^KIxS0g8P7dMvo;6Kfh&HD; zAap{`5{%?mf4fCqBzu!0(Rt9L+wUMFa4%2FLS88hL3yPN#aafVbytNYnkP0WspbV0 z3zzh0per25_TiFDwKr*z31+)CS3Q(>;DiJIBbixVc5W_og)u^s<79NK>SZ5QzcpWh zR?B_`V*i8m!4%y@z2?|1Bn=>eI%1Q|7V1ZE6C5$c59~$KEAmPwy(%5wE1RGvkF#Vp z;T4+f!}aqk1wo1WX)p`6RuEYwQ3Fp z!50gP%8;AH_(I}C_P#8%)EbQ9#jKx!w4DA(?4R4Q>eOy z1awSWI#h9oA>{)K88zLL+;$(gN1hByiq|c5Lig4>|LopcnRj;Pot0V8{(IwCh$l=g znA5O8LLH_R--fgD)N$$BO7J{b?f!!F+7utBie5?tCQys@0h5shb)aN`Hn0G&g`hCC z#ZQ5Jur>?TVUDB+*`-SvZi$>bE9Z{oR5FU1U^-kiK^4^O(;$rY5|HMx_Gp4fL6OTY zV#RyR_2BgMjYjI|@=r#%I=a^$Y?nW#)K#jSJnWn)8@n)UNi*Q>_t{-xUPYHNjZrF2 z%0a#`g(?T{RFCh-$rEGpb@;l)=*byO))j5I3oRfJ)fMng4Is2yk;FcySFf{+fXG}*-wFcS51?D99@q`A(}g9 z;E4&+K(=*$q6?jN6`0lsx|||k1_+@cqFpEHQ$|NOuWkcmpTD@>$1^nsrQVD<#!kT- zq=f4y;KnmmeU}VYX{RkCQuA_z7wSZzJmn9PQ`R&3mtHcfv@WNiHSaZ)XO$)0ekq&$ zVFPXLzg$^y9}aLxJnibWg_R~fUTHkFR3$$K%d6IC@FBeOAiSFcp&)h1^T@h-nGP{} z{A5j}5`B|Lsye-LQ}MwnZUUB9bTzj`T|hS!j=8BC715vo-!(7hpgdL&W>75$-{yj-=z`=okYxhG| z<{-`ar}11?>(q+X^LjkJ36f=BuMNn4kS+9r*`$!OR;U@s_zaO|Ohg&1*$pT|wZdn= z98X5Rmu&@L*=VRI#+KAABRL6tl865%=;l(oymYEMvC)e&yt^ge6LSlgJ4>gsz+1Zc z6=fAAK$7>i@a?lxDna)y(BY<{%+cHJgHy8y0zs><;&B!5@!`8ocz*6w1LMQQlT0__ zK}VL+1I%2PV_^`M9vMo(#5izbXGk|C`AcQ6=V?j^IE)IXq9EuZ_Ozf~*h0@OtH7?? zwu#L>4J4Ugv%=a8xwox#m*5}Q+!BF#nY_G0ME7Bn498zWCSWV*!EpjUqUc|AIg+TsS(o_04cD~u_q^3P-*YA*&?o# zm+JQNsb@hZs7>Rp+jw_5k9iqi)AN+J##3V1+<59-8i?aMj8Y|3O^?)d2+mN8^~Kz5 zpQ(+8cE%<9ZpRQV@4_oFGVT*aIt-2?6RSX;{ORqeJP32`AHeoc6TGAj!m+jwCzNiYD5fT2#jO-)Rs}cvO{#GYZ~-*B&I2LF#ia{Kz((A?2tD zi+EtZ4@Th~@K}9gFtW%^rJ%t1E4>q7r{dZY(@>o#`Zm*Wq;B7R{~a{r1UEe!htUve zKUu@iSEEVPC>2(=fG%6L>mV>3sNII8nym)2&rr}t!&2QYgMj`cx{3!QFJ9VQV0#Kn z)f)=-X2Ozer|+2u-RW{~3y#V4IH280>R&Yiaim~`l+q}&og<83LE;2V9sG%5rT~|p zf-b!~we?C8M8Tm_d{kYO5bL!li;@BP9gXBc1yV&}i?r78sf@n9BF`z-b!}*3$b?~P z*Ug|~6lwhAbXZ2Mo!3T!ZB(*9#LyXAXEl0tp;H9+UQOWrFujXEJnvGt6usx6(a6{q zgETx#P+7yTp%vZ&9@$h;KnH5W#K0MC$sG%WC+QUwG3K(RahO| z`4qzmL&FB_48SK1`L#W4KuK0KcJt5d!335csp`OvIn}QQ8_6NYQF*D6z?}w8uaa zOcF5x=Xoe(XK)n_J}?JQ^Gk|>v8k*&d?jGEX<>I*+~Yk$vy7G9z0?+fr!eJ~QM8`< zko*>`wA;GZai}zNs+Etzj2NnC!VERE5pi}Xp9z)mgKYxayZ~HC zUS6KL5q#RzrJsnenv`!wJ~eHcv~N*yC@M{7JVH(CmQK^ydM=f9E;ym-`WBf=t->>y z&$C(2tW7mWeYHVPuHEas;Sgiiwt^dYjJ}JJcDqMs{XgKPq*vRA$8Y8C(SGtO&g476 zGZfwG_qKG&ttcGsXBZcE*7BQ&y`#642xi0acKcXkcpDciu4X?0W@6Et#oO#2Nl*0* zgDBKEu&YI2_v|&^FOYi{%7Gnx=vO+yON-c}fv}A66=s=Q`(DR(0{$OG4C<+F!>Vgu zXqM4WA%ep|sKNgK?QI_K{M|fZoU4rh*hdT5r?oJq>pDpk4f9|v2!|BINKD}PUX5N& zuTvan*jC$==G9h5e#>cYd#gknGvaYq?x6R6Pd^w`UScD<7GdR6gSDA$<#xRkIk}oX zH#@N$2+=!oOqAvTr=MunTa*QxLEv|qfhm-WB~N%MMr1M>jpB>Dj()>Bm2R#Mx~|?V zkmSqZihEn$_GtjOq-=OqIhpO0(hR96#yV6oW{+A1n|ih6>F3kysHp|wv=Nl*eb<60 ziOG`Id+=HxhpHCYj#t{yw;H=|mKJ;ZXiD=-y)%syrGDW@wu^@ z!g{!!NJkEoZXLv%B&E~KzP=J>LjpTZd-LU*_NJ<7)lE{b*OXeN?VZwN5T3TP^LYv0 z(DxxMW*lVr#0Tx%<}$>SPBhmJF6C*7o~hXOtM9->?(q7UGId>Gd#0-#xxE0}m=J3> z6sFWxJP?xpdvxclX5?0bIbSaEiX%Psy#M3{Q){|f<&$~Lotn8c$X~=&tOH#R;4kXZG z5}?X!N$(OGR}?1xGcQ>y!5q-+m9Z@c7n3886+qmB)6JY(mWdV5oLX+0G|y1FMxtjZ zT`SNkkh{*xKfu8gF2z0Ru+XKmNL&S1K+yW2(RL0$tfNhD7rKmf%5861rMeUV&R0-w zB(uRn?#sb!;-Mop2F?sYizs`7P-*(uIfE#0@_-#yhQKLY;qjRgCWttJh_!HNCKgN1 z)lfY{SnI)-d>y837PZ(sO0|9M$aP-2GL!n{8OmZR=de+N6J@DXRVMX&RW3iHE?3G9 zq05;nrlXhCdb|ixha1I!;irj`*4FeQWdVU+ge=HuoWB#|fZ^VS1k>l!==m>40tltm zFAf5euet}%y7ilWyi?mYGH~n@@Fu}{`vIU0Ec?g?Ht#vYWh+JnG@gBz9vxk>h_-Nh z9*dM?(<3rAIVMYPS}c|2$S$FCsG{ZNl4v>b`neZ|-3JV8G%k~HO7}j^K2XFAQ&dWk zT?cm%xBGy%qvXeN;7y*N(nb~pts8sUSe;=06^l8!s@JEg(iaR+$E8Pgp; zjO}Q+pb9xA`t5s*LOIH?7f2Ye+?u5A7kOxt!1d_S=nk#kt8hGy1ZC%wB8Z#t_BFf! zfOjVDZbErvt6g%BQrN=5S7Jq3nAoCWLp?OHgim@2iPbwAm@41FNn$?242kSELJ3&* ziUUmDV*zuSaiDdUTf~TpTSDe|2&$J&i;`1c@fz{uG@TmX2P1!+gB^=SoicqLn=PFZ z2_2gW54;oK!|QHBUhqkX0$z&!o4#vmD+9B=Zi^jgM#j~*@(zxjaY!qQxBwlzx?6;OLHx zl1XNs1y+9;4TeHb;!nZaOJ44AELfxzP+*?|FV4S3Oa2tBs>*l!M@PLk^0I+k3k6N| z-DlPgc<(pm%p%6}MJCobLort&oM)m(Z~qq0#z_N{+mvjDn=1F>Td_OW1MPuC9EGgSNsSl0BJdpG(P;`k}oc#gY{yo!iri#aJ$+BG`R` zC63%*^PaYQPAn`R0PE6M!_I5ip&PLlx$UvSB05S=T&305K(97En zazUbHE-XE;Yy@l?QA*r+BJJ9lCrL{?ROSSN9RR4uD$VAUytBu5r8uCyC&jVK?Kci= zHs1^wTN#%&mK;d71m{?tO)hq_B6pe`cy|NJ$QM_TMv2*)%28%kJrC^VO}<5QVi2Fg zS|f=^di}aB)}%raV0dkEoW%D9N8v!lc?>086r~ZI?Jw|{DGa247X>JT0JaI9!iKc= z?RL!`j-L{>I;?`g<@-3;a1|z(5U*CF z!5eD`T;A85jh&~`xK69kl%b8uYYga?q7AXk&Ie=J%eZRF*|jUWL9Nx*Rj_afkDNC; zB?20rv^5WyT1;>5_ja}+x~Zec4coJQoCY zI!}rIZ(?z`Vr^*7P)e!yUxQU=FLVxdvmU(f9qw)Kz4=S9eG%NH6THA1ClkE2J4mnL zIl$M4z2n2}&Fw9^lzSC^M4N}k0D1z*2dZH!KTLvE7!QC8Zv>x5!RG$E!{cDLcX+(r z+v#u78=BikyW2-c;tTZ~+E&tB`b+Si$=}lnM8Sqf(Z`ZYalSsA=Batej+976=8L)q zZ)edf{>Sf(g3+(f&OCF^3W-yVd>{};l=WjSL40WoBCUZ-zN)a!Q6bo@RZXeXx>zt2 zS$b#MKi6!C5?F{i#|U8uEa^JYf=lT&(p4=2HPW$KEgK6;h9ehJ5qg)d#(xuMCcOed z`&F=LJc;?^0Q@Ao)ZSlT zoMnralysn2&7(aay7&b|$hgAY?i8O^K#XG1s``P-vYM%Im*yI29I35iG-c_h-(Dpp zvbLhPhL3wkzq{0Nn^XL!<6c)8o`B=bC3F1}qbN3mW+!N#HG?+p5+jC=Gt!LVRiRcC zFQj^b_5K)K<>6hG>&d8yg@(}zrvM)W42}#>6ba7SVSc8m9jS7jO3f_nj#Ki;sZ%fW z97y@bjCC+Hi*A?;T#t`A*P7P&m}@-DF(N!;0;XoqG-)rzrj81UWuAdize7CDRo3U} z`W6fzO*y)pWbs$#mOsFRgL3 z^5$1#^*FB1o@0 z1%)D!9tMT-=_ZHnAXlFJ^Nf9~w zElv~dL)}>+^&y>hWnu?GaIxa8q+egKXeerG{PAlY^1b_99ujL^+vhG^=j%Q%GOx4$ zqLh`8ai{plA}f2!KN_RQ`~7LCe5)PJo|I4g|IxEvmt8_q&f7W=95$wS&QnaQn{s`uGT`fVvhcRwWtJe$3zgGCndh@}o); zV4Lpo?A|u2%#4i8jEszojE`DeD<0;ns#Tfv-s8gE8>r9#_qvE(Z833snZ=Aj}2q@EjheGvT2{`rV1!FN2H zMDCWw{PgS9I8{FO%R0SRc;3IgODuo|q6~-@RK>lY$P)h^hX3)2Y4g9v4Ii+q^PKFu z`E7_?Q|@N!u2*Q^JqB@hiMweQ)w7GW>M0JrY*d}>@Ut!uWqrJ2h7$*W7i{Yn;Q z^wMl8$cD{71qLxyv-(51`NL2hTP_9ZXXrJ9TFYAwAF?iw&}{H2P5o~=(YCXbi;5_itv@NKn|b&==W(eA5V6?FDb*wbQ1d3?e7iSkwg z&6qLAP;Y2PV$;J%hylD(G(WjlZqh&>o+bCG%WeXXnPvEm7p!3+hU2xl1@8z@z9sWu zOr+zqTN^&!fq!TxZYR8g-$wLd`AH>PVUYfgNs{~EEC@WtS~UHJ-@I)>gZV1_r5498 z!eOYl<7QP6n1SP=}1fD7BWVY8F~iX5!ze-QSVTtMzI>l&h?b;?2wl zj{3`xaqEZDY;Ae_c4KRJ``s~FHf7FK`DUB0>dzTM+h9z_%nBdy>uGdGBhg*i5bB`C zlp56fn_lCaUgII?HNGh|z9}`nxKiW4#-K?50ccBceVku)5d2vk0WHuVm(B0hukYdK zyxWO&RB?Vk2WJntwBOVt4?{fyD?d*`l6=#TeAAD7ZT-k+XHn2^+Zo9>Mau(Iv;Ymv zSG6SHG%deJO$#ip0k*7$CHbac`4>~L0J(fd6-)A2G%R#@H5095X}emMq_z3G)U(uT zTHNfLw6lcv1=jY}(-*r3uLzgb9wnezP5kPrGj?O&O12MQyyzV4c+Ijz)k!)Efe%`9 zQLeUSZ#K43>YBAsK&7BhIpRpSs~F8@dp4PXPcT+nq(6dcyEL;$4$H~2e3T{o#aTX} zF#3?i2aI?yfhFQnG1b|i7!S+iVq1;jeY51>ss|d=m_LAc#eZ^e4pSfxwY4?QQ8&&< zf0ilh*4H=j|2O_D^4X1_tGOrx$*u9j`lIwz5s~_Fo}P}1V$#&z{q*>k_4QT@VUJ(r z<0V`FvaWVSlluMBFA5MtQsv7*QeYSgAOyb<8H6bZPL# z%*eG&P5kJz^umIk4)cjZUKONQlYE+~pUoC9mp5+|MU?;bmSVmU3B4oABv1LGOovJ) z1Ci|?Yd>5l&hqYu=W9Q_So@&|7LL#=9h4s$CcFtG!~;^}U}D(>I?ju<00aS#cH`>D zM#~Q^sGC`4ty-$tOd7lJ@1~Nz$50u-B&!ZDf&N#MQ)sMCOT^k6Xv>csrhD7ON@}Aw zj%MTTPUFvw8DvDBL7p{ZIFs_* z{hLLutsw6qNyU6pGR^9$x4&%_;h?M2!g}pn!t+qHGyBd-XyWL{tsJ$s7AdY&pNB53 zZ{?+7IUwXeZ2Vo{h7wgcfJj`>SZVb`Ld1)Ak&cnfVtqPq1uKlgLvT^Fr41823;XfTCc08jiXu&jI2rXW+3c zhZ1Xz^B1<3)2eTp-WgtTWUU&Dd*bct*J|U>tM=ZK(@ksj&s5blf>%`=qAq(an6JVf zKDMB;YJ?Wz#X%YdCE)D-=P{_F%8TN?n)RDD)_b-6LI3-Gy%-0O3-HzmL;_+UUD z9(4}(1k9fofq6Iq?V$iVRx}8o3|L6OVSzqb1Sq8Uka(V`-v-`4cK7!WUt5U3R6@i> zCW!w4>ys-9^BTWs5>Wq9|99g^{+518C*lxrJ28|?vSmW@DC!`#5@bi+@p(3Z01fc5 zomdv-g+QwXtRtgQzGQC?IlqHSVk$23asZMseD+3?P;^CN!*1UWLw1X{+^XUTcOr3G zTsVd!U;Uxb@bcJ<_b&TaVttMQi0GK-SIH{XmaLy z&Eaz5e%kDom^nt|B{A}AtgEApMwo0k%0zBrUTeD;A#9ZYmL)ELhB$n^fo~6LXDI%&4nrl6o)eN3xP_Ins z?I|FUc8qMG?Iyn|V2U)r3p|(CgZoPKTtbM=T2dcjW;3QJ!RM${(u7R06z75_x6tBz z(0QVtxA%kwC$a&(7*DG_KA1PCx2oU3WoN%;=lNiiy(~(1i>i**H@w9DnhhRn|8l=k zdTp9HAAd|9Y4eV7K2wkcx5PT7bbCnQ+K}RP0jkijn9#Lo)E`i?I1oRZLC z_dqD~sN@z{3qq-)lQ5H|5G_n2@v0qTt9Ui-;p7Ia)#sh{3+Oh$5k*_z@KU@+FD2K) z-SjIU3b*K`@I1L74WQI`xvIA>G}$&l3s2}I^D~r&h2zzRe{yQk~E$ z)i>ZoPXoNET_@u#8+$qD$_l!eJ=TTa17eWoa80$E*3CA*P~m2?pV zK)C3?hm>#PjS0i|y3;PS$z;}H?(zI5U(oNYQm%#0dSypxta*a|+bNW4Us`+<%}v7H zlD$}ku+(=fstIN#Fl(BUI=ZYBFV#Le$odnjuG&{yP2FFOPC9anhXz*vVLO8F_@RQO zslN7$K0r5GvY-cMWJUwT4a7DNb{m1J(%a3$CL4Cg%OH~tKL;+a#sJ%{0=+*wPY}UD z#WX`r0j&kk!Og?*)1p5aF0$r$Rist_RdEA*C$ky6TvlTyfZ0C&)I6V*Sin$iUO%1v z&%qx1nuC5eT#9H-D|ZOop((BER4z~La`0k^s*5d(qDC6TQTBgl`GnR}^rB%9?o}{) zpnF1G%o$xBkn}-h{m(ow3jy)Tw z($gG|2pu@Vn1=njQPLK9YL^{+HvD{J2ho11p;KzMFEDb+%I=Byw6Ii-No*I@Y=eO1 z>wcqDU%5}+!|k@67*d|!Pi$6~=?12-zL)CNTeKg$SY~ZV5XXG6mGUzcH(10Cq!zEdnD|9X?#4ahA&ciUYhX`K1U+2?vb$RNS&1zVV*x{H= zn7^?bdhvVXvW~ZWwOm*Va&`M5z$mPQ<@9^z-1vl6o?Ez^Ab^h5jd)3lPf z*Y`yyssa=D+FmnZD3e!B7*%km%@g|J{qUf;;s7WFIl?^}Nx4l*7pyhF5eH|Me zvN%b$V~cN=N5HER$b*inDlWC8#z{PO?G0_)A>a>eKrQJ*Frl$pDkYHEIYd1Kn0%h} z2k*%Ulnxj**#KLF8uB}=-;MT2lhhR-nr9#`Dj6-Dqoo5D8qx3BDWuf8Mvwvd(j{j-h7#xt#T0iRH=ultfVALp(Uwd`xc^zTfc)cYAG1XfEO564UiAz_%>` zeSS>Xo;&T9FZ+|};VD+>j*rxFGjn8yw&pSPkA7$dx_R_uJrT6*s*EZgL+9y_cn<5- z7j1o$@8!egbQ!nMSFG4({mCTHCS=oLVPHl;ctsYz$hPW>;zPDXbsktv3)yJ-wRc+s z^ioTECMP0(b+J1uc+{rVn~k>)UJ|pHl-ijybBS%ZYCwT)#Hz8z0^^pCbQS##1b(OB zHz&3IsyDR~koX=0CyRg6*H*&y&G+>0j~gJ>n!Ry`NfgtQSw0%Re%UlQwbh+O(V;Pz zlK3$|1<0UgK54A3HCDFdS|gh5`1JQtW;} z<$;Sd+TVS4EYCipH#na3$EC4*WI&q=;tBi#+7f8WX1Ku=Z-ukIrg(;1mw|fK?bo#g z8!Wp{qFaBpZVil)3gB6}Vu86n>h3*v)2}Wu+t_%C>Hcx)>HhH#Hr-D<+ke09Y(v}l zWPc1N`(q7le~eD{$3GlxKRY@+xHWBK<0Yp1$EBzHk4D@0etgT>-d4blI{S?~jUtLZ zo;>p~A$P(vU(f8zDh7vgaGrsG;xm>Nn*zN8fT^Xa5b|kEH|@l8&sXH|vqsu`+VNf` zbS5_U-3mS}B*Wg}4U6vsQg*$S#D9MRzmWHZ)Hno($%2zr*S?b(5k|bx`NkUIJ6**D z-|9gXgtXv6e>L(n0%^hH^FHUs9lcVxckMubD=)@kV&#=Lg1v0DTDg@HB60y1cg%4? zS8eOu=g(go7bvnx7I==rsstsq_gwUwZBJP^g?@Z8CGZ`5q zNK|sY8&~4R6+VEqkC~xcpbQ-3cj5R4t_V(chnI`FZwAGr)?mfc4lS-9*9!emFYSL_ z@~xpxv%iG$)wqVbp)x!jY{dx_Y`J;voR$0N-nDz;DW`tBxZ^tx2bI!4R?%m*Ce#ON z@XJ&O9P;D>IHIgTFlWOU6;_|B~DM52z_#X32m2w&b5rTm5atAJSRwYWN*hek?TAl1h9B z#C-Mr^2&Md0(npB`8!_e@8>2S)QsH8oh!L9zq`t(gL7$p77WJtMSxjXvfEeH$@Fp1 zA5&n)Vm!JAqe+gmm?pg<>6Z|FK?j;2XIETELFm;df{~X=HU@=aV8s`ELa^~*Mx$hi z_x*yH1*#@9*YgoNW&H?+_zNE(;!dLryhCVO`ur~uYPgX`;>ztc6hZlD+fsY^YymG8 zyycrwLsEYn?W%ZNbDsvVN$@t%+wUIifj2<)>wu|J`95H3EcZe{Y9f!>5WPcKSICeh zGBF!V$$3IcrlChH1Igi;jl#Dnm zE}B#}!ILrhDS4FqDOuZS2VYwP;syc-P2R$RR4bT> z35l45*A=Qkt{d8v$hPtZaI5#g`Lp*~o&)2T%Y~7-f6K4Ww3cxC+m+Sh<2wS+`~YU2 zCK--Q{!AaTkJAhixWUwY4>vw_U8PoZRtu$OJdzVUS?V}W^qi%GIN>`7Br1R(qyyhd zem3!(oa--kNl7EDRR=z~+HV*gOLGhR*(g-QqNnP%uV(SAcV3`{lqr4(=@dyC$Df!7 z)BI$rzz>PY6F?LDs?5k#>>^VHf->49J5v%~HWAvF(pk8}XSB?JyX>pgV%aJYL&g6T zr&ybPj29re6jzz*U(8CTzCK3k#a7sc)?Dj^DzMN~l^iRIAW~MM>0pwdWaJ8bqAM_# z9AYcE0?yj!^ft+;Kv9&HQBJ3tI|$;N!8GHau=6Gv2s2^|u^}G_HuLI>Zm-upJm_sd z-`#n&zk8H+hC?n@Ozmi<{^}=|D2^vZp|)?Yv-S(*A3MCvXy5cl@YB|tQa$60Iv@^| z3=}46U}{8g0Px@en)=U+q|B!oUcDju>IcAI73UL3-ACP|&ghr{{;qYXnV?dqefQX+}vA zOqK+C)OqpJgZlXHP(xH7eHK)IjzG1?uK;9sW82>o3#rB`BD2+lH3}NZ_3RG~M~z*# zYQ~U57|ga5w;im#=*+(1lMu-lidAz1UG z%`s0=3uBOD4hUV^9k%TcFEhD^yv_?@-zz@BBcf=#+30F+!K5MJ^@!{D*}*5GE&?qCi;B|5Oaj2dEMwOnOJ z={L#BV#F5-kIk4k6Vy;$l*-u%FSyB2C&<&!jWaYZWtPqQY+BQ#=}jJ6n2h$yIwygeSxjw7`9&lKH_)oFi8mm-IWBN*UY> ze7^tf6D`7xt8bx*@%0Pk$KiK8Rpu_nO30t)Er#I=uMWD-_1lq0nj3VL*0NI2CdwN8 zoL>H%u?5+jY2#Y+W=?uW$;n%WlzDqBOUxl(74wFqXDGLVv}k}#qd|->Gu+4k1>bd7 zqcZYdOK=T;MNB%U`X$lTLL_~|KmSI(5*{CQ$i_(8Ns<;8#R3L~3uJxKET&aYfzEk` z3VoxhB%Mo1T3R96LsUmwEv|O;r%q_b;t`4i9XqR)s&q<1Rh9IILqN%>jzLeVk#+UP z|6Sx`sH&6x&DT@sL_1SZSL1|evrDah(!DM=4~uBnq_WAYvgNg@nV@cIXH(y{a;uJ_ zRh-6G@uYw^F&}pUvBD}Uwv-N1@IpdHKBfAr)Y}kVCvT)~kKcw^zfX&2Ua)KnNS=Xj zF4J@LoF_7UvD@oGbcFJ{oMsoW+u=_8x|ocH5v89&sq$ok!WZQk=lI0eW0T8M7!6iu z^JFt-ynS(&PTyDD%k4_tnLn!%bAplMCQ9M) z%d}c%c?XnI?&MmZ#zX-LXm2%XDEcZ%ja{6cCKn7YB$CwaubI4@TpUBPQQWio2j~WT z<+v$(^wt@GPGQRI<$ZQ-J`E@N2gRziaz#F_#&pQTyoCE-nSAI^@?ut+VYs^o?pJ3R zk6u5T@fM?<6HF4o0FFa56=Rg%5ST;aTb|~TjEd8mbQ8Mu&WxXz8OqT725vGa;LX^a zKe|V?=VuDZlS~gDbZG*=UR zjWg6|UKdIrYSU{qM%!$YrU$KU)XbYF_u0gG&8MTRRWpTMcsTr^NS~qQ=C_@~lWcmG zWi&>fGu@dU;MIBN@ZP-ClcIQ9gm0QXZnEimOWL+m(e_8)4v>$fkTEwo*t2H3g>)2= zu3YtN*m_GH4+pQ_$rm|#S6kIpR)r1%+oBf@mmZE?2=BHJU%coX>_j0YhvU_DID&SZ ztF(N->{)YS06Eq@E?2Nr*`_#>V_Ak#AW zWqmyoPkh0~-WMl}FNHVkI4?Ay zG56fy){=#m`>$Kc!fX2@IEe`@`{$aiyOF9@IUDM@{q!t3KMRxL?`ReS#l5js)W>em zNTT{&Hf-BIE0v_FF>k_P*w-12NGLG%!JH2@<4Vjc+_V0&Kh8$UC1hsMj8^rSUtCTg zsLCYk5Bn!M<}B1=C%q|@kuK=Q73}~T_tka#0uA(wQ!Rf`!Uyz;!Uq7=s(*Qz^(PVV zETQEjyDMnj9g@T@;__B^M@cuMVtmFoe^X$jD(#DZ3)ua#@)`c-8K1#p`VM$3AeAoyO2Umaj*nfhN~_zx5{b`S2sI~^lIisl}0C; zHD}+O-Bo3hTBI*Jw4|r+t26w|rj}F<);ZuYUBz<wFv_LAzao93Df@Z@qw5YS6)kO20lm{OLb<>h5I?vIp2agq)Czz?sB*{Ui4 ze+At6XxykiDiqajLmMJM>LoSP*wB2q_~`;=oaY6=u=`cEHLS1-m=uT&t>3um0b)=`6V=Rx1|ic_DjKr%eOk@(tZzw!nFpJUJ^t+N`|v*Yt~O>u>m zD1JF^T8lt2Aw0h5puf@>|3K$sFq|c*th#D&>iRV!PBkL_LM%aO{PDq0rs*5oMJ)wa zR;F;3PIF^(#JAvf{FKt>m*RZbJS%4>O?Arsk4C%EXn8;BS@Em3b z#cT?opA{1_Cvt~$U%0ia5%P^z7CD}PpP~R`K%BpqhV{lsmN^jm<{56WvjBx`+n1zD zEUFNovFwXT(2CSyKAJUL@qys%tNMIb{CAui)J#Y0r6&^yjB5`nI+Ws;W4tKpc zfj@)`qMG0%3K1}ey1y<)5A#N?I?w7=awexen`+P`0LLYazx%OPI(Gu zQ*H30ZyV)wG8?F_jZ0}cRmV33`v*&vOBB5`csu~2chSH37vD~E*YyEyv}JI8$Xjsk zIAQ{z7q6g+5Fnv}(K$R1g(f_q#F_5878(5^v&@)toc;E1>W| z^yUfyi(X{oa>*?Z)rFWuCi?5Md{RzPWzR35uyL$$ zF(^3umgKBB#)l;YwC;?`g2P)~ofqaQJqM2r4q4sY?j&qr!2YYMAy^)`u@ZoY(6L&6 z@O-Q3v~tN#o8SX5qlvdK8Wph+G;m}8V|}&l1BI+WI(Sy33j?LKwWUun553rNw)$UV z44)RMw#exgY3821#ws%$qKQFgY@9f5l6}FcN%Eq%hvCrhIkIs; zxrmOtFQDPZdUAu6o*luO9&G;utD0b}$>G5^)>D_5-Iu!^2)4Sm!ENCGbbkj0E# zf1+RNRXyg!J&>wq%EQ|m+zf450Mj`d#^qJtlc~RJEVt%j!>jSP*fjF<+%1DhJb*1jcq~Wk_p^HxO~KzO z{Ko|EFcB2U0LVB{2Q?w&K|3))N^GnIK2ePnp~U}-3nlMtA`D3T;RG`BJ6c8jQ0g{) z9*}k$8alpxzb1)c8W7R#SOKlz!dp7FgbQ$KeC+rdWsx)Xz+m1Bj1; zA>ioVQF;fP^era(iAs&=t`!v?z}}VEe1#p%>M{t^g3(AoIbePW)d21z{8*-@+^Pl4 zr%jn}BWbyw^m@bbzegFw%^}HDm>N3acYJ2zMzQfygVYIya-P4~KC`6ko@<` zmyn@SEg^Sx#IOfJ$cW9?BjoNlpNb4KK+fJLpQuGq>HILntwRm^fRKfGA2|`8d_xyG zV&pD@hI$tX~g1xTqt5)aVLQ(g`@CB|(YqRP6b)@6o!f1#>c(2`s>V^pGso%`vB=O=}$@YwE3yC>C>YgddpI7 zwol1#l=sqW-%cjkX_e)?4efyu5A!i5ZN{8y2~kGm=);eVCN-k9#ig#J-w5%k>cr(|lZgWAQ`uIS z?OP{Xo0H;u!Om$llR6x%^G8K3g=PKm`lbf_+f-%*cDj&hgYVD*;jXW*0c`uc#NoNH zS}#8vlSPVsv+xSG;s7_PMzfU!4;l0BLF?f;x8FI~=^pG=pLARycGmGkL=@o~f~kSp z5HT{TJ9al8_xAv#P>sn_r&tnUla1FIr`DN3oWfzkevWcmr;SA!XorBfEYyD7U?!Rn zIYFvzj;kA|CbhwJou-#t_*3G7xUuZnEnpHh`%4!v893jd!>II;#(sBBrsYIblmx!2FzCrhaY0bqLpf6L&^s-qdZG@b zIV--2mUj~^&1SD&L)%^TWV0QPjZj)WumF;rQx{G!Ibzs%+f*< zJ|qG{iT6M6aH>0d9H@w=p6vO9-`Dq@xxsuT@*z#hL9j6R9{Zvj>h zllW@9Ps=LQKfIDg-CMh(=TCFJxucwDNdB3RPYX50aWE}01p+1ggS{GMf||C^uS#GwFJ559HqZ{O@K%~l+{e7l z!|~IiKXJsYh<=bib7d3OXBpAU%#tH0-mZDI8vhm&H<^ocPxU0xbrr(=U$gff`5m_L zUx*iNv)AbezpN9VN9R=$jbcK3%YTw`)+?L0Vu=g^3Io)L@DK}k44$GXG!$OZaP+Gb zH@^h_PyW+HZE!5(p=7)@SHcb6I5yPTsJykX1mS=K#tm_;?AA>ic7v`wTA%yc1SF#V z-T2H(y<6T&R_0$iD%>g>&x_(cE=lDho?Udo`J#eYqmqX7R?7>*@k}{QYIMbqi_46D!!+_fFfS;tC&o~@V3)pHZ~#< zq}wd>3kZ~4OspkAfT+n^y(Pc837*r-#c(jNK00&ic9ed^Wo#$cx>B^(HP`yBw$^V+ z<-nekfq;0b@uC>aTM0#gC&dJ|m5CNW^h0T9DL-%1lsPW} z_^)Xdlc2U;hV0zG&K0-7Sb-r&;2a_2;)=yAG&IrtJOQ&`HB%*r>I-fYh8dgmWedHv z2;Q7N`rOR<_WW7>??lN4?}La9){4dDA1D#j?YLxay0#>#6L*$=jd9G4sx249F;Zy> z07h~1gq|<)__O$X*s@9y-zbTm;F4;orctE}f&Byf#O%ku+WJ%2Q4rkobd+5=+v+kO zykDDLk}>+#c|OWC1Y~z+mo2%)e(mgccRI(r>1P*!0WWC!!xoO+yEl2m#h zH1z1J(a`PnYzxvruxxupF--nfaYAVz8`T=mGStc4UdF!l(mehm_nUjw;mH+u7Th9$xLRTu-n&!jN!bQe<=BMM7e zm{kK>TFylxfC)0Dy1~*Q^v=;y_t%=Gq4L<`kdH{s@^FRd0uk5;pwnkWmUYUBJXb}$ za#rWvBFMVDy{N55+(}30|En9{@}}LDPIhYb@6)uK-WB2buvyb%?3q`{M+-bz?HwJy zdfD6A?HwN-{-e$!)~iUQzmt{INpX#%>E*v=7;h02hzr{)xKeBWyP2niiDCxd|UzPGG#M|F^dG<_+v0PdUG-=mt{Jl$=fa^fUtw zLsp-d&H3s)ADpB7ryJ_maftLjra03nMS-6prszjP(J!^m5aV1bI^t-Rli&G}WwY%||`O@JsO`^ec}Sfdm>ap$CeJW;=MHkM_0u;_z1t&H482zyF(8 zii{1~JwMz>_6Gm5lP-rz(^1i|nhu81;IJ3?(RvOy93Nrhz|fGc3g(>!3d|2~LB7djx zQQ?OUi;9qRkX8tFONYGL>6DQwx#<5l#Frlr*QUi9rg>4le8{J{jFQVCaZ?Y9PImjE z53z3fo7(inL@{E;u=-?uP-X&Xs)PhI`_{?F+X{v8H86^SV$KYHz)1GdSf2xxxbbnJ z-q#F*YtK7xg8h6Yged&XK29+o58&}VNFo3JZ`cCGFS0(UV9scGp8z;o6}2XKm_Yc@ z?%qLXpCgv8Y#;6)9x;ii`zd9WVo6I8nJ(60wabg*eYRbUib;9|h7HHO=Q~PpRKhfd zGF@5OJKEhnuy7vL!r7Z-kXzeAI)e`Yi%{Y`iVW*W!jU@t8zhD_vnlM4h7?JA|fl%i-pMAFBo8)iz*&1%5E9 zcnqHlW7r|jMIBBVzdb{XQ27;vL@05x|G?Jmjv))*G*|oz-08>J742l$r)knVFJ>d~ zo&KPB9Eb2u6Abu#+8<=Z_T1#&wB?OZ2|x8!gr0&=y{BNlwJsUanG@YB7>YlTyr{T( ze>R#XANp#mC?-DxsS(4JW8y(f3eWBkPB73ddIa1|4hrHd4O_1wE+iK(^E@JMq;WL_ z&Qvd>^RCH3URiAH!U1u?iuw37LRzDWHaF3T)jGU^x>Z!P`=^Y3kG;7x7<~G%0ut-3 zH%zcj*$9N+;G?Sey}f*vRwZmdCNl76`NjwF7OPh#asDJ4(@l=U&ruKZHZLlg&sfuq zt}Pzu{3%`$UJVU*om=79!B6Z0e9a~lykK&cVFsD8951Ms`qya^Sr(hjPk#4ZHdbm0 zd`>(o97C65yHsxL7|pEfTcVkP4O7!+XY#wt(!>oAnAl!6g=ar?+Lm~Y>m!0LU!qH7 z0*tVPtQP)g6bvYP$zbO2E8a^6nhp^IHda=huK$XqL9rZJ+gu5dOm!M5slC@QjoU0W zfL%m?{S#0TKKvTsY7?*1^b@RlTdRpfwYH+V__bDrBfK1@{hNUyG5~Lr?&~h%v+=a4 zYjNz04*9#dUzV+_pco{w%`I5$_XYGZW{Jxq&m% zhyF=9 z*E@C;!VdNO>Yn7wZwKp}w%IMW^>WATA#SsA7TG!0oJqrOtTmjBP?a0QAxFVdToybx zCLyFmij^XPRXGkAM8Nd3og|H)V2xiM9jd!buV+sOX^a<*CZ3Q1UISv0+t8~{iq&b! zw9Versyf(RWC4ZgC#X4xg*XD}R297);g&1mjez@9C*_bj6O8_(fDAF-QB~^xt0e-r ze=k#rDOh0q?2qN+KquIOb6}3UxwG(I`hYDk5f+UFrh?IkO$HTJhz3VlnN62tA}dQv z)R9R67Ds#4FkNR#{zgh$tWqHWlzx&J%bMm;Bdi0|ZI&&ENB>VDdLRR0)zKKFPQHyo znYoz;vP*0wu_uSARZlJ3o0-b;jKdFGcBJszFeuf~oq{*I%3CY9M+#GOdMAGscL*L1 z%gf%ogckXtOa|s6xZKIL|Y9W0kW=4%K%0$COsVVx*^^z892ez|sy*h|FlO zd%63fY6lzH2o~l{3CLrPS%%s#zR4n4(SR}8q`rYiZjDx4vLkITKpt=tiZ!@NT(`C5 zX{VBKSgBD`N_T`4@GKrj1;Auc`47=`Jw-v^~F zQ0d2TY;(zS@AGi6hfNiG0n2&l=aS(u^Uo!-qL)TD^{=(8LMQi7*7l-5Jx@&JM!R_uqaVaCZW3r$ zEodiI#0$6Hk=jaL7nu@I4_Jw(?4#u>p82ywR-NGxRGRQ_PU)Iy@54eHvZ}e)-dd-;4jx?|O;%(=F9&_?3 zu~LeOKRhfzHje70o<7`%56V%YIXVP+fPcNrQggH}z~T)+^EzkXpo#R4>i?Ln$ycz= zvvPLQgyR1J{t1m%dqL@GT%kqAIKX81*Gygl4P;U|?z_ro!Vm32e+nzw$k-|j(6xIw? z&Iuv_n}w&7n#1V@0OtckL(CW`My(RoU+oba$06+9|FBjSw2XlX!*SqBuZzk1#7sUs z-(<$xF#CWy0b>Np$6Ro7aA14RL8N{6$~J!hw*vh)TF>bp94n)4ebHAdmc^Yp1AP?n z1;9cwz(j3mc-F>ekA`POBP`AQR$D$CM~0c-`cr_%jW8#Ow`UI%`=h!l&ZVh~zid+9 zXrN{=a*{LuPl{kLXF^O=6!~+3sW9!<6FclA5khd7jykdMJnOXZoAqQ7Gk{*LK@m)( zDA9-7DTbE5f_^iw=F?J{>+>3sQ=@i4xSjM-N+t;?pIu%~3XsGiz}sq9frT!ahPr4e zaZX9F#U%>~9w|9O0TTBA#|N@ca|co~K)VPG(S@BsPvn__jaX1nNMD+RM*TSG?zcrP z4^I=sdw_Eo^&5_eu?~%NM$>#c!`K9zzKe>Jl1wjkXK5PcKVUw41b4j(4zv)XK_R1# zn<4unW9t+QdsAFB_dA*ltHWd`?D}q0LKfKH=;Y3Hg4XE|hEi}@D`-Urue~+RprQRY zlDRXZh7(~z;ONDf z`1gMkWwC%>wirSL80YuxNhbW>ZKaT)KM_H<)uP{M;&wdsDQ=OXH~yMn{)sVC{na^` z@jO>^)+}2X*8|>lrv9_CoDD-)_9ObfCw|DZ+V?>i;(4xU_PiJkX)#Si5%m{%{twK4 zeA(Up`>U5C!U?Z6_}$Zlr}oW}z{VZ*t;>Jnyi>Z*SoA`tznL&{Iw}?n&>d}?at-UB zjW##td{p|;Q@)E~Iw`<3)nOhWZaXZ*sw|901AwZU=C3i`h9-IpRy|1u#Tq64Kpv!+ z>jwxPs;XKe;Gtp^9OJ1u(Fr|IN4NnMix_2;gdDFo zj(YDFWw8Fd_|bdj{0#5>E@W4M_gtC})%CnuR-)!w?Li})&k2J~7P>f{p zLra`!RIC1PV;$$TWIM1vMUH{7{Xb8VD-`yaX(#_dHG|HLz`3WXMGqFg{_PWx;Ej9E z2iwRT_Ff5{_&%|=ePU@x7p)zc*oDG@y2rPd#16#_eVB3wtNOdMtG$mdL2X4*jx}Mc z5dV``)$E%se{!T#b$G^eWiptE1_Y&GK#3E2WvMeR8kRMFv{4`CV58;ONOXEOil#Cg zVxUZ2d{s=;X^8epY46?cuj;b*ZfCc%!^U@5cPHx)4HOY^^8kW9;nrqyaN}*l$5t4p zbKzDs7NO4-KOE5(kw|O1E47V2upAgWk7+Avvr*(Se0r0CujMf-2ryY$q2Qu6EQW#t z8E9zsYIdNRzb4@(w}hgCRa3s&<_gk!la?h{sO6C61|^wHm7gC_?d%z^x{ znU}jCmB8B!`~V^#orVtTY+6PwQA+ciJ&2*X6X(7h~6Wj2sZ)_W7fI*(M z2pr>wKszf{tZNuzA48!HA@<;!(r|=_gs2JIQJERZW zu?MmhrV&_?EAh#1a3fYK;zQ`xZoA$=(fB358YTlgM4#Ma4%$;ENUk_EJvZ!*lqEBe zGWxzWv?Aw?X1^L7mWI$Ox!Cfn=Hw9YG6ulRRa{Nn8;vaWZy($tgc+>7h}ia_!Y8a! zbNR5f8daAK7G)cA?-dr7yM9$yiTE*>3tTM`s zFa8RLjb_pefOb)SA2IAdITEC^H-18wWAK5kz{~Yn^)TC@90`f=WbhCbkkoBtLx_>K zB2K1|=kXN9lv&Z;--FU23vV_t=cuQ`TKbV@IC14Sde#6yL-3$_(%!Uj~zwP@$uRgO5GRq^n3gtDcQRFwo#d zD71BmwD}ay*o~As;|DqNYpi{%i)r+w1^d?X?mo5P*Qys9Y*+t6^G()RUe<7TD@YpJfQJeU*Dz)GaCn7~9!h>>mTWM~Z=xYxOB1=q53MMS6!B zqih~;{0|?kl#v=I6VKg?Svdt*Tzp!LM#UANv^$<%WD^vJHq)4;@8S4q(Vq-^V5xVM zosO~ryd;Ajm*fV_|BVL3h&AycZDU-F*G`}{1e_jg#3p$*k$l3=BAtL{L~W;YwpzTs zH3qd`qZnxSXW%K(iWzK%MwTnCQ3#Nknll{sswu5Dv1BB2MN4QC>ugUly1OKhcxt+d z-oJ(=CPr~2jBJz);^zjpEsLiUcZ>I;m#yBWWDv0osgWd^ElEJ8Mz`dBc%(DQyXs(djAQsaq>OaF-_EdBA7!RY{rqun#0R27UG&zq^mPm8!CoA0wY^Vl+$MWoGZBgOT-zE^AOhx*#j|V_ zvv;=Ju}qyzefEdA1yt5{k&@qgEZYsWp=~@mjF^vCpAElJ|ceq0Z1+T`si8fP#{{u!TL>NpFGS-P=+7S4a z^7teW%Z~l4QkK|bXaaL?R-uHa7H3-7+A_7c{J5YZ5F`x!2x}`0k2iGVm|J z2(rF;O41AzF5ahXw57E`tb!}k{&3ivoj~EUVnQ}`3{@v`+RLW&7nXK+fY@{u5~kEG z;LXNcAv^>$uIsDG;y>9I%WR!hHT6m`u(*o!ZS#B3rd^s*EV6h!FFg8k>9q{nyGu)d zE(PLE^8IpMstarKHomC*x4)?K*VJQJH0RA=)?bs`9+bX6OInTgvb1PA#1*#DFg2i0 zi4(h$E&iC#@fYG^JnNoypF>bQW2-UJfgx=A!&_$PG0Q=%nX5UZjp}Yl$ z5mbS*2>$gF);Uvdlq}GQhYjucPp_%|uP+5J@4!Ea@@Bua&op82^_#uOamF_QfHRa(x+3=4R)UF?7rMT{6}03 zILt0b#WjWiH<~~b(RBfBpoJYM|44z+NLm6D?2RJ(3XeGpLZBLdh1A8qs*fOpa*sxo z4dL(ExLVb>V@9sEeenlNJ9p@9pq;tZ__GnsVachSVFvL&jCumUCXD2X{vgsEUZZLNivQ7$Z#Q zDaKeO2I4eNMxADi2;w1W#>A%k{MxYxtx9@za4*WF`a8Iw^yA`>u1SiI`;VwgijVY< zs7><1)ffe`KHl0%KGhETA2Q8lrm9*-90uQ-Vm2MeSVt3?6M6>sh5|(oR8~F15niyT z{wV~IAvC-%4 zfC?P@8@|=BqdTbtt-*=BEWp`Nb&Z&lMaPBHTI4$5>l|yc9^Lka;9PHo+Au2Dqu^gH z)@Q@+*pupw4sS`F+M+5oU!k{vK8=JRPoK7Un`P8#&XT*zkHr;eMt{c2j%pK2(tZeB zLv30sI%^A!zFKLvWb>-ETVf4-465hE2!k`syOWPr+8JXF0HSN63yK- zbPLa{?k=vMTUI?cC;gd2uUZ-OIn{MSlTdqZEUu+n{)AZkc(|<+P^!v2TJ%$nET=E@ zfEj(^63RD2)uEEGCQY7Jy}6X4wQq5~q36^cPRecdhh_*dc=Hnexg&`y5uLLpR3bVi zXa|R=jX-OM;q2l9(sxet5Bc;uRkZ(fHZ`KFk}I!Nr59`vtnd42>MEQF;3AQlxa+{2 zjK9b9OH@>2zfKjToJ(Km!umUoG`Cn}xPt;TgJ%l_hSRyJFeDq(t_~A(`&ek6Zs6`w z&QNht8_^ML)t3+2Xy8hMw4DVsX^UcHX-Y%ywj*`@$!ZAJG>w@nE@Q2DAgmR|?NV)Q zH%_B>y%e<3)S*#Zio1~idOYjpiEhDL0leg0MW>ivvk}d=Fa~7XMWk|{w!IL3Ub~y* zTgb=?#(-p)92ZC{tE5i}vUgc$0*_~edAq)jUY2Q^6#e-JQp~z;5Vba%%qA2Hz$cnz zD}7J{(TSh`1p{K<<)qMO#fxsQ*F8MYDOE4Pfv>n4Qv_uzxY&aPe(@Rc;_$GyyF%94 zy5cEBY`%g7i_Y2ew@(y~`bO6L-EW9&Pj9xL%) zA#n+KDT8xZ7vL$p;vB+Ugf~_bybFHtdXf?fod|aE?E?$n5niNJzz>ur-2Cj|26aEe z0sl--ABxzbA9ANTp5$j|*@Q!b>N4$M6ECHfJ&?26fGsF|rbc`oDLu|FvM%^0eozOF z3w2u|n=_^~A-z}I+q=CUxXQxMXPxf;F5EgF!7t9Fx|KY};oHRNq;s|?aAGhvX70b$RH6`JksN>U7r5*3FzowbBb!@v@mni=-*L~BOq&6=oHHHZA@ z#trl2noRdc{p)N})*$k7k{4>qui1{B%J>yl%W;iMuGG+IzR+lrE35)?(VyU}eJ>jn z<01Tj$!k1Q7yGIG-bj-!%9^L@{DYu|7k%=tA`dqK8f3}*445)R8agiuh(vvC0ve6g zJSg5%s)_cp*(mhePMH5ag&^YKEAEMXx_V!Eo zS23rF;`tK};yalr!Yd(?Z|dG0%%KC{W+lXl!M`C~8*X$(C&{V0IPqwC53u@QNu$@Ze309`2_7OP(Zu6~n<0|w(wvP;h|E5PRJt7do9~WF%IHs$qgh_&?d0zt`jd0D z-bj#pY8@T)Z;AilJuLN3Hd2QzBkwLk7k1B(Ciw)V?bDfJpn3&(&ec@Uuu(g?%1|~! zF&;gK5H!R{QynDv1L%Y@i5{hK-C6ZVt2YFqVu4q5E4Tt$&$aR-(z_*hpw;s*O!X#Op~AQKAT7Cx<1R2y-YCyreL7F0sS2i1=#be z%T0zs-unqCE~h3n3G-oG=HxX5AsAs?fP6|E&znrbd#wBB%qXgZLH`mQmN5&o@Ht5>6M3wI4gwQZY(Ve4Y<#AKYQ-XnzW}x;{mDcTP?3k?iO=XtK;h+o`$`NFm{M~GC#fPW)NYO!GF$SJY z-2AA+&aOc$xdf>QgH&H5glrWjLnEm7YNY5R?NLy0=|M%Nko?=e^xgJF z)OIL1TAMbzu;x0YEx143xtkm9q*kSrT$yXJ>#3X_~Ai4QoQD?TuC&(oNN!LMZ+&X@=$ItU#z* z*V9Urh_bQXPP`s|B558Ec`pjEMskvPpk<;l8d z@CP^RM@^C!yS-j#&t~H!ots+Rj{5!5XflJvbrk8%z;Y_OxTHKMvBo`(D|PJpv3b%I zZwN_aqXDnY2#1YYd5^IxxPDlxp)ns1eA`pAHGxbdps`om_^(@$=K6WSO?#16JTUkm ze{>+qmw}3*J_?5F4_1d*jy8Xc%_*pg-`=|6Yip`%I6p_=NHB>xghT)xkRa;~)%TnM8-&+0cZ1>1ytmP0-)GScd zh45vv>ioJQ*x6r`bvMAZYU~aR#w9DP_@malnAzI=uBpCFe6u2Ac!%(vpUD1xx=Tko zgn|>Y+w~H)&Yh)B8lyVF-_4d&jydi)O%NU}`qc%GpU% zef=MecB9d%JJx8|HfoQ>)~4CjjtdV&^5`dL5a`ix12iyWmXJ~qNL@zyDn$z5{L7C> z`d!{Q>0Ss??1{o_tU#$blbCOsl>*s&QZjj|r#`K?#D# zxy4-dkeBCROct{t0NVoxMT}$DAK+8bBb(>CG%M0Jelzss#X)FkWCM!7Vq^v~i7^H= zx|lP7bE%@|OER1pU8mxy2>;Zt8XeMl(oOgiz9NAEdgE0OHADLC86O+ia>W*^69DO8G%~CPIwb*_x8;r z^q(SPb%DUd9w=FPU?*264F>B~&2x_#eSA^Y+$~K7oGFQ`X&)&+Ejblmr+YYVhP1FK z;^2>D=|lZ*nGv&aYufT{?znh5nt@$Xc*0NxBS7YplVURFpxNKy0^^~z1on91!*otA zAOiWJ_dvro5m#VXP>f;z6jS+S9YUk;zuNtYJKCYz4QD3IXpSI~MK~Dfs_f$<4ZQYU zm(%P*=X-|7PEa=Xhr^s+JLs{~c{>7Y(r_9!6)n8S{g-|B-FF(>qurf)WFuP$oG&Rc z9ugEjZ8Y>lx7p4RMq=^#MvKA(ZwX{6XIOUMo)+qS1S1W&H|T8$2dAKBHcXO$M{ewrO@RAq)tMrcs)+4oxwjHjn zVx!#=rHZ$Q=#zwY_KiWb*G2)wF(qd~KiXQjUsX3xnlIsglf2pAeRiC5_K)BG_~z+b zOuw6FR~%}+e|Zj1pGu4w%pk4@S$DJ=b}Fng&%Pu*j@%%;(XZOf6q|u>RKrHW5b@=) zJ5Oi9+=xz9Yc>qZYQ>83L4Ju6y%or{L18rsvV38Ik?>3}p)5$F?0(+=kkO5RTq7X& zuC@r%t>KP%6Q^KT`lcHc2dXYKRd9c$XADRHC0AhQ@5J`1SfG-wUp-&jc>bs7hsSFi zfrc%%HXbhPQzw`~tl0_~VEs^!Ixk*&V}1Nb9c#F(kN$<0_2=KySYwB=8FBSlWe%vQ z@j>May4I4u2~NDX#!1>TSff-9oMwp+SM%RzV5ZU!SY?G1#mRL7NpdVQ)l68MgB#0W z)Zb|PAD$adDPGq4E!Hw!d`g4WwyI}!Lnwd;Hymh^?egJ{wRAKNbC-n~(d%j;#nxX| z6k~RYAhwvaiZ_Y>dKs(cY3amqsdZM~-Lpz{B@Lo8RNbLD^~G#7%~ea|&m%o){A(>a z7m%AMH81fgRV&#*x=bA}7JT>uxy(V4teM~j1uf|6#VR?6peS0L&=}}3-|jruUWzvf zn@K4?1LSNSB=sc3QcnOL2lQv|1=q7@K72;3CFyAeDmg$<-C?1wxQH%K^0~U@7Ng<} zWHp!YZ9Wr+?8#A;O~R+BV23^66Z;Cq)wF(ZXrG<{+vISZ=oksFP;}n{ChC;15|87K zqHQedfP84%MKKwIJtAJVk;!^cV>J@190VDv1Z^%krxFS}A|vxp`pWS#{9GMksBMvz zB;7sO>mKax9`)M#`f_;i^ssZZ)9dc+rYJnO#2C?WQgQd*Me#l(jYv57utkqv9gd4B z=rJFM=Of+kZ3}kti;i9&l-}t5>%Lf4bcuB}zN3$ZeI7|1*<;dG`` zC8p4W&_#cGo+_DQSX?w8Y4J&b^C)iK+y?FA^jBS>9n~pSk*$T(1{D>0ti?nks!jC- z%Zx`dB#*;4w%%KQ6RfVVxjP0|V9a11X*=km1r?XL#yAN6m9xCox;ytN(hx#JN1Pl!6|51oK)`7xDLjIA8 z$f&=gsZh7P@jxEp^;pMe5q{qmUJIh_G-xWU)3=7EEi1HkA&{U&fTajwgn9`g2ag&+ zJkbZBVVcb2c*k&GV zFriqzGraHX$LR9SqqpX1-Q+Uo$MqlLGO}Yj;1Gx-_+lMifrJ*}%^R>VerGOW9JK{q zQ8!JL4vI8ziteM391#6fVLHvFk|IFnr zHy?n+;0@makH9&e@)X=L&Qk5KzgB^Ly8EBI+pmth2Ya=(*j2f<4w)QMhihwZ6=}yS z@-uLf92_3(vXgX@7(CD&8q2MJ^dtIUJft5xk*I}?ZJ2iQDFHgyRDjO;`VN8-!2LlQKYTlE4vWJOjjMcOZO}OtB*g_6MrqY0 zY^AsH#1@geF@WFr`R8@{LnAcEzxQJ(ov<2`nHEYbKOioAt$!imld2UZafVug|zX*jT{rT~jx zy-6bgvXB-!U@qH^kqw&@8Z*`mpLy6~JZbWPI28aWV)TGosYp@8>J2n_a`F_JczQLq zgVrv?w@CIP;Ki1KLvXO2Sonz43Xg{U`cu?IjJzqH?s6pIvBD|224Ey*&$TCuXtimH%cUE@b$#H|`+764@;nO8$eO*r&QU86UB|H~EogABxe3%zG%cY|A-JbZQE1I)>nM4iEE` zs+qZl1GV%wyC=AC&ZcnYSp?@68yL9+Nv(3@u4okohsoNoROw8z{+Dl>=G4#8Bhhmh zkO}1+1k|CtLmB%V&cC9A$8DmqV#~#lQB=Ib%_tr*XRfrhMshl%)~M3V;T-m|vmUi#*Z zM7rWGKNjuNt6y6<^v)#vkWI>r-bN=1=7cWG{;a3CPkxlk2eX4;|FY$6rx@{@{VB$! zajG0v#g0etP?U{X}F@yY40fd~I`05S93q__vPTX*&(`VKwODZy9i+yd43vBON$)e_ot}U$h z2mP`Cf@k5|g%gqyQsRlaAF9)2tgedMc-HT3h*3<+g5;pn87jlD5*dF|Eu))GD~Dy$ zTHo8a=8-`oN(T*gT!~OZgGr%LNec~{vd>8k*nzv({5@vCc?Tax0q5~LR)qfy(trwC zCw0vgt4~5_`p4OQi^)kfmxrhXVz6CW1hK3YS{%_Uyw73X%^eQRxfeN;B)?a* zOH7t!x>An|G&=S)5R}?y4CfeZS=9#^B!C_gU3(%Lin6%KC@3^wkyfmmy*>Kq$r;d; z;>K2}rd6g>mku}9*OOKfar%pIJdRCC8QQ%%6oQ-swO zKw@b8hpG>T&tPztn+F^1=ISRDoS7y6A(t z;kV4Yh>(UvmttbWMJ}pHqT}e57x%NFM(%Y;k$d##QBgXER%iXm2^JI(_)f} z@$?EMk4{vB_z51MR&dEo!#cD_8U2caVJ!* z?(Ck*zz1|0RjX*!J}eg)nLsRor(ToMfiGuZ1_*9EW1+XCimC1zGCo*w#lpK1x~8NH zas&Aa$p9aQFTl}DdeC+Zsf+%#F^4+ukI#UIbrJnCL%?O52CQiW^|7E|oXp0-Y%txJ z?UlOT(prP)`Zu}UPR3!8+gHtphdR!m2q9ufL_?ARM5=s@afj*#u@DwoL9Xj~kq|73 zUIpW+E;@3IBYkIi)j9jh2U`Bxw+d(`(`kfPjuywI4<20{NeM2K)h{7kCs31q4H1G= zWlIPoaMMoK*-C>Wh*!-4KAJ2&1;ypu8CZ!-fHOS3kYr_5FzLE0eTdR$(X``Q*>&t&kHs~1@eOMF)e}D*~qomW- z0-H81RbNP6OxcFQR=J`##X&yGr#dJlnQ7^R3XTvk@gEOe6?U3n?~Ibdq0*b6(_Q5o zZ6uP4qxEqN-_1NZo=21?)a)>8JQH%mV0%_YJJ-O@)X6)B*FnimW+jLnm~?=_+@w*< z-fx@p{x&C>*Cy=EO{Yv~BNad+@>no%c0CjDKzTL+cjN_{70`KiH#V>aY#@GGvY&{x z>-WvuzvOPIJm0?UpwGX9PIC@W@**;|NG2hfp|8xn>?H@#GCOIR(_*1LC$>k@)s|8Q zakL<0>*3%c02x)&dX53pqPqokUegW`T1U;I!dA#a?!(Z@=yPMS`L zR|(}z)Uy4cxVV^&b4oc-;yhyZh)MEnW8Jr7TZm0;+og9`v1g)979DNWND!% zzY^3k+PQQoZ3eFjEZSUQj5fV(p{A|(>M2YH3lbb-Es0g;)!06K@uG9EBO5^h$8OXM zs}6G8vc1Rw(N5N*-RkxA`(34iJN1ho+R4VFc-KJU(Gg?8oq7fcJmLz~mJVm41pYqx z9qXqg;Cyu?v8k=9=Mw~_hmTlvR}>Jl(s5J6^1q6f%&PT3#x^Pml)fl2D2aR(ZZ>{c zUx%PTO$$UDjsKMV0&h=is?2BnRMgU;3CA-KGDq2|Hi^;GHp#%rAzejIBEu&#IwCM3 zbfNIDSRj3_{=_xWx!x*lD<^TinjO_IUQ-&(w*$lawzZp|x59O6ye$#&FERZ+kqn zsZ0Qph?g|XPA0h%L6UB_HdS#f-|;j^cx*>v`t7sFlIjWbtc<E)p8r#OEXwK3b%tU6d(3hEO6wMaIGEJxY6R~U&X=RU z&P+1QPW!VFTAHf0(e2?GOi2hCCRuu-`H~+ILJ+xg|HswkS2eW9rG~udoqR$`dA2kN zVq~9^Rs5YCpX8&w%pp1nefaxq+J_JDva<1Ho$t@ZL_+08KF|Q9ZO;uEctu0qHH4E} zckaecZ9^?>?}l^RoRn%ds$kx*0@fz%wX}-adRLK5SKWvva%Y;qMKtlCl0d-b=S5oy ziHy^Sx7WR!3<1zX>O-;P@Rme!uHIe|5Zb`1*hkvv=4+ zwR~1gc=ha@Ed~&B2ETfFcX-dc$8|tp7dYk5^XZa3Y#()c&m9=s6A&5a!sb*N_0V^A zJ3BGpi{aLLe&`Ng9h6f|me}5R6W0eUBPwFz)jYFO2hQ6nZY0G9!u#_^J5VlEWp$-< zW(OV#i)-NP82HHQ1IzqkHtJ6c)#J%*N>=|R+kfPzoPmyBL492jg-=u@+YE&krc1QnH}i5A&=&9cYio{7*#$mih9eA6I@Iz?2Cw_9>ORmo6&`i~oGM_jcSGm|9%E$vHLyGh(hYuPj% zyi?5XpuMr#sA3q7Nuj`Xb4U=Hb+EBwqk>F@{gLGQAnw2M8t~(p5gS1=Hak?wY*S8q zV=3NPv&B=#i0zJdXC-idu^s<{I^?I3QO119-Q{kX*w$_V>;~scWIMR!&a&x6Yq(G? z>x{F?DF(}gOi_@^65qVg0|4{15x!%UBqY%xNU;aK>&ITLSXmu8ZE2%`YfH$BNdlO&-BJ(S@uPTjyi z90sUR;TdhPwW{WOjh1$S2Tt(rY!Y%t5}piaXn|gQs6OSV*Bm95!pegeMh?EiZii$- z>h}jdIZGb2@EC_~=wTya*q0S&zj-ZSuL9ao8f)RQO=J{?YeHL{;m3Q8j)9wh()e>p zEuwI=!lL1vq6?lqaGouEHq?v~YZ}8qPb{utke_ZAshGN}CVnl`T2HzBxpe!;>~I>& zrA84_5! z#Mu4%70ZL(Q2S1hUw6Lc&H z&6CU2y%iD!HT`FRj=HK&6&(#T4Cb!~0D`z%)5ojTYA27@VfKd^$jTQK7o4~@8BFt} zJyP5X!i3n{zBuWV{k|eMaGd4nQNj56Y7F9eMv{;5^%>E&AzER&7RE44zgAI{T233! zY65EdXi-hZ6OWKs(;&25#K4ngyi<9tO%C7puiN$Giw+Fdk8V(y28rq;L8JuPAt6Wf zs?liZZajgpoqQr?padG#a;&EtzTg(HKz*2E!X@B`R%aF0i_=P)m?o@NCT=Ka0rqNI z$<3@9YH^;njGW{*fH9ziCUw9N% z^0@hejrOgm%=05}|31YBex7F6Lo&V1=ry0-6iqY&M;hZ4eBg-vQ=_7My{Wxd-KiJt z|5DY?O(2Pga?MSB2dO|>r*T|-6VZ(E4iez%Hc%}2o==s>XH$nTrx<8dQzicjh*P%` z^vRzVCQ+`xB$aY2hfoR0g{agWPXIbDiOXIB*@Gb(i98O|mGSh~Wl+{4>dNAqjOXfZ z`%F%FWUJ{_ui0&0mDq+0q5P$$_0ro;j^TcG9z$Gq^R0x&1?G5h9#`&Pqx#TpV0Aa2 zZ&0++R=q!R|W@K7{ZIVZGKO73hhe;Df<{B`_YKhI;S4L>NFY)Yi31PR?EE&tM`n~QQ0QV-b z5lt@5%)X4I@_B`k@W5JD9I074(ba8MZ*fteb^#5T%7eA;%;QGA+2pi8z-V2Zp&4V_ zD&eDZu+wPM-@WIZ{r$t&?_PI~!LXS=IzNsMJEr#0tAp2_e>Bt&V_?;pvbho^eF45} zY={j0mZvzzRAT<4e8mYSYYt+~gRQST8=!I6QSUJl{_^s|`in0^z*=5k4T+znVr)(G ze@+3aoA{@3#WScl6J;x@@~q@zRb9D{qs}vLfYuQY#TOZ4`YT+ zXJzDdkyGhHH29;eciF!hH>w^?p_5;;!Q+rUzl7M7`Yq9_tNeDYYM_s_0Oq~~LP`43 z?GQkvALCW8BUOK^N9$1(EwN1%$dTfoKtJMZ(}PkqcnQeVai6HTO63K=p|yN*7V;+i z{5JOdzdq;vUk7)Yql6K+l&vb&z@OAL;QxIhqg_~_&dl=Eif<`#GbhlEr<=&foqXa4 zP;yoel!ebTFvb;&M;|KIEk>3Gf=^M`$y(TxfirLW8nFI)bHR-pJ1VU3m*nxf7Y%G) zpLM1pL}Dk|pg$`il<^2s0{2g|?84;%pb-wmdsDct{D7eulhN9&zxc$3$(c%6=2^?C$l_wK|V>NTT!fe zgomn6VE!9yN?l?CYE`zyyfq2{=F#b&l+8$;^dsEzYinH3t?^qcU<)B0e{oEAu&#fa z(xuSZ3XxhIadYE8)`4aDDvR4~q~Q!heL|$6i{b<3vmRexfYCsdHt&7cSQ-@jCpz$o zki21SeZ!Wqy8WYy>MUw-HvhzlY$4BR2`=3@&*zktH??y5f;LA75Y37ghj-e}cJJtT z*AdxuhoMp}G>~*zj*W78ih(y&9}0e=I%rcc1V&s3LA@{3D{P~#)fForBqfM)>@>ki zKbyb`@iDfgJpi+$_pC~upT9pZI20Aq}VKcKusd1+qOv*b?=6pfSP?BWtyH~wT| z2jKj1x7AQ&S~&zFSX#`K^RQe2k@FZb1x zV;xDk5A}({FR}Lq{^zxA?)GiMNA|}yaf!kv`$)zI@3ZU@q5(n_GldYHeV*C1X-D6| z_>XKjcBupzzk5>3X7n=qACgplMIw#T5T}((=pyYaC~H(WEcmw-p?=K zkZ%6%)AtA{#Sb^F*wUJ~cup2gL=?zH%?kF><}BNKC8&E%f$S1(wkA(L#VmBDho)7x z&;S4SzP7oI8%g-Hwrc;w6n!a?4#`M%oXx7Dt5qb~*2S`1lALVL>r#!#ku+zDqnjZu zbMxqa`-6S~(0CbgNXbd|F0Q+cID=^bjYgxq((HPKSycVLBJsP#6WMa0M)psYV@|8AQTmLkDq>4T;ftp&0lSk0wTAq{6X( zIG7^SrT0lCW3n|K85D0Va*Ty;6RO`K4a8+TeoJ0X8#XeQGiXhOY9C~mZGCPT%b z@@oi`;~k}E@csVtqvL(tY;+LI!#9N!;|9tZx(BYqv?z()0NFL<0Jk%zoC1}zlc$v! z7xJ`W2226PT06hj`#yc9mIy{qH7SXO0d**a!G+qv>#p=AtZ82V- zU>Pzk{OHl)e_#Vi&TNlNlTNVO;yA?y{|G2Wq%!w*z>A83l1cIKYZ#F;41-z+!j_4G zjdVImKhz)aoXcGwddy!na{DHoP=vxTUj&fGFwx=rQUC;;+gg32Szm~V8rw#iQXB*~akM5+uV#*T;H9)*(vgBWoVfzv=~d=axScW=>Kc+80%nVJ`qT;U zIaxiSO-T`z6(ONO9wbQtH$6@UsmGzD+MBf05}7`&`zD_yZYbb_Y8N5^*l2J-o75U7 z1?sg+b#O!J@2*%p5_u%@Kz_go;7lQrYCWk}7y0G1+NEL6CDc~`jRsF6Hher zq!NEx;^2T}oWXxj^TCG^DM+%5i+q6jgbnpP@wS<_7@ES9<~xl6?=Vv{`wK|}4<}P- zQVq*-$EDnwP))pM6iLlaBav=P%X*j$oqcofQ*!HQzKVq1lh3|yiOy=nxCn~_7d zPUpv1ia7sg27&*X8ijd4i8Bh!1fd4v%4+i<>0KTGW7c3!NN)>RnJyQbAWf)RviCI= zPJ;~DAQr;eFZ@Go7kpgxBWQm+<}3)KY^a7x>|cF0wnv9(5t;B#S*A1f8Q;Lt`(k`pM5qSOWaOeI*VVeYd@3^coa5cc@xHFK=jA z>EzIQ2oict4gT*_U&iFP#RdDyTyk*3SQSJu7);A#I4vEC z+T0I$=A5_}u2(1K3YR3^BAtR54R^f{v@ zmcX50{(eFiT?-4T2m&6e(Brcz;Olt2!+S?Tb6S8j_mOIb=6HKDq{(X6ySPk&3dHja z??UWEVFX!l-A5Tk*NSyBuHog_Inrq`M?lF^KM95)W3}0!B{ki;79*==)lM7&-A2zu z$!Mq?*)^)_@$}Yo#{0#VR#ljssIgv=ekIxJb+9~yCNeQp+P-u}hXXS&fdk7+-=I(^ zoN$#~cW9;vlqr0yAhw`5M+>rCI|P`r&zn*8=sG1WfF5KiWixT8PvM(Z*OW$|pFhf2F46>#0I_W}tGD5Mly!-+hS=Ya zICT@Qf|j;POBTzo{6e3R6d6b~MZJ30@`OqpcoggE!Q9dYc@KTwLFH=;^nLP262}I4qLhzLpIy?J*|LljIXB&`q5kPaEr0@5WA9i}r zHvV?JbNHtBf{v*@bvTc!Os6{L@&{yFeuI*}1Eht|T9n(y)qK!5AJa0&Fhg_CVmDNh zA@TAcPHn^&0ev(a4qL)1V6HK`&ortWL_#p`ZDOdgrMKA^SIP4fgLp^9LkwK~T03=< zOk$nZYKH~+nw)Q)giW!pwqvl|FAmTEL9u<}vB}K0=KeDZ8@69)#j(ymYOdVoqJsCO z6f(Wt++?saYWW7t{7{(go1U@Aj?MuR>3LU6jC2f9&!FDAPRBD=fMdyaiX;S~3LttD zuFNGtdzpLP9A_6J>HKY`V#>tV@C+>eqfMBm6R0&-h*>%x>jal)FS3cznlhC|=^%;= zvk|O`f~1KTLMdyDGO$#-kIM4CUq73emaUczfUWLaq4YMLDe-5_WwPy@=r$WeDjD}d z*;`T@tH{7novO=!@909I8(1aZl~GE>ndv-k?nMye#)<>*G)85>RpU3 zd_`6`2)_LX8*7;%SPhu7?nXaVgZq<=HFEmWZLRUzi0N9f)D}WOUPnK&UZ|#<=TzA~ zotSFelto}Pk`B(0R zh8M!$!S-bQQ?jxwAjQ5puC}Z=4`m(kYpU^J#U9TMpia1e;5Kw~iM<0?m-Uv-zNOQ^ z^=%qCVo$MTa^D{upPEE>N8|5vB>br2#k|)FNC8(IjQaF z#3x_&SgN^RAkcU=I7rP+<|T2Jb+lpTim4ekdg`!o4L(ZId>vZoe;ZM@wiC2|MS5^- zK%}o@jSi<~L0dU9s9#&aHD^%UcyJjy(#P*xs+J?&4hH{+1pbEv{)YtqhXnqI z1pbEv{)YsHJAwQ<-Ydm zwFWtzR~wHQnBA2cC|U2w;>UFl*q(!734~Zh)4cgoE>jOiqPnh4N%43ABJiKYKo8?# z?fKpzO0&UqVm!$*vH*tC4$B@msJzm~K^_1b7s+J6>UfZa9Cy1en>VY%T$L)F)2Z-1U3o23eC8^@!3xm&LX#%d^yX%SoDw46o43VE1!a_~sMT{}P0jtYCP0EziJkqP*M$H*qH9uDHGLI=5v{Fu8 z6mRgit!(7p0M0YTDXM-F$Te9aps6cMlKr=0_15Ri1?qd8_G`zuKOQbOLi8&@RReSm zx6#|Q999humGong4?Sq=aYlZesqH#T%TbOVq^WRPG_RSBBL&n?>^L3fQesmNm z%IkX0XNC=JyThCF2@iQ&PQc_nTI#U!S0Ol{<`+A1>$!q(o}!!Cpim2u69;fYfcnYz zN<2MS2f|cm5%9oIYRU3(tUl~{rr>0TkD?w1V#u_P#&wT}4aA`ZHeSFU^9@4va0o0u z&uI6gZXhO#AVytF2Qhh2vP%^o7#&Ft*!MEmoubWWhl>+Bww=nkQ#C>@YIf<=q0m6~9=$4x3Usl4#E2KX z#Z0)_v2mJ?KY$f%Qh;a~e@5Vm%OsPZxNmXf2IzK4EPRT>$9Lmgzeif`QVC%(-0L z*4@YCLH73KOd}0y4+farjN$%C?BUbc!>?lxpRIRwm`dbd(EOVijK9Plej9uE*Vx0& zjpfF$8O6h96cL+G*CFX&1jT1S%%02;rFVPL-F(8eGq-D_e$AoQ$#Wja*r~FV{1yWc3Tv@e+qD4V zvX!vIlBl<`4xkPhONdui$b!5y+7t=0hSW9ckOdoVcv(5#dY)tUXpBKIUaHzShCOp!b&X^0^4Qbon|4G$l(XyV!{5}fdORi^U$ySC zSmcnK-&#(K@MUOnJLIdIsD^loe03`xh}(`ZTx{5G#!F+@TkWACueI^sZ4Pv|m3Gb$ z{IWrrU&uOat+4>3X@TI=ogem(ox+Q``?DeMxPVICnm@W6c-I97g68jcyJLXqD&LfJuM%h$)| zx(G&xDZ6d_46!+J;q#dirG|xcxQ$Czrt*zN^jp_77B+rtC zsLfP=Pt+x%s)xUqjV9^e<;2w18d$BIaE;RtdkrA|EQY)Y;Lj3ZBN=s%{X;l|i^Ya# zKVkDoU_qhhp{;+59U9xoU!hp=Uaqh`9&+vAO%N!b#jf4xW7rmi(iLmhm3WpveqN59 zECV=XHP%xT&dI)FU4-TW`tdN zLAA7ksUN1mglIy9FZ6(9|Icu9E7O@ zWo-2jeBWMbA@r^>n_d#xW67^ftDikOldXPkqM_?y?qaE@X_707^gnMw3HP^O_I6Hp zApS@v>y+su4v&sb_UG$UL|!92??kpnC&#gyugJ*nGBpS%DGKFMT8yR#h96CI7dlaI zF;kdaVUu?7joR?=mAGC0Mp%yAOlX93AA!HzG?_)-F?$;s(R@db*iYAGz0y zZP$R*T+H|s=8_j1E-^9IMXr;^B_wdt>IU?6IV#Sc4{52|N$WK`^ILPj z7^>$lJI+V0{*gTYW#+aCI4DpR2el%_! zr&rR+gXWdq+>G)_9sy@u@j+NsiUo=};dli4s||AefLbPuMeXSEMQ_4cc^3@J8P2Z} z!{DzB=CegoqV50*60C!vZ>)=r@yGEzY}AyWZF~`SC@{&Y*#TwABdv_?=IduxCke>? zi~TL#XK72Q1AH(Yq4yr9fWR6pChan*YhD$%zgRkgy0#G=FNMBCv(kz6^#k`&&uW6`!SGw=mzN+`h|qPZ z_Kv5C6J4KVk#1}HrFbWH0c_kKW$dg>w-|QvJjFU3N+cD1Is;Q=YX;`L0LqkaNS?90 zm&>*q^@odmuc&LZKMSiT{sy9d90BQqk)yNUez^pktuS|RTOO-cQxy(g%6)bucTKeJ zBv$JLmUdB1puD`T1#TZ;srM6W5~bJ-z$VYK{h&X8+u6x4VG-09o81xQtmh)HkC5u# zpf?2iF}7tuu}6{{z|h+GUkOFAysy+lM}&@Kr(msJgv8t=7NO4NfW{iW5StWB=Mh6~ zM+iVsRxl$NbP}hGNNZ{y(Pb@VFluZh+O#5LaL4mgU=QO|IiG@xo23Y7&EYkXv?Gh| zqUZpWCRas;vd|QxA%pz_36CMpboeo^v>{h}iF*Pry4qrz5R=gayU0r&FpZWl&)ZDb zmK>JF%?$}f7YbkrHNqgy$%up6{LPgmoscd(iz!qk7XeMSEEKyQnUP5sDUzvd#5j{Z4ynh%BXV*6SrxNn;U?aF27N~CpH(V;8}mJgi- zHmxBs5Iyvdtpkd)@3v8F({E}} z$S@^S_hHI++sU)VFd?@PCX^uNr3*^g20)uIM{S^f+I3~*NCeJ1 z>gfGE0-pcj9I}>tNbc3$yc~?OH$^4IM#c2NwU##Jn3}XLWQW~;x#|2&I?K(|^uO#p z?T79>XI-p-DZ8{2LK#dG_x|!ut%e-9qUu#*F|$ znqk1-fpqsTB>9-REGPNc&t|`tWU=Thjm~88NgAEW|IVXR(<%iH;iTJtoP@vrNf$-Yo3der=NRdZ#Tr?c<$Q&?P^)Y*5mv{;{W(TV@34^>YVVjoH9U1y#FS-Z61ne(F-P)&P0qj$}1^F&hz zoP3@k$^`e6hqjvM9wuGP%mm_Mgn9iSeqOG>v&jit2f(*c$n@flb65nDn|E9ro?-%u zHxd=mjDxa+Q`xn)tFE*YIHEWK{uOmIMEvSxgS20h8LyGf-NYCzk<4$AE5tg6l zoFJ6k+9?pLK{6IeQ@hi$QdGI4>FKH%8Pze#xSUc2rRPF*<@9Nd2DJii*K}xo&n`f7 z-8EWYElj%-`YrkdsD`0L+$FjAC(g`iBzlI6FLPVjFO-wjA@>|6fXYqj#l-kn-V0R_ zUDp9+bgYJ*8GlCkJte=_63vRvjjkxp1t_#7nY`6pg{~u+^MJPnNc~=t;yYSE$)e5wRho7v z8fi~Zw9X-9E5U@T{3>1gP0m8Iq2ii@f|>RqSh2T>YZPzZrM&#pB4p~iZlolXv10)ykHKuY9fg8oq! zr!NMHLx#e$=!3ww4jgr$#^iekd~m}eZJik%yAP=DOp_fhC(s@bqHRWVPtwz1^mRp% zoqhyZ=fA<^jhCX1M~OJD6Pl*EMO;G>>UQ{TH)%cUKkl`X&Q>)&$Kc%F6Zaw^;dMkL zgM4n>^TiP0YFp6$j{p(=cP)Im)#}Pt{DU{2A#moi+I!!>H2VkPu_aEXD@+vmFyuY~ zaZ%L5p|<}E$eRf9cSzdaMSCG>_a8svun*0;y_>stbr-*AJ8atRz~LgRU6vcr=cP0< z`N#DDltlxZI5{8Rfa*pNavhiY?5nuuF5}z<(=y)z0t;iM{1QISQh_$BU8AA_s;a3C z=fddtJWS~9e37*Q`(HvVu+YSL?$Q|na2TO;(o1d_CpK3CaL#_R4T=jdFb_jck|p}p zENxhxVw7A>RbDbJ0`4o)5hO#oi;qlkBY5GSn*U}`O;LAo@!2Pw z&m#w3$1b2g?CMws-tKf}*_?$^TigL_{6sl}bLUzerLkCNPb2OO9UQZbXL_U&rwp3gsPENwTi8C5*aAaz0B0M|D9$zKk9^KSD!tq7uG zh4r988E$6l*Y3;g!4%PvPfQm0Q&DMwatLF3N}I2N5;f@1mVqv$yYuQ*lG8bha-4}A zg$QHH?I3bGL{@%o7VHOE`dY5pHbBxW|<<_n_1gtFX&6A>h}4* z@8l|w5tF6|H!hM3nXbPsL=_Dko?}$qVS&=R`lK>|(e)f*JBQ_J{(U86QW4lOnD*QV zK>Ei(Lx_gegky9$M+BY|x#{BmPRh=n3!T_vED%)2mga7?2zeV3qKTAnPicCsmZS}; z7H_pM4~G7JfkQ>`Ene{shI&V>El9e>l44|Mgv6xzw0_nHE&uC1*Q+9unM+HfMjTtA ztC#z)4t9^;obDed{w8ej_0GZZn^!xp_iKjg_%?atWpAQJ9)%%X=~y?8dWl3<9^CnQ zUu--9&k^povj{l+605$p$fa?C`{p7LvxOjLNg#le?pS{T>f`3@U~SF2m~w!=+4;J> zi#Fm@D*1=Ab=A2=J&GrJUUZ3AJ*|-oxc-f-Dz>PySA7e&_L%Xhj@BQuR@a7Z)C)YQ z2@1j{e}HX&>q(-M4%JxH$my}R5E=$!w`DKAh3Il3JebeNHfGB3{yC3kTlU@Y9wWKuzZVXtS2 zF4j5{aaiM{?R<nG}^KMDul=++G`-)>+JK`?^Xch-Fv%K4p zww8eG2X`#{sgZB4vXpBhLjjeaz=IdNleZ7y5^k8r_1zy_84lz+%?vSFTXC0CQlO||vaSJ}9KtDp9Z^71SA z^%Z`q@O!4%M45kjv|C(Xt6wEQt{CX2b=B{uAjSxrPEMMm4PXek6+U=>;{r3j(RY%*>y z&2tjtML8vg=Rw!pjQ-c(L-Te~5^rEPlET?0CAgcypL#`2Pj+`b2-PNTAo_}g`|zZ@ zD)9Df{dMt%YXf44N@BjuF@p}egDI|x*x+7N!eygKX)N} zBo)C!-FpfKvXV_&_LeeWJ*pE=tN_kJcsm;Y zhDkI!jV7)OX-_?Hgc+PYX7`}B(UFb@nyB;ik}oA6)=B z+}->kev9ZgUMzFy^^Prr@Xcn9=yhHUe!zKT;I(cS4MIyrq`fqDNwL;6aT~-pY+uey zI5gpHKY7h%Qij4oHix?Qb#XYp>x|=E zt9jxUE!O3JvH$UChUJtY$qn4+sAMw^R2E=!xAi2$VAE1GLr69InCr;~=iYsGa2Sgh zcSf(vS(kJ2@@-=cOG$ z(Z3Sm@RAbUEKfF;By?iwI%P-7P|iyf5ztDaNOci;BQSLZY{|Cd$8?kr!KRzzEx*h}rE=CRjw1iY;4B^S{=ZDCF!*NHAVKtEhg zeR6x1k7VE$yD0{Tz?Ql`9*wDDkUDF;#2RXRY6t$9smbJ%87kE_oszn)&N3*&{w~H~ z-+RiU<-Xnat7;I})g|=Yjn)+Cmq~s3`R{@<9(MQ(SB9P{UL0GdHB(!d2DB$?M%t6a zoG7wN;IcSl=TK2dZ!u*q$|1DoR*`N-n)sEIm<-NEtT#@=9@PGrq~i>7FI^WOGmM?E zb=^&B-*P&}!;uvqGNyv+sKSL@pLRu(U*D7p8s!(rN_4^<53o|bu6V~HYLT2{{AW5G z=9IoyNs;P^sIF1$W7p@8*;PImX+P697UCA9X~7XHQSA71UmPiEGAeK`YF^L-gW{Sd zsG7zP0RuUR&9ltZ
  • 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 CD5PZo literal 0 HcmV?d00001 diff --git a/Moose/Base.lua b/Moose/Base.lua index a01b9e2ee..278af6459 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -25,7 +25,7 @@ local _TraceClass = { --CLEANUP = true, --MENU_CLIENT = true, --MENU_CLIENT_COMMAND = true, - --ESCORT = true, + ESCORT = true, } --- The BASE Class diff --git a/Moose/Client.lua b/Moose/Client.lua index 1f671531a..d927f46bc 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -34,9 +34,10 @@ CLIENT = { --- Use this method to register new Clients within the MOF. --- @param string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. --- @param string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. --- @return CLIENT +-- @param #CLIENT self +-- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. +-- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. +-- @return #CLIENT -- @usage -- -- Create new Clients. -- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) @@ -169,7 +170,7 @@ function CLIENT:GetClientGroupName() end --- Returns the Unit of the @{CLIENT}. --- @return Unit +-- @return Unit#UNIT function CLIENT:GetClientGroupUnit() self:F() diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 5f4c77ccc..fa402e00d 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -55,7 +55,8 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) -- Escort Navigation self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenuReportNavigation, ESCORT._HoldPosition, { ParamSelf = self } ) - self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) + self.EscortMenuJoinUpAndHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) + self.EscortMenuJoinUpAndFollow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self } ) -- Report Targets self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) @@ -65,6 +66,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) -- Scanning Targets self.EscortMenuScanForTargets = MENU_CLIENT:New( self.EscortClient, "Scan targets", self.EscortMenu ) self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 30 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets30Seconds, { ParamSelf = self, ParamScanDuration = 30 } ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 60 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets60Seconds, { ParamSelf = self, ParamScanDuration = 30 } ) -- Attack Targets self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack nearby targets", self.EscortMenu ) @@ -138,6 +140,20 @@ function ESCORT._HoldPositionNearBy( MenuParam ) MESSAGE:New( "Rejoining to your location. Please hold at your location.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPositionNearBy" ):ToClient( EscortClient ) end +--- @param #MENUPARAM MenuParam +function ESCORT._JoinUpAndFollow( MenuParam ) + + local self = MenuParam.ParamSelf + local EscortGroup = MenuParam.ParamSelf.EscortGroup + local EscortClient = MenuParam.ParamSelf.EscortClient + + self.CT1 = 0 + self.GT1 = 0 + self.FollowFunction = routines.scheduleFunction( self._Follower, { self }, timer.getTime() + 1, 1 ) + EscortGroup:MessageToClient( "Rejoining and following orders ...", 10, EscortClient ) +end + + function ESCORT._ReportNearbyTargets( MenuParam ) MenuParam.ParamSelf:T() @@ -280,6 +296,63 @@ function ESCORT._CancelCurrentTask( MenuParam ) MESSAGE:New( "Cancelling with current orders, continuing our mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/CancelCurrentTask" ):ToClient( EscortClient ) end +--- @param Escort#ESCORT self +function ESCORT:_Follower() + self:F() + + local ClientUnit = self.EscortClient:GetClientGroupUnit() + local GroupUnit = self.EscortGroup:GetUnit( 1 ) + + if self.EscortGroup:IsAlive() and ClientUnit:IsAlive() then + if self.CT1 == 0 and self.GT1 == 0 then + self.CV1 = ClientUnit:GetPositionVec3() + self.CT1 = timer.getTime() + self.GV1 = GroupUnit:GetPositionVec3() + self.GT1 = timer.getTime() + + else + local CT1 = self.CT1 + local CT2 = timer.getTime() + local CV1 = self.CV1 + local CV2 = ClientUnit:GetPositionVec3() + + local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 + local CT = CT2 - CT1 + + local CS = ( 3600 / CT ) * ( CD / 1000 ) + + self:T( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + + local GT1 = self.GT1 + local GT2 = timer.getTime() + local GV1 = self.GV1 + local GV2 = GroupUnit:GetPositionVec3() + + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 + local GT = GT2 - GT1 + + local GS = ( 3600 / GT ) * ( GD / 1000 ) + + self:T( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) + + -- Measure distance between client and group + local D = ( ( CV2.x - GV2.x )^2 + ( CV2.y - GV2.y )^2 + ( CV2.z - GV2.z )^2 ) ^ 0.5 - 200 + + local S = ( 3600 / 30 ) * ( D / 1000 ) -- We use a 2 second buffer to adjust the speed + local A = ( CS - GS ) + S -- Accelleration required = Client Speed - Group Speed + Speed to overcome distance (with 10 second time buffer) + local Speed = A -- Final speed is the current Group speed + Accelleration + + self:T( { "Speed:", S, A, Speed } ) + + -- Now route the escort to the desired point with the desired speed. + self.EscortGroup:TaskRouteToVec3( CV2, Speed ) + end + else + routines.removeFunction( self.FollowFunction ) + end + +end + function ESCORT:_ScanForTargets() self:F() diff --git a/Moose/Group.lua b/Moose/Group.lua index ede103434..e5144068c 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -199,9 +199,9 @@ end --- Gets the DCS Unit. --- @param self +-- @param #GROUP self -- @param #number UnitNumber The number of the Unit to be returned. --- @return #Unit The DCS Unit. +-- @return Unit#UNIT The DCS Unit. function GROUP:GetUnit( UnitNumber ) self:F( { self.GroupName, UnitNumber } ) return UNIT:New( self.DCSGroup:getUnit( UnitNumber ) ) @@ -558,7 +558,7 @@ end --- Return a Misson task to follow a given route. -- @param #GROUP self --- @param #table GoPoints A table of Route Points. +-- @param #table Points A table of Route Points. -- @return #DCSTask function GROUP:TaskMission( Points ) self:F( Points ) @@ -570,6 +570,39 @@ function GROUP:TaskMission( Points ) return DCSTask end +--- Make the group to fly to a given point and hover. +-- @param #GROUP self +-- @param #Vec3 Point The destination point. +-- @param #number Speed The speed to travel. +-- @return #GROUP self +function GROUP:TaskRouteToVec3( Point, Speed ) + self:F( { Point, Speed } ) + + local GroupPoint = self:GetUnit( 1 ):GetPositionVec3() + + local PointFrom = {} + PointFrom.x = GroupPoint.x + PointFrom.y = GroupPoint.z + PointFrom.alt = GroupPoint.y + PointFrom.type = "Turning Point" + + local PointTo = {} + PointTo.x = Point.x + PointTo.y = Point.z + PointTo.alt = Point.y + PointTo.type = "Turning Point" + PointTo.speed = Speed + + local Points = { PointFrom, PointTo } + + self:T( Points ) + + self:Route( Points ) + + return self +end + + --- Make the group to follow a given route. -- @param #GROUP self diff --git a/Moose/Unit.lua b/Moose/Unit.lua index 18b410ae9..67089077a 100644 --- a/Moose/Unit.lua +++ b/Moose/Unit.lua @@ -1,5 +1,5 @@ --- UNIT Classes --- @module UNIT +-- @module Unit Include.File( "Routines" ) Include.File( "Base" ) diff --git a/Test Missions/lua/MOOSE_Escort_Test_Follow.lua b/Test Missions/lua/MOOSE_Escort_Test_Follow.lua new file mode 100644 index 000000000..57b203189 --- /dev/null +++ b/Test Missions/lua/MOOSE_Escort_Test_Follow.lua @@ -0,0 +1,19 @@ +Include.File( "Mission" ) +Include.File( "Client" ) +Include.File( "Escort" ) + + +do + local EscortClient = CLIENT:New( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ) + local EscortGroup = GROUP:NewFromName( "Escort Helicopter" ) + + local Escort = ESCORT:New( EscortClient, EscortGroup, "Escort Test" ) +end + + +-- MISSION SCHEDULER STARTUP +MISSIONSCHEDULER.Start() +MISSIONSCHEDULER.ReportMenu() +MISSIONSCHEDULER.ReportMissionsHide() + +env.info( "Test Mission loaded" ) diff --git a/Test Missions/MOOSE_Pickup_Test.lua b/Test Missions/lua/MOOSE_Pickup_Test.lua similarity index 100% rename from Test Missions/MOOSE_Pickup_Test.lua rename to Test Missions/lua/MOOSE_Pickup_Test.lua diff --git a/Test Missions/MOOSE_Spawn_Test.lua b/Test Missions/lua/MOOSE_Spawn_Test.lua similarity index 100% rename from Test Missions/MOOSE_Spawn_Test.lua rename to Test Missions/lua/MOOSE_Spawn_Test.lua diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow.miz b/Test Missions/miz/MOOSE_Escort_Test_Follow.miz new file mode 100644 index 0000000000000000000000000000000000000000..4594f3756d34f0a1f1c7f73eb6418c51f8d9ebc6 GIT binary patch literal 39292 zcmZU)Ly#^Euq67mZQHhO+dggEwr$(pr)~SRZQHgz|9uf}ac34)5m}2|Rz@KeWk5ht z0RR9b0O-G5zD1p|%?to=qX7Z%{=-7T%2Fx}qJ}PpMuyI&4Dv$iQW8R{QVR0)Hm-)p zzMD?C5=qC8Pa0!STZ!nelY_iNWGWYA6)O=omgTD}8_E}u_-%^e>nFP^?G9%f#@rqS7;1<2HyF=X>|I8S<%WwG*HDdn|~f33g4F6;W! zap`6h&f?KVoIlAk|taPZ;qvunEL8mzuUf1dV$tU^xy0r29F~chjLHCOnIy@g9ABOfzh?;>0nOM{F$zk9 z#_?7^a0#ED`b4HJO%V*=$UqLs`yp>VS*;jqNro#Eg+U(dB96)-*P#lBee@Ia{5^a= zTNOR&PJ_PN)1$rDXEpMDQa%U)Dllft%Ldu=9MC__eSUE2Qb|GRvaUjw+vu3(897!N z+B~IWp7Ds}hG&{Hq1jSCVB9*JXX)zp?)H9Zxg4{L$A38}!C{sHd_TK9WdYs>Rh@;r z=HvLxaopaB#4cCtEK9P~WKwFt<&3A60tww($$>nUlLq+xOwvk`eKg3KVxtLvJliV_NmXjzDr#_cyrIF-MF4deFts^m>@Xi zU#CHjwRp65;CklS)L)6Tz@|;WiWMAd-#Iyu+abtfmHA|2)2Rp~ zd1>^JoHfu+Owm?eXq}dZl}}?)3EsFz&?AFXXmP56DgY)B)|C*7H2TC9wzs}un%CTz zukaqwTGUBM#D?lmyS3Y{Z?*<4X(I>SetN;E zIbqZ-uMh(WctxO55J@V0fO+n7+y0AR7EW`a;KRMc7o)Z)JU>0NxfODzB_b}Mjgcu1 z5gEm(<=8bErU4$~Gv;R+dB^+V$2K?I=W#pU`Hl+!>|n#N8pDjUoev${xOW+UwF5a15)j$k1~}DV^qJLts~rULc2vt-uw@o8Y7>D)j8m zSnjHd7n>F*RbG5tzh0icp5lod8B3f)-0uhg3c9H5khc635li16H&VPJ51Hj!Odp6q{#H`{QWr1!kEmk_FNJP z2@94;Br7pieYiQh36{&BcvDAZtcF8SLNZM9C<8Vm!`GM_aoSj$r+I1PJ zlBb}OCVTK?@^h!r$}O;H-BD@<>|y?h$^uVKKm?1TU~kc2-f$uJp>`^pZ%L4q;DA!n z>|oiqE$@6wRT92mj$5Mpgy1lMXx2_dtqVI-V@>HS8)E(oV2)?HZ^FV(V{`(z05^-( z)^*ay*x;q2`6`wL*}h_TXw@pYUw>SESOGyVCzsjje^6OYOetL@fz-#BFdIR3M-?9t z<}_`2PwTGL3`Gcm_k)6pTYukvNAOryns#|FLajSlwh&}a@GHhI43MRo?L^a#pgLO{ zK<(M}3AEOHUv&+dlSB^Lv0pnbXZ-5&iEql)87;P?K&mecuToE6;t;ffy0rP_iST+(aD4}MhKo7lx~f|ir_gt`6~ zbc_liPpps=W}I*@EXLr8)8zTM5@=^W1~@3FD&3|6doKupBXYDxw;naH_X-&$WgoNE zP;r2Cp08cpc3Ev04zATQ=bxUYcr=$r@Dw7~658r=J_I&Tjm!Ul^OikOMXg3Z|S zKB^qh;v^cS{A5%L12Ra&YPv{+=5rjNt-waf*ArPGWVw6Qrd+N zaD@IlWp(UMO9hVo7_M>nNvVZ3%5wB{CpgEu8rJWAsq5ZZgID(DVc%*h-!lyk(Q?vh zNrPy*pEjoB+QtfR6Clo-Q};p$5|Ile3auKn72D|BO&ceEj?9-`7U{7*ZVj%;ywG=- z9KSI!zZ_`0)+f2}I5f+g^+}5V9=^zefT=b+*q0x|Rve)AaOWrU1&eRFpQs)cwkv&Z z@hMcXQ9^kw4@y3+K6rO3sfv*L?#01{ma<$|K2GZ#$TA)s8MloyE&5Q& z@xpaU0zDPh`}$-1ylZ*g=$*#f&DU)S7t%NHbS-G3nWNopfrA#8-9;nIv;3J3*+Q9$ zX#h-!?t+PPOsPDafP-Oq%DuoB$~~J zca5^b`vif1v$uJ?91RxxZ%;wm9#qc69x?RXebT7vtHCX|=D&-x4;xQ42DaX;!P>mV zxj=BsnzX?oz=Cz^!XHX~5M5-)tX_~dcQ?-)WUyiYYXECMS!elhM;ouV#u{pra7uk% z=@5y`pYnsGd#~!c2VN<9@|-ky!7H~#w^e7pwG=UV5t}a;dNT+xLgBueZd-NSTa=Jn zbo0^N`j?l|d;ok-W-&=EILt+%<><`$$XpMS>V9$@gw|j)>m-x{C=a~4n)X2@0&d0_ z9zm#)yh&v+onBK&!634*T@)cj!_sEEWaDQ#R_$ypUsiN^MMUuHgD0{8nk|X0^q&ZwJ14l_y9q?f;J(N4{@Vhk|^ zxsxh*#Z)c+zyw>b-w)Lj3qOu;zI?nlK03MkMQqjG74&ngkJVQgHjLS4%p_ufG7Lrs z2doS_Lg}M_k3$55Q~XkK#|6h=#zMWYeCuj`sllr$FU@Z5VV2fWGy{yD-RZX$u6PB#5q2zPf_-twJ(Ubai*q@}k0@);HW7n{8jYWl%q{m(o+u8hy z*|V`&|KwT;J(xJq`dNHwGbK>X#sT^Jjt2{2+`8)V700-KrTgPkhc_|tSOR2Pq=SzI zh^fI4uJS=zsaK+C?zi|&o3EjNS%!@|R+0~wo#OF9$KyQ5OA*o9UkWimq3x(~5TmMq z7z8s0Sa!P#lD|z5V+~EK5&%5{W=t_*R9LR`W~%EeRj30U_&VjoXvhZBL+8u1p{|o1 zWn9YG=`~tdb%;ypg=L;+nPf0yE?IApMeC(67f-rX^7Ka)q@(RqOX$!B4pbCoJyg7; zb37{cC_23YAN*b5!ChW`R(}upczgsTA8k4QIf9N?YHb&A+yGi>Ph)zOLQR}!WXno2 z^{5Av9icQET0qQ_nGptAh7fMXG?GVhfT{7cjMAA)NLK%!16`a&9b*I^9^_ z@}Q#W3)fOG89)bv>RB~z1nI;Roe$veUlrQ9r|*6K<+(TgenaG^NlB4RhD}^FlLj&$ z*)Jq9IknlDRfEBb?3F^XZ1Oxjzy7>X*AT+q9+()6k$6vy4hR_EU+}Rr8IT_ z$x~ZgRS4G@5ruWgCWdQ_w;lpC&>dpVo{|nGD}cRM)I)gyGABLJDYT1coN%{OmX?6q zQ1f4g1KjNuW@pl>9>F_vjiX$2&9z`yp$*o!Bj+{&G9@(>n1sa1B|)Ge7pbmno>?O) zAT-oOjI`TKGQ0!-Mq*atji(y*@Ik;fWIK@gojLp--51M4vb?q}SbnC*IT#Lu4W^!|5crkQ^yhB<~dj z=ZZoj&wb3;%o@JQ)v#cix|hwp(2t1`6*@#wrVM;eHxnezq3ZNHxC(#d`WCv_@)Zvm z0b|YA1%CPfE)X!^ob_=&C-XMoCyRY%$eY00pcrGqENa!$7q&Vw-oTog*jgF{8K3z6 zcJg83sCz3sg#;V(2=o`dJx#+f9asUfIl-zTsR_sV9*>i*n%caBJ+-XMW+W)Q22TYT zxW;fMCd6zQ3Z}S$)>H9@bzPCvo=*A}q1p1@tii@|sYJ`AX*p~exv>%)h~sZ8Bl)=2 zY^23-#`Br3iPCVQrI9he)F|+DA<+!F(6QlKEvY(jLV8SUZZ%SIxZXhYz$b*}rk=+1 zzWaoG_Oc<#q=@t4WR$e4v&?5pSR^d^l8-lGa|K(^UJv()yqX!orJoE;Srr+`{H=+C z3+PWt!wrW$?{HqVmS&A= zvu7c(f-5Z$#jgG7Z92we@^T&A*5@~DQ3tTNri9LM5cAlogjC#ZRZP&8h z3Q!nsu~RQ6ICo)&UyXrUEeJ~38GiWfsMqv}YyDojMzlVIdSCU-+N8a|R(0yl#bcQ> zZ0@AcTZ=|gjsaR>X5bJ@1*15$n)5=-o-aD@yp1G~pf{aXk)#cUj9pczZS}ikgFpNO zme$+Fwk6vDU$&tfS;8O4K{LQcF!BYY1kJ-?CmEX1s3@v;Zn zMsXJcbO(26q&SWtSy?Ku>X@66`Y_|im7vx|6kz4%Ho51^)3w#cUb&ao=Tqr@Ak=jp zkTT67E?tq`1V1kPl(GCS#IpwvA4TEW6zccOi=i|yj~S*}fTebs@jAc^qhpTEvfoi? zZO(ns{&}}r)i(_U7u1%83UDMPirGYBXRE z6Wz27e2@7pvemcsnd)E_cOCYF_}MqR{~@XB|9!mcfORxPaiZJOXdxGFUH)%Mi`-$l z^6J4{Q7nnOJ zd?hs`s=US%Bhf42u=52Yi~ySLg>)g1+A^H$+w@R`pAF}@^RxFdy(-g>e;k`o z4rmxo0)%a5h|T&|0tJ`|^Re2C<1Gtk~2kM>5+B`+ylqf?bR2c#TH*B*Fy6 z0ZBip&Bi>uO(EV9{%^V|i7GvVHZ^3Dqs|(4;9HqY5_Z|j@oxD#wsCFX_3N^6rPrSh zn70`5sR^pEs4E{>pDIHuH_p(wNz~&8?7E&hIZjE6r5&4) z^T!s?!5Nwlc<#m>ORzrbO$%<3F3fvPOYG0v$J`}7;auM*#JDMt-el_%Hw|JT!H%#p z_uRppSVrVqr$sM3^%=^(Y~kLv~Aw7!G1d)>q=gT#<{xNb}+GPoA+-a$ExU2r23@dzfp8 zMgY$*Wsi;gw=oMjT%}FD!s-zs8@UqKA4Lr3MSt{3`y5vg)%h)?IhBf=x11rLmdZ-d z40j?GG;@~rAlE*heo33=9(vL%;nLh*Ojz_bxT{2YiMaMV(2BsT$=Q^;YmF6=@%%8^7&$l(^G+;5 zWlou+?DH3tgDVf5)=yBR3{%#Tq##U5v@kwSt68W)2|Jg9Epg~8-+}7PvKn2WxdmKo z3i_Q9W2TugU_5EbICR`nS_wmq0hZ7Aw5&tlsIOa#`Xq^dizjK*8Y2D#i0xnv^7ifL z-;>+ff47s)PEB3Cyq!NUmdQ5y{*R7q=>p=;vv4z>6_RumU$wk1iWoB}OLyd|AdMu2 z=60*7Vz=TZ+wL#+xUt!PB4stjCQ-wHL*#9weQ1N?YW@lwmewJj^-~l!uS}s@^6rtb zpKXu)87*Z%0jJ~5;SSkETvS2@wmDI8l-)2mCxu?fm(7x*7o|;BU|x~%agh-F$sXy* z>-%+vhk+p@!}o+^VN3aXFQbxhPwtfWaje|gr8a*`Wqv*qgH1N#TI|l}1+QDdt`7OL zvBt=)HfsmbInEp0JM*DkU*HK*crke4MVLbf%$!_n19!7)V$IOVONu8S#35myAtU-& z0^+Y82ERPti~fyO1iuQeHI!qx^ie_DoEu$0jbU3pB`OZNG8(-~yN6^n6BkLcwAR36 z^-Up&sBj2=IS5zeh+Di`f2VD@06m(dqRQ$sB@qx)VurD_YTwTzDTz?7jicOBn;HV_93E{H+$r>xpMFuPL-yJ9L-%~vLP!(kjJE{!nU^; z;Bf6y*<3VAbJv99T9k)FjVw^Rf7iyBP2J%m+0C#5;9St1eaUs&vSfEG_d_|-ZoOW6 z)h&78_@B&c{wA7>&vA3(?r}vtT9C6VxzEaSL8w4XbQFocH+{wsJpcJ zVj=P4fgA`r#u>ve7X(vOUCN80DM6>;Z-{IZJBhKIUWtPVN&t6h3vYy87@6g?yaa4( zy11(xEfu9ExHw{&;;B7o@!CpXN$CWAnqR&a2MK}Ei$khq(ION-5yK^tNYfQel!oLQ zr;CLY^3{I)J>7r)u*x6sW)n4K+O~}WQ?!G#rs_wU$}Etq`c_tK z7sG$#nr9BKkAGNZSpNC?mxP3{nYS{Ic@J*EU;1F)uV?3IEsYuc^c&C}bW#U|ln!9?Hk@Xg7hB@%AA zl_HL?Ubnjax?Q)6I}vkiF3HIth&5^6pG^vnbZ&M!I?QPHQvI<)=$d6drw1+sv4UX> zK@5bKj(yk0MvH#*F#QplbLxH_dDitqcl1s^)MopOJ`~2d(k>GLwgR#BdKnJYx2{+J!PN*O+?MERz*r*izqKq&Qh$2nsK(ewkR%AxI9TG#45XCU{l#Q>dWztXA z9}eDZ*;sM?oMqN^$V^ID=Q$w@TG?ETX@qyt%E4LypvUn2|3b{duYcfe8|5#nGlek& z7o+-(_VFVM*C@r~$8_?umU@f*dI3eY=L)lc9@L~959|-QcbhK&2)&M0= zrbE@i)|?F{;%)lw*0N&zS#kmwZZ8s6dqi?R`#<(28lcCNg3EbM0ovSR&`Xt;Og^JY zxs8vnZW_>XVOph_?k+nMTHFijz$A(H)k$bd?D7n*)pmZO&v*Gvk~987+k<$TYRaur z&ShVcjgE0H(%ojH?_>a77-44-mmj5M=qA})zX7FC2)7=Zp}G4j_Y3x`o2qHYzEn}X z<~e-+O0~bO=xDh{OZ1SZL6z7^*#S?m-9uugdd-$2-UvN877CT5;2}}rKOx#DhD$LR z_#%P;_|Cku)tGmH?j}~sUV=F7uv~kg<$!8Z3Tq%uebt3+SA3goCgW;D)V2r;LbZqk;$D_wBfdB$XQXZcD6*bV3 zR22kufGg2Ba_Moi;0CwmccOW{Gf6{LtXPunq7-M7x9B2lQMrUSs_AOK)ugBE3K)h! zjCMPBppZsovP|NljiShS6K(j5d?4mHY?1wCae?>e{1pS%OW294o0{*K$3B&;a?gfM zosfLdk17>j*jC-W011l%ByWT8{bmE0mrfo>=)DU|-5*pK0uQ9YWvwM@&O*vacbww83~Sbye=GN< z-y*->t|xdg;oiL8(oWIisii*Ya-|t>wVBvb@}&KswXJGReRnzuuao=LVFT3{GC4sO zh$mqS-MqpWNk4j+*naLV z>T#J5Li$)6`=AExc$()JSo^W+?^Vkr*z3x&Na8S3#x&U;R~roP0TZS+6U{IT{^*F9 z7{v?4Z~QVeeBIfTi(Skux`_)iYb6s{G=;w<-E}M{G91vAIzT_x8;aEL!ywO4OgRW%&BcM^Mk(Sn>dW?$Qt99iTp@m_WPTpd;jeCFzq%lcn*_g0O zF}=T`8LayU679GeWT&v;yDUM_@mMrf+jk0hN3CoMl{LP0?a!{=S!ao|x&+2*x##`3IZzK^b`iiV`Ry!_0|xIH6%@*8(U!U{jWz~*=6a-G;>}4J4h?ZJ z@k)L-f19>aZqJ-WGID)$a+S4CDIO!6JZqs>X8)^cv{!6=T|RU;5gbW>aZL$23+WXc z48w}~8S&nPp^7iH3m>7I<6JqQf<$G3SeaHKAi#DaM&Vx>X_@5&oMQnz=Dn4tA28{B zQmYqRFmD28{{bF9tuAcsAUJYgkzV@KzJqGf7%Ne$3_7Z9AYG|pMMNZ6x^MxWtKo%V zze@^29$nn-iUcBpKs;zzS5J%)k~xl3M)n|obDC=ATP@_nAx(S3&SFX0HP3Z2XKb>> z-~%gEB^5rCy^29HEjKkzlU+za-pw^fbkl{izM0aI`(=UDqwTYbRFe4BN^tXns}!|T zTN+P)XS~eauD;R&S(Fj*p)eMAH?*>N8XSM+zw)ALdsXXvBbLCeapmD5_G~CfMPce= zYLZC2X;1@mitd4~6E6(QMpQDae%e!%Shq(M@#NU*y>$#~uzVxm9YD@Eq1NRxY^iAF zs+GjsF2@KDrM=V*-5B7fc+`9OVb{q+N69L&U202o@S zs-8{H^YzuwdL7@P8-qC|34fx96p!%dC0cBpou+qY@iHt7!A|JlOScg8UBMt?ZEvNd zc{eU$A4a`|E4yP?Udc*1DRp&$X}9+@BiH(0;UigDWYz#3>>RQ}bq2g@+Vioc>SRWN zsk7dRN{&^pVl(dQQU0>7Tk=WVkc5EDk+3E z?R(&)f^2Z`H0V^J&Yr4+72+~N45a$TZDSWe9a9EX6Y`sv@t=W__A)bWGn;(68T8fk<(|@C zM-P3r!IP{;mJoDoN<*2Il&X-Bi7-4k<}<>!oefhZ>m=vmeN^N9D!+XxuPsKjKslEe z_6hE`XFTKZ-9ObcySqNaz5hLxd4@*lU?jX-hFzI~w*_v`OmH`=ZT2vg#$I#7ePuq^ zB1ntzja7*(pAo${Id4r94wF=VE@tBD=+_gClPLEC+MWDX{o0Zwz@LazU53P1Qg(7V zd^)_EI0d@=7LB_R>b^k_-)-SJtM4s7*A|Pa&@2635OLK&Hb46Br*6b$xhUl+Vk~CL z)e)9h5hyHS14VhWp8LI%vxQ>iz3GLj&Ty|I{icx#xSZ!jYl>iuMV#IpQ62?w{fd9a zmmu+rDvpX}q1fT9Tj10`09s3E+FDk%bdWTtE>7t*|Y1xhThp+j3$J=9A<8bfx`yQ@Pq)sD<6qa9o#^ zRi5j>#T-+s0{Q%Gjp$Ua!*KU5EjGyuDSZZ+O*Z;C3%SrCuSZg%76a?Qz%Ho*0slID zh~m@7&1IK|@^OE&!@%=r1$_!sR`neMyjd5!nBD0;an_x>Xvte>6DZ|+q*AYIEtoz7 z=P%1#xMFEx_Uehw(WDO<*YdmK73CIR&~>vL1c<8PXhia&4Y#05YdpQb>=dR(VRs78 z{iV3=0sHAPFx1P_f3`jJs~p=WUwWR@l*)jgPS;}qY|%`K(2(kQP*3~+!%7w zKcM6(Of#wNl@$hQV2AaUZh2 z|8Y@bu=~a|=X{it$jSMqV|OO52Xae&a~HqFSBRbh+pq#EKN`VL{Nua&S6rT)Xs_Oe zI2Am_07~6VuQoIZ@9Txh7|h=W;mXn`gufp$6y=LKM=p)=pY?B6psHvZ-S`+(os;pF zjvK673)32GBd!8i2p=ILLi8fu`z1<<0!?<5vnsrx-?@A=(EFHM=nXaL7dWS(u6(Fm6nz3+v)Q=#usDHls~Gkq0SWuN7(57X zuI&j#BC$MJ1sx^3r_|}r7StmO@*gTU*s!A-?A4|a#oECQJiTA)>4dYrO>7~cezg#@ zBIjlT;s7vewFc?RCd0dxBz&H&?>L5E`arYl98U8R+1V#4L>C~!MkRD6a1N{8HSlwn zt?yNi)3veBpivG2{07NINKA1UI8s#w&i^hF$f=l?vbrX_+TFK|w;VDlGfE}g`Q#vKc`mtxsflCKK$9e9S^cjw z7$Ts!do-8J(7f-WK6kK0=dppcbNC^m3eD&nuR;5Mny|I_E~JzvmgniVQL_iRfNgzoCA@7UEK z!&_l(t(r0L{yZd<&C5&4>Sa)iiuLMPb5o^>yhNP;X8;Af&4sRTDNgMnkJrYS6V(~Luua<7kcDMCIgd=)Q=k+qep_;GR zJiM7MR`QG&+o_-AfQIHCJ$t1xCO+0$tHp3s!nzmIHYcAn*6}1jj~*9}7&z&kI;CKO z)FDJY$zi=bTyGzOKoA(I&GhWplG%IG_+Iu*mbssG%>vatvWx0|=sM$q_gZRYsv0r^ z9d!=-Gl8B^Ho?ZCz9ngcZA)c~V7)+Wj=C=tn3 zIk;y$4rIF=gJX5n-X2|_PiMK!{nr`1hught-k_yUgJSx+5-Z(nU{bxMie{0rTvoSBLf)26sRn^{$ z2`@oKr~w&xay2~Cb(QcvXj*0B`o}qZ&kZud#7fyDN0!8~f6V<;qE$#@)y={rf~)&t zqd+n7aG7{|`QH^=Gn<*r`N|o@fG`wn@)PX5>KOA{55>fBIr8OnlKeAYVR`fgQB57# zpt>He4U0Wl8td@cb5uI zYgaZWVY&Z-l;r z?_Ew1_!XnbR3ck2WpXwGvUL0Yzt8Ev5Q_iH7gH&c+5rEb9|rcn!1{lEG0F;Rs$wet z^7XU#2k3_`Y&dk!BLEX~Sok7La$<5U1 ze;BScx9vB$QT@RqfA{|)Xw;+}krP4P&4owRE-tIvVlVqUMTr$R}ThE-p0G$rP)XOc-@8M-a zpw_MuX*F8fxNNM_k|zhi7axZ}T9Vl9J43M`524OY#KQOwDBcP7Ir3b)#|J$mfaa6$ zo~sTK6rUqB6H0QH256^6#v8hA6pKAMNWA4l`Tx@btx1}f_m)gcN#>d0GTg_&hM6e~ z5+jnt8bCqS`V)$Ih9UjNmYYb5n4k@)ieI_a&shExH+@M94Nzd`Vm$VGF&R5lH!BFb zZT=qj!DX;O9IKGw^e!+#3vDRe86G)Ba6jBxYZ`SoUntqur5BQ`@coT!^gZS>o@_~_ z_Oo+^8NTm{jOrvKvr8_g2%*(ex)^-8#hf|*y!wohP|hx3$cJPmV(OvX%w&=u&4G+M z;Z+eIJ*Pd8AqKUoqg+i+fGUL{4uT3bJre1T1Jf;X6c-WDq+yQ)i#8l#ME-&$fh=;6 z=lY0C>Q9eaGG8FqhB)}7%@K(R$pN#LVjzrB;L3!W+w!oNIGbPKGP=$;k14sT~gdUex;zf&N zAYE!Al^s7VSN+E~m{RD|4Lz3i;2fx2L-z!bYRSFR*Dc7%k~FiVJRRYM4o&xJ2pB4}*5 zHATN=YnyJojS&WJ+RDqnD_wp0P7*2p0m=K{L~_=!0c!$RQ_KyOEU`ZwR0yu8(WEHt zULI(q38%93*sCU@5BF)xh=pUYzYREXZW29dY9_i=T1|o(lQPhkR!0OGU3y z+MdKmzDnYqqH^h?y1g`PHrYT5#pGjj%~sO}Xmt^d?BL`R4L^g!Jy-G<<$1;ekSlJn zxn-K+Yg@g2NwoS%XXq3KWp#SWV^6CSXO}pGxv*!G4s-!0LuPP<1yB@F$w3Dz+)D1Hjz>Vq=li1@ALDOblX%_lf728+MizShwu9_ zlj!6(6D?AvM(dR_`~cgi$+}~(8@S4-@Q1FJ?ERg*z$-0`MsKM;ici(CjgD;>MUrf^ zFlE!VKav$Op8*Xl9j7RrN3yly5H8g23A2`=HqYEdgpOE+k#W3>{8gd#AdNv}bL zEv&fgGJ^uNUxWYt`xFW`?MMp+^!1C(*4N~Om#Jv=p8y|9(Fx*;0#~mBOmJ#bL7ETu zu7MiwK=CL=c6J{8;uKKDN%O2*o1U4Obq6nA7bCiYv90iyA2wXM8Ctuu zG^nZNdv@gY+ife^ww)jMV(oxvyRo*FOE@qR0~_x zcDgIE3q4nr)y8HbUwPJVu)deNbQCgA*8C=SE?)?*r=@*ea_2scL&Up;yNvQ(S3B*P zdt7L`=Ee_aFMjjByw15jpL#A+hLpqY9Sv@)Ykdr9ZmiS1m+0<~U~Cdo-0-7vL!CCh zpIxQ2+QkI&tTBoYAO3xnrZmH(bv)Br)00U=+I7LXSLjw(y2)$QA@jXh%QZtZHo1IQ z4&z?6ztN#BChyRNn7aqs1I_9lzHxdk#l5P(t$|Psm*0LPytP-jyW0oa2hG|hOT?() zqC8K_H3?`>=wHx4OeMl?wVp0|*KwOy%J6gqZt|e`d8uE?o0x~L_G>8#x_$Z9GPQEt zell))!(kNXF*!g`ZR1%Rs7EWIw2U!bEeTe$PbZC7>k@_G7!xX012K{9_lUvK(9 zdtX(R6`Q|?F1@`u!@FG5@X4~7TSrxIO|QS3-n5;YHM`NhRqN5Lzbl{rv&^$qPv$M1 zC)ei8Ykt!&&mv8q&fkv89o^Y?4!c#3<>4=Z)lU@1`xaOPQbcs`bm)#w5&E6CUqL;B~pv zPlCM1!|Qc|AHSdSzMuOTv0Of#I(iHZ^K+3|exFY5ovA$DpSN^hjqlf0h~M9X>~glV z^4%{IK97etuq%H9ksVs|w(-8n=h`5Oc!F)d{e1kMV-9{@-G=^KY6JtwB$gq1z=~QZvGBG)D>w*3 zhy_q=N?kzktpsA9ktq#DQZx4a7a~6jmD01#`Kfke_rL0zf;#toyXW_50 z|0m1OX^Lq~JY(r|!DqHUPhEfZ**)qP!Yj$6Q_oLn)^+7^4p*^P&zj9jb{TygPiN?O zv&dvw+1Hlo_I)Oe$NBj%4;LIa_(&`3}W7#7Tbg(;Fl1hzQ`lOr=10DkaVOh1(xj(yg@8nv8;*p%j2 z5fmxpn>nw~;lg?BV>WHnrZA%8B9cY)fQe7QhCCG^NUScfQ)0Lt80jIX1@5dL7IuwF zL9Tcbijd*}#6#^eu>5-g*S}ZbU>BL3xTNzC?7v zUGU_5!tFbzC#6tYBp)R(XFJ~?7O%??6s}u0in@6ZH!b4nUq<7nUQL?ZTL0{Ku#H2yvs7CvPeE~3}IQTgAG z6ji*CXpoQTr|cl7=C|%Sqrzd~=umVRx;XNJ{~z@EX@A|fdA$r@z&|>7Sz1ro3*t@x zT+OHd+z5odW2s*;3v^|_Qvx$f=z|X{jDnxcU(M$DU?B^PG7309nQDIFiUhz$2Oo^e z+V{Xlixizgj+kpYYTn@v{``yj)u=uTBi&9m9DY>RqD>t>oHMGRO`AAy(EJZ5YvIaA zmo{oz{2#u)0l3np`!ku?wrwX9+qR7x+cqY)ZBK05wlQ%gwm0wl)zR*;{oLCZ z-TgbK&#%utji*ip-D`GV-!kwDqQMALWwjs-fp6=``a1^ftA{gQwrcTNYKp(+i-iW! zwnNb8osP;q^)0WjH5Pg<7tfm{_&9m(sxGUUhuDK z_Ekv;6I0^ZFrpUy@z?~?<2n@jj;fgza)Utf(Fyb>1z(eAXa{IBKJ5_Pee&F_fbQ#=KS|sz;u5PJ)Ff3xpFA3H@1EeEK!Yu~&Uu12} zpNUyxai+c67?bEve}Q(Fub(+1ugQ8A$%KlcBr~B)@}!w`^&^foPK#{h3DrIsKQWzu z8wxQg#Q=07=(<7q#g}ue1f#=vdxT76D8<#Bv8iP)Jp^p%dWd4C+(U?fGJZv>#hfUh z3AhbdNQL&|6FMjiq5w`Kk4l<`nac6m3*yw?GB)dwgS15OC_A_S^%U?LrLNb{4FA7FkzCOnj@Y|U zB=REG=M`a%$CD`W>C6ZwYWW>p0#Vfdk&97zakhbshT~&OCBH|Vcp#I z6foJuQLvv%89lPHV$1W|sf9L1;S^svV@>4M&{3gO^S?XZ z+$hY^IQOkj0vDFCVy=7&A*lrO$+f3sa_%IcFDpGX?@VpR`^y=SwJ*H6q`oore{9bd z?i;208>rZyRsv;y^7lV6n*OA7P0tO-&)FVEwO8ii4~xv+8@Lot?Js3Bck0*;GgdAg zjpPA=jS&{#ma3ljhnOnkdLf}#3?Lb;^-)5jT|fG~?hXIhe@Z8caLTFMfgTX1xPzM5 z9VcYm`LLokzXMH?KMl9>xnLd0s+Z<2WS2{ z#pM4Esr=(H|KllVtJx@Th#`Jj&ph-0ZCR~8)bb@sPnlL=B(jiUNt*>4aECuNp^@N< zb_UOqd)w&na`S9}bDe-Nytw;&!B^R_)j->N`+`y=w?D#cvq%RMBibqT{vsrF*9z8U z>oyz8lnH?=r-lUMLvg`+7X4ahk8h+eH^_Ww56P_QSW6oVMpYBIkmlru{fok6E&CGv zT8ESf2J+H&NM4f~=^}Y<=jBYVc97Q*7ymj~QeT98)Er1|k5tmt@5zB>T+suwCg45|b~n9OkbQ)FH6vW;guLL*KVWD!|zLf*Yz zvcdFFei3w$V>&==tU}c3iS3Fk?KOE44H93#{fQVnce&F%o}z4bwO{R$zEV~ap$f)8 zP-rRmRA`tO$1TZqK(U_dHM|vDS=Nr978Zn)s;r#9zT5q35lg+F^^Agm+nL@C%pbzB zXECmes94)CS7$)QZ%Wi&^-#1Bj3ZEdP1L_i6l;=V5TNX%aiBuUyQL2^PjNX0gRP3D zmh6Nop-->-2@Qx~GY;qCxAMZ|CSX0AaknLp8aFnK9N}lKGqb_Qo~R&%b5s^P!-}-p zzR35`Pj?GqKZE(3!eVLN;M|9Qzd75qAz+&SSzke!Sw_;ICSIPvoXMhpeyWU^aVzyA z?iZ7rzxD&YZP*zbl6)?q=>`>N9|S@?0P)WaX{FY{A!cuJf>E6uzdR9|z5HUZ*8~vb zJ~J8EYKCF^HLrya=p=QKfqb`49^(;DkYc%j9Y1Wa3~u>Lp@2 z;+^f3VOi05Yl?WQg+lRIUyDV^mt@npPPG{v%T05oq0@?Z|Cnca7eASvHGYMzZYqZy zg;G0<*z*YSn!il7FbEyjt>y0b6ZiwZdvg;!_Z(}JE3ipyd#@d1LS>P*^jvMEb4x$O z(EwZ1z|oE9@T`+o_6oy)rzH&e6C0MfPSmr-$&TkT?gaO$00?iYLM;dHu5ezd+?m)( z#gq>zE^gv8D84;e10edvD)EUocKX{h^dtHV`Dz2g$(q}-UujVc48MV+&m#5{Hlj8e zTY4C$ZT39HN9uG}nau!pi(kK!^hBtGjJwJ+O`Tfq*~mA}!j8NvX{4&fQc*=BajE;h z`iy|}-hS>9BZ!Xu=5A8|HM$`;=1iSdDSi4o`R|H)eG~mVN7KGbOMB%x%(Xe3riBPXIP@*=(<$5vp$i0m z5%+V?fAgT15!*_}4BOXg#&1s!Zqu9)!((u#j}T0JIhF4HLn!JFzN=}XhO9bb4em@r zBG8<+Ryj8&6avGXJH@@U_s7mrtsblq{X_O#;T=8b$}_S`)MPV=PN!}1acFJvpUw^! zZ8@2OLM-*toLf{4oqiyq-cSi|IW+k2Z|p^A^The>vvdvA(V=X!5`H&2W-e{R?5d;u zjZx?BEh=TM>Xaq+?d_^6(grHkAXN2v(1JWp%@8u?(;M8sQPCWGN@6v#*Mf{ zvq~$)=S^_p+tHriR#Tx6rS^_Lq^E17u)TCQ=hioHH7@0G3oqd?pFXWWWsws;jE_iq zb7#etOj!8&p4ZTPGFc&GtwSyAvPQlx0NhqZ(G&D|pO#or9+CW398f+*uz2q?mD#J4 zBd;bj<||6|75e&iKwN7e{UIe~T<*8qgfY{e6$t1p;m5B+@J2i++5#gz0i!bTXe)zH z1XWn@9Ah$+9E(g#OcT_}XOoD}3ZrM}BsP8f6F^_TxkPSs^NaqdJlJvgvpWs64B3@^ zG96Y_bW-`?QN)b6VfDQz_FgP2Fbf`fR|b18R_8qk10US{vURV#{e<8t@Ejv3?~`>; zf%-uD6Dt~OHuT>6#e@fY^eI00gVfq00`gt#6sp%Q-Xbo4-#aKT?hhDNgs#VrHDy4* zFtv1?7`zI+|W{^T53;Ody_0nOII7b$7i>9=aqh4?VoQ1Uk3{lm6aI$?npWO9k0&=xtIL@ z$1~rrJsw_~&YzxIYUI66=5Ata_&%1- z8SHklH+q?F6W#Q;w{|+Y!sPtixWN7HZx1gr-`w07t}gw2Y~z1c;R>~OK?cOw@b`H6 zczrxpo=@n1-Y#uTWHMao`TRv~QG#)7{isANcsX79x;{Fr>|keqaR7B!N^@N2 z7tgvjV}ClHdHH*J?$^=N?Y%R7y?ID%M`j4$`c%G;{PDM8riOt)4xISVo)7B=hlgwb zVd~?dXLI}WtxbAONR|`)j|u&b&qw9T1@Z;O{lbQuoBqzWF9+7@?Pu6yEYt|!m$TR1 z(d+Hh213hUVp~uqC)Sux0)iQ!vQTk*Z{P%wv|XSW++8Ne-QC0mrZNsn?Pd;tH2B^_ ze`$K4{eAxd!PWkk*w$Od5MU0>MlUH1qC$rQe27-yWRbNK$3a4N=v`pFn@CqG0ZCvv z1%Gkq6U2Vp-aExq!90i#UnFzQ9YyhaLg|EG+N1txPtfik9D zG}zT4e<{-hc@%y;kQ{83)jpsNM*R&$0B)RFnXUli|uKGwJQik=fAR-y4!;e7s zU_v~St$xCFFr(f)qF*$KA_PCi>&E*D`S1ccl3@z?N$p3gA6aAmqWvm1NWc`ak^%Zn zrY(Nu7)J_W5g6orKuAEM3!g9~SjcnP)aUDWz4|zYOPU)bL8lH4pTMqY{@@KohQ_2Q zp}a;2CqNh>N}K{tSR?}+#b>GFujT<7E^{j|iX6-XEW{V65EBmqnObVB5HM@%XdVUa z0T%o>FwW!a5DfC=6pBcmEcmZIkal=mZ53QSx1vNk$e2lPwexJ*)^TJzAT^MfiV_7i zi3IEc^HfRUud_l~f)oTGBye9Tj!-;hK*)m&3=r{8&S`?+Rt&A>XYWsC3CB=PTIgR^ zL6hcd#d%WDXP{uJW#W67Tn5*L-$G6LMHCVI_L}mnyKlX ze&X}Yz89ydy?)e04GjVg6A~-IVcF+KqWl*l2}$50lHg!_q8MZG;3{%684;aD_-=SO zpt6pPK$FD3l>AYJR9beC$De|t87Wu$qSO}KJ&@Rjv$;WCD2<4+AARH31T&j|4W*@| zgOoCA0dd?f7ceqLm!Y3GbVL3|vKsfvLlK72u{i~80!Kl_!&}iu>F=K?UlsF+EYpT2kA4kNxxK8!b2b^loK}T zGqK4SDCKd?Zh0KW@j)PMHh8V`Xz-%1;raCkPkxd_T0F6!d3>B`m7Q{iPeu*QvFf1 zP(rD}#70}3lxg!O+w(atXeiR_q|f^%GB!Y|a$xRfCb8k1F38}wq(fRpb<-nMl*sCf z4QO-llcRgTOC`ZmR_8~H>wTl%i z{2o%KAmz5gx7q*7&vlaH+-Dg|rx2qFI|rcES4q^gH! zT7_lpkYEGZF zTwPj@E)~_1y#AMqI0Ea^Wc!{iG&Sk+vdpWcDJ@dOI0{WAIUQ4jCF!P1qM2Pot;b*6 z97^o~wGfGD`%qE%4M7g?)+X zV1H^w+R=0l3bO(Vv;LI2B@RbP7*ETiFqc)b%;Unm(QG0IiaIk2g7~D6F;Sr&0Q1NM0blYZVPD43y@hI#AZc^%#D!he%}OSH>K3t z#VW|qLS>x5WIzd3j*y|i1d?k7mh=Tvm|qfu4HwkE3CxHL`#hA+Ny_m`L5D9b4lJ=K z{%>q`5gLBiC$t?0CbGQVyiWS*{Y+Hk-n9r*PlJt`y2e9k3HYM z&ehj#nBC{q(AVeZ2LH$9cY0y)``Aa=`JD0lxXHw@zj2RKkfMA{nvKo1H#ffm7o!Rt zUmfWC?dR^~=fpg-yISBg%l~=z@COf!4UWtE_VMGq<*Eh&#WwEP5YB&SJ?uofo_Cu^ z(pBFlUc+XxA50QGnH0z9t+MrzbglJ!O-xyZ7LTZF%iY|pCamC3+q$JOPbnM7`mj|B zJN=&Sj-F4^4nhJY<<%B28ylVoin;p{H~p;~obIofvMcSldDrsN3#nCRA&>9+Pr`Mg-etQ-H#a~|!za0qLkicoPHcPSt3~WuYtxVtl+tBq$CT4? zPS{duB}wH?Y*|7TNYZ`o@!yjY*AvA9*en*+Q9io2?Vm#F`DXmy_aX;d~0d8}@+KM8i9P zI(~zW7OD~ho*#et9i}=u^zP!77X-y+2kbg~Lz?lLM}wB*N!|HFm-2>Ih@N~D3EUOJ;p z*a@Q?Sie8t<%95|(mNx|`b;OQ3h`EoIMDx1AQj@B_84um&F4h;B;tO_5~U!?JvLE2 z={8&VGjnG>{ertB<)ft$BsX4Pch_dNmIZTHRrMhS@_nsD>PJR>SeG+$|$Ibf|()6D=r>*|cV~!I8YI;&GtQT)Lau>cQn=*XA z95@#>onNY<+O_!-YYIP)|IJHa%;vx~*#XH3a>AQ*o(DBYygdWhE*$V>r|-Z8sp*eP z_>RZt3UUgIIpl@E4{B5uDSINF#Bc7|t22tu%&w0VPWIPb zBikf<9~HnFiJ!Ze9dK9h zg7S(#L~$jIH^anGQ;9FhedZLl7j7%4yhb0FT{fuRWrq*H+3ddKx0PwI^DGI=G~g3} z;(k}+OH@RwmeHgksa2&q=vjoot5z7Ic$_2%(J(z$kVrHJ(WrOZc2GCpYfL8cuuZCU ztzj{3Og3X|Q-lGZC*`UPYPYm9nq1CICSFZPnPgV+TrvM(ln5gk>Y6M3^8%qBDASl}qd% z$*Cf%FV`taYLjV`N!pgW#6?XQ0&e20x%;#!V8)cUaC)4;XvWk=l?xSAbG_lE{Z#@u z!Lt@GGub9{iPXoup}tj{+PT|Mf7pPX=f!ufSF8+GFJC+VG{7w$D4Az%ZJmHsrxeJKRrb?76AcKS5Ge^9L7+k>Q z?p&>imp^xkIV+vwAMjUy8V1&B&wNGSc-em;G5iM-+`o`a!iMAVEP=agPg$qi^5>j{ zx&7Zv&C95RaOBJp>_?!YOHjVsfpT3ralT^b=dkhlu{2fr)H0K+s~1l2&i~(Wrxa`H z2 zB22%q#4)n6;6M`lfoGcM)lnTojl9JR@{`Bo0E!mcKswFAL4u~Je1wzpW#%zpzUOtY zP$8h4RsjA2M{j$hPY{tYNd-dBiF1ETF--1Y8dnojM2+b8l*;o82wPHyJ(3i0@G|?CFur;)?F#ab-U92K24Z?)T zYnT6Jn5In3CK?-pKga+Y8Mxgj(Vn>lJ};6`g>lo9X`(K>fd-=|l;Dy6WXjC)C!U#1 zy>?%&7gz812uc1<+F}!tyOlec3rJ)~N0_vL0qtH|DvqHh$@|(kZzylRz)0cEiCAhy zbwTb^?BB`DHvO=P_NC%fu|yzn|Cm(|9GPT|CfWP6U-A_G2omWm)pVjiwD+_tNj#hP zx^+-U|C&q1PwR9LQzZUT=CayH&&_oRR4!tQqgHnyOCD7fu#wSaC3 zw#IJst97Gs!WuI4#t+Bj2q`;rtc_(Q@K%2!bqV#jvjBL&dDac^r!s9T&d0CVY4 zB^+$iWN{r{lkk#Znc5z&Mfd^w->P36IOG4vmWaM>iS+-YdQlrAfQbpfFa8NEviON(jxrYZt^19|_U3lIev_lA&h)3-s+Pc~ zSx1IFbUplAnGE)lsX1it`pyM0!LAK9Z2<%8{<=Jf)3k)W-w!j!GL*AC6Aj`dudBtJ zR|Jv#8+Z2Di6iDBv&(Tvut55Qe64khV?Qfc9f-G4{o$03Y@CJU3@C)1$@41%ARLG# zR#heA)%cnZN?NyPrHT;|AZTkvGT={Bv^UT7=v(~T7!SYtpQfot!aUrpgBNQ0Qk$Ce zrWro-tS&w{oW&RrC=yxC6oJ2pB+m3G=OVkT+EuR#MEr8EW|pgDQ?~xzv;=7vHpWX1 z%Kx`4XTUxXs=j47`z=q5|0zoo3u9*sJ6l6X59u)(`mxCwY1#^vTGic(BPF0fb25y) zGB?ZbO{a>!76JN3ww9g6O0)_A3G$Xk5rN{Ca;A>Hf|8c;3Gf-ANsIdj1(QGG;)%-9 z$ZkRrZ7|P-?wF-}kFc>3&Fmd~6(vnAJD~*cqKK${;g(04Wi?;VFQ4>^GCt_m|CE}MQ0>cm2`5#**Duh0y ze7}KBekaWT3DCySUJ2l2=i+D#n2@D~l%ktvpp%kQ{XY=%(*8kc>?mpKtJhin4Nqx| zoxg{JZJUChiEO)=nSqI&MU$bFRZ$Y65}yT@_jj9QITckol{>4Z0NcwOM8|LkI>j+Y z@?cmIdg@@u;qk#is<6v4^~o7^(NQtwK`GS%@#YNJ|7bIOa}L89IS^3JI55!nbR3Y4 zg_F~_9xi;Q9M3sYj`(tg_EgnG)-A?v^_>?3Q_QsilFo`rcH5Je2D8XE4Gf|clH)B| zcwK29oqZyc+>;_QgVvr)3~>))aEM9HzX%fiv)J=(y%b%P3wp2KAaS#t?1AV5S>g7} z9*&pYzFu`1dax!1j-%vegcJvE+ z_&#t^sWHh;@bjNoneaE_wPT1P;V2>SeH{e|qHw~)DKCxHV6u$hFztav=#^IDO^rdOl zB45U!z9{7N(xCkos(%O}p!7y#Std?O*Donq4%+w%!|}8=OZ7a*I02_KM2wN#EU2d4 zl*T@vQo$1U+>SxzGJ4sdyhvnjdQ>(GF5B9YC0R#c8!xut==!T^W_cL;rv4%59f>v1 zd7h1ZP5Jdh<$L)^n8adB8+qqm2Y%fUke<8WIYfiC0IIc{A0?lk+`cO7)sSM!Ad#Op z#HkPBu%^RQ&=>NgP%dNwj^t|m9GGtt9KQfL1*9;)hm+Zj(VnOif4Oq-yFH6UjNh(z z$0hD!>b=w6R@M(p5h~`>2HMZi)?HpIjvM1Mikcmzq6@s!Z5#^yE|W`NFNwd|As~VG z0^4zUubxal)XMn@hVE3$|MY+Q`M5i{Ze_T~hVL+gSC6!$obrbGR(_#-L>h?ssy@2; za;8hPVgpD2 zwlNSHe>ZEf1wQf0t;^fAK9XA9F<>il{b&eQTz&1c!yo-bQgP8((ENW^n3lCCdenExQ^s2Ax@o?HrkP%iTA-OuMZY z&7xQ2zuo$4GsfXrwo{!T&T3kqDH{yq2{GjFX_RHhouxm&MbMk~=E2knUq$;F`-MW# z6uNiDcC95(!$0<}L?Q3P5M5|V4BT2KYdrN1mXXU796CCOM54zI(j)@iVZYf-)anOEVZ7K>6!E&^F;V z_rxj=JXR3X#7?A0`8BYOp!nQwX2@gsIo(i@(i^%K_%lC*Sd+oBSbtmU+NoJyWDmqR zc_?!9E58X=Jzz(O59CZ#r6ung+F}NTM;x65*v;)`AxySE3~RX3LpE3!y~SyA6lTe| z+xuQA@GAJjuvX@MjX5%HMC>X52bmrIy7SJ%!BZd~rP#o7rsgpPu|8(D;zi1DTHmhg zl=~WJtQ!&;zGMBIZ0GjW?83-}JJ%K`2k_kU8izXUc}_asN*56RLw$T#`u5|C29o*S zQ_dBy(R|ce(>jcK59(jPf8wQ4^m8{lj3w^aye{zc`1DB|xShz$-^tIE$UB(!Xcn?w9GY_b%PuEUtGMBCzVsqByh&0bY^Ypf> zI8XnUjb*s~YuJKSAx9q6^}yF{}Cpn=*(Or`H<| zs~8@`2XSz1cQ5Z+FVN2VXXow8(37qB;GR^>fGU-{Oz_%-YjLT-M~olVhkGAvhYi*D zJ)h#egi-S_WHRXs?HMB(Na^gBn{Kq|a4_N{<93)4O!d@Su{O9;K;{@ad#9EWlDwb@ zW>SEv1y3X7me8CBo5lKdbh>Ll9ATp%qmCDfLYAz32!x`Ic zW529P)6$CqwL)HPwHy1MUd@XBT(;PVtRu5pEgWwG@7LdZhjk0yB4B5o8Y<+^ecRW(1C5&c zUP(Y9H!IG-_j*EbvJyY8Y>06Iy^@}wgl=oxgVvx65nG9=P?WS^m`!H_aJGpX6+L4Quz#;bA*lN6(Q*uPVUSpG4bvQjNYq27xl> zEk(1mdkQx{csJmA=P@Zr*d13`TSl8 z8DYr>*K^VrAD%kL(2hpa)e|o=%o4e#K6P0)>lv=ZG{?h^X3foT6h4lwi?Cv3kmcNl ztz&zah>OA3>hB+b`8(r+r#lbGj#~XSoGG4JviA*+vv*GT_mA9Ta%F-twwFNm)1R6X zeC!PHOHhO{54xU5lYgaR)rfRq1HbV8M%9n-)B3pUgz7H0-3IEb>wSRTCU-`@|9fj^ zFEa)uy+}A)hiB0N95I*)aZ^;bU0h*QS%;yQ&s6@ap`}MdltpQV0G*~j`YHt9VK|)9 z!|#DBo?Mh@&-UWTX61>ZDfDg_q0`82hf4QW`D;OTj^L*@((m70Bh;+!?x?|QC7D<2 zN@+IINC>}SHxg|3sl>XCbNu@sJom^WiMM8%!&7||z&b&7w{kayNuRu;d6Z`8e`Qqq zWlwi1w5pbV9_!tAPR!`Lz58Umgmhs{;ur9H7US`-jE&fEg+hPIPM;k-H*WEs#VN4{ zIFZ?!WUsb!oa*J^$7`|bL07e-A%36(U~^Nj=sE2-Y)(IW=rs9wdAYVeq4wDwge5fD zqs;UpmRD_#A7oWZeMJ4J3v2C-Zhe>?^w10Db5r&9=}`ZIeSetRbiO{JmD$#eLth?~2r1fnX zc0GN%wrk-NtTk!dg})`=2A+NM9}kF6F58ezYp_aPWtBm%9kqq2r#kP_B0si<4LVM( zIwXVf+m_M~JoI9n0j1ha?-C}^AQ#Mn96xjmZofPmw^^odr}VePK3HNc9E=7LU5A?R zfp;+zlvK*#whOQ6yNXC_6ui$cqg*cKWQB6m4}95-JrFuj<@?-W5wYc)kRBYi+&hm6 z*k^z+ypBLf(3qL6M9pN=TbJ7uc_o7!=+}e<(WhP=>H?f1e4KE4mFxH-ZhE@S;DUd> z$Qe`J|C~k~ldVXwfb&RI8d}Tka#uW9@Z$9C;XZQXt3YQ@3#zaer9sMr~&>g-f^-)>u-72B=gIVN}uq3At#Z3i^7Z_EngVRSImsJ_%3qENqb)w_2#Kz315TW|i zIptd(tc&V%mAcKc+3rQL+UIYlE_W%mQ8=$qQwluuPSTai6zpBV$jkP(3h9qfh&{Ta^I zTkj~DX(3+A0rwyhjjXh_@IXgDE=z3-@3K~*3UuQnjA*dolx^rF)YEuOn4Ag}{WD}? z;)eXCujb3@MPn`heYZ2S6+&c7C7s|2?CYPIE7inGAzTEa-~S=I{o)n3i!T1u*Q)Q- z;bI9Cg~T!!e?J_B2>?=4exHgZ!Q`Kp9Z6KW%weW%cEtrU)5FB~+gfDqbnbDNbA z+NKlBr_l;eqVoe|qH|-S%C#N8*bv&W_bGygI5t6F!~3c!BQ<46zh0x1tR>Z!=A}r@ zio{Wli67< zGajZMTkIPb%I(5u4*ghO-pA}5yD};=YFxX2Zzdw2&RckPWLW9T?xs3TRQ+VeI#(H~ThgaHP3y=U|ii@OmGl zx?Z~HiHz|xD5=|c13vm94zf3qYt)kOkUNDZMi}SKly0?N^&a{vdisoa$IA(C6~srn z+Qn8Ybnb$!QX=1O3%Kyg&sUIvI%_wh7>X3#oKFji)58!miQA@Yao?nNJrQI8YP?+s zWJH5qdTLX(lPOP@H47`N6d}DPVJJ(}NRY!$R|~lDNaL23F=JM%@q`bf=fbIkwBZ?} zbfgN+4@B6uyU2n^X?9&`^ZEOgB%q1R(^b5Tl^AZ!4iYOa*G(e6d`;6tz@Kvd3p=@*>Z=F5I~qnu8SBrvn>$ne6pPudhr-fcd=zLmI|W$8SYdjgc8VinX@1aKEtL( ztpu#TZJ?q60Sy=hxFtTMrFVf!(BSsk3ey$u?j=2SdYFjT zt&ciB5~+|dxJ}zno^|Rz>`ht@5>IwrlWp;OuZ0LzfmEB~Jf267 z&I>o@2+B#RzqY^pX}fGv$t^X5U8rGdjZ6WinRgSN^2!?giJ$$828vDkX|8y>7yF!> zy^b>Z$UK6wu}Aoh!fjt~YpX-p*!k*l%BtZQ7XLm;I7)3BJ2E^KcS8_~NcZ@wezW_* zqN@1kk22^>x?E-jFbcdH_BNCjvm-3?`|_0jUvty|ZLq-r9^o%4mcnDgTbCL9n|P@S zVnSHbF(WT&&~n(L76v%ZddUdB)Bh8ied9ghj$FNEVnI4m9TXIl*U)6XISj#J>jktjk-wG3+tpdfOdkbKmGHPQD zSL@F*l1d7B#hA2G7GxYEhSx10n_cj%+M5-z`C z?BA?GhZzTb6juTz-etVXkt7PwQ&iwGvC@w z^Pxkl0HY(QT^a|f9x_HQx{OSn?D5R-fW&D~45hT=r;PCLvM4wWPU>&nxK*Z8MHEO@ z6BfbZLRtPM8kwJ!FHZ}53d*s8kt*BOyC@~rm##P4?IVTZpvGEf-&8Yp8&L)lf^SVAfqpYc0O=x}7c1sYt9rAG*^yV+ zwVy?I4&g8@onkelK<&Joxnq0^@r}I{%m5k8;A)at44t*-WvQntCcMmx4s#f_LLir< z&`!j+<-CA0rP4d!LkLeeT!9bdudTEf1;D6m=O548n3_Fg`&bJ0lokVyOO&AIwu9$b zH6A!J@^ztss)+RF*Tc#sf>nti5#vJV9J!o$=>UYINsd-}9>1|x6TMKdGWuHiPY#7n ztPN>)$7i_F7Cll5DYM&|tv7Jnb7{4A$RLsQT;BRf5X7Z&oF)I1%G`C%gBKX-SxCp9 z5pO(Xbgk|y2vsc7aRlejh^1IUWSAxZ@iYZn3BoZpS8r#Z%53tK-W$MH$DgKY%@i;F zDt0MH0+LYW`ss-2*A#foce9|ff|su9UJR%pmB&I$__dK3LO{QYcN>c)&Ho|CMB{^B zFs8k*&+^Sm=(MtVz*OLK-dI7vRMo)JiQ&N)ry_3=hjd~?92jxImmR#W401Y!e!73l z7nFXW7k4&HBZD!+4kw;AdGU(=KJBtOJ9V7JJZuPMl_c!-l(e#Lql|euSDEqcEl`2n zz$zfal2GsiWDaM0u`M+jC54n{_4upgf7xh1T}D3`tQ*V5CeV>2J@rq3=DS%$L98s- zUdh=)WK2V$ig*wt6hIEdZMq5Rq0-lE2W5Gn>AfHpMerb6c+C%(ga^LxdUS|lRW@=6 z&Ciz8TEf+om}^+H{}4A$a-*_H5b!^BH^=%Yh_kfb^T7|zNjC8=nm2-k1d&`W^?@Dc zooJrQNzAp0)yE3{{ZUl>lP#`Tv?39xtcl_QaHXiNrmU_OaqvWBH4WCG{X;m3VWhMz zx+=_vvp)tzRSN?NfH@q%>-wt3TT6K;%$Y*zw!1s|`Wc0beE}~VMg)K0q4koV*hrx})}~!zqUi%ajTn$BpDnrqc*U;P&bgu>}J&Ml=-;F9w|MjHU(X%ev3siLkyfg;jB?XHaCib0oiOgwi@2 z^eK{fDfp;;`xg1tdGM%Goo%JZmY9O%QyqkZB1~`g5y%APMzqQBmepy(MJ2xw(*Nvt_HsuA0m|&R&tWb zm&B=CU1|j?ahQ_8eU>y|bMl;FMO(lb51&@b!*~=qq^bpq1jvJSpE>=^9v}0E7>si>S?|&w z=m8v`Be_o!uTvKb{i;<%wDRVzv%i;Eb< z0_ZM=8A?Z3p0&Tm>4Eh|7QK>t1JM~wJ3OA|LNZuYtbpCfO?~Q|sH_1U%%{5vv~MWY zxLX;CtR3G#{q_n<{tiq|`X?cXRG6AFPvheB82P>xphVMv(g4$BU?KVBCAN(30}zKj za~QisDXM`8)i&tJbHU}V)TF_vfqRr&G!`JZ9CpU?iv_+-ZX6PFV6NQUTWRI!fBzco^EyvYl0+_t1iJW^0x0Bs%U8#JDkt;$W;P&N zS&k>{k3D=;Dtm+Rnf`x_z@{FqhXpW$9HTSJeSq_VoV4j{Obve|>_*2`+s}luf?P0XJj9fM z0_?~X?~~Xq<9fBwOD!(F;iqO$_gzxUvxASy!Hcvq&sDWKyBv`cC=QCR@P*{)=+xZR z9jw?NxkxMAN}jlaj5&;qew7y2U4YB()OUMhnv}CfD#!4k;iN zf5&uazOC4NTx3vjD#eZpEY8qp)T7E4>_}ukiGB95$6)fkaRfBjiz+oLm_TsLEMV5O z_k%hRqq;}>cA#tf=8#x8@pqIgc?64{*nuKpv?|J0pi6xr!?Hm^R9uL_8VuCoAO~}F z{*q@101I#v3JAqLm)z!J@Rys*eaQ^PgSCws8AP{U*{+&sq0t9G+rE)t$L69-X~(K* zFV_cPMSO}l74HE=aah*+4tEAaC>M!E;+ORM5nFRt$Qh~7eU{sA`&`G#6zHdFEF8|9 z1uKpby&cqQgl`@7FlB!{A2TBfnx3pw+!*@6_R}%10FXl`6-zD28wX!m9v@ z97@)H{%vS`_+AiK%ch%dzerHhuvmAt=73}XZyIEf+ndN>H5w5j>L9+;@rUL%WObNl z-s%I(?{}1(VN_Kkk7-6rlp=G_{0m(UDZ5JO*dC%gN@uF(c4b%{(mGLfMg=rgfkhUY z?8M~$tS{ind-ujYp4HXI#yWTH7pT+$R%18nrQe%6oc4vHur&aULTQTXA1@K5GV{cq zZ{BhWv2L!kJbvx)q~=C-t%3x8hHQTmPX&geA~&}#np`82LU}Y|&JO7yajpC2`8w=} z{l?tgcVi8VjikFr+IvbOA&+C_;$Ojp4*BynwX2E=jnk$Nljc=Va#(x!<$U0O*5r*& zqF#;kmDXnDU#+a=MSKm_SRAXBm$oubxNn+&b$O^N&98CGO5r^b&|S6>o6qQYSKZg1;{Hrf=F8^%>7z`%n(v&Hog|mx9;!fWCxTJu0Zgson&8qo$&^ zbA-D~N-X~x5XTOV_}-!Nbtb9KdkZhgD+1(oorz|10!WGmx+HcU$S1GN78)ivd)b8C zR`9gF(A52u&`?GsN{k0?)KFcd8r#zLo#i?zkmu7aa-J7S(V4?{BnOxL*3&3!=~N@2 zrVN};(&3Bb`>l3gjuR?HEGZkXD_>Xeq3Eak>-h3o2r~lZLE}iQ4kOT}bxirzm+t!| zran7bS{UiO2qw~6g!c7Vm8=OXVoWDjs7*3PWIbZ=nY3KoztWZMq%utZ$~i1W+BtI& zru5gBZv~ajm30aVnOq3tt)wmEqv`hG<_NHYlUjNNehMrzaZjWkn+aE*1i*lcy?u~- ztbF34-Qg}SF>1^T%33pqHrRgYm%x!=3(u&SdAS^?lzkC4Wy7x(6;?-4R!c=lMw{B^ z6L-615Zmux4MC4rxUu4b=R#Z-|jw)8-Ysi2YHO7aaM)E?>g)DnxFp z4HzoZj(UpAd+1^RHF9dZRK?IYZ+~_^o8p-3PoAP7P7_|;3h=CLXRNMOk-!I_h$kmo zE3$sEt@L0gNiyst*_kI)%aiP>ncm+6k^{eF^O9nu&~4S0CNx+TiVP7ou(L`c^nbPj z+DyV>?xImykvtIHN+`={v41Wl*n#P1lVbDi3D+84u* zsG^tCsiOnQysPkEo*JdzH?19uBQr8(Rj|lcKeW8!+PO?zg{*VtA~JBJ4%V$3lV-44pfpQUI@&Mnd$NUPD+Sh~7Hyj_+ydTc}vm(^PUz5BaX< zQiL9PxS;fi%>7|?VX_9LKEx}Qw#6roh?)`nWl-*ZsA`gH!mU?$3TgV<{@6Kb6~&=< z$d)$!3Ao$IZxvXp)v69+LDM!31{Wde2w#Zrgc*##)FDsIEK)W0%R@{S`A7K*&&U60 zdTczN2-LknlI|$SM^kq%RXDtGN+tbGnuFC==jTQcl4xMD=WfKF6AV%fwWsj+Xs$#d{-Y(`3a_OsqHCxwui z&hKIKUU30-hF6$v?1hvkx|+JGmWv*rjc*}h-=RporQAZ7nYf$S(C5P7?_Mg0W+hq1EW*~kdA-?rw?xTn&PtWcqn*lFE$&B^q*!Rfxd@s1242kk+hYnw!Gvbov5{fSvy(Mgj#N|{X$db zn5r=nL6t`QfpMq4?7W+w0U5X!fAgyC`l}7QWm(EytAt?0G*vjJkUV5o|Jp&MF-8b2OoqpQ{13Xf>*E`fKq#jBJQiKZvd0uhKw7EKw1s z4VkEI&3BzorT^Y!*csS>f?hr{(P;>1$!QCinCkH+jx0UCDQg-xPS>1;)dzGOU#-Yn znk!u$w||ZAGk99xl^IaGG4~^02_2W4V~n4F|70Ct;VObvWVBdCX1iOm>zi-l1Z}0C z%71eNK2&I}VmJu!M;&NJ9T3w%yrQtHg_)0SsEeGa)ECZf{p%XVEa-qA12F*b3%fw^ zVmX|<$Hl5d?|x%#?-^v$MNu|8 zm7E80#?~L^vp6_V9`@st;Ir?Aa;O%g7B}~k`{LQJKRZ4xyFM&kTmb)tJo5V^e{R~V z<^M2*KJB?M5e7)3Hu2twb97`(1vJ)|rlQgWTU(CRFzj^F@JfEE2I<}S?YSvg09p{M z=Kb90qibjMM6xuP!R}a}?op)hdDTZnJa{<_`WaMgq|XD69aYdZI4x)}y_{puSL;?Ai0zAP@w-i=Hx^gyPEqVXZWhjYOOG9O!C z|=4x{^GWI A3=R zAQtW#Br^?3SP|vY??AsV7%Tkb+p4qHZ*M;CMw6lSZQ0T4y^I>oEEU>mH;pUYem+$* zQxkHUrMBgJ&Zjxwd}D&2CzO;1em%cfd^eH!xQw2kDyXmb(6S;!Y0=s{ouf;lPcCc~ zijEo|G<&`NB$nQ8#k|)0^-Vwx`yt<}`X&GHVQZsT?%+?z?FLH3f^WsiYAnq4&f2J* z+{;Ksw(C}v&QrrXT4{H!a#R^bUx`c+ok)HxqGijho+Eb=E{x*Is7xtT+l6cQG-RRZ z;=^uNiNMEC^L2anbFbULH6Vsi(%3GyNNbsRDanKrPOZjfUar^ZtPaK^4*?y;!Rb~R z+YeK@7M-{4RVsS{XCLmUTP=*DxZDqwrG>|t%_r|;9E_Kex>E( zb)QANcTEB@+g0k)P$lhDgv3bzG)m$FbPc0j8fmZ8rpzqq=sxa9ufEKFBl3&E{4fdc z%F0nwd4^)VIJXwj&lp!(BcN-M@ZGE8smw!otJPa1uTeBv#H3Z9Y5qj;*2}Pxy&!&G z>i}Dt*tsDDDMSgtuD#qxmzftI1-aK2Z;G>>5L1GVv0G)uxwL>wwA1fUa`9~AFhL{k-z>Kdk_v>>)O7%wZ|1P4I%jBd7i&==hPs2?g=JXp_f3-6gykS78xazwU)H!c zl8GzxKOJZ-r>LIT#ZBTIbXOg%4XUZ8&HlUx zI@!&TbDkuIlKM`x2P?|4@^atZ_grRFKeqUS!L@% zrWs5syg$a9^U$r!g}bap}ptN`1p&8O0;2O(%II>O{ZgLjM>nZ_YC{%q-ssu3{tZx{ykbA)ibf?oAXaS zxZtZV!usZiV9g<)D^&zIjf2Z(%zVHEc5esu?F5(}iLJyq_?l;(HL*Uym?8SCPUrir zpZsu<4Lo?WyuZ?d>DNC!l~#O<_Hu9gS~p`trV;(=r19agK4PlTx9tvT-nscQNpyC* z0?^bJXiVSlcKCGAD4^_3^&jDnGpOKz#}Q8b2k=!D%)xCWWOqUH<#X*ACQAtl!*;pB zpStD#ht<5~6H-gwD>|;+@53kGth?4qK0*xs+MS~1pmFCoS>+;v9nu5AnK5U|gt@Ph zisu-SHwv3%Hf!2fLbP{VCp0~lCT7c~l_YE)N;-_I`io_L5Ceq~M{6-DB+(OrE581*C4ymmUkRi?O^haRcSd z^KIEd)fuyL{T%;ar;de_ip5~8O+eKO0Kk?;2Kd3f>>S;Fz3serX8YZ;L3B||@~}{2 zImETtbitZEE(8!+VN_RET9d+bix!^$TO7L!P5`O&aY&96cdALNrKp(08X)+7-aATf z-|YL5z*(|Me~;N;emjw}gCi}1Ef{@R-kUn^{`Jq8H$T;<>!jeR-Lhay_lZBBAN`D0 zd4>_7mwM|kx=|$c&2yQJwGkLQ>oX@HKlN72rgaz@r*Pj_K8JUwr>_N)-Z7R4bnoOz ze8zlMR=(dLz4nJ8Tr6Y79yK#=(7yJN2gYw_r?XZ{3?&wu)+(+ zi=R>hO!=&G`kw||`JaGdQ0QlszZw_av8MdhovYaJX{)QEBj%ymW?Mk}*5=ZXmdvm} zopLkYw>t*fc-X7*qTV100PDN}l*|HC=0pJiS$aGGE4F=cTzvkI
    k)9{W8+y`z0 z_qMyEckjNY`aL5}eZ3233oZ(GqlpW|KTwQf000i^a@z@94DMDFmlz8y=I>P!FE^gR zW#CpMzhpd-!D0NH`sBDY+)9m?v?`TP+EsaGipeoa@+|*#Fx%h>OMb%Uxm}t#Psc);)&{#C2g^0w37?@4&x%vT%vGUZhK6 zp_b!KL6ja4sn-cK`I_;0EF5DVITp3IEJmaD#AXsLP Date: Thu, 31 Mar 2016 10:07:59 +0200 Subject: [PATCH 12/14] Progressing on the Escort positioning system. --- Moose/Base.lua | 4 +- Moose/Client.lua | 41 +- Moose/Escort.lua | 73 +- Moose/Group.lua | 1 + Moose/Menu.lua | 1 + .../lua/MOOSE_Escort_Test_Follow.lua | 27 +- .../miz/MOOSE_Escort_Test_Follow.miz | Bin 39292 -> 40943 bytes .../ABRIS/Database/NAVIGATION.lua | 3262 +++++++++++++ .../ABRIS/Database/ROUTES.lua | 3 + .../Config/View/Server.lua | 209 + .../Config/View/SnapViewsDefault.lua | 1698 +++++++ .../Config/View/View.lua | 128 + .../Ka-50/Cockpit/Scripts/ARK/ARK.lua | 53 + .../Scripts/World/GPS_GNSS.lua | 880 ++++ .../Scripts/World/birds.lua | 27 + .../l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua | 29 + .../l10n/DEFAULT/Moose_Load_Dynamic.lua | 43 + .../l10n/DEFAULT/Moose_Load_Embedded.lua | 23 + .../l10n/DEFAULT/dictionary | 25 + .../l10n/DEFAULT/mapResource | 6 + .../miz/MOOSE_Escort_Test_Follow/mission | 4024 +++++++++++++++++ .../miz/MOOSE_Escort_Test_Follow/options | 203 + .../miz/MOOSE_Escort_Test_Follow/warehouses | 807 ++++ 23 files changed, 11540 insertions(+), 27 deletions(-) create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/ABRIS/Database/NAVIGATION.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/ABRIS/Database/ROUTES.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/Config/View/Server.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/Config/View/SnapViewsDefault.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/Config/View/View.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/Mods/aircraft/Ka-50/Cockpit/Scripts/ARK/ARK.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/GPS_GNSS.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/birds.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Dynamic.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Embedded.lua create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/mapResource create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/mission create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/options create mode 100644 Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses diff --git a/Moose/Base.lua b/Moose/Base.lua index 278af6459..80f3f50e6 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -14,9 +14,9 @@ local _TraceClass = { --SPAWN = true, --STAGE = true, --ZONE = true, - GROUP = true, + --GROUP = true, --UNIT = true, - CLIENT = true, + --CLIENT = true, --CARGO = true, --CARGO_GROUP = true, --CARGO_PACKAGE = true, diff --git a/Moose/Client.lua b/Moose/Client.lua index d927f46bc..ca8a03f21 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -65,9 +65,48 @@ function CLIENT:Reset( ClientName ) self._Menus = {} end +--- Checks for a client alive event and calls a function on a continuous basis. +-- @param #CLIENT self +-- @param #function CallBack Function. +function CLIENT:Alive( CallBack ) + self:F() + + self.ClientAlive = false + self.ClientCallBack = CallBack + self.AliveCheckFunction = routines.scheduleFunction( self._AliveCheckCallBack, { self }, timer.getTime() + 1, 1 ) +end + +--- Checks if client is alive and returns true or false. +-- @param #CLIENT self +-- @param #boolean Returns true if client is alive. +function CLIENT:IsAlive() + self:F() + + local ClientDCSGroup = self:GetDCSGroup() + + if ClientDCSGroup then + return true + end + + return false +end + + +--- @param #CLIENT self +function CLIENT:_AliveCheckCallBack() + + if self:IsAlive() then + if self.ClientAlive == false then + self.ClientCallBack( self ) + self.ClientAlive = true + routines.removeFunction( self.AliveCheckFunction ) + end + end +end + --- Return the DCSGroup of a Client. -- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @return Group#Group +-- @return DCSGroup#Group function CLIENT:GetDCSGroup() self:F3() diff --git a/Moose/Escort.lua b/Moose/Escort.lua index fa402e00d..02527a343 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -23,17 +23,20 @@ Include.File( "Zone" ) -- @field Client#CLIENT EscortClient -- @field Group#GROUP EscortGroup -- @field #string EscortName +-- @field #number FollowScheduler The id of the _FollowScheduler function. ESCORT = { ClassName = "ESCORT", EscortName = nil, -- The Escort Name EscortClient = nil, EscortGroup = nil, Targets = {}, -- The identified targets + FollowScheduler = nil, } --- MENUPARAM type -- @type MENUPARAM -- @field #ESCORT ParamSelf +-- @field #Distance ParamDistance --- ESCORT class constructor for an AI group -- @param self @@ -56,7 +59,10 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenuReportNavigation, ESCORT._HoldPosition, { ParamSelf = self } ) self.EscortMenuJoinUpAndHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) - self.EscortMenuJoinUpAndFollow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self } ) + self.EscortMenuJoinUpAndFollow50Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 100", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 100 } ) + self.EscortMenuJoinUpAndFollow100Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 200", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 200 } ) + self.EscortMenuJoinUpAndFollow150Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 400", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 400 } ) + self.EscortMenuJoinUpAndFollow200Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 800", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 800 } ) -- Report Targets self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) @@ -91,7 +97,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortMenuCancelTask = MENU_CLIENT_COMMAND:New( self.EscortClient, "Cancel current task", self.EscortMenu, ESCORT._CancelCurrentTask, { ParamSelf = self, } ) - self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) + self.ScanForTargetsScheduler = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) end @@ -147,10 +153,16 @@ function ESCORT._JoinUpAndFollow( MenuParam ) local EscortGroup = MenuParam.ParamSelf.EscortGroup local EscortClient = MenuParam.ParamSelf.EscortClient + local Distance = MenuParam.ParamDistance + + if self.FollowScheduler then + routines.removeFunction( self.FollowScheduler ) + end + self.CT1 = 0 self.GT1 = 0 - self.FollowFunction = routines.scheduleFunction( self._Follower, { self }, timer.getTime() + 1, 1 ) - EscortGroup:MessageToClient( "Rejoining and following orders ...", 10, EscortClient ) + self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + 1, 1 ) + EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient ) end @@ -297,58 +309,79 @@ function ESCORT._CancelCurrentTask( MenuParam ) end --- @param Escort#ESCORT self -function ESCORT:_Follower() - self:F() +function ESCORT:_FollowScheduler( FollowDistance ) + self:F( { FollowDistance }) - local ClientUnit = self.EscortClient:GetClientGroupUnit() - local GroupUnit = self.EscortGroup:GetUnit( 1 ) + if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then + + local ClientUnit = self.EscortClient:GetClientGroupUnit() + local GroupUnit = self.EscortGroup:GetUnit( 1 ) - if self.EscortGroup:IsAlive() and ClientUnit:IsAlive() then if self.CT1 == 0 and self.GT1 == 0 then self.CV1 = ClientUnit:GetPositionVec3() self.CT1 = timer.getTime() self.GV1 = GroupUnit:GetPositionVec3() self.GT1 = timer.getTime() - else local CT1 = self.CT1 local CT2 = timer.getTime() local CV1 = self.CV1 local CV2 = ClientUnit:GetPositionVec3() + self.CT1 = CT2 + self.CV1 = CV2 local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 local CT = CT2 - CT1 local CS = ( 3600 / CT ) * ( CD / 1000 ) - self:T( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) local GT1 = self.GT1 local GT2 = timer.getTime() local GV1 = self.GV1 local GV2 = GroupUnit:GetPositionVec3() + self.GT1 = GT2 + self.GV1 = GV2 local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 local GT = GT2 - GT1 local GS = ( 3600 / GT ) * ( GD / 1000 ) - self:T( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) + self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) -- Measure distance between client and group - local D = ( ( CV2.x - GV2.x )^2 + ( CV2.y - GV2.y )^2 + ( CV2.z - GV2.z )^2 ) ^ 0.5 - 200 + local CatchUpDistance = ( ( CV2.x - GV2.x )^2 + ( CV2.y - GV2.y )^2 + ( CV2.z - GV2.z )^2 ) ^ 0.5 + local Distance = CatchUpDistance - FollowDistance - local S = ( 3600 / 30 ) * ( D / 1000 ) -- We use a 2 second buffer to adjust the speed - local A = ( CS - GS ) + S -- Accelleration required = Client Speed - Group Speed + Speed to overcome distance (with 10 second time buffer) - local Speed = A -- Final speed is the current Group speed + Accelleration + -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome + -- the requested Distance). + local Time = 1600 / FollowDistance + local CatchUpSpeed = ( Distance / Time ) * ( CatchUpDistance / 1000 ) - self:T( { "Speed:", S, A, Speed } ) + -- Follow speed required = Client Speed - Group Speed + Speed to overcome distance. + local BreakSpeed = ( GS * ( ( 1 ) / Distance ) ) + if BreakSpeed < 0 then + BreakSpeed = 0 + end + + if BreakSpeed > CS then + BreakSpeed = CS + end + + local Speed = CS + CatchUpSpeed --- - BreakSpeed + if Speed < 0 then + Speed = 0 + end + + self:T( { "Client Speed, Client Time, Escort Speed, Speed, CatchUpSpeed, BreakSpeed, Distance, Time:", CS, CT, GS, Speed, CatchUpSpeed, BreakSpeed, Distance, Time } ) -- Now route the escort to the desired point with the desired speed. - self.EscortGroup:TaskRouteToVec3( CV2, Speed ) + self.EscortGroup:TaskRouteToVec3( CV2, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) end else - routines.removeFunction( self.FollowFunction ) + routines.removeFunction( self.FollowScheduler ) end end @@ -462,6 +495,6 @@ function ESCORT:_ScanForTargets() end else - routines.removeFunction( self.ScanForTargetsFunction ) + routines.removeFunction( self.ScanForTargetsScheduler ) end end diff --git a/Moose/Group.lua b/Moose/Group.lua index e5144068c..7754f9e01 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -592,6 +592,7 @@ function GROUP:TaskRouteToVec3( Point, Speed ) PointTo.alt = Point.y PointTo.type = "Turning Point" PointTo.speed = Speed + PointTo.speed_locked = true local Points = { PointFrom, PointTo } diff --git a/Moose/Menu.lua b/Moose/Menu.lua index 9c10272bb..3d4320d6a 100644 --- a/Moose/Menu.lua +++ b/Moose/Menu.lua @@ -102,6 +102,7 @@ function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu ) end local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) ) + self:F( { MenuClient, MenuText, ParentMenu } ) self.MenuClient = MenuClient self.MenuClientGroupID = MenuClient:GetClientGroupID() diff --git a/Test Missions/lua/MOOSE_Escort_Test_Follow.lua b/Test Missions/lua/MOOSE_Escort_Test_Follow.lua index 57b203189..5bcce439c 100644 --- a/Test Missions/lua/MOOSE_Escort_Test_Follow.lua +++ b/Test Missions/lua/MOOSE_Escort_Test_Follow.lua @@ -1,16 +1,35 @@ Include.File( "Mission" ) Include.File( "Client" ) +Include.File( "Spawn" ) Include.File( "Escort" ) do - local EscortClient = CLIENT:New( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ) - local EscortGroup = GROUP:NewFromName( "Escort Helicopter" ) - local Escort = ESCORT:New( EscortClient, EscortGroup, "Escort Test" ) + local function EventAliveHelicopter( Client ) + local SpawnEscortHeli = SPAWN:New( "Escort Helicopter" ) + local EscortGroupHeli1 = SpawnEscortHeli:Spawn() + local EscortGroupHeli2 = SpawnEscortHeli:Spawn() + local EscortGroupHeli3 = SpawnEscortHeli:Spawn() + local EscortGroupHeli4 = SpawnEscortHeli:Spawn() + local EscortHeli1 = ESCORT:New( Client, EscortGroupHeli1, "Escort Alpha" ) + local EscortHeli2 = ESCORT:New( Client, EscortGroupHeli2, "Escort Bravo" ) + local EscortHeli3 = ESCORT:New( Client, EscortGroupHeli3, "Escort Delta" ) + local EscortHeli4 = ESCORT:New( Client, EscortGroupHeli4, "Escort Gamma" ) + end + + local function EventAlivePlane( Client ) + local SpawnEscortPlane = SPAWN:New( "Escort Plane" ) + local EscortGroupPlane = SpawnEscortPlane:Spawn() + local EscortPlane = ESCORT:New( Client, EscortGroupPlane, "Escort Test Plane" ) + end + + local EscortClientHeli = CLIENT:New( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ):Alive( EventAliveHelicopter ) + local EscortClientPlane = CLIENT:New( "Lead Plane", "Fly around and observe the behaviour of the escort airplane. Select Navigate->Joun-Up and airplane should follow you. Change speed and directions." ) + :Alive( EventAlivePlane ) + end - -- MISSION SCHEDULER STARTUP MISSIONSCHEDULER.Start() MISSIONSCHEDULER.ReportMenu() diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow.miz b/Test Missions/miz/MOOSE_Escort_Test_Follow.miz index 4594f3756d34f0a1f1c7f73eb6418c51f8d9ebc6..e62ab61013e7f573c1cd360d736031ac24bcdb93 100644 GIT binary patch delta 25528 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/DCS/Config/View/SnapViews.lua +SnapViews = {} +SnapViews["A-10A"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 65.000000,--FOV + hAngle = 0.000000, + vAngle = -26.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 49.626770,--FOV + hAngle = 0.000000, + vAngle = -90.631294, + x_trans = 0.180499, + y_trans = -0.137064, + z_trans = -0.250000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 30.395041,--FOV + hAngle = 0.000000, + vAngle = -94.329208, + x_trans = 0.372718, + y_trans = -0.054055, + z_trans = 0.250000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 55.238567,--FOV + hAngle = 0.000000, + vAngle = -90.631294, + x_trans = 0.158523, + y_trans = -0.137064, + z_trans = 0.250000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 35.000000,--FOV + hAngle = 0.000000, + vAngle = -10.651850, + x_trans = 0.327622, + y_trans = -0.278207, + z_trans = -0.244799, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 34.340549,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 35.000000,--FOV + hAngle = 0.000000, + vAngle = -10.651850, + x_trans = 0.327622, + y_trans = -0.278207, + z_trans = 0.244799, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 68.628296,--FOV + hAngle = 68.292320, + vAngle = -11.477349, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 68.628296,--FOV + hAngle = 0.000000, + vAngle = 30.227919, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 68.628296,--FOV + hAngle = -67.172974, + vAngle = -11.477349, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 70.000000,--FOV + hAngle = 20.000000, + vAngle = 8.000000, + x_trans = 0.360000, + y_trans = -0.041337, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 70.000000,--FOV + hAngle = -20.000000, + vAngle = 8.000000, + x_trans = 0.360000, + y_trans = -0.041337, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 75.000000,--FOV + hAngle = 0.000000, + vAngle = -23.000000, + x_trans = 0.360000, + y_trans = -0.041337, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["A-10C"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 65.000000,--FOV + hAngle = 0.000000, + vAngle = -26.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 49.626770,--FOV + hAngle = 0.000000, + vAngle = -90.631294, + x_trans = 0.180499, + y_trans = -0.137064, + z_trans = -0.250000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 30.395041,--FOV + hAngle = 0.000000, + vAngle = -94.329208, + x_trans = 0.372718, + y_trans = -0.054055, + z_trans = 0.250000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 55.238567,--FOV + hAngle = 0.000000, + vAngle = -90.631294, + x_trans = 0.158523, + y_trans = -0.137064, + z_trans = 0.250000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 35.000000,--FOV + hAngle = 0.000000, + vAngle = -10.651850, + x_trans = 0.327622, + y_trans = -0.278207, + z_trans = -0.244799, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 34.340549,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 35.000000,--FOV + hAngle = 0.000000, + vAngle = -10.651850, + x_trans = 0.327622, + y_trans = -0.278207, + z_trans = 0.244799, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 68.628296,--FOV + hAngle = 68.292320, + vAngle = -11.477349, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 68.628296,--FOV + hAngle = 0.000000, + vAngle = 30.227919, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 68.628296,--FOV + hAngle = -67.172974, + vAngle = -11.477349, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 70.000000,--FOV + hAngle = 20.000000, + vAngle = 8.000000, + x_trans = 0.360000, + y_trans = -0.041337, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 70.000000,--FOV + hAngle = -20.000000, + vAngle = 8.000000, + x_trans = 0.360000, + y_trans = -0.041337, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 75.000000,--FOV + hAngle = 0.000000, + vAngle = -23.000000, + x_trans = 0.360000, + y_trans = -0.041337, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["F-15C"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 70.611748,--FOV + hAngle = -1.240272, + vAngle = -33.850250, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 32.704346,--FOV + hAngle = 25.696522, + vAngle = -34.778103, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 32.704346,--FOV + hAngle = 0.000000, + vAngle = -47.845268, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 36.106045,--FOV + hAngle = -28.878576, + vAngle = -36.780628, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 88.727844,--FOV + hAngle = 128.508865, + vAngle = 13.131046, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 41.928593,--FOV + hAngle = 0.000000, + vAngle = -4.630446, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 88.727844,--FOV + hAngle = -128.508865, + vAngle = 13.131046, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 88.727844,--FOV + hAngle = 81.648369, + vAngle = -9.500000, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 88.727844,--FOV + hAngle = 0.000000, + vAngle = 34.180634, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 88.727844,--FOV + hAngle = -80.997551, + vAngle = -9.500000, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 56.032040,--FOV + hAngle = 14.803060, + vAngle = 3.332499, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 56.032040,--FOV + hAngle = -14.414484, + vAngle = 3.332499, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 88.727844,--FOV + hAngle = 0.000000, + vAngle = -9.678451, + x_trans = 0.264295, + y_trans = -0.064373, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["Ka-50"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 67.452896,--FOV + hAngle = 0.000000, + vAngle = -40.067383, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 37.846794,--FOV + hAngle = 51.644135, + vAngle = -51.870411, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 36.178646,--FOV + hAngle = -1.912186, + vAngle = -34.446247, + x_trans = 0.000000, + y_trans = -0.025421, + z_trans = 0.073226, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 73.605141,--FOV + hAngle = -90.361992, + vAngle = -44.103138, + x_trans = 0.169696, + y_trans = -0.073508, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 91.348198,--FOV + hAngle = 109.752129, + vAngle = 1.484382, + x_trans = 0.190306, + y_trans = 0.044778, + z_trans = -0.150335, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 42.512844,--FOV + hAngle = 0.000000, + vAngle = -4.478010, + x_trans = 0.154018, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 91.348198,--FOV + hAngle = -108.852020, + vAngle = 0.085984, + x_trans = 0.190306, + y_trans = 0.044778, + z_trans = 0.139404, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 89.777542,--FOV + hAngle = 16.411518, + vAngle = -27.209915, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = -0.218292, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 88.727844,--FOV + hAngle = 0.000000, + vAngle = 34.042202, + x_trans = 0.142145, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 59.208893,--FOV + hAngle = -32.128311, + vAngle = -5.720805, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 56.032040,--FOV + hAngle = 14.803060, + vAngle = 3.332499, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 56.032040,--FOV + hAngle = -14.414484, + vAngle = 3.332499, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 89.777542,--FOV + hAngle = 0.000000, + vAngle = -15.592758, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["MiG-29A"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 76.124840,--FOV + hAngle = -2.623254, + vAngle = -26.566959, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 34.911949,--FOV + hAngle = 24.601770, + vAngle = -32.350807, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 26.184198,--FOV + hAngle = 12.026249, + vAngle = -40.075508, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 39.454399,--FOV + hAngle = -26.664328, + vAngle = -32.355324, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 81.240005,--FOV + hAngle = 131.503998, + vAngle = 10.804660, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 44.201855,--FOV + hAngle = 0.000000, + vAngle = -2.378299, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 81.240005,--FOV + hAngle = -131.503998, + vAngle = 10.804660, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 81.240005,--FOV + hAngle = 76.013145, + vAngle = 2.248441, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 81.240005,--FOV + hAngle = 0.000000, + vAngle = 36.304676, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 81.240005,--FOV + hAngle = -74.774559, + vAngle = 2.248441, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 68.250000,--FOV + hAngle = 13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 68.250000,--FOV + hAngle = -13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 81.240005,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["MiG-29G"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 76.124840,--FOV + hAngle = -2.623254, + vAngle = -26.566959, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 34.911949,--FOV + hAngle = 24.601770, + vAngle = -32.350807, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 26.184198,--FOV + hAngle = 12.026249, + vAngle = -40.075508, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 39.454399,--FOV + hAngle = -26.664328, + vAngle = -32.355324, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 81.240005,--FOV + hAngle = 131.503998, + vAngle = 10.804660, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 44.201855,--FOV + hAngle = 0.000000, + vAngle = -2.378299, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 81.240005,--FOV + hAngle = -131.503998, + vAngle = 10.804660, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 81.240005,--FOV + hAngle = 76.013145, + vAngle = 2.248441, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 81.240005,--FOV + hAngle = 0.000000, + vAngle = 36.304676, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 81.240005,--FOV + hAngle = -74.774559, + vAngle = 2.248441, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 68.250000,--FOV + hAngle = 13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 68.250000,--FOV + hAngle = -13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 81.240005,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["MiG-29K"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 65.000000,--FOV + hAngle = 0.000000, + vAngle = -26.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 30.000000,--FOV + hAngle = 20.000000, + vAngle = -43.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 30.000000,--FOV + hAngle = 0.000000, + vAngle = -43.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 30.000000,--FOV + hAngle = -20.000000, + vAngle = -43.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 30.000000,--FOV + hAngle = 20.000000, + vAngle = -23.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 30.000000,--FOV + hAngle = 0.000000, + vAngle = -23.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 30.000000,--FOV + hAngle = -20.000000, + vAngle = -23.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 30.000000,--FOV + hAngle = 20.000000, + vAngle = 2.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 30.000000,--FOV + hAngle = 0.000000, + vAngle = 2.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 30.000000,--FOV + hAngle = -20.000000, + vAngle = 2.000000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 68.250000,--FOV + hAngle = 13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 68.250000,--FOV + hAngle = -13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 60.000000,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["MiG-29S"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 76.124840,--FOV + hAngle = -2.623254, + vAngle = -26.566959, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 34.911949,--FOV + hAngle = 24.601770, + vAngle = -32.350807, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 26.184198,--FOV + hAngle = 12.026249, + vAngle = -40.075508, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 39.454399,--FOV + hAngle = -26.664328, + vAngle = -32.355324, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 81.240005,--FOV + hAngle = 131.503998, + vAngle = 10.804660, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 44.201855,--FOV + hAngle = 0.000000, + vAngle = -2.378299, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 81.240005,--FOV + hAngle = -131.503998, + vAngle = 10.804660, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 81.240005,--FOV + hAngle = 76.013145, + vAngle = 2.248441, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 81.240005,--FOV + hAngle = 0.000000, + vAngle = 36.304676, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 81.240005,--FOV + hAngle = -74.774559, + vAngle = 2.248441, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 68.250000,--FOV + hAngle = 13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 68.250000,--FOV + hAngle = -13.070938, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 81.240005,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["P-51D"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 80.000000,--FOV + hAngle = 0.000000, + vAngle = -45.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 80.000000,--FOV + hAngle = 45.000000, + vAngle = -45.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 80.000000,--FOV + hAngle = 0.000000, + vAngle = -75.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 80.000000,--FOV + hAngle = -45.000000, + vAngle = -45.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 91.040001,--FOV + hAngle = 157.332764, + vAngle = -28.359503, + x_trans = 0.063872, + y_trans = 0.082888, + z_trans = -0.116148, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 50.000000,--FOV + hAngle = 0.000000, + vAngle = -8.722581, + x_trans = 0.212078, + y_trans = 0.057813, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 80.000000,--FOV + hAngle = -143.000000, + vAngle = 0.000000, + x_trans = 0.350000, + y_trans = 0.059000, + z_trans = 0.100000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 80.000000,--FOV + hAngle = 45.000000, + vAngle = -5.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 80.000000,--FOV + hAngle = 0.000000, + vAngle = 10.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 80.000000,--FOV + hAngle = -45.000000, + vAngle = -5.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 80.000000,--FOV + hAngle = 0.000000, + vAngle = 10.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 80.000000,--FOV + hAngle = -20.000000, + vAngle = 8.000000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 80.000000,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.120000, + y_trans = 0.059000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["Su-25"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 68.767799,--FOV + hAngle = 1.929517, + vAngle = -30.846605, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 29.223452,--FOV + hAngle = 37.489525, + vAngle = -38.883888, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 40.635601,--FOV + hAngle = -0.438357, + vAngle = -33.138290, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 24.797405,--FOV + hAngle = -34.382549, + vAngle = -34.808853, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 69.302101,--FOV + hAngle = 89.405373, + vAngle = 1.213156, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 29.761202,--FOV + hAngle = 0.000000, + vAngle = -6.880077, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 69.302101,--FOV + hAngle = -89.691940, + vAngle = 4.554290, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 69.302101,--FOV + hAngle = 52.113377, + vAngle = -3.970644, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 72.856201,--FOV + hAngle = 0.000000, + vAngle = 30.866713, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 69.302101,--FOV + hAngle = -50.664936, + vAngle = -3.970644, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 47.680202,--FOV + hAngle = 43.054649, + vAngle = -7.799250, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 47.680202,--FOV + hAngle = -41.743240, + vAngle = -7.799250, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 69.302101,--FOV + hAngle = 0.000000, + vAngle = -15.137112, + x_trans = 0.050000, + y_trans = 0.010000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["Su-25T"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 80.663399,--FOV + hAngle = 0.000000, + vAngle = -30.619938, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 39.764698,--FOV + hAngle = 28.661316, + vAngle = -41.406044, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 38.090847,--FOV + hAngle = -24.622110, + vAngle = -45.153934, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 36.062012,--FOV + hAngle = -20.779360, + vAngle = -23.755520, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 80.663399,--FOV + hAngle = 99.816956, + vAngle = 8.032285, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 58.718098,--FOV + hAngle = 0.000000, + vAngle = -5.000803, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 80.663399,--FOV + hAngle = -99.999687, + vAngle = 8.032285, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 80.663399,--FOV + hAngle = 58.382488, + vAngle = -6.648195, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 94.037704,--FOV + hAngle = 0.000000, + vAngle = 41.421227, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 80.663399,--FOV + hAngle = -57.531212, + vAngle = -6.648195, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 60.203396,--FOV + hAngle = 55.124939, + vAngle = -8.400513, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 60.203396,--FOV + hAngle = -52.633553, + vAngle = -8.400513, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 90.000000,--FOV + hAngle = 0.000000, + vAngle = -18.382137, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["Su-25TM"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 80.663399,--FOV + hAngle = 0.000000, + vAngle = -30.619938, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 39.764698,--FOV + hAngle = 28.661316, + vAngle = -41.406044, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 38.090847,--FOV + hAngle = -24.622110, + vAngle = -45.153934, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 33.645596,--FOV + hAngle = -36.653450, + vAngle = -23.703861, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 80.663399,--FOV + hAngle = 99.816956, + vAngle = 8.032285, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 58.718098,--FOV + hAngle = 0.000000, + vAngle = -5.000803, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 80.663399,--FOV + hAngle = -99.999687, + vAngle = 8.032285, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 80.663399,--FOV + hAngle = 58.382488, + vAngle = -6.648195, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 94.037704,--FOV + hAngle = 0.000000, + vAngle = 41.421227, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 80.663399,--FOV + hAngle = -57.531212, + vAngle = -6.648195, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 60.203396,--FOV + hAngle = 55.124939, + vAngle = -8.400513, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 60.203396,--FOV + hAngle = -52.633553, + vAngle = -8.400513, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 90.000000,--FOV + hAngle = 0.000000, + vAngle = -18.382137, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["Su-27"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 71.824692,--FOV + hAngle = 0.000000, + vAngle = -32.458889, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 33.361835,--FOV + hAngle = 41.045925, + vAngle = -40.805656, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 30.427544,--FOV + hAngle = 0.000000, + vAngle = -41.808968, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 34.392349,--FOV + hAngle = -32.597401, + vAngle = -35.293747, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 87.468338,--FOV + hAngle = 129.012665, + vAngle = 14.547977, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 43.977936,--FOV + hAngle = 0.000000, + vAngle = -4.951577, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 87.468338,--FOV + hAngle = -129.012665, + vAngle = 14.491872, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 87.468338,--FOV + hAngle = 82.862923, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 87.468338,--FOV + hAngle = 0.000000, + vAngle = 38.979362, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 87.468338,--FOV + hAngle = -82.461266, + vAngle = -12.843998, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 68.786629,--FOV + hAngle = 15.618313, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 69.165199,--FOV + hAngle = -15.683434, + vAngle = 8.549150, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 87.468338,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.113927, + y_trans = -0.004946, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} +SnapViews["Su-33"] = { +[1] = {-- player slot 1 + [1] = { + viewAngle = 71.824692,--FOV + hAngle = 0.000000, + vAngle = -32.458889, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [2] = { + viewAngle = 33.361835,--FOV + hAngle = 41.045925, + vAngle = -40.805656, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [3] = { + viewAngle = 30.427544,--FOV + hAngle = 0.000000, + vAngle = -41.808968, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [4] = { + viewAngle = 34.392349,--FOV + hAngle = -32.597401, + vAngle = -35.293747, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [5] = { + viewAngle = 87.468338,--FOV + hAngle = 129.012665, + vAngle = 14.547977, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [6] = { + viewAngle = 43.977936,--FOV + hAngle = 0.000000, + vAngle = -4.951577, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [7] = { + viewAngle = 87.468338,--FOV + hAngle = -129.012665, + vAngle = 14.491872, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [8] = { + viewAngle = 87.468338,--FOV + hAngle = 82.862923, + vAngle = -9.500000, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [9] = { + viewAngle = 87.468338,--FOV + hAngle = 0.000000, + vAngle = 38.979362, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [10] = { + viewAngle = 87.468338,--FOV + hAngle = -82.461266, + vAngle = -12.843998, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [11] = {--look at left mirror + viewAngle = 68.786629,--FOV + hAngle = 15.618313, + vAngle = 7.522498, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [12] = {--look at right mirror + viewAngle = 69.165199,--FOV + hAngle = -15.683434, + vAngle = 8.549150, + x_trans = 0.000000, + y_trans = 0.000000, + z_trans = 0.000000, + rollAngle = 0.000000, + }, + [13] = {--default view + viewAngle = 87.468338,--FOV + hAngle = 0.000000, + vAngle = -9.500000, + x_trans = 0.113927, + y_trans = -0.004946, + z_trans = 0.000000, + rollAngle = 0.000000, + }, +}, +} \ No newline at end of file diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/Config/View/View.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/Config/View/View.lua new file mode 100644 index 000000000..9baf3b7df --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/Config/View/View.lua @@ -0,0 +1,128 @@ +-- View scripts +-- Copyright (C) 2004, Eagle Dynamics. + +CockpitMouse = true --false +CockpitMouseSpeedSlow = 1.0 +CockpitMouseSpeedNormal = 10.0 +CockpitMouseSpeedFast = 20.0 +CockpitKeyboardAccelerationSlow = 5.0 +CockpitKeyboardAccelerationNormal = 30.0 +CockpitKeyboardAccelerationFast = 80.0 +CockpitKeyboardZoomAcceleration = 300.0 +DisableSnapViewsSaving = false +UseDefaultSnapViews = true +CockpitPanStepHor = 45.0 +CockpitPanStepVert = 30.0 +CockpitNyMove = true + +CockpitHAngleAccelerateTimeMax = 0.15 +CockpitVAngleAccelerateTimeMax = 0.15 +CockpitZoomAccelerateTimeMax = 0.2 + +function NaturalHeadMoving(tang, roll, omz) + local r = roll + if r > 90.0 then + r = 180.0 - r + elseif roll < -90.0 then + r = -180.0 - r + end + local hAngle = -0.25 * r + local vAngle = math.min(math.max(0.0, 0.4 * tang + 45.0 * omz), 90.0) + return hAngle, vAngle +end + +ExternalMouse = true +ExternalMouseSpeedSlow = 1.0 +ExternalMouseSpeedNormal = 5.0 +ExternalMouseSpeedFast = 20.0 +ExternalViewAngleMin = 3.0 +ExternalViewAngleMax = 170.0 +ExternalViewAngleDefault = 60.0 +ExternalKeyboardZoomAcceleration = 30.0 +ExternalKeyboardZoomAccelerateTimeMax = 1.0 +ExplosionExpoTime = 4.0 +ExternalKeyboardAccelerationSlow = 1.0 +ExternalKeyboardAccelerationNormal = 10.0 +ExternalKeyboardAccelerationFast = 30.0 +ExternalHAngleAccelerateTimeMax = 3.0 +ExternalVAngleAccelerateTimeMax = 3.0 +ExternalDistAccelerateTimeMax = 3.0 +ExternalHAngleLocalAccelerateTimeMax = 3.0 +ExternalVAngleLocalAccelerateTimeMax = 3.0 +ExternalAngleNormalDiscreteStep = 15.0/ExternalKeyboardAccelerationNormal -- When 'S' is pressed only +ChaseCameraNyMove = true +FreeCameraAngleIncrement = 3.0 +FreeCameraDistanceIncrement = 200.0 +FreeCameraLeftRightIncrement = 2.0 +FreeCameraAltitudeIncrement = 2.0 +FreeCameraScalarSpeedAcceleration = 0.1 +xMinMap = -300000 +xMaxMap = 500000 +yMinMap = -400000 +yMaxMap = 200000 +dxMap = 150000 +dyMap = 100000 + +head_roll_shaking = true +head_roll_shaking_max = 30.0 +head_roll_shaking_compensation_gain = 0.3 + +-- CameraJiggle() and CameraFloat() functions make camera position +-- dependent on FPS so be careful in using the Shift-J command with tracks, please. +-- uncomment to use custom jiggle functions +--[[ +function CameraJiggle(t,rnd1,rnd2,rnd3) + local rotX, rotY, rotZ + rotX = 0.05 * rnd1 * math.sin(37.0 * (t - 0.0)) + rotY = 0.05 * rnd2 * math.sin(41.0 * (t - 1.0)) + rotZ = 0.05 * rnd3 * math.sin(53.0 * (t - 2.0)) + return rotX, rotY, rotZ +end + +function CameraFloat(t) + local dX, dY, dZ + dX = 0.61 * math.sin(0.7 * t) + 0.047 * math.sin(1.6 * t); + dY = 0.43 * math.sin(0.6 * t) + 0.067 * math.sin(1.7 * t); + dZ = 0.53 * math.sin(1.0 * t) + 0.083 * math.sin(1.9 * t); + return dX, dY, dZ +end +--]] +--Debug keys + +DEBUG_TEXT = 1 +DEBUG_GEOMETRY = 2 + +debug_keys = { + [DEBUG_TEXT] = 1, + [DEBUG_GEOMETRY] = 1 +} + +function onDebugCommand(command) + if command == 10000 then + if debug_keys[DEBUG_TEXT] ~= 0 or debug_keys[DEBUG_GEOMETRY] ~= 0 then + debug_keys[DEBUG_GEOMETRY] = 0 + debug_keys[DEBUG_TEXT] = 0 + else + debug_keys[DEBUG_GEOMETRY] = 1 + debug_keys[DEBUG_TEXT] = 1 + end + elseif command == 10001 then + if debug_keys[DEBUG_TEXT] ~= 0 then + debug_keys[DEBUG_TEXT] = 0 + else + debug_keys[DEBUG_TEXT] = 1 + end + elseif command == 10002 then + if debug_keys[DEBUG_GEOMETRY] ~= 0 then + debug_keys[DEBUG_GEOMETRY] = 0 + else + debug_keys[DEBUG_GEOMETRY] = 1 + end + end +end + +-- gain values for TrackIR , to unify responce on diffrent types of aircraft +TrackIR_gain_x = -0.6 +TrackIR_gain_y = 0.3 +TrackIR_gain_z = -0.25 +TrackIR_gain_roll = -90 \ No newline at end of file diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/Mods/aircraft/Ka-50/Cockpit/Scripts/ARK/ARK.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/Mods/aircraft/Ka-50/Cockpit/Scripts/ARK/ARK.lua new file mode 100644 index 000000000..61aa112a2 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/Mods/aircraft/Ka-50/Cockpit/Scripts/ARK/ARK.lua @@ -0,0 +1,53 @@ +mode = ADF_ADF +receiver_mode = ADF_RECEIVER_TLF +homer_selection_method = ADF_HOMER_SELECTION_AUTO +channel = 1 +volume = 0.5 + +local theatre = theatre or "none" +if theatre == 'Caucasus' then + +channels = { + [1] = runway_homer_pair(Airdrome[Krasnodar],nil,localizedAirdromeName(terrainAirdromes[Krasnodar])), + [2] = runway_homer_pair(Airdrome[Maykop] ,nil,localizedAirdromeName(terrainAirdromes[Maykop])), + [3] = runway_homer_pair(Airdrome[Krymsk] ,nil,localizedAirdromeName(terrainAirdromes[Krymsk])), + [4] = runway_homer_pair(Airdrome[Anapa] ,nil,localizedAirdromeName(terrainAirdromes[Anapa])), + [5] = runway_homer_pair(Airdrome[Mozdok] ,nil,localizedAirdromeName(terrainAirdromes[Mozdok])), + [6] = runway_homer_pair(Airdrome[Nalchick] ,nil,localizedAirdromeName(terrainAirdromes[Nalchick])), + [7] = runway_homer_pair(Airdrome[MinVody] ,nil,localizedAirdromeName(terrainAirdromes[MinVody])), + [8] = { + [ADF_HOMER_FAR] = NDB(beacons["NDB_KISLOVODSK"]), + [ADF_HOMER_NEAR] = NDB(beacons["NDB_PEREDOVAIA"]) + } +} + +elseif theatre == 'Nevada' then + + local beacons_by_name = {} + + for i,o in pairs(beacons) do + if o.name == '' then + beacons_by_name[o.beaconId] = o + else + beacons_by_name[o.name] = o + end + end + + local nevada_pair = function (id_1,id_2) return { + [ADF_HOMER_FAR] = NDB(beacons_by_name[id_1]), + [ADF_HOMER_NEAR] = NDB(beacons_by_name[id_2]) + } + end + + channels = { + nevada_pair('IndianSprings','Groom_Lake'), + nevada_pair('LasVegas','Nellis'), + nevada_pair("Milford","GOFFS"), + nevada_pair("Tonopah","Mina"), + nevada_pair("WilsonCreek","CedarCity"), + nevada_pair("BryceCanyon","MormonMesa"), + nevada_pair("Beatty","Bishop"), + nevada_pair("Coaldale","PeachSprings"), + nevada_pair("BoulderCity","Mercury"), +} +end \ No newline at end of file diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/GPS_GNSS.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/GPS_GNSS.lua new file mode 100644 index 000000000..2cb4a8e8d --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/GPS_GNSS.lua @@ -0,0 +1,880 @@ +SAT_SYS_GLONASS = 0 +SAT_SYS_GPS = 1 + +almanac = {} +--GPS +almanac[0] = {} +almanac[0]["System"] = SAT_SYS_GPS +almanac[0]["Number"] = 1 +almanac[0]["Orbital"] = "F" +almanac[0]["Eccentricity"] = 6.294000e-003 +almanac[0]["Time_of_Applicability"] = 5.898240e+005 +almanac[0]["Orbital_Inclination"] = 9.885676e-001 +almanac[0]["Rate_of_Right_Ascen"] = -7.862702e-009 +almanac[0]["SQRT_A"] = 5.153700e+003 +almanac[0]["Right_Ascen_at_Week"] = 8.096750e-001 +almanac[0]["Argument_of_Perigee"] = -1.777773e+000 +almanac[0]["Mean_Anom"] = -5.315745e-001 +almanac[0]["week"] = 1390 + +almanac[1] = {} +almanac[1]["System"] = SAT_SYS_GPS +almanac[1]["Number"] = 2 +almanac[1]["Orbital"] = "C" +almanac[1]["Eccentricity"] = 8.794000e-003 +almanac[1]["Time_of_Applicability"] = 5.898240e+005 +almanac[1]["Orbital_Inclination"] = 9.487811e-001 +almanac[1]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[1]["SQRT_A"] = 5.153700e+003 +almanac[1]["Right_Ascen_at_Week"] = -1.329172e+000 +almanac[1]["Argument_of_Perigee"] = 2.138637e+000 +almanac[1]["Mean_Anom"] = 7.311702e-001 +almanac[1]["week"] = 1390 + +almanac[2] = {} +almanac[2]["System"] = SAT_SYS_GPS +almanac[2]["Number"] = 3 +almanac[2]["Orbital"] = "F" +almanac[2]["Eccentricity"] = 8.424000e-003 +almanac[2]["Time_of_Applicability"] = 5.898240e+005 +almanac[2]["Orbital_Inclination"] = 9.262804e-001 +almanac[2]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[2]["SQRT_A"] = 5.153600e+003 +almanac[2]["Right_Ascen_at_Week"] = -2.341514e+000 +almanac[2]["Argument_of_Perigee"] = 6.749357e-001 +almanac[2]["Mean_Anom"] = -2.296153e-001 +almanac[2]["week"] = 1389 + +almanac[3] = {} +almanac[3]["System"] = SAT_SYS_GPS +almanac[3]["Number"] = 4 +almanac[3]["Orbital"] = "D" +almanac[3]["Eccentricity"] = 7.413000e-003 +almanac[3]["Time_of_Applicability"] = 5.898240e+005 +almanac[3]["Orbital_Inclination"] = 9.482889e-001 +almanac[3]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[3]["SQRT_A"] = 5.153600e+003 +almanac[3]["Right_Ascen_at_Week"] = -1.309589e+000 +almanac[3]["Argument_of_Perigee"] = 1.623504e-001 +almanac[3]["Mean_Anom"] = -3.022943e+000 +almanac[3]["week"] = 1390 + +almanac[4] = {} +almanac[4]["System"] = SAT_SYS_GPS +almanac[4]["Number"] = 5 +almanac[4]["Orbital"] = "B" +almanac[4]["Eccentricity"] = 7.432000e-003 +almanac[4]["Time_of_Applicability"] = 5.898240e+005 +almanac[4]["Orbital_Inclination"] = 9.387437e-001 +almanac[4]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[4]["SQRT_A"] = 5.153700e+003 +almanac[4]["Right_Ascen_at_Week"] = 2.779487e+000 +almanac[4]["Argument_of_Perigee"] = 1.099033e+000 +almanac[4]["Mean_Anom"] = 2.970984e+000 +almanac[4]["week"] = 1390 + +almanac[5] = {} +almanac[5]["System"] = SAT_SYS_GPS +almanac[5]["Number"] = 6 +almanac[5]["Orbital"] = "C" +almanac[5]["Eccentricity"] = 6.020000e-003 +almanac[5]["Time_of_Applicability"] = 5.898240e+005 +almanac[5]["Orbital_Inclination"] = 9.337591e-001 +almanac[5]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[5]["SQRT_A"] = 5.153600e+003 +almanac[5]["Right_Ascen_at_Week"] = -2.407627e+000 +almanac[5]["Argument_of_Perigee"] = -1.788263e+000 +almanac[5]["Mean_Anom"] = -2.149877e+000 +almanac[5]["week"] = 1390 + +almanac[6] = {} +almanac[6]["System"] = SAT_SYS_GPS +almanac[6]["Number"] = 7 +almanac[6]["Orbital"] = "C" +almanac[6]["Eccentricity"] = 1.052400e-002 +almanac[6]["Time_of_Applicability"] = 5.898240e+005 +almanac[6]["Orbital_Inclination"] = 9.353229e-001 +almanac[6]["Rate_of_Right_Ascen"] = -8.080868e-009 +almanac[6]["SQRT_A"] = 5.153700e+003 +almanac[6]["Right_Ascen_at_Week"] = -2.433580e+000 +almanac[6]["Argument_of_Perigee"] = -1.767301e+000 +almanac[6]["Mean_Anom"] = -3.141503e+000 +almanac[6]["week"] = 1390 + +almanac[7] = {} +almanac[7]["System"] = SAT_SYS_GPS +almanac[7]["Number"] = 8 +almanac[7]["Orbital"] = "A" +almanac[7]["Eccentricity"] = 9.822000e-003 +almanac[7]["Time_of_Applicability"] = 5.898240e+005 +almanac[7]["Orbital_Inclination"] = 9.741390e-001 +almanac[7]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[7]["SQRT_A"] = 5.153600e+003 +almanac[7]["Right_Ascen_at_Week"] = 1.857849e+000 +almanac[7]["Argument_of_Perigee"] = 2.674034e+000 +almanac[7]["Mean_Anom"] = -2.009745e+000 +almanac[7]["week"] = 1390 + +almanac[8] = {} +almanac[8]["System"] = SAT_SYS_GPS +almanac[8]["Number"] = 9 +almanac[8]["Orbital"] = "A" +almanac[8]["Eccentricity"] = 1.839300e-002 +almanac[8]["Time_of_Applicability"] = 5.898240e+005 +almanac[8]["Orbital_Inclination"] = 9.617541e-001 +almanac[8]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[8]["SQRT_A"] = 5.153600e+003 +almanac[8]["Right_Ascen_at_Week"] = 1.777005e+000 +almanac[8]["Argument_of_Perigee"] = 1.274962e+000 +almanac[8]["Mean_Anom"] = -2.349578e+000 +almanac[8]["week"] = 1390 + +almanac[9] = {} +almanac[9]["System"] = SAT_SYS_GPS +almanac[9]["Number"] = 10 +almanac[9]["Orbital"] = "E" +almanac[9]["Eccentricity"] = 7.061000e-003 +almanac[9]["Time_of_Applicability"] = 5.898240e+005 +almanac[9]["Orbital_Inclination"] = 9.728876e-001 +almanac[9]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[9]["SQRT_A"] = 5.153600e+003 +almanac[9]["Right_Ascen_at_Week"] = -2.563014e-001 +almanac[9]["Argument_of_Perigee"] = 4.377980e-001 +almanac[9]["Mean_Anom"] = 1.210716e+000 +almanac[9]["week"] = 1390 + +almanac[10] = {} +almanac[10]["System"] = SAT_SYS_GPS +almanac[10]["Number"] = 11 +almanac[10]["Orbital"] = "D" +almanac[10]["Eccentricity"] = 5.744000e-003 +almanac[10]["Time_of_Applicability"] = 5.898240e+005 +almanac[10]["Orbital_Inclination"] = 8.959309e-001 +almanac[10]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[10]["SQRT_A"] = 5.153600e+003 +almanac[10]["Right_Ascen_at_Week"] = -1.478816e+000 +almanac[10]["Argument_of_Perigee"] = 3.750011e-001 +almanac[10]["Mean_Anom"] = -1.522048e+000 +almanac[10]["week"] = 1390 + +almanac[11] = {} +almanac[11]["System"] = SAT_SYS_GPS +almanac[11]["Number"] = 13 +almanac[11]["Orbital"] = "F" +almanac[11]["Eccentricity"] = 3.088000e-003 +almanac[11]["Time_of_Applicability"] = 5.898240e+005 +almanac[11]["Orbital_Inclination"] = 9.927564e-001 +almanac[11]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[11]["SQRT_A"] = 5.153700e+003 +almanac[11]["Right_Ascen_at_Week"] = 7.956600e-001 +almanac[11]["Argument_of_Perigee"] = 1.279395e+000 +almanac[11]["Mean_Anom"] = 1.004349e+000 +almanac[11]["week"] = 1390 + +almanac[12] = {} +almanac[12]["System"] = SAT_SYS_GPS +almanac[12]["Number"] = 14 +almanac[12]["Orbital"] = "F" +almanac[12]["Eccentricity"] = 2.591000e-003 +almanac[12]["Time_of_Applicability"] = 5.898240e+005 +almanac[12]["Orbital_Inclination"] = 9.868729e-001 +almanac[12]["Rate_of_Right_Ascen"] = -7.885391e-009 +almanac[12]["SQRT_A"] = 5.153600e+003 +almanac[12]["Right_Ascen_at_Week"] = 7.819592e-001 +almanac[12]["Argument_of_Perigee"] = -2.158621e+000 +almanac[12]["Mean_Anom"] = 5.412611e-001 +almanac[12]["week"] = 1390 + +almanac[13] = {} +almanac[13]["System"] = SAT_SYS_GPS +almanac[13]["Number"] = 15 +almanac[13]["Orbital"] = "D" +almanac[13]["Eccentricity"] = 9.828000e-003 +almanac[13]["Time_of_Applicability"] = 3.194880e+005 +almanac[13]["Orbital_Inclination"] = 9.554204e-001 +almanac[13]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[13]["SQRT_A"] = 5.153600e+003 +almanac[13]["Right_Ascen_at_Week"] = -1.123869e+000 +almanac[13]["Argument_of_Perigee"] = 2.690266e+000 +almanac[13]["Mean_Anom"] = 2.220476e+000 +almanac[13]["week"] = 1389 + +almanac[14] = {} +almanac[14]["System"] = SAT_SYS_GPS +almanac[14]["Number"] = 16 +almanac[14]["Orbital"] = "B" +almanac[14]["Eccentricity"] = 3.494000e-003 +almanac[14]["Time_of_Applicability"] = 5.898240e+005 +almanac[14]["Orbital_Inclination"] = 9.629340e-001 +almanac[14]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[14]["SQRT_A"] = 5.153700e+003 +almanac[14]["Right_Ascen_at_Week"] = 2.873124e+000 +almanac[14]["Argument_of_Perigee"] = -7.819243e-001 +almanac[14]["Mean_Anom"] = 2.623629e+000 +almanac[14]["week"] = 1390 + +almanac[15] = {} +almanac[15]["System"] = SAT_SYS_GPS +almanac[15]["Number"] = 17 +almanac[15]["Orbital"] = "C" +almanac[15]["Eccentricity"] = 2.141000e-003 +almanac[15]["Time_of_Applicability"] = 5.898240e+005 +almanac[15]["Orbital_Inclination"] = 9.601170e-001 +almanac[15]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[15]["SQRT_A"] = 5.153700e+003 +almanac[15]["Right_Ascen_at_Week"] = -2.371499e+000 +almanac[15]["Argument_of_Perigee"] = 3.087694e+000 +almanac[15]["Mean_Anom"] = 1.611217e+000 +almanac[15]["week"] = 1390 + +almanac[16] = {} +almanac[16]["System"] = SAT_SYS_GPS +almanac[16]["Number"] = 18 +almanac[16]["Orbital"] = "E" +almanac[16]["Eccentricity"] = 7.636000e-003 +almanac[16]["Time_of_Applicability"] = 5.898240e+005 +almanac[16]["Orbital_Inclination"] = 9.569597e-001 +almanac[16]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[16]["SQRT_A"] = 5.153700e+003 +almanac[16]["Right_Ascen_at_Week"] = -2.359858e-001 +almanac[16]["Argument_of_Perigee"] = -2.649216e+000 +almanac[16]["Mean_Anom"] = 2.675029e+000 +almanac[16]["week"] = 1390 + +almanac[17] = {} +almanac[17]["System"] = SAT_SYS_GPS +almanac[17]["Number"] = 19 +almanac[17]["Orbital"] = "C" +almanac[17]["Eccentricity"] = 3.602000e-003 +almanac[17]["Time_of_Applicability"] = 5.898240e+005 +almanac[17]["Orbital_Inclination"] = 9.580209e-001 +almanac[17]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[17]["SQRT_A"] = 5.153600e+003 +almanac[17]["Right_Ascen_at_Week"] = -2.312385e+000 +almanac[17]["Argument_of_Perigee"] = -1.161079e+000 +almanac[17]["Mean_Anom"] = 1.310619e+000 +almanac[17]["week"] = 1390 + +almanac[18] = {} +almanac[18]["System"] = SAT_SYS_GPS +almanac[18]["Number"] = 20 +almanac[18]["Orbital"] = "E" +almanac[18]["Eccentricity"] = 2.796000e-003 +almanac[18]["Time_of_Applicability"] = 5.898240e+005 +almanac[18]["Orbital_Inclination"] = 9.564693e-001 +almanac[18]["Rate_of_Right_Ascen"] = -7.908080e-009 +almanac[18]["SQRT_A"] = 5.153600e+003 +almanac[18]["Right_Ascen_at_Week"] = -2.889565e-001 +almanac[18]["Argument_of_Perigee"] = 1.379612e+000 +almanac[18]["Mean_Anom"] = 2.461750e+000 +almanac[18]["week"] = 1390 + +almanac[19] = {} +almanac[19]["System"] = SAT_SYS_GPS +almanac[19]["Number"] = 21 +almanac[19]["Orbital"] = "D" +almanac[19]["Eccentricity"] = 1.162900e-002 +almanac[19]["Time_of_Applicability"] = 5.898240e+005 +almanac[19]["Orbital_Inclination"] = 9.418592e-001 +almanac[19]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[19]["SQRT_A"] = 5.153600e+003 +almanac[19]["Right_Ascen_at_Week"] = -1.289972e+000 +almanac[19]["Argument_of_Perigee"] = -2.923686e+000 +almanac[19]["Mean_Anom"] = -2.349194e+000 +almanac[19]["week"] = 1390 + +almanac[20] = {} +almanac[20]["System"] = SAT_SYS_GPS +almanac[20]["Number"] = 22 +almanac[20]["Orbital"] = "E" +almanac[20]["Eccentricity"] = 4.893000e-003 +almanac[20]["Time_of_Applicability"] = 5.898240e+005 +almanac[20]["Orbital_Inclination"] = 9.545093e-001 +almanac[20]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[20]["SQRT_A"] = 5.153600e+003 +almanac[20]["Right_Ascen_at_Week"] = -2.280969e-001 +almanac[20]["Argument_of_Perigee"] = -1.674502e+000 +almanac[20]["Mean_Anom"] = 1.106852e+000 +almanac[20]["week"] = 1390 + +almanac[21] = {} +almanac[21]["System"] = SAT_SYS_GPS +almanac[21]["Number"] = 23 +almanac[21]["Orbital"] = "F" +almanac[21]["Eccentricity"] = 4.822000e-003 +almanac[21]["Time_of_Applicability"] = 5.898240e+005 +almanac[21]["Orbital_Inclination"] = 9.691247e-001 +almanac[21]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[21]["SQRT_A"] = 5.153700e+003 +almanac[21]["Right_Ascen_at_Week"] = 7.667399e-001 +almanac[21]["Argument_of_Perigee"] = 2.497634e+000 +almanac[21]["Mean_Anom"] = 3.184700e-001 +almanac[21]["week"] = 1390 + +almanac[22] = {} +almanac[22]["System"] = SAT_SYS_GPS +almanac[22]["Number"] = 24 +almanac[22]["Orbital"] = "D" +almanac[22]["Eccentricity"] = 9.277000e-003 +almanac[22]["Time_of_Applicability"] = 5.898240e+005 +almanac[22]["Orbital_Inclination"] = 9.585183e-001 +almanac[22]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[22]["SQRT_A"] = 5.153900e+003 +almanac[22]["Right_Ascen_at_Week"] = -1.274840e+000 +almanac[22]["Argument_of_Perigee"] = -8.815651e-001 +almanac[22]["Mean_Anom"] = -1.695551e+000 +almanac[22]["week"] = 1390 + +almanac[23] = {} +almanac[23]["System"] = SAT_SYS_GPS +almanac[23]["Number"] = 25 +almanac[23]["Orbital"] = "A" +almanac[23]["Eccentricity"] = 1.257400e-002 +almanac[23]["Time_of_Applicability"] = 5.898240e+005 +almanac[23]["Orbital_Inclination"] = 9.551027e-001 +almanac[23]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[23]["SQRT_A"] = 5.153600e+003 +almanac[23]["Right_Ascen_at_Week"] = 1.721853e+000 +almanac[23]["Argument_of_Perigee"] = -1.329870e+000 +almanac[23]["Mean_Anom"] = -1.769623e+000 +almanac[23]["week"] = 1390 + +almanac[24] = {} +almanac[24]["System"] = SAT_SYS_GPS +almanac[24]["Number"] = 26 +almanac[24]["Orbital"] = "F" +almanac[24]["Eccentricity"] = 1.745700e-002 +almanac[24]["Time_of_Applicability"] = 5.898240e+005 +almanac[24]["Orbital_Inclination"] = 9.908749e-001 +almanac[24]["Rate_of_Right_Ascen"] = -7.840012e-009 +almanac[24]["SQRT_A"] = 5.153700e+003 +almanac[24]["Right_Ascen_at_Week"] = 7.961836e-001 +almanac[24]["Argument_of_Perigee"] = 8.161502e-001 +almanac[24]["Mean_Anom"] = -5.841961e-001 +almanac[24]["week"] = 1390 + +almanac[25] = {} +almanac[25]["System"] = SAT_SYS_GPS +almanac[25]["Number"] = 27 +almanac[25]["Orbital"] = "A" +almanac[25]["Eccentricity"] = 1.991000e-002 +almanac[25]["Time_of_Applicability"] = 5.898240e+005 +almanac[25]["Orbital_Inclination"] = 9.596563e-001 +almanac[25]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[25]["SQRT_A"] = 5.153600e+003 +almanac[25]["Right_Ascen_at_Week"] = 1.754124e+000 +almanac[25]["Argument_of_Perigee"] = -1.900854e+000 +almanac[25]["Mean_Anom"] = 3.046487e+000 +almanac[25]["week"] = 1390 + +almanac[26] = {} +almanac[26]["System"] = SAT_SYS_GPS +almanac[26]["Number"] = 28 +almanac[26]["Orbital"] = "B" +almanac[26]["Eccentricity"] = 1.162800e-002 +almanac[26]["Time_of_Applicability"] = 5.898240e+005 +almanac[26]["Orbital_Inclination"] = 9.610106e-001 +almanac[26]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[26]["SQRT_A"] = 5.153600e+003 +almanac[26]["Right_Ascen_at_Week"] = 2.882583e+000 +almanac[26]["Argument_of_Perigee"] = -2.242868e+000 +almanac[26]["Mean_Anom"] = 1.860642e+000 +almanac[26]["week"] = 1390 + +almanac[27] = {} +almanac[27]["System"] = SAT_SYS_GPS +almanac[27]["Number"] = 29 +almanac[27]["Orbital"] = "F" +almanac[27]["Eccentricity"] = 9.462000e-003 +almanac[27]["Time_of_Applicability"] = 1.474560e+005 +almanac[27]["Orbital_Inclination"] = 9.874838e-001 +almanac[27]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[27]["SQRT_A"] = 5.153700e+003 +almanac[27]["Right_Ascen_at_Week"] = 7.647503e-001 +almanac[27]["Argument_of_Perigee"] = -8.614589e-001 +almanac[27]["Mean_Anom"] = -4.488983e-001 +almanac[27]["week"] = 1390 + +almanac[28] = {} +almanac[28]["System"] = SAT_SYS_GPS +almanac[28]["Number"] = 30 +almanac[28]["Orbital"] = "B" +almanac[28]["Eccentricity"] = 9.296000e-003 +almanac[28]["Time_of_Applicability"] = 5.898240e+005 +almanac[28]["Orbital_Inclination"] = 9.452992e-001 +almanac[28]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[28]["SQRT_A"] = 5.153600e+003 +almanac[28]["Right_Ascen_at_Week"] = 2.826698e+000 +almanac[28]["Argument_of_Perigee"] = 1.306413e+000 +almanac[28]["Mean_Anom"] = 2.148725e+000 +almanac[28]["week"] = 1390 + + + + + + +--GLONASS +--1 îđáẹ̀àëüíàÿ ïëîñêîṇ̃ü, íî́åđà 1-8 +almanac[29] = {} +almanac[29]["System"] = SAT_SYS_GLONASS +almanac[29]["Number"] = 1 +almanac[29]["Orbital"] = 1 +almanac[29]["GLONASS_Data"] = {} +almanac[29]["GLONASS_Data"]["NKU_Number"] = 796 +almanac[29]["GLONASS_Data"]["Cosmos_Number"] = 2411 +almanac[29]["Eccentricity"] = 1.184000e-003 +almanac[29]["Time_of_Applicability"] = 0.000000e+000 +almanac[29]["Orbital_Inclination"] = 1.126443e+000 +almanac[29]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[29]["SQRT_A"] = 5.050500e+003 +almanac[29]["Right_Ascen_at_Week"] = 5.979807e+000 +almanac[29]["Argument_of_Perigee"] = 2.622634e+000 +almanac[29]["Mean_Anom"] = -5.519651e+000 +almanac[29]["week"] = 1390 +almanac[29]["Commit_date"] = "06.02.2005" +almanac[29]["Life_dates"] = {} + +almanac[30] = {} +almanac[30]["System"] = SAT_SYS_GLONASS +almanac[30]["Number"] = 2 +almanac[30]["Orbital"] = 1 +almanac[30]["GLONASS_Data"] = {} +almanac[30]["GLONASS_Data"]["NKU_Number"] = 794 +almanac[30]["GLONASS_Data"]["Cosmos_Number"] = 2401 +almanac[30]["Eccentricity"] = 4.486000e-003 +almanac[30]["Time_of_Applicability"] = 0.000000e+000 +almanac[30]["Orbital_Inclination"] = 1.128459e+000 +almanac[30]["Rate_of_Right_Ascen"] = -6.759654e-009 +almanac[30]["SQRT_A"] = 5.050500e+003 +almanac[30]["Right_Ascen_at_Week"] = 5.997871e+000 +almanac[30]["Argument_of_Perigee"] = 1.709531e+000 +almanac[30]["Mean_Anom"] = -5.367633e+000 +almanac[30]["week"] = 1390 +almanac[30]["Commit_date"] = "02.02.2004" +almanac[30]["Life_dates"] = {} + +almanac[31] = {} +almanac[31]["System"] = SAT_SYS_GLONASS +almanac[31]["Number"] = 3 +almanac[31]["Orbital"] = 1 +almanac[31]["GLONASS_Data"] = {} +almanac[31]["GLONASS_Data"]["NKU_Number"] = 789 +almanac[31]["GLONASS_Data"]["Cosmos_Number"] = 2381 +almanac[31]["Eccentricity"] = 2.459000e-003 +almanac[31]["Time_of_Applicability"] = 0.000000e+000 +almanac[31]["Orbital_Inclination"] = 1.122958e+000 +almanac[31]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[31]["SQRT_A"] = 5.050500e+003 +almanac[31]["Right_Ascen_at_Week"] = 5.960713e+000 +almanac[31]["Argument_of_Perigee"] = -2.683407e+000 +almanac[31]["Mean_Anom"] = -1.791788e+000 +almanac[31]["week"] = 1390 +almanac[31]["Commit_date"] = "04.01.2002" +almanac[31]["Life_dates"] = {} + +almanac[32] = {} +almanac[32]["System"] = SAT_SYS_GLONASS +almanac[32]["Number"] = 4 +almanac[32]["Orbital"] = 1 +almanac[32]["GLONASS_Data"] = {} +almanac[32]["GLONASS_Data"]["NKU_Number"] = 795 +almanac[29]["GLONASS_Data"]["Cosmos_Number"] = 2403 +almanac[32]["Eccentricity"] = 4.054000e-003 +almanac[32]["Time_of_Applicability"] = 0.000000e+000 +almanac[32]["Orbital_Inclination"] = 1.128543e+000 +almanac[32]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[32]["SQRT_A"] = 5.050500e+003 +almanac[32]["Right_Ascen_at_Week"] = 5.998081e+000 +almanac[32]["Argument_of_Perigee"] = 1.497160e+000 +almanac[32]["Mean_Anom"] = -4.293681e-001 +almanac[32]["week"] = 1390 +almanac[32]["Commit_date"] = "29.01.2004" +almanac[32]["Life_dates"] = {} + +almanac[33] = {} +almanac[33]["System"] = SAT_SYS_GLONASS +almanac[33]["Number"] = 5 +almanac[33]["Orbital"] = 1 +almanac[33]["GLONASS_Data"] = {} +almanac[33]["GLONASS_Data"]["NKU_Number"] = 711 +almanac[33]["GLONASS_Data"]["Cosmos_Number"] = 2382 +almanac[33]["Eccentricity"] = 7.040000e-004 +almanac[33]["Time_of_Applicability"] = 0.000000e+000 +almanac[33]["Orbital_Inclination"] = 1.122886e+000 +almanac[33]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[33]["SQRT_A"] = 5.050600e+003 +almanac[33]["Right_Ascen_at_Week"] = 5.960713e+000 +almanac[33]["Argument_of_Perigee"] = 2.740933e+000 +almanac[33]["Mean_Anom"] = -2.523604e+000 +almanac[33]["week"] = 1390 +almanac[33]["Commit_date"] = "13.02.2003" +almanac[33]["Life_dates"] = {} + +almanac[34] = {} +almanac[34]["System"] = SAT_SYS_GLONASS +almanac[34]["Number"] = 6 +almanac[34]["Orbital"] = 1 +almanac[34]["GLONASS_Data"] = {} +almanac[34]["GLONASS_Data"]["NKU_Number"] = 701 +almanac[34]["GLONASS_Data"]["Cosmos_Number"] = 2404 +almanac[34]["Eccentricity"] = 4.766000e-003 +almanac[34]["Time_of_Applicability"] = 0.000000e+000 +almanac[34]["Orbital_Inclination"] = 1.128276e+000 +almanac[34]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[34]["SQRT_A"] = 5.050500e+003 +almanac[34]["Right_Ascen_at_Week"] = 5.997906e+000 +almanac[34]["Argument_of_Perigee"] = 1.802417e+000 +almanac[34]["Mean_Anom"] = -2.426512e+000 +almanac[34]["week"] = 1390 +almanac[34]["Commit_date"] = "08.12.2004" +almanac[34]["Life_dates"] = {} + +almanac[35] = {} +almanac[35]["System"] = SAT_SYS_GLONASS +almanac[35]["Number"] = 7 +almanac[35]["Orbital"] = 1 +almanac[35]["GLONASS_Data"] = {} +almanac[35]["GLONASS_Data"]["NKU_Number"] = 712 +almanac[35]["GLONASS_Data"]["Cosmos_Number"] = 2413 +almanac[35]["Eccentricity"] = 7.570000e-004 +almanac[35]["Time_of_Applicability"] = 0.000000e+000 +almanac[35]["Orbital_Inclination"] = 1.126344e+000 +almanac[35]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[35]["SQRT_A"] = 5.050500e+003 +almanac[35]["Right_Ascen_at_Week"] = 5.979388e+000 +almanac[35]["Argument_of_Perigee"] = 2.566068e+000 +almanac[35]["Mean_Anom"] = -3.921228e+000 +almanac[35]["week"] = 1390 +almanac[35]["Commit_date"] = "07.10.2005" +almanac[35]["Life_dates"] = {} + +almanac[36] = {} +almanac[36]["System"] = SAT_SYS_GLONASS +almanac[36]["GLONASS_Data"] = {} +almanac[36]["Number"] = 8 +almanac[36]["Orbital"] = 1 +almanac[36]["GLONASS_Data"] = {} +almanac[36]["GLONASS_Data"]["NKU_Number"] = 797 +almanac[36]["GLONASS_Data"]["Cosmos_Number"] = 2412 +almanac[36]["Eccentricity"] = 4.060000e-004 +almanac[36]["Time_of_Applicability"] = 0.000000e+000 +almanac[36]["Orbital_Inclination"] = 1.126564e+000 +almanac[36]["Rate_of_Right_Ascen"] = -6.785834e-009 +almanac[36]["SQRT_A"] = 5.050600e+003 +almanac[36]["Right_Ascen_at_Week"] = 5.980069e+000 +almanac[36]["Argument_of_Perigee"] = 2.673633e+000 +almanac[36]["Mean_Anom"] = -4.812026e+000 +almanac[36]["week"] = 1390 +almanac[36]["Commit_date"] = "06.02.2005" +almanac[36]["Life_dates"] = {} + +--3 îđáẹ̀àëüíàÿ ïëîñêîṇ̃ü, íî́åđà 17-24 +almanac[37] = {} +almanac[37]["System"] = SAT_SYS_GLONASS +almanac[37]["Number"] = 17 +almanac[37]["Orbital"] = 3 +almanac[37]["GLONASS_Data"] = {} +almanac[37]["GLONASS_Data"]["NKU_Number"] = 787 +almanac[37]["GLONASS_Data"]["Cosmos_Number"] = 2375 +almanac[37]["Eccentricity"] = 5.670000e-004 +almanac[37]["Time_of_Applicability"] = 0.000000e+000 +almanac[37]["Orbital_Inclination"] = 1.126524e+000 +almanac[37]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[37]["SQRT_A"] = 5.050500e+003 +almanac[37]["Right_Ascen_at_Week"] = 3.895554e+000 +almanac[37]["Argument_of_Perigee"] = 6.085085e-001 +almanac[37]["Mean_Anom"] = -2.977407e+000 +almanac[37]["week"] = 1390 +almanac[37]["Commit_date"] = "04.11.2000" +almanac[37]["Life_dates"] = {} + + +almanac[38] = {} +almanac[38]["System"] = SAT_SYS_GLONASS +almanac[38]["Number"] = 18 +almanac[38]["Orbital"] = 3 +almanac[38]["GLONASS_Data"] = {} +almanac[38]["GLONASS_Data"]["NKU_Number"] = 783 +almanac[38]["GLONASS_Data"]["Cosmos_Number"] = 2374 +almanac[38]["Eccentricity"] = 4.520000e-003 +almanac[38]["Time_of_Applicability"] = 0.000000e+000 +almanac[38]["Orbital_Inclination"] = 1.126239e+000 +almanac[38]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[38]["SQRT_A"] = 5.050600e+003 +almanac[38]["Right_Ascen_at_Week"] = 3.894071e+000 +almanac[38]["Argument_of_Perigee"] = -2.509589e+000 +almanac[38]["Mean_Anom"] = -1.020057e+000 +almanac[38]["week"] = 1390 +almanac[38]["Commit_date"] = "05.01.2001" +almanac[38]["Life_dates"] = {} + +almanac[39] = {} +almanac[39]["System"] = SAT_SYS_GLONASS +almanac[39]["Number"] = 19 +almanac[39]["Orbital"] = 3 +almanac[39]["GLONASS_Data"] = {} +almanac[39]["GLONASS_Data"]["NKU_Number"] = 798 +almanac[39]["GLONASS_Data"]["Cosmos_Number"] = 2417 +almanac[39]["Eccentricity"] = 2.023000e-003 +almanac[39]["Time_of_Applicability"] = 0.000000e+000 +almanac[39]["Orbital_Inclination"] = 1.132205e+000 +almanac[39]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[39]["SQRT_A"] = 5.050500e+003 +almanac[39]["Right_Ascen_at_Week"] = 3.884018e+000 +almanac[39]["Argument_of_Perigee"] = 2.718313e+000 +almanac[39]["Mean_Anom"] = -3.933620e-001 +almanac[39]["week"] = 1390 +almanac[39]["Commit_date"] = "22.01.2006" +almanac[39]["Life_dates"] = {} + +almanac[40] = {} +almanac[40]["System"] = SAT_SYS_GLONASS +almanac[40]["Number"] = 20 +almanac[40]["Orbital"] = 3 +almanac[40]["GLONASS_Data"] = {} +almanac[40]["GLONASS_Data"]["NKU_Number"] = 793 +almanac[40]["GLONASS_Data"]["Cosmos_Number"] = 2396 +almanac[40]["Eccentricity"] = 1.822000e-003 +almanac[40]["Time_of_Applicability"] = 0.000000e+000 +almanac[40]["Orbital_Inclination"] = 1.129789e+000 +almanac[40]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[40]["SQRT_A"] = 5.050500e+003 +almanac[40]["Right_Ascen_at_Week"] = 3.896863e+000 +almanac[40]["Argument_of_Perigee"] = 2.723776e+000 +almanac[40]["Mean_Anom"] = -1.193647e+000 +almanac[40]["week"] = 1390 +almanac[40]["Commit_date"] = "31.01.2003" +almanac[40]["Life_dates"] = {} + +almanac[41] = {} +almanac[41]["System"] = SAT_SYS_GLONASS +almanac[41]["Number"] = 21 +almanac[41]["Orbital"] = 3 +almanac[41]["GLONASS_Data"] = {} +almanac[41]["GLONASS_Data"]["NKU_Number"] = 792 +almanac[41]["GLONASS_Data"]["Cosmos_Number"] = 2395 +almanac[41]["Eccentricity"] = 5.290000e-004 +almanac[41]["Time_of_Applicability"] = 0.000000e+000 +almanac[41]["Orbital_Inclination"] = 1.129957e+000 +almanac[41]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[41]["SQRT_A"] = 5.050500e+003 +almanac[41]["Right_Ascen_at_Week"] = 3.897806e+000 +almanac[41]["Argument_of_Perigee"] = -9.519367e-001 +almanac[41]["Mean_Anom"] = -4.578920e+000 +almanac[41]["week"] = 1390 +almanac[41]["Commit_date"] = "31.01.2003" +almanac[41]["Life_dates"] = {} + +almanac[42] = {} +almanac[42]["System"] = SAT_SYS_GLONASS +almanac[42]["Number"] = 22 +almanac[42]["Orbital"] = 3 +almanac[42]["GLONASS_Data"] = {} +almanac[42]["GLONASS_Data"]["NKU_Number"] = 791 +almanac[42]["GLONASS_Data"]["Cosmos_Number"] = 2394 +almanac[42]["Eccentricity"] = 9.200000e-005 +almanac[42]["Time_of_Applicability"] = 0.000000e+000 +almanac[42]["Orbital_Inclination"] = 1.129742e+000 +almanac[42]["Rate_of_Right_Ascen"] = -6.740456e-009 +almanac[42]["SQRT_A"] = 5.050500e+003 +almanac[42]["Right_Ascen_at_Week"] = 3.897404e+000 +almanac[42]["Argument_of_Perigee"] = 2.518211e+000 +almanac[42]["Mean_Anom"] = -2.530167e+000 +almanac[42]["week"] = 1390 +almanac[42]["Commit_date"] = "21.01.2003" +almanac[42]["Life_dates"] = {} + +almanac[43] = {} +almanac[43]["System"] = SAT_SYS_GLONASS +almanac[43]["Number"] = 23 +almanac[43]["Orbital"] = 3 +almanac[43]["GLONASS_Data"] = {} +almanac[43]["GLONASS_Data"]["NKU_Number"] = 714 +almanac[43]["GLONASS_Data"]["Cosmos_Number"] = 2419 +almanac[43]["Eccentricity"] = 8.730000e-004 +almanac[43]["Time_of_Applicability"] = 0.000000e+000 +almanac[43]["Orbital_Inclination"] = 1.132105e+000 +almanac[43]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[43]["SQRT_A"] = 5.050500e+003 +almanac[43]["Right_Ascen_at_Week"] = 3.883808e+000 +almanac[43]["Argument_of_Perigee"] = -3.039139e-001 +almanac[43]["Mean_Anom"] = -5.228304e-001 +almanac[43]["week"] = 1390 +almanac[43]["Commit_date"] = "31.08.2006" +almanac[43]["Life_dates"] = {} + +almanac[44] = {} +almanac[44]["System"] = SAT_SYS_GLONASS +almanac[44]["Number"] = 24 +almanac[44]["Orbital"] = 3 +almanac[44]["GLONASS_Data"] = {} +almanac[44]["GLONASS_Data"]["NKU_Number"] = 713 +almanac[44]["GLONASS_Data"]["Cosmos_Number"] = 2418 +almanac[44]["Eccentricity"] = 2.044000e-003 +almanac[44]["Time_of_Applicability"] = 0.000000e+000 +almanac[44]["Orbital_Inclination"] = 1.132430e+000 +almanac[44]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[44]["SQRT_A"] = 5.050500e+003 +almanac[44]["Right_Ascen_at_Week"] = 3.883983e+000 +almanac[44]["Argument_of_Perigee"] = -3.722784e-001 +almanac[44]["Mean_Anom"] = -1.240457e+000 +almanac[44]["week"] = 1390 +almanac[44]["Commit_date"] = "31.08.2006" +almanac[44]["Life_dates"] = {} + +--2 îđáẹ̀àëüíàÿ ïëîñêîṇ̃ü, íî́åđà 9-16 +almanac[45] = {} +almanac[45]["System"] = SAT_SYS_GLONASS +almanac[45]["Number"] = 9 +almanac[45]["Orbital"] = 2 +almanac[45]["GLONASS_Data"] = {} +almanac[45]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[45]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[45]["Eccentricity"] = 1.184000e-003 +almanac[45]["Time_of_Applicability"] = 0.000000e+000 +almanac[45]["Orbital_Inclination"] = 1.126443e+000 +almanac[45]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[45]["SQRT_A"] = 5.050500e+003 +almanac[45]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[45]["Argument_of_Perigee"] = 2.88430067 +almanac[45]["Mean_Anom"] = -5.519651e+000 +almanac[45]["week"] = 1390 +almanac[45]["Commit_date"] = "N/A" +almanac[45]["Life_dates"] = {} + +almanac[46] = {} +almanac[46]["System"] = SAT_SYS_GLONASS +almanac[46]["Number"] = 10 +almanac[46]["Orbital"] = 2 +almanac[46]["GLONASS_Data"] = {} +almanac[46]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[46]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[46]["Eccentricity"] = 1.184000e-003 +almanac[46]["Time_of_Applicability"] = 0.000000e+000 +almanac[46]["Orbital_Inclination"] = 1.126443e+000 +almanac[46]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[46]["SQRT_A"] = 5.050500e+003 +almanac[46]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[46]["Argument_of_Perigee"] = 3.66930067 +almanac[46]["Mean_Anom"] = -5.519651e+000 +almanac[46]["week"] = 1390 +almanac[46]["Commit_date"] = "N/A" +almanac[46]["Life_dates"] = {} + +almanac[47] = {} +almanac[47]["System"] = SAT_SYS_GLONASS +almanac[47]["Number"] = 11 +almanac[47]["Orbital"] = 2 +almanac[47]["GLONASS_Data"] = {} +almanac[47]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[47]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[47]["Eccentricity"] = 1.184000e-003 +almanac[47]["Time_of_Applicability"] = 0.000000e+000 +almanac[47]["Orbital_Inclination"] = 1.126443e+000 +almanac[47]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[47]["SQRT_A"] = 5.050500e+003 +almanac[47]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[47]["Argument_of_Perigee"] = 4.45430067 +almanac[47]["Mean_Anom"] = -5.519651e+000 +almanac[47]["week"] = 1390 +almanac[47]["Commit_date"] = "N/A" +almanac[47]["Life_dates"] = {} + +almanac[48] = {} +almanac[48]["System"] = SAT_SYS_GLONASS +almanac[48]["Number"] = 12 +almanac[48]["Orbital"] = 2 +almanac[48]["GLONASS_Data"] = {} +almanac[48]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[48]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[48]["Eccentricity"] = 1.184000e-003 +almanac[48]["Time_of_Applicability"] = 0.000000e+000 +almanac[48]["Orbital_Inclination"] = 1.126443e+000 +almanac[48]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[48]["SQRT_A"] = 5.050500e+003 +almanac[48]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[48]["Argument_of_Perigee"] = 5.23930067 +almanac[48]["Mean_Anom"] = -5.519651e+000 +almanac[48]["week"] = 1390 +almanac[48]["Commit_date"] = "N/A" +almanac[48]["Life_dates"] = {} + +almanac[49] = {} +almanac[49]["System"] = SAT_SYS_GLONASS +almanac[49]["Number"] = 13 +almanac[49]["Orbital"] = 2 +almanac[49]["GLONASS_Data"] = {} +almanac[49]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[49]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[49]["Eccentricity"] = 1.184000e-003 +almanac[49]["Time_of_Applicability"] = 0.000000e+000 +almanac[49]["Orbital_Inclination"] = 1.126443e+000 +almanac[49]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[49]["SQRT_A"] = 5.050500e+003 +almanac[49]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[49]["Argument_of_Perigee"] = 6.02430067 +almanac[49]["Mean_Anom"] = -5.519651e+000 +almanac[49]["week"] = 1390 +almanac[49]["Commit_date"] = "N/A" +almanac[49]["Life_dates"] = {} + +almanac[50] = {} +almanac[50]["System"] = SAT_SYS_GLONASS +almanac[50]["Number"] = 14 +almanac[50]["Orbital"] = 2 +almanac[50]["GLONASS_Data"] = {} +almanac[50]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[50]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[50]["Eccentricity"] = 1.184000e-003 +almanac[50]["Time_of_Applicability"] = 0.000000e+000 +almanac[50]["Orbital_Inclination"] = 1.126443e+000 +almanac[50]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[50]["SQRT_A"] = 5.050500e+003 +almanac[50]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[50]["Argument_of_Perigee"] = 0.52930067 +almanac[50]["Mean_Anom"] = -5.519651e+000 +almanac[50]["week"] = 1390 +almanac[50]["Commit_date"] = "N/A" +almanac[50]["Life_dates"] = {} + +almanac[51] = {} +almanac[51]["System"] = SAT_SYS_GLONASS +almanac[51]["Number"] = 15 +almanac[51]["Orbital"] = 2 +almanac[51]["GLONASS_Data"] = {} +almanac[51]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[51]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[51]["Eccentricity"] = 1.184000e-003 +almanac[51]["Time_of_Applicability"] = 0.000000e+000 +almanac[51]["Orbital_Inclination"] = 1.126443e+000 +almanac[51]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[51]["SQRT_A"] = 5.050500e+003 +almanac[51]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[51]["Argument_of_Perigee"] = 1.31430067 +almanac[51]["Mean_Anom"] = -5.519651e+000 +almanac[51]["week"] = 1390 +almanac[51]["Commit_date"] = "N/A" +almanac[51]["Life_dates"] = {} + +almanac[52] = {} +almanac[52]["System"] = SAT_SYS_GLONASS +almanac[52]["Number"] = 16 +almanac[52]["Orbital"] = 2 +almanac[52]["GLONASS_Data"] = {} +almanac[52]["GLONASS_Data"]["NKU_Number"] = "N/A" +almanac[52]["GLONASS_Data"]["Cosmos_Number"] = "N/A" +almanac[52]["Eccentricity"] = 1.184000e-003 +almanac[52]["Time_of_Applicability"] = 0.000000e+000 +almanac[52]["Orbital_Inclination"] = 1.126443e+000 +almanac[52]["Rate_of_Right_Ascen"] = 0.000000e+000 +almanac[52]["SQRT_A"] = 5.050500e+003 +almanac[52]["Right_Ascen_at_Week"] = 1.79067e+000 +almanac[52]["Argument_of_Perigee"] = 2.09930067 +almanac[52]["Mean_Anom"] = -5.519651e+000 +almanac[52]["week"] = 1390 +almanac[52]["Commit_date"] = "N/A" +almanac[52]["Life_dates"] = {} + +SA_mode = false +AS_mode = false diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/birds.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/birds.lua new file mode 100644 index 000000000..8aee1f700 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/Scripts/World/birds.lua @@ -0,0 +1,27 @@ +birds_avail = true --Birds availability. false - there is no birds +birds_maximum_hrad = 200 --Maximum altitude above ground al sea level bird could be met +birds_maximum_absolute_height = 8000 --Maximum absolute altitude bird could be met +birds_minimum_velocity = 40 --Minimum velocity bird could be met +birds_delta_time = 3.55 +birds_probability = {0.006333333*150, + 0.004166667*150, + 0.001966667*150, + 0.001090909*150, + 0.000741818*150, + 0.0006*150, + 0.000510545*150, + 0.000447273*150, + 0.000389455*150, + 0.000349091*150, + 0.000310909*150, + 0.000282545*150, + 0.000250909*150, + 0.000220364*150, + 0.000196364*150, + 0.000174545*150, + 0.000152727*150, + 0.000128727*150, + 0.000103636*150, + 7.63636E-05*150, + 0*150 +} diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua new file mode 100644 index 000000000..e6aaa973d --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua @@ -0,0 +1,29 @@ +Include.File( "Mission" ) +Include.File( "Client" ) +Include.File( "Escort" ) + + +do + + local function EventAliveHelicopter( Client ) + local EscortGroupHeli = GROUP:NewFromName( "Escort Helicopter" ) + local EscortHeli = ESCORT:New( Client, EscortGroupHeli, "Escort Test Helicopter" ) + end + + local function EventAlivePlane( Client ) + local EscortGroupPlane = GROUP:NewFromName( "Escort Plane" ) + local EscortPlane = ESCORT:New( EscortClientPlane, EscortGroupPlane, "Escort Test Plane" ) + end + + local EscortClientHeli = CLIENT:New( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ):Alive( EventAliveHelicopter ) + local EscortClientPlane = CLIENT:New( "Lead Plane", "Fly around and observe the behaviour of the escort airplane. Select Navigate->Joun-Up and airplane should follow you. Change speed and directions." ) + :Alive( EventAlivePlane ) + +end + +-- MISSION SCHEDULER STARTUP +MISSIONSCHEDULER.Start() +MISSIONSCHEDULER.ReportMenu() +MISSIONSCHEDULER.ReportMissionsHide() + +env.info( "Test Mission loaded" ) diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Dynamic.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Dynamic.lua new file mode 100644 index 000000000..e12d51570 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Dynamic.lua @@ -0,0 +1,43 @@ + +local base = _G +env.info("Loading MOOSE " .. base.timer.getAbsTime() ) + +Include = {} + +Include.Path = function() + local str = debug.getinfo(2, "S").source + return str:match("(.*/)"):sub(1,-2):gsub("\\","/") +end + +Include.File = function( IncludeFile ) + if not Include.Files[ IncludeFile ] then + Include.Files[IncludeFile] = IncludeFile + env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath ) + local f = assert( base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" ) ) + if f == nil then + env.info( "Include:" .. IncludeFile .. " from " .. Include.MissionPath ) + local f = assert( base.loadfile( Include.MissionPath .. IncludeFile .. ".lua" ) ) + if f == nil then + error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) + else + env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath ) + return f() + end + else + env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath ) + return f() + end + end +end + +Include.ProgramPath = "Scripts/Moose/Moose/" +Include.MissionPath = Include.Path() + +env.info( "Include.ProgramPath = " .. Include.ProgramPath) +env.info( "Include.MissionPath = " .. Include.MissionPath) + +Include.Files = {} + +Include.File( "Database" ) + +env.info("Loaded MOOSE Include Engine") \ No newline at end of file diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Embedded.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Embedded.lua new file mode 100644 index 000000000..350bb9c92 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/Moose_Load_Embedded.lua @@ -0,0 +1,23 @@ + +local base = _G +env.info("Loading MOOSE " .. base.timer.getAbsTime() ) + +Include = {} + +Include.Path = function() + local str = debug.getinfo(2, "S").source + return str:match("(.*/)"):sub(1,-2):gsub("\\","/") +end + +Include.File = function( IncludeFile ) +end + +Include.ProgramPath = "Scripts/Moose/Moose/" +Include.MissionPath = Include.Path() + +env.info( "Include.ProgramPath = " .. Include.ProgramPath) +env.info( "Include.MissionPath = " .. Include.MissionPath) + +Include.Files = {} + +env.info("Loaded MOOSE Include Engine") diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary new file mode 100644 index 000000000..a731c15a0 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary @@ -0,0 +1,25 @@ +dictionary = +{ + ["DictKey_GroupName_19"] = "Escort Plane", + ["DictKey_WptName_11"] = "", + ["DictKey_UnitName_20"] = "Escort Plane", + ["DictKey_GroupName_15"] = "Lead Plane", + ["DictKey_sortie_4"] = "", + ["DictKey_WptName_23"] = "", + ["DictKey_descriptionRedTask_2"] = "", + ["DictKey_descriptionBlueTask_3"] = "", + ["DictKey_GroupName_9"] = "Lead Helicopter", + ["DictKey_descriptionText_1"] = "", + ["DictKey_UnitName_10"] = "Lead Helicopter", + ["DictKey_WptName_22"] = "", + ["DictKey_WptName_18"] = "", + ["DictKey_WptName_14"] = "", + ["DictKey_WptName_17"] = "", + ["DictKey_UnitName_13"] = "Escort Helicopter", + ["DictKey_WptName_26"] = "", + ["DictKey_WptName_25"] = "", + ["DictKey_UnitName_16"] = "Lead Plane", + ["DictKey_WptName_21"] = "", + ["DictKey_WptName_24"] = "", + ["DictKey_GroupName_12"] = "Escort Helicopter", +} -- end of dictionary diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/mapResource b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/mapResource new file mode 100644 index 000000000..19be00d9b --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/mapResource @@ -0,0 +1,6 @@ +mapResource = +{ + ["ResKey_Action_5"] = "Moose_Load_Dynamic.lua", + ["ResKey_Action_6"] = "Moose_Load_Embedded.lua", + ["ResKey_Action_8"] = "MOOSE_Escort_Test_Follow.lua", +} -- end of mapResource diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/mission b/Test Missions/miz/MOOSE_Escort_Test_Follow/mission new file mode 100644 index 000000000..6c1f6e2bf --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/mission @@ -0,0 +1,4024 @@ +mission = +{ + ["trig"] = + { + ["actions"] = + { + [1] = "a_set_flag(9999); mission.trig.func[1]=nil;", + [2] = "a_do_script_file(getValueResourceByKey(\"ResKey_Action_5\")); mission.trig.func[2]=nil;", + [3] = "a_do_script_file(getValueResourceByKey(\"ResKey_Action_6\")); mission.trig.func[3]=nil;", + [4] = "a_do_script_file(getValueResourceByKey(\"ResKey_Action_8\")); mission.trig.func[4]=nil;", + }, -- end of ["actions"] + ["events"] = + { + }, -- end of ["events"] + ["custom"] = + { + }, -- end of ["custom"] + ["func"] = + { + [1] = "if mission.trig.conditions[1]() then mission.trig.actions[1]() end", + [2] = "if mission.trig.conditions[2]() then mission.trig.actions[2]() end", + [3] = "if mission.trig.conditions[3]() then mission.trig.actions[3]() end", + [4] = "if mission.trig.conditions[4]() then mission.trig.actions[4]() end", + }, -- end of ["func"] + ["flag"] = + { + [1] = true, + [2] = true, + [3] = true, + [4] = true, + }, -- end of ["flag"] + ["conditions"] = + { + [1] = "return(true)", + [2] = "return(c_flag_is_true(9999) )", + [3] = "return(c_flag_is_false(9999) )", + [4] = "return(true)", + }, -- end of ["conditions"] + ["customStartup"] = + { + }, -- end of ["customStartup"] + ["funcStartup"] = + { + }, -- end of ["funcStartup"] + }, -- end of ["trig"] + ["result"] = + { + ["offline"] = + { + ["conditions"] = + { + }, -- end of ["conditions"] + ["actions"] = + { + }, -- end of ["actions"] + ["func"] = + { + }, -- end of ["func"] + }, -- end of ["offline"] + ["total"] = 0, + ["blue"] = + { + ["conditions"] = + { + }, -- end of ["conditions"] + ["actions"] = + { + }, -- end of ["actions"] + ["func"] = + { + }, -- end of ["func"] + }, -- end of ["blue"] + ["red"] = + { + ["conditions"] = + { + }, -- end of ["conditions"] + ["actions"] = + { + }, -- end of ["actions"] + ["func"] = + { + }, -- end of ["func"] + }, -- end of ["red"] + }, -- end of ["result"] + ["maxDictId"] = 26, + ["groundControl"] = + { + ["isPilotControlVehicles"] = false, + ["roles"] = + { + ["artillery_commander"] = + { + ["blue"] = 0, + ["red"] = 0, + }, -- end of ["artillery_commander"] + ["instructor"] = + { + ["blue"] = 0, + ["red"] = 0, + }, -- end of ["instructor"] + ["observer"] = + { + ["blue"] = 0, + ["red"] = 0, + }, -- end of ["observer"] + ["forward_observer"] = + { + ["blue"] = 0, + ["red"] = 0, + }, -- end of ["forward_observer"] + }, -- end of ["roles"] + }, -- end of ["groundControl"] + ["usedModules"] = + { + ["F-86F Sabre AI by Eagle Dynamics"] = true, + ["Su-27 Flanker by Eagle Dynamics"] = false, + ["TF-51D Mustang by Eagle Dynamics"] = true, + ["M-2000C by RAZBAM Sims"] = true, + ["Su-25A by Eagle Dynamics"] = false, + ["Su-25T by Eagle Dynamics"] = true, + ["F-5E/E-3 by Belsimtek"] = true, + ["MiG-21Bis AI by Leatherneck Simulations"] = true, + ["Mi-8MTV2 Hip by Belsimtek"] = true, + ["Bf 109 K-4 by Eagle Dynamics"] = true, + ["A-10A by Eagle Dynamics"] = false, + ["Hawk T.1A AI by VEAO Simulations"] = true, + ["FW-190D9 Dora by Eagle Dynamics"] = true, + ["MiG-15bis by Belsimtek"] = true, + ["MiG-15bis AI by Eagle Dynamics"] = true, + ["A-10C Warthog by Eagle Dynamics"] = true, + ["Combined Arms by Eagle Dynamics"] = true, + ["UH-1H Huey by Belsimtek"] = true, + ["C-101 Aviojet"] = true, + ["./CoreMods/aircraft/MQ-9 Reaper"] = true, + ["C-101 Aviojet by AvioDev"] = true, + ["F-86F Sabre by Belsimtek"] = true, + ["F-15C"] = false, + ["L-39C/ZA by Eagle Dynamics"] = true, + ["Hawk T.1A by VEAO Simulations"] = true, + ["Caucasus"] = true, + ["Ka-50 Black Shark by Eagle Dynamics"] = true, + ["M-2000C AI by RAZBAM Sims"] = true, + ["P-51D Mustang by Eagle Dynamics"] = true, + ["World War II AI Units by Eagle Dynamics"] = true, + ["MiG-21Bis by Leatherneck Simulations"] = true, + ["Flaming Cliffs by Eagle Dynamics"] = true, + }, -- end of ["usedModules"] + ["resourceCounter"] = + { + }, -- end of ["resourceCounter"] + ["triggers"] = + { + ["zones"] = + { + }, -- end of ["zones"] + }, -- end of ["triggers"] + ["weather"] = + { + ["name_ru"] = "ĐÑĐµĐ½ÑŒ. Đ›Đ¸Đ²ĐµĐ½ÑŒ", + ["wind"] = + { + ["at8000"] = + { + ["speed"] = 0, + ["dir"] = 0, + }, -- end of ["at8000"] + ["atGround"] = + { + ["speed"] = 0, + ["dir"] = 0, + }, -- end of ["atGround"] + ["at2000"] = + { + ["speed"] = 0, + ["dir"] = 0, + }, -- end of ["at2000"] + }, -- end of ["wind"] + ["enable_fog"] = true, + ["atmosphere_type"] = 0, + ["turbulence"] = + { + ["at8000"] = 0, + ["atGround"] = 0, + ["at2000"] = 0, + }, -- end of ["turbulence"] + ["name_es"] = "Otoño. Lluvia fuerte", + ["season"] = + { + ["iseason"] = 1, + ["temperature"] = 20, + }, -- end of ["season"] + ["type_weather"] = 1, + ["qnh"] = 760, + ["cyclones"] = + { + }, -- end of ["cyclones"] + ["name_de"] = "Herbst, Starker Regen", + ["fog"] = + { + ["thickness"] = 0, + ["visibility"] = 25, + ["density"] = 7, + }, -- end of ["fog"] + ["name"] = "Winter, clean sky", + ["name_fr"] = "Automne, pluie violente", + ["visibility"] = + { + ["distance"] = 80000, + }, -- end of ["visibility"] + ["clouds"] = + { + ["thickness"] = 200, + ["density"] = 0, + ["base"] = 300, + ["iprecptns"] = 0, + }, -- end of ["clouds"] + }, -- end of ["weather"] + ["theatre"] = "Caucasus", + ["needModules"] = + { + }, -- end of ["needModules"] + ["map"] = + { + ["centerY"] = 633185.71428572, + ["zoom"] = 50000, + ["centerX"] = -286145.14285714, + }, -- end of ["map"] + ["coalitions"] = + { + ["blue"] = + { + [1] = 21, + [2] = 11, + [3] = 8, + [4] = 28, + [5] = 26, + [6] = 13, + [7] = 5, + [8] = 16, + [9] = 6, + [10] = 15, + [11] = 20, + [12] = 12, + [13] = 40, + [14] = 45, + [15] = 9, + [16] = 10, + [17] = 3, + [18] = 4, + [19] = 2, + }, -- end of ["blue"] + ["neutrals"] = + { + [1] = 23, + [2] = 25, + [3] = 29, + [4] = 30, + [5] = 31, + [6] = 32, + [7] = 33, + [8] = 17, + [9] = 35, + [10] = 36, + [11] = 39, + [12] = 41, + [13] = 42, + [14] = 44, + [15] = 46, + [16] = 22, + [17] = 7, + }, -- end of ["neutrals"] + ["red"] = + { + [1] = 18, + [2] = 24, + [3] = 27, + [4] = 34, + [5] = 37, + [6] = 38, + [7] = 0, + [8] = 43, + [9] = 19, + [10] = 47, + [11] = 1, + }, -- end of ["red"] + }, -- end of ["coalitions"] + ["descriptionText"] = "DictKey_descriptionText_1", + ["pictureFileNameR"] = + { + }, -- end of ["pictureFileNameR"] + ["descriptionBlueTask"] = "DictKey_descriptionBlueTask_3", + ["descriptionRedTask"] = "DictKey_descriptionRedTask_2", + ["pictureFileNameB"] = + { + }, -- end of ["pictureFileNameB"] + ["trigrules"] = + { + [1] = + { + ["rules"] = + { + }, -- end of ["rules"] + ["eventlist"] = "", + ["predicate"] = "triggerOnce", + ["actions"] = + { + [1] = + { + ["flag"] = 9999, + ["predicate"] = "a_set_flag", + ["ai_task"] = + { + [1] = "", + [2] = "", + }, -- end of ["ai_task"] + }, -- end of [1] + }, -- end of ["actions"] + ["comment"] = "MOOSE Load Method", + }, -- end of [1] + [2] = + { + ["rules"] = + { + [1] = + { + ["flag"] = 9999, + ["coalitionlist"] = "red", + ["predicate"] = "c_flag_is_true", + ["zone"] = "", + }, -- end of [1] + }, -- end of ["rules"] + ["eventlist"] = "", + ["predicate"] = "triggerOnce", + ["actions"] = + { + [1] = + { + ["file"] = "ResKey_Action_5", + ["predicate"] = "a_do_script_file", + ["ai_task"] = + { + [1] = "", + [2] = "", + }, -- end of ["ai_task"] + }, -- end of [1] + }, -- end of ["actions"] + ["comment"] = "MOOSE Load Dynamic", + }, -- end of [2] + [3] = + { + ["rules"] = + { + [1] = + { + ["flag"] = 9999, + ["coalitionlist"] = "red", + ["predicate"] = "c_flag_is_false", + ["zone"] = "", + }, -- end of [1] + }, -- end of ["rules"] + ["eventlist"] = "", + ["predicate"] = "triggerOnce", + ["actions"] = + { + [1] = + { + ["file"] = "ResKey_Action_6", + ["predicate"] = "a_do_script_file", + ["ai_task"] = + { + [1] = "", + [2] = "", + }, -- end of ["ai_task"] + }, -- end of [1] + }, -- end of ["actions"] + ["comment"] = "MOOSE Load Embedded", + }, -- end of [3] + [4] = + { + ["rules"] = + { + }, -- end of ["rules"] + ["eventlist"] = "", + ["predicate"] = "triggerOnce", + ["actions"] = + { + [1] = + { + ["file"] = "ResKey_Action_8", + ["predicate"] = "a_do_script_file", + ["ai_task"] = + { + [1] = "", + [2] = "", + }, -- end of ["ai_task"] + }, -- end of [1] + }, -- end of ["actions"] + ["comment"] = "MOOSE Load Mission", + }, -- end of [4] + }, -- end of ["trigrules"] + ["coalition"] = + { + ["blue"] = + { + ["bullseye"] = + { + ["y"] = 617414, + ["x"] = -291014, + }, -- end of ["bullseye"] + ["nav_points"] = + { + }, -- end of ["nav_points"] + ["name"] = "blue", + ["country"] = + { + [1] = + { + ["id"] = 21, + ["name"] = "Australia", + }, -- end of [1] + [2] = + { + ["id"] = 11, + ["name"] = "Belgium", + }, -- end of [2] + [3] = + { + ["id"] = 8, + ["name"] = "Canada", + }, -- end of [3] + [4] = + { + ["id"] = 28, + ["name"] = "Croatia", + }, -- end of [4] + [5] = + { + ["id"] = 26, + ["name"] = "Czech Republic", + }, -- end of [5] + [6] = + { + ["id"] = 13, + ["name"] = "Denmark", + }, -- end of [6] + [7] = + { + ["id"] = 5, + ["name"] = "France", + }, -- end of [7] + [8] = + { + ["id"] = 16, + ["name"] = "Georgia", + ["plane"] = + { + ["group"] = + { + [1] = + { + ["modulation"] = 0, + ["tasks"] = + { + }, -- end of ["tasks"] + ["radioSet"] = false, + ["task"] = "CAS", + ["uncontrolled"] = false, + ["route"] = + { + ["points"] = + { + [1] = + { + ["alt"] = 2000, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 0, + ["y"] = 629928.57142857, + ["x"] = -285709.42857143, + ["name"] = "DictKey_WptName_17", + ["speed"] = 138.88888888889, + ["ETA_locked"] = true, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["number"] = 1, + ["key"] = "CAS", + ["id"] = "EngageTargets", + ["enabled"] = true, + ["auto"] = true, + ["params"] = + { + ["targetTypes"] = + { + [1] = "Helicopters", + [2] = "Ground Units", + [3] = "Light armed ships", + }, -- end of ["targetTypes"] + ["priority"] = 0, + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [1] + [2] = + { + ["alt"] = 2000, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 15.86677699613, + ["y"] = 629307.14285715, + ["x"] = -283595.14285714, + ["name"] = "DictKey_WptName_24", + ["speed"] = 138.88888888889, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [2] + }, -- end of ["points"] + }, -- end of ["route"] + ["groupId"] = 3, + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["alt"] = 2000, + ["alt_type"] = "BARO", + ["livery_id"] = "af standard", + ["skill"] = "Client", + ["speed"] = 138.88888888889, + ["type"] = "Su-25T", + ["unitId"] = 3, + ["psi"] = 0.28586852603922, + ["y"] = 629928.57142857, + ["x"] = -285709.42857143, + ["name"] = "DictKey_UnitName_16", + ["payload"] = + { + ["pylons"] = + { + }, -- end of ["pylons"] + ["fuel"] = "3790", + ["flare"] = 128, + ["chaff"] = 128, + ["gun"] = 100, + }, -- end of ["payload"] + ["heading"] = -0.28586852603922, + ["callsign"] = + { + [1] = 3, + [2] = 1, + [3] = 1, + ["name"] = "Uzi11", + }, -- end of ["callsign"] + ["onboard_num"] = "010", + }, -- end of [1] + }, -- end of ["units"] + ["y"] = 629928.57142857, + ["x"] = -285709.42857143, + ["name"] = "DictKey_GroupName_15", + ["communication"] = true, + ["start_time"] = 0, + ["frequency"] = 124, + }, -- end of [1] + [2] = + { + ["lateActivation"] = false, + ["tasks"] = + { + }, -- end of ["tasks"] + ["radioSet"] = false, + ["task"] = "CAS", + ["uncontrolled"] = false, + ["route"] = + { + ["routeRelativeTOT"] = false, + ["points"] = + { + [1] = + { + ["alt"] = 2000, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 0, + ["y"] = 628607.14285715, + ["x"] = -287052.28571429, + ["name"] = "DictKey_WptName_21", + ["speed"] = 138.88888888889, + ["ETA_locked"] = true, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["number"] = 1, + ["key"] = "CAS", + ["id"] = "EngageTargets", + ["enabled"] = true, + ["auto"] = true, + ["params"] = + { + ["targetTypes"] = + { + [1] = "Helicopters", + [2] = "Ground Units", + [3] = "Light armed ships", + }, -- end of ["targetTypes"] + ["priority"] = 0, + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [1] + [2] = + { + ["alt"] = 2000, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 23.784032372968, + ["y"] = 631664.28571429, + ["x"] = -285595.14285714, + ["name"] = "DictKey_WptName_22", + ["speed"] = 138.88888888889, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [2] + [3] = + { + ["alt"] = 2000, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 37.530380607896, + ["y"] = 633007.14285715, + ["x"] = -284238, + ["name"] = "DictKey_WptName_23", + ["speed"] = 138.88888888889, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [3] + }, -- end of ["points"] + }, -- end of ["route"] + ["groupId"] = 4, + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["alt"] = 2000, + ["alt_type"] = "BARO", + ["livery_id"] = "af standard", + ["skill"] = "High", + ["speed"] = 138.88888888889, + ["type"] = "Su-25T", + ["unitId"] = 4, + ["psi"] = -1.1260144038135, + ["y"] = 628607.14285715, + ["x"] = -287052.28571429, + ["name"] = "DictKey_UnitName_20", + ["payload"] = + { + ["pylons"] = + { + }, -- end of ["pylons"] + ["fuel"] = "3790", + ["flare"] = 128, + ["chaff"] = 128, + ["gun"] = 100, + }, -- end of ["payload"] + ["heading"] = 1.1260144038135, + ["callsign"] = + { + [1] = 1, + [2] = 1, + [3] = 1, + ["name"] = "Enfield11", + }, -- end of ["callsign"] + ["onboard_num"] = "011", + }, -- end of [1] + }, -- end of ["units"] + ["y"] = 628607.14285715, + ["x"] = -287052.28571429, + ["name"] = "DictKey_GroupName_19", + ["communication"] = true, + ["start_time"] = 0, + ["modulation"] = 0, + ["frequency"] = 124, + }, -- end of [2] + }, -- end of ["group"] + }, -- end of ["plane"] + }, -- end of [8] + [9] = + { + ["id"] = 6, + ["name"] = "Germany", + }, -- end of [9] + [10] = + { + ["id"] = 15, + ["name"] = "Israel", + }, -- end of [10] + [11] = + { + ["id"] = 20, + ["name"] = "Italy", + }, -- end of [11] + [12] = + { + ["id"] = 12, + ["name"] = "Norway", + }, -- end of [12] + [13] = + { + ["id"] = 40, + ["name"] = "Poland", + }, -- end of [13] + [14] = + { + ["id"] = 45, + ["name"] = "South Korea", + }, -- end of [14] + [15] = + { + ["id"] = 9, + ["name"] = "Spain", + }, -- end of [15] + [16] = + { + ["id"] = 10, + ["name"] = "The Netherlands", + }, -- end of [16] + [17] = + { + ["id"] = 3, + ["name"] = "Turkey", + }, -- end of [17] + [18] = + { + ["id"] = 4, + ["name"] = "UK", + }, -- end of [18] + [19] = + { + ["id"] = 2, + ["name"] = "USA", + ["helicopter"] = + { + ["group"] = + { + [1] = + { + ["modulation"] = 0, + ["tasks"] = + { + }, -- end of ["tasks"] + ["radioSet"] = false, + ["task"] = "CAS", + ["uncontrolled"] = false, + ["route"] = + { + ["points"] = + { + [1] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 0, + ["y"] = 630514.28571429, + ["x"] = -283495.14285714, + ["name"] = "DictKey_WptName_11", + ["speed"] = 55.555555555556, + ["ETA_locked"] = true, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["number"] = 1, + ["key"] = "CAS", + ["id"] = "EngageTargets", + ["enabled"] = true, + ["auto"] = true, + ["params"] = + { + ["targetTypes"] = + { + [1] = "Helicopters", + [2] = "Ground Units", + [3] = "Light armed ships", + }, -- end of ["targetTypes"] + ["priority"] = 0, + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [1] + [2] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 33.043857683573, + ["y"] = 630528.57142858, + ["x"] = -281659.42857143, + ["name"] = "DictKey_WptName_26", + ["speed"] = 55.555555555556, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [2] + }, -- end of ["points"] + }, -- end of ["route"] + ["groupId"] = 1, + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["alt"] = 500, + ["alt_type"] = "BARO", + ["livery_id"] = "us army", + ["skill"] = "Client", + ["ropeLength"] = 15, + ["speed"] = 55.555555555556, + ["type"] = "Ka-50", + ["Radio"] = + { + [1] = + { + ["channels"] = + { + [7] = 40, + [1] = 21.5, + [2] = 25.7, + [4] = 28, + [8] = 50, + [9] = 55.5, + [5] = 30, + [10] = 59.9, + [3] = 27, + [6] = 32, + }, -- end of ["channels"] + }, -- end of [1] + [2] = + { + ["channels"] = + { + [15] = 0.995, + [13] = 0.583, + [7] = 0.443, + [14] = 0.283, + [2] = 0.303, + [4] = 0.591, + [8] = 0.215, + [16] = 1.21, + [9] = 0.525, + [5] = 0.408, + [10] = 1.065, + [3] = 0.289, + [11] = 0.718, + [6] = 0.803, + [12] = 0.35, + [1] = 0.625, + }, -- end of ["channels"] + }, -- end of [2] + }, -- end of ["Radio"] + ["unitId"] = 1, + ["psi"] = -0.0077819440762977, + ["y"] = 630514.28571429, + ["x"] = -283495.14285714, + ["name"] = "DictKey_UnitName_10", + ["payload"] = + { + ["pylons"] = + { + }, -- end of ["pylons"] + ["fuel"] = "1450", + ["flare"] = 128, + ["chaff"] = 0, + ["gun"] = 100, + }, -- end of ["payload"] + ["heading"] = 0.0077819440762977, + ["callsign"] = + { + [1] = 1, + [2] = 1, + [3] = 1, + ["name"] = "Enfield11", + }, -- end of ["callsign"] + ["onboard_num"] = "050", + }, -- end of [1] + }, -- end of ["units"] + ["y"] = 630514.28571429, + ["x"] = -283495.14285714, + ["name"] = "DictKey_GroupName_9", + ["communication"] = true, + ["start_time"] = 0, + ["frequency"] = 124, + }, -- end of [1] + [2] = + { + ["lateActivation"] = false, + ["tasks"] = + { + }, -- end of ["tasks"] + ["radioSet"] = false, + ["task"] = "CAS", + ["uncontrolled"] = false, + ["route"] = + { + ["routeRelativeTOT"] = false, + ["points"] = + { + [1] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 0, + ["y"] = 630514.28571429, + ["x"] = -283788, + ["name"] = "DictKey_WptName_14", + ["speed"] = 55.555555555556, + ["ETA_locked"] = true, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["number"] = 1, + ["key"] = "CAS", + ["id"] = "EngageTargets", + ["enabled"] = true, + ["auto"] = true, + ["params"] = + { + ["targetTypes"] = + { + [1] = "Helicopters", + [2] = "Ground Units", + [3] = "Light armed ships", + }, -- end of ["targetTypes"] + ["priority"] = 0, + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [1] + [2] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 23.658540331395, + ["y"] = 630528.57142858, + ["x"] = -282473.71428571, + ["name"] = "DictKey_WptName_25", + ["speed"] = 55.555555555556, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [2] + }, -- end of ["points"] + }, -- end of ["route"] + ["groupId"] = 2, + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["alt"] = 500, + ["alt_type"] = "BARO", + ["livery_id"] = "us army", + ["skill"] = "High", + ["ropeLength"] = 15, + ["speed"] = 55.555555555556, + ["type"] = "Ka-50", + ["unitId"] = 2, + ["psi"] = -0.010869137177245, + ["y"] = 630514.28571429, + ["x"] = -283788, + ["name"] = "DictKey_UnitName_13", + ["payload"] = + { + ["pylons"] = + { + }, -- end of ["pylons"] + ["fuel"] = "1450", + ["flare"] = 128, + ["chaff"] = 0, + ["gun"] = 100, + }, -- end of ["payload"] + ["heading"] = 0.010869137177245, + ["callsign"] = + { + [1] = 2, + [2] = 1, + [3] = 1, + ["name"] = "Springfield11", + }, -- end of ["callsign"] + ["onboard_num"] = "051", + }, -- end of [1] + }, -- end of ["units"] + ["y"] = 630514.28571429, + ["x"] = -283788, + ["name"] = "DictKey_GroupName_12", + ["communication"] = true, + ["start_time"] = 0, + ["modulation"] = 0, + ["frequency"] = 124, + }, -- end of [2] + }, -- end of ["group"] + }, -- end of ["helicopter"] + }, -- end of [19] + }, -- end of ["country"] + }, -- end of ["blue"] + ["red"] = + { + ["bullseye"] = + { + ["y"] = 371700, + ["x"] = 11557, + }, -- end of ["bullseye"] + ["nav_points"] = + { + }, -- end of ["nav_points"] + ["name"] = "red", + ["country"] = + { + [1] = + { + ["id"] = 18, + ["name"] = "Abkhazia", + }, -- end of [1] + [2] = + { + ["id"] = 24, + ["name"] = "Belarus", + }, -- end of [2] + [3] = + { + ["id"] = 27, + ["name"] = "China", + }, -- end of [3] + [4] = + { + ["id"] = 34, + ["name"] = "Iran", + }, -- end of [4] + [5] = + { + ["id"] = 37, + ["name"] = "Kazakhstan", + }, -- end of [5] + [6] = + { + ["id"] = 38, + ["name"] = "North Korea", + }, -- end of [6] + [7] = + { + ["id"] = 0, + ["name"] = "Russia", + }, -- end of [7] + [8] = + { + ["id"] = 43, + ["name"] = "Serbia", + }, -- end of [8] + [9] = + { + ["id"] = 19, + ["name"] = "South Ossetia", + }, -- end of [9] + [10] = + { + ["id"] = 47, + ["name"] = "Syria", + }, -- end of [10] + [11] = + { + ["id"] = 1, + ["name"] = "Ukraine", + }, -- end of [11] + }, -- end of ["country"] + }, -- end of ["red"] + }, -- end of ["coalition"] + ["sortie"] = "DictKey_sortie_4", + ["version"] = 11, + ["goals"] = + { + }, -- end of ["goals"] + ["currentKey"] = 452, + ["start_time"] = 43200, + ["forcedOptions"] = + { + }, -- end of ["forcedOptions"] + ["failures"] = + { + ["OIL_RADIATOR_SENSOR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "OIL_RADIATOR_SENSOR", + ["mm"] = 0, + }, -- end of ["OIL_RADIATOR_SENSOR"] + ["TURNIND_POINTER_FAILS_NO_VACUUM"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_POINTER_FAILS_NO_VACUUM", + ["mm"] = 0, + }, -- end of ["TURNIND_POINTER_FAILS_NO_VACUUM"] + ["helmet"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "helmet", + ["mm"] = 0, + }, -- end of ["helmet"] + ["GUN_LEFT_IN_MOUNT_LOOSE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_IN_MOUNT_LOOSE", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_IN_MOUNT_LOOSE"] + ["es_damage_MainInverter"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_MainInverter", + ["mm"] = 0, + }, -- end of ["es_damage_MainInverter"] + ["rws"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "rws", + ["mm"] = 0, + }, -- end of ["rws"] + ["AN_ALR69V_FAILURE_SENSOR_TAIL_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALR69V_FAILURE_SENSOR_TAIL_RIGHT", + ["mm"] = 0, + }, -- end of ["AN_ALR69V_FAILURE_SENSOR_TAIL_RIGHT"] + ["MainReductor_ShaveInOil"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MainReductor_ShaveInOil", + ["mm"] = 0, + }, -- end of ["MainReductor_ShaveInOil"] + ["asc_y"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "asc_y", + ["mm"] = 0, + }, -- end of ["asc_y"] + ["MAIN_L_GEAR_D_LOCK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MAIN_L_GEAR_D_LOCK", + ["mm"] = 0, + }, -- end of ["MAIN_L_GEAR_D_LOCK"] + ["AAR_47_FAILURE_SENSOR_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AAR_47_FAILURE_SENSOR_LEFT", + ["mm"] = 0, + }, -- end of ["AAR_47_FAILURE_SENSOR_LEFT"] + ["tail_reductor_chip"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "tail_reductor_chip", + ["mm"] = 0, + }, -- end of ["tail_reductor_chip"] + ["TACAN_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACAN_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["TACAN_FAILURE_TOTAL"] + ["OIL_RADIATOR_MOTOR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "OIL_RADIATOR_MOTOR", + ["mm"] = 0, + }, -- end of ["OIL_RADIATOR_MOTOR"] + ["SUPERCHARGER_WIRE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SUPERCHARGER_WIRE", + ["mm"] = 0, + }, -- end of ["SUPERCHARGER_WIRE"] + ["CADC_FAILURE_TEMPERATURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_TEMPERATURE", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_TEMPERATURE"] + ["FUSELAGE_TANK_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FUSELAGE_TANK_LEAK", + ["mm"] = 0, + }, -- end of ["FUSELAGE_TANK_LEAK"] + ["AN_ALE_40V_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALE_40V_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["AN_ALE_40V_FAILURE_TOTAL"] + ["HORIZON_BAR_NOT_SETTLE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "HORIZON_BAR_NOT_SETTLE", + ["mm"] = 0, + }, -- end of ["HORIZON_BAR_NOT_SETTLE"] + ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_WING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_LEFT_WING", + ["mm"] = 0, + }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_WING"] + ["OIL_DILUTION_WIRE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "OIL_DILUTION_WIRE", + ["mm"] = 0, + }, -- end of ["OIL_DILUTION_WIRE"] + ["FLEX_S_BKP_LAMP_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FLEX_S_BKP_LAMP_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["FLEX_S_BKP_LAMP_DEFECTIVE"] + ["TAIL_GEAR_FAIL_GO_DOWN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TAIL_GEAR_FAIL_GO_DOWN", + ["mm"] = 0, + }, -- end of ["TAIL_GEAR_FAIL_GO_DOWN"] + ["GUN_FAIL_RIGHT_CENTER_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_FAIL_RIGHT_CENTER_GUN", + ["mm"] = 0, + }, -- end of ["GUN_FAIL_RIGHT_CENTER_GUN"] + ["LeftEngine_ShaveInOil"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "LeftEngine_ShaveInOil", + ["mm"] = 0, + }, -- end of ["LeftEngine_ShaveInOil"] + ["MAIN_R_GEAR_D_LOCK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MAIN_R_GEAR_D_LOCK", + ["mm"] = 0, + }, -- end of ["MAIN_R_GEAR_D_LOCK"] + ["R_GEAR_DLK_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "R_GEAR_DLK_FAULT", + ["mm"] = 0, + }, -- end of ["R_GEAR_DLK_FAULT"] + ["GMC_GYRO_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GMC_GYRO_FAILURE", + ["mm"] = 0, + }, -- end of ["GMC_GYRO_FAILURE"] + ["L_GEAR_DLK_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "L_GEAR_DLK_FAULT", + ["mm"] = 0, + }, -- end of ["L_GEAR_DLK_FAULT"] + ["K14_FIXED_LAMP_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "K14_FIXED_LAMP_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["K14_FIXED_LAMP_DEFECTIVE"] + ["GUN_FAIL_LEFT_CENTER_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_FAIL_LEFT_CENTER_GUN", + ["mm"] = 0, + }, -- end of ["GUN_FAIL_LEFT_CENTER_GUN"] + ["engine_droop_failure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "engine_droop_failure", + ["mm"] = 0, + }, -- end of ["engine_droop_failure"] + ["TGP_FAILURE_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TGP_FAILURE_LEFT", + ["mm"] = 0, + }, -- end of ["TGP_FAILURE_LEFT"] + ["CADC_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_TOTAL"] + ["COOLANT_POOR_CONNTECT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_POOR_CONNTECT", + ["mm"] = 0, + }, -- end of ["COOLANT_POOR_CONNTECT"] + ["TURNIND_POINTER_FAILS_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_POINTER_FAILS_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["TURNIND_POINTER_FAILS_DEFECTIVE"] + ["GUN_FAIL_RIGHT_OUT_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_FAIL_RIGHT_OUT_GUN", + ["mm"] = 0, + }, -- end of ["GUN_FAIL_RIGHT_OUT_GUN"] + ["BOMBS_DAMAGE_LINKAGE_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_DAMAGE_LINKAGE_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_DAMAGE_LINKAGE_LEFT"] + ["FUSELAGE_TANK_PUMP_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FUSELAGE_TANK_PUMP_FAULT", + ["mm"] = 0, + }, -- end of ["FUSELAGE_TANK_PUMP_FAULT"] + ["hydro_main"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hydro_main", + ["mm"] = 0, + }, -- end of ["hydro_main"] + ["CICU_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CICU_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["CICU_FAILURE_TOTAL"] + ["GUN_LEFT_OUT_MOUNT_LOOSE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_OUT_MOUNT_LOOSE", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_OUT_MOUNT_LOOSE"] + ["TAIL_GEAR_U_LOCK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TAIL_GEAR_U_LOCK", + ["mm"] = 0, + }, -- end of ["TAIL_GEAR_U_LOCK"] + ["RADAR_ALT_TOTAL_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RADAR_ALT_TOTAL_FAILURE", + ["mm"] = 0, + }, -- end of ["RADAR_ALT_TOTAL_FAILURE"] + ["GUN_RIGHT_CENTER_MOUNT_LOOSE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_CENTER_MOUNT_LOOSE", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_CENTER_MOUNT_LOOSE"] + ["TAIL_GEAR_FAIL_GO_UP"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TAIL_GEAR_FAIL_GO_UP", + ["mm"] = 0, + }, -- end of ["TAIL_GEAR_FAIL_GO_UP"] + ["asc_r"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "asc_r", + ["mm"] = 0, + }, -- end of ["asc_r"] + ["BOMBS_SOLENOID_FAULT_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_SOLENOID_FAULT_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_SOLENOID_FAULT_LEFT"] + ["sas_yaw_left"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "sas_yaw_left", + ["mm"] = 0, + }, -- end of ["sas_yaw_left"] + ["DEFECTIVE_MECHANISM"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "DEFECTIVE_MECHANISM", + ["mm"] = 0, + }, -- end of ["DEFECTIVE_MECHANISM"] + ["PITOT_HEAT_ELEMENT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PITOT_HEAT_ELEMENT", + ["mm"] = 0, + }, -- end of ["PITOT_HEAT_ELEMENT"] + ["ILS_FAILURE_ANT_LOCALIZER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ILS_FAILURE_ANT_LOCALIZER", + ["mm"] = 0, + }, -- end of ["ILS_FAILURE_ANT_LOCALIZER"] + ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_GEAR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_LEFT_GEAR", + ["mm"] = 0, + }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_GEAR"] + ["CARBAIR_SHORT_CIRCUIT_BLB"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CARBAIR_SHORT_CIRCUIT_BLB", + ["mm"] = 0, + }, -- end of ["CARBAIR_SHORT_CIRCUIT_BLB"] + ["LEFT_TANK_PUMP_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "LEFT_TANK_PUMP_FAULT", + ["mm"] = 0, + }, -- end of ["LEFT_TANK_PUMP_FAULT"] + ["Surge_RightEngine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "Surge_RightEngine", + ["mm"] = 0, + }, -- end of ["Surge_RightEngine"] + ["RightEngine_Fire"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["mm"] = 0, + }, -- end of ["RightEngine_Fire"] + ["GUN_FAIL_LEFT_IN_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_FAIL_LEFT_IN_GUN", + ["mm"] = 0, + }, -- end of ["GUN_FAIL_LEFT_IN_GUN"] + ["CADC_FAILURE_TAS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_TAS", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_TAS"] + ["STARTER_SOL_SHORT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "STARTER_SOL_SHORT", + ["mm"] = 0, + }, -- end of ["STARTER_SOL_SHORT"] + ["asc_p"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "asc_p", + ["mm"] = 0, + }, -- end of ["asc_p"] + ["sas_pitch_left"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "sas_pitch_left", + ["mm"] = 0, + }, -- end of ["sas_pitch_left"] + ["GUN_LEFT_IN_AMMUN_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_IN_AMMUN_FAULT", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_IN_AMMUN_FAULT"] + ["PUMP_RELIEF_VALVE_SCREEN_CLOGGED"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PUMP_RELIEF_VALVE_SCREEN_CLOGGED", + ["mm"] = 0, + }, -- end of ["PUMP_RELIEF_VALVE_SCREEN_CLOGGED"] + ["abris_hardware"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "abris_hardware", + ["mm"] = 0, + }, -- end of ["abris_hardware"] + ["EEC_Failure_LeftEngine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "EEC_Failure_LeftEngine", + ["mm"] = 0, + }, -- end of ["EEC_Failure_LeftEngine"] + ["COMPASS_POINTER_PULLS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COMPASS_POINTER_PULLS", + ["mm"] = 0, + }, -- end of ["COMPASS_POINTER_PULLS"] + ["Failure_RightEngine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "Failure_RightEngine", + ["mm"] = 0, + }, -- end of ["Failure_RightEngine"] + ["ecm"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ecm", + ["mm"] = 0, + }, -- end of ["ecm"] + ["TGP_FAILURE_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TGP_FAILURE_RIGHT", + ["mm"] = 0, + }, -- end of ["TGP_FAILURE_RIGHT"] + ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_BROKEN_WIRING_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] + ["OIL_RADIATOR_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "OIL_RADIATOR_WIRING", + ["mm"] = 0, + }, -- end of ["OIL_RADIATOR_WIRING"] + ["IGNITION_NO_OUTPUT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "IGNITION_NO_OUTPUT", + ["mm"] = 0, + }, -- end of ["IGNITION_NO_OUTPUT"] + ["AAR_47_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AAR_47_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["AAR_47_FAILURE_TOTAL"] + ["PILOT_KILLED_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PILOT_KILLED_FAILURE", + ["mm"] = 0, + }, -- end of ["PILOT_KILLED_FAILURE"] + ["GUN_LEFT_CENTER_MOUNT_LOOSE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_CENTER_MOUNT_LOOSE", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_CENTER_MOUNT_LOOSE"] + ["VHF_VT_BURNED_OUT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_VT_BURNED_OUT", + ["mm"] = 0, + }, -- end of ["VHF_VT_BURNED_OUT"] + ["COOLANT_RADIATOR_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_RADIATOR_WIRING", + ["mm"] = 0, + }, -- end of ["COOLANT_RADIATOR_WIRING"] + ["asc_a"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "asc_a", + ["mm"] = 0, + }, -- end of ["asc_a"] + ["AIRSPEED_INDICATOR_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AIRSPEED_INDICATOR_FAILURE", + ["mm"] = 0, + }, -- end of ["AIRSPEED_INDICATOR_FAILURE"] + ["GUN_LEFT_CENTER_BARREL_WORN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_CENTER_BARREL_WORN", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_CENTER_BARREL_WORN"] + ["TURNIND_POINTER_VIBRATES"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_POINTER_VIBRATES", + ["mm"] = 0, + }, -- end of ["TURNIND_POINTER_VIBRATES"] + ["GUN_FAIL_LEFT_OUT_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_FAIL_LEFT_OUT_GUN", + ["mm"] = 0, + }, -- end of ["GUN_FAIL_LEFT_OUT_GUN"] + ["SAR_1_101"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SAR_1_101", + ["mm"] = 0, + }, -- end of ["SAR_1_101"] + ["ROCKETS_INTERVALOMETER_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ROCKETS_INTERVALOMETER_WIRING", + ["mm"] = 0, + }, -- end of ["ROCKETS_INTERVALOMETER_WIRING"] + ["GUN_RIGHT_OUT_AMMUN_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_OUT_AMMUN_FAULT", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_OUT_AMMUN_FAULT"] + ["GUN_RIGHT_IN_AMMUN_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_IN_AMMUN_FAULT", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_IN_AMMUN_FAULT"] + ["D2_LEFT_CYLINDER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "D2_LEFT_CYLINDER", + ["mm"] = 0, + }, -- end of ["D2_LEFT_CYLINDER"] + ["Surge_LeftEngine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "Surge_LeftEngine", + ["mm"] = 0, + }, -- end of ["Surge_LeftEngine"] + ["BOMBS_RUST_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_RUST_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_RUST_LEFT"] + ["GUN_RIGHT_CENTER_BARREL_WORN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_CENTER_BARREL_WORN", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_CENTER_BARREL_WORN"] + ["asc"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "asc", + ["mm"] = 0, + }, -- end of ["asc"] + ["COMPASS_NO_TORQUE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COMPASS_NO_TORQUE", + ["mm"] = 0, + }, -- end of ["COMPASS_NO_TORQUE"] + ["COOLANT_BREAK_BULB"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_BREAK_BULB", + ["mm"] = 0, + }, -- end of ["COOLANT_BREAK_BULB"] + ["PROP_GOVERNOR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PROP_GOVERNOR", + ["mm"] = 0, + }, -- end of ["PROP_GOVERNOR"] + ["MANIFOLD_SHIFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MANIFOLD_SHIFT", + ["mm"] = 0, + }, -- end of ["MANIFOLD_SHIFT"] + ["RIGHT_GUNNER_KILLED_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RIGHT_GUNNER_KILLED_FAILURE", + ["mm"] = 0, + }, -- end of ["RIGHT_GUNNER_KILLED_FAILURE"] + ["es_damage_SpareInverter"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_SpareInverter", + ["mm"] = 0, + }, -- end of ["es_damage_SpareInverter"] + ["STARTER_BURNOUT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "STARTER_BURNOUT", + ["mm"] = 0, + }, -- end of ["STARTER_BURNOUT"] + ["UNLOAD_VALVE_NOT_LOAD"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "UNLOAD_VALVE_NOT_LOAD", + ["mm"] = 0, + }, -- end of ["UNLOAD_VALVE_NOT_LOAD"] + ["TURNIND_INCORRECT_SENS_VAC_LOW"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_INCORRECT_SENS_VAC_LOW", + ["mm"] = 0, + }, -- end of ["TURNIND_INCORRECT_SENS_VAC_LOW"] + ["Failure_LeftEngine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "Failure_LeftEngine", + ["mm"] = 0, + }, -- end of ["Failure_LeftEngine"] + ["GUN_RIGHT_IN_BARREL_WORN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_IN_BARREL_WORN", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_IN_BARREL_WORN"] + ["K14_MOV_LAMP_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "K14_MOV_LAMP_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["K14_MOV_LAMP_DEFECTIVE"] + ["ILS_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ILS_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["ILS_FAILURE_TOTAL"] + ["GUN_RIGHT_OUT_BARREL_WORN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_OUT_BARREL_WORN", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_OUT_BARREL_WORN"] + ["fuel_sys_transfer_pumps"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "fuel_sys_transfer_pumps", + ["mm"] = 0, + }, -- end of ["fuel_sys_transfer_pumps"] + ["PITOT_HEAT_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PITOT_HEAT_WIRING", + ["mm"] = 0, + }, -- end of ["PITOT_HEAT_WIRING"] + ["TURNIND_POINTER_NOT_SET_ZERO"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_POINTER_NOT_SET_ZERO", + ["mm"] = 0, + }, -- end of ["TURNIND_POINTER_NOT_SET_ZERO"] + ["MD1_GYRO_TOTAL_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MD1_GYRO_TOTAL_FAILURE", + ["mm"] = 0, + }, -- end of ["MD1_GYRO_TOTAL_FAILURE"] + ["VHF_FM_RADIO_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_FM_RADIO_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["VHF_FM_RADIO_FAILURE_TOTAL"] + ["RIGHT_MFCD_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RIGHT_MFCD_FAILURE", + ["mm"] = 0, + }, -- end of ["RIGHT_MFCD_FAILURE"] + ["F2_BOTTOM_CYLINDER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "F2_BOTTOM_CYLINDER", + ["mm"] = 0, + }, -- end of ["F2_BOTTOM_CYLINDER"] + ["LEFT_WING_TANK_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "LEFT_WING_TANK_LEAK", + ["mm"] = 0, + }, -- end of ["LEFT_WING_TANK_LEAK"] + ["CARBAIR_BREAK_LEADS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CARBAIR_BREAK_LEADS", + ["mm"] = 0, + }, -- end of ["CARBAIR_BREAK_LEADS"] + ["GUN_LEFT_IN_OPEN_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_IN_OPEN_CIRCUIT", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_IN_OPEN_CIRCUIT"] + ["EGI_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "EGI_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["EGI_FAILURE_TOTAL"] + ["UHF_RADIO_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "UHF_RADIO_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["UHF_RADIO_FAILURE_TOTAL"] + ["GUN_RIGHT_CENTER_AMMUN_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_CENTER_AMMUN_FAULT", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_CENTER_AMMUN_FAULT"] + ["LEFT_GUNNER_KILLED_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "LEFT_GUNNER_KILLED_FAILURE", + ["mm"] = 0, + }, -- end of ["LEFT_GUNNER_KILLED_FAILURE"] + ["VHF_VT207_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_VT207_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["VHF_VT207_DEFECTIVE"] + ["RightEngine_LowOilPressure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RightEngine_LowOilPressure", + ["mm"] = 0, + }, -- end of ["RightEngine_LowOilPressure"] + ["radar"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "radar", + ["mm"] = 0, + }, -- end of ["radar"] + ["RIGHT_TANK_PUMP_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RIGHT_TANK_PUMP_FAULT", + ["mm"] = 0, + }, -- end of ["RIGHT_TANK_PUMP_FAULT"] + ["COOLANT_UNPRES"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_UNPRES", + ["mm"] = 0, + }, -- end of ["COOLANT_UNPRES"] + ["ARN_82_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ARN_82_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["ARN_82_FAILURE_TOTAL"] + ["FLEX_S_NO_POWER_SUPPLY"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FLEX_S_NO_POWER_SUPPLY", + ["mm"] = 0, + }, -- end of ["FLEX_S_NO_POWER_SUPPLY"] + ["eos"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "eos", + ["mm"] = 0, + }, -- end of ["eos"] + ["HYDRO_LOW_AIR_PRESSURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "HYDRO_LOW_AIR_PRESSURE", + ["mm"] = 0, + }, -- end of ["HYDRO_LOW_AIR_PRESSURE"] + ["K14_MOTOR_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "K14_MOTOR_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["K14_MOTOR_DEFECTIVE"] + ["GENERATOR_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GENERATOR_FAULT", + ["mm"] = 0, + }, -- end of ["GENERATOR_FAULT"] + ["FUEL_PUMP_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FUEL_PUMP_FAILURE", + ["mm"] = 0, + }, -- end of ["FUEL_PUMP_FAILURE"] + ["RADAR_ALTIMETR_LEFT_ANT_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RADAR_ALTIMETR_LEFT_ANT_FAILURE", + ["mm"] = 0, + }, -- end of ["RADAR_ALTIMETR_LEFT_ANT_FAILURE"] + ["hydro"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hydro", + ["mm"] = 0, + }, -- end of ["hydro"] + ["BAT_SOLENOID_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BAT_SOLENOID_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["BAT_SOLENOID_DEFECTIVE"] + ["LeftEngine_Fire"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["mm"] = 0, + }, -- end of ["LeftEngine_Fire"] + ["SUPERCHARGER_LIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SUPERCHARGER_LIGHT", + ["mm"] = 0, + }, -- end of ["SUPERCHARGER_LIGHT"] + ["L_GEAR_UPL_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "L_GEAR_UPL_FAULT", + ["mm"] = 0, + }, -- end of ["L_GEAR_UPL_FAULT"] + ["fs_damage_right_cell_boost_pump"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "fs_damage_right_cell_boost_pump", + ["mm"] = 0, + }, -- end of ["fs_damage_right_cell_boost_pump"] + ["TACH_RESISTANCE_ADJ"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACH_RESISTANCE_ADJ", + ["mm"] = 0, + }, -- end of ["TACH_RESISTANCE_ADJ"] + ["MAGNETO_1"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MAGNETO_1", + ["mm"] = 0, + }, -- end of ["MAGNETO_1"] + ["BOMBS_NO_VOLATAGE_AT_RACK_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_NO_VOLATAGE_AT_RACK_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_NO_VOLATAGE_AT_RACK_RIGHT"] + ["GUN_RIGHT_OUT_MOUNT_LOOSE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_OUT_MOUNT_LOOSE", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_OUT_MOUNT_LOOSE"] + ["TailReductor_ShaveInOil"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TailReductor_ShaveInOil", + ["mm"] = 0, + }, -- end of ["TailReductor_ShaveInOil"] + ["R_GEAR_UPL_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "R_GEAR_UPL_FAULT", + ["mm"] = 0, + }, -- end of ["R_GEAR_UPL_FAULT"] + ["BOMBS_TRAIN_DEFECTIVE_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_TRAIN_DEFECTIVE_WIRING", + ["mm"] = 0, + }, -- end of ["BOMBS_TRAIN_DEFECTIVE_WIRING"] + ["autopilot"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "autopilot", + ["mm"] = 0, + }, -- end of ["autopilot"] + ["BOMBS_TRAIN_DEFECTIVE_SWITCH"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_TRAIN_DEFECTIVE_SWITCH", + ["mm"] = 0, + }, -- end of ["BOMBS_TRAIN_DEFECTIVE_SWITCH"] + ["CARBAIR_SHORT_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CARBAIR_SHORT_CIRCUIT", + ["mm"] = 0, + }, -- end of ["CARBAIR_SHORT_CIRCUIT"] + ["STARTER_RELAY"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "STARTER_RELAY", + ["mm"] = 0, + }, -- end of ["STARTER_RELAY"] + ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING", + ["mm"] = 0, + }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING"] + ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_CENTER_OPEN_CIRCUIT", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] + ["GUN_RIGHT_IN_MOUNT_LOOSE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_IN_MOUNT_LOOSE", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_IN_MOUNT_LOOSE"] + ["hydro_right"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hydro_right", + ["mm"] = 0, + }, -- end of ["hydro_right"] + ["sas_yaw_right"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "sas_yaw_right", + ["mm"] = 0, + }, -- end of ["sas_yaw_right"] + ["DOORS_TVC_BROKEN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "DOORS_TVC_BROKEN", + ["mm"] = 0, + }, -- end of ["DOORS_TVC_BROKEN"] + ["SADL_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SADL_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["SADL_FAILURE_TOTAL"] + ["fs_damage_left_cell_boost_pump"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "fs_damage_left_cell_boost_pump", + ["mm"] = 0, + }, -- end of ["fs_damage_left_cell_boost_pump"] + ["BOMBS_DAMAGE_ELINKAGE_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_DAMAGE_ELINKAGE_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_DAMAGE_ELINKAGE_LEFT"] + ["r_conv"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "r_conv", + ["mm"] = 0, + }, -- end of ["r_conv"] + ["ENGINE_JAM"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ENGINE_JAM", + ["mm"] = 0, + }, -- end of ["ENGINE_JAM"] + ["MAGNETO_2"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MAGNETO_2", + ["mm"] = 0, + }, -- end of ["MAGNETO_2"] + ["SAR_1_95"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SAR_1_95", + ["mm"] = 0, + }, -- end of ["SAR_1_95"] + ["BOMBS_SOLENOID_FAULT_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_SOLENOID_FAULT_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_SOLENOID_FAULT_RIGHT"] + ["CDU_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CDU_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["CDU_FAILURE_TOTAL"] + ["STARTER_SOLENOID"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "STARTER_SOLENOID", + ["mm"] = 0, + }, -- end of ["STARTER_SOLENOID"] + ["TAIL_GEAR_C_CABLE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TAIL_GEAR_C_CABLE", + ["mm"] = 0, + }, -- end of ["TAIL_GEAR_C_CABLE"] + ["STARTER_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "STARTER_WIRING", + ["mm"] = 0, + }, -- end of ["STARTER_WIRING"] + ["engine_driveshaft_failure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "engine_driveshaft_failure", + ["mm"] = 0, + }, -- end of ["engine_driveshaft_failure"] + ["PUMP_RELIEF_VALVE_LEAKS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PUMP_RELIEF_VALVE_LEAKS", + ["mm"] = 0, + }, -- end of ["PUMP_RELIEF_VALVE_LEAKS"] + ["HUD_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "HUD_FAILURE", + ["mm"] = 0, + }, -- end of ["HUD_FAILURE"] + ["mfd"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "mfd", + ["mm"] = 0, + }, -- end of ["mfd"] + ["CARBAIR_GND_LEAD"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CARBAIR_GND_LEAD", + ["mm"] = 0, + }, -- end of ["CARBAIR_GND_LEAD"] + ["GMC_MAGN_COMP_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GMC_MAGN_COMP_FAILURE", + ["mm"] = 0, + }, -- end of ["GMC_MAGN_COMP_FAILURE"] + ["es_damage_GeneratorLeft"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_GeneratorLeft", + ["mm"] = 0, + }, -- end of ["es_damage_GeneratorLeft"] + ["SUPERCHARGER_SOLENOID"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SUPERCHARGER_SOLENOID", + ["mm"] = 0, + }, -- end of ["SUPERCHARGER_SOLENOID"] + ["engine_chip"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "engine_chip", + ["mm"] = 0, + }, -- end of ["engine_chip"] + ["ARN_83_TOTAL_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ARN_83_TOTAL_FAILURE", + ["mm"] = 0, + }, -- end of ["ARN_83_TOTAL_FAILURE"] + ["CADC_FAILURE_MACH"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_MACH", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_MACH"] + ["ROCKETS_DEFECTIVE_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ROCKETS_DEFECTIVE_WIRING", + ["mm"] = 0, + }, -- end of ["ROCKETS_DEFECTIVE_WIRING"] + ["COPILOT_GYRO_TOTAL_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COPILOT_GYRO_TOTAL_FAILURE", + ["mm"] = 0, + }, -- end of ["COPILOT_GYRO_TOTAL_FAILURE"] + ["RightEngine_ShaveInOil"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RightEngine_ShaveInOil", + ["mm"] = 0, + }, -- end of ["RightEngine_ShaveInOil"] + ["EEC_Failure_RightEngine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "EEC_Failure_RightEngine", + ["mm"] = 0, + }, -- end of ["EEC_Failure_RightEngine"] + ["laser_failure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "laser_failure", + ["mm"] = 0, + }, -- end of ["laser_failure"] + ["ARN_83_ADF_DAMAGE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ARN_83_ADF_DAMAGE", + ["mm"] = 0, + }, -- end of ["ARN_83_ADF_DAMAGE"] + ["AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT", + ["mm"] = 0, + }, -- end of ["AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT"] + ["PUMP_FAILS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PUMP_FAILS", + ["mm"] = 0, + }, -- end of ["PUMP_FAILS"] + ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR", + ["mm"] = 0, + }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] + ["TACH_BREAK_IN_INDICATOR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACH_BREAK_IN_INDICATOR", + ["mm"] = 0, + }, -- end of ["TACH_BREAK_IN_INDICATOR"] + ["BATTERY_OVERHEAT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BATTERY_OVERHEAT", + ["mm"] = 0, + }, -- end of ["BATTERY_OVERHEAT"] + ["CARBAIR_SHORT_CIRCUIT_LEADS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CARBAIR_SHORT_CIRCUIT_LEADS", + ["mm"] = 0, + }, -- end of ["CARBAIR_SHORT_CIRCUIT_LEADS"] + ["NOSE_AIRSPEED_INDICATOR_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "NOSE_AIRSPEED_INDICATOR_FAILURE", + ["mm"] = 0, + }, -- end of ["NOSE_AIRSPEED_INDICATOR_FAILURE"] + ["GUN_FAIL_RIGHT_IN_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_FAIL_RIGHT_IN_GUN", + ["mm"] = 0, + }, -- end of ["GUN_FAIL_RIGHT_IN_GUN"] + ["abris_software"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "abris_software", + ["mm"] = 0, + }, -- end of ["abris_software"] + ["ILS_FAILURE_ANT_GLIDESLOPE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ILS_FAILURE_ANT_GLIDESLOPE", + ["mm"] = 0, + }, -- end of ["ILS_FAILURE_ANT_GLIDESLOPE"] + ["COPILOT_KILLED_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COPILOT_KILLED_FAILURE", + ["mm"] = 0, + }, -- end of ["COPILOT_KILLED_FAILURE"] + ["CADC_FAILURE_IAS"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_IAS", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_IAS"] + ["COOLANT_RADIATOR_SENSOR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_RADIATOR_SENSOR", + ["mm"] = 0, + }, -- end of ["COOLANT_RADIATOR_SENSOR"] + ["GUN_LEFT_CENTER_AMMUN_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_CENTER_AMMUN_FAULT", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_CENTER_AMMUN_FAULT"] + ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_NO_VOLATAGE_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] + ["AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT", + ["mm"] = 0, + }, -- end of ["AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT"] + ["TACH_BREAK_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACH_BREAK_CIRCUIT", + ["mm"] = 0, + }, -- end of ["TACH_BREAK_CIRCUIT"] + ["hydro_main_irreversible_valve"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hydro_main_irreversible_valve", + ["mm"] = 0, + }, -- end of ["hydro_main_irreversible_valve"] + ["TAIL_GEAR_D_LOCK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TAIL_GEAR_D_LOCK", + ["mm"] = 0, + }, -- end of ["TAIL_GEAR_D_LOCK"] + ["hud"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hud", + ["mm"] = 0, + }, -- end of ["hud"] + ["INT_HYDRO_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "INT_HYDRO_LEAK", + ["mm"] = 0, + }, -- end of ["INT_HYDRO_LEAK"] + ["BOOST_REG"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOOST_REG", + ["mm"] = 0, + }, -- end of ["BOOST_REG"] + ["SAR_1_2_95"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SAR_1_2_95", + ["mm"] = 0, + }, -- end of ["SAR_1_2_95"] + ["fuel_sys_left_transfer_pump"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "fuel_sys_left_transfer_pump", + ["mm"] = 0, + }, -- end of ["fuel_sys_left_transfer_pump"] + ["LeftEngine_LowOilPressure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "LeftEngine_LowOilPressure", + ["mm"] = 0, + }, -- end of ["LeftEngine_LowOilPressure"] + ["FAULTY_ROCKET_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FAULTY_ROCKET_LEFT", + ["mm"] = 0, + }, -- end of ["FAULTY_ROCKET_LEFT"] + ["es_damage_MainGenerator"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_MainGenerator", + ["mm"] = 0, + }, -- end of ["es_damage_MainGenerator"] + ["MainReductor_LowOilPressure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MainReductor_LowOilPressure", + ["mm"] = 0, + }, -- end of ["MainReductor_LowOilPressure"] + ["IGNITION_TERM_CONNECT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "IGNITION_TERM_CONNECT", + ["mm"] = 0, + }, -- end of ["IGNITION_TERM_CONNECT"] + ["es_damage_StarterGenerator"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_StarterGenerator", + ["mm"] = 0, + }, -- end of ["es_damage_StarterGenerator"] + ["es_damage_Battery"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_Battery", + ["mm"] = 0, + }, -- end of ["es_damage_Battery"] + ["ILS_FAILURE_ANT_MARKER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ILS_FAILURE_ANT_MARKER", + ["mm"] = 0, + }, -- end of ["ILS_FAILURE_ANT_MARKER"] + ["VHF_SQUELCH_RELAY"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_SQUELCH_RELAY", + ["mm"] = 0, + }, -- end of ["VHF_SQUELCH_RELAY"] + ["COMPASS_ERRATIC_OPERATION"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COMPASS_ERRATIC_OPERATION", + ["mm"] = 0, + }, -- end of ["COMPASS_ERRATIC_OPERATION"] + ["TACAN_FAILURE_RECEIVER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACAN_FAILURE_RECEIVER", + ["mm"] = 0, + }, -- end of ["TACAN_FAILURE_RECEIVER"] + ["sas_pitch_right"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "sas_pitch_right", + ["mm"] = 0, + }, -- end of ["sas_pitch_right"] + ["BOMBS_NO_VOLATAGE_AT_RACK_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_NO_VOLATAGE_AT_RACK_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_NO_VOLATAGE_AT_RACK_LEFT"] + ["TransitionalReductor_ShaveInOil"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TransitionalReductor_ShaveInOil", + ["mm"] = 0, + }, -- end of ["TransitionalReductor_ShaveInOil"] + ["TACH_POOR_CONNECTION"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACH_POOR_CONNECTION", + ["mm"] = 0, + }, -- end of ["TACH_POOR_CONNECTION"] + ["VHF_AM_RADIO_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_AM_RADIO_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["VHF_AM_RADIO_FAILURE_TOTAL"] + ["main_reductor_chip"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "main_reductor_chip", + ["mm"] = 0, + }, -- end of ["main_reductor_chip"] + ["VHF_CRYSTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_CRYSTAL", + ["mm"] = 0, + }, -- end of ["VHF_CRYSTAL"] + ["COOLANT_SHORT_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_SHORT_CIRCUIT", + ["mm"] = 0, + }, -- end of ["COOLANT_SHORT_CIRCUIT"] + ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_BROKEN_WIRING_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] + ["F2_TOP_CYLINDER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "F2_TOP_CYLINDER", + ["mm"] = 0, + }, -- end of ["F2_TOP_CYLINDER"] + ["FLEX_S_MAIN_LAMP_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FLEX_S_MAIN_LAMP_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["FLEX_S_MAIN_LAMP_DEFECTIVE"] + ["MANIFOLD_LINE_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "MANIFOLD_LINE_LEAK", + ["mm"] = 0, + }, -- end of ["MANIFOLD_LINE_LEAK"] + ["CADC_FAILURE_DYNAMIC"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_DYNAMIC", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_DYNAMIC"] + ["CADC_FAILURE_PRESSURE_ALT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_PRESSURE_ALT", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_PRESSURE_ALT"] + ["K14_NO_POWER_SUPPLY"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "K14_NO_POWER_SUPPLY", + ["mm"] = 0, + }, -- end of ["K14_NO_POWER_SUPPLY"] + ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RADAR_ALTIMETR_RIGHT_ANT_FAILURE", + ["mm"] = 0, + }, -- end of ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] + ["es_damage_GeneratorRight"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "es_damage_GeneratorRight", + ["mm"] = 0, + }, -- end of ["es_damage_GeneratorRight"] + ["BOMBS_DAMAGE_LINKAGE_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_DAMAGE_LINKAGE_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_DAMAGE_LINKAGE_RIGHT"] + ["fs_damage_engine_pump"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "fs_damage_engine_pump", + ["mm"] = 0, + }, -- end of ["fs_damage_engine_pump"] + ["VHF_SHORTED_CTL_BOX"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "VHF_SHORTED_CTL_BOX", + ["mm"] = 0, + }, -- end of ["VHF_SHORTED_CTL_BOX"] + ["CADC_FAILURE_STATIC"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_STATIC", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_STATIC"] + ["CADC_FAILURE_BARO_ALT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CADC_FAILURE_BARO_ALT", + ["mm"] = 0, + }, -- end of ["CADC_FAILURE_BARO_ALT"] + ["GUN_RIGHT_CENTER_OPEN_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_CENTER_OPEN_CIRCUIT", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_CENTER_OPEN_CIRCUIT"] + ["IFFCC_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "IFFCC_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["IFFCC_FAILURE_TOTAL"] + ["CLOCK_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CLOCK_FAILURE", + ["mm"] = 0, + }, -- end of ["CLOCK_FAILURE"] + ["GUN_LEFT_OUT_AMMUN_FAULT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_OUT_AMMUN_FAULT", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_OUT_AMMUN_FAULT"] + ["BOMBS_NO_VOLATAGE_BOTH"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_NO_VOLATAGE_BOTH", + ["mm"] = 0, + }, -- end of ["BOMBS_NO_VOLATAGE_BOTH"] + ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_DAMAGE_ELINKAGE_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] + ["GUN_LEFT_OUT_BARREL_WORN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_OUT_BARREL_WORN", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_OUT_BARREL_WORN"] + ["EXT_HYDRO_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "EXT_HYDRO_LEAK", + ["mm"] = 0, + }, -- end of ["EXT_HYDRO_LEAK"] + ["BOMBS_ARMING_BROKEN_SOLENOID_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_BROKEN_SOLENOID_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_BROKEN_SOLENOID_RIGHT"] + ["DEFECTIVE_INSTRUMENT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "DEFECTIVE_INSTRUMENT", + ["mm"] = 0, + }, -- end of ["DEFECTIVE_INSTRUMENT"] + ["AN_ALR69V_FAILURE_SENSOR_NOSE_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALR69V_FAILURE_SENSOR_NOSE_LEFT", + ["mm"] = 0, + }, -- end of ["AN_ALR69V_FAILURE_SENSOR_NOSE_LEFT"] + ["mlws"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "mlws", + ["mm"] = 0, + }, -- end of ["mlws"] + ["BOMBS_ARMING_NO_VOLATAGE_BOTH"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_NO_VOLATAGE_BOTH", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_BOTH"] + ["BAT_SOLENOID_WIRING"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BAT_SOLENOID_WIRING", + ["mm"] = 0, + }, -- end of ["BAT_SOLENOID_WIRING"] + ["STARTER_LOSE_CON"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "STARTER_LOSE_CON", + ["mm"] = 0, + }, -- end of ["STARTER_LOSE_CON"] + ["FUEL_VALVE_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FUEL_VALVE_LEAK", + ["mm"] = 0, + }, -- end of ["FUEL_VALVE_LEAK"] + ["FLEX_S_NO_GUN_SIGN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FLEX_S_NO_GUN_SIGN", + ["mm"] = 0, + }, -- end of ["FLEX_S_NO_GUN_SIGN"] + ["fuel_sys_right_transfer_pump"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "fuel_sys_right_transfer_pump", + ["mm"] = 0, + }, -- end of ["fuel_sys_right_transfer_pump"] + ["COOLANT_RADIATOR_MOTOR"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_RADIATOR_MOTOR", + ["mm"] = 0, + }, -- end of ["COOLANT_RADIATOR_MOTOR"] + ["CARBAIR_OPEN_CIRCUIT_BLB"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CARBAIR_OPEN_CIRCUIT_BLB", + ["mm"] = 0, + }, -- end of ["CARBAIR_OPEN_CIRCUIT_BLB"] + ["AAR_47_FAILURE_SENSOR_TAIL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AAR_47_FAILURE_SENSOR_TAIL", + ["mm"] = 0, + }, -- end of ["AAR_47_FAILURE_SENSOR_TAIL"] + ["GUN_LEFT_OUT_OPEN_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_OUT_OPEN_CIRCUIT", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_OUT_OPEN_CIRCUIT"] + ["TACAN_FAILURE_TRANSMITTER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TACAN_FAILURE_TRANSMITTER", + ["mm"] = 0, + }, -- end of ["TACAN_FAILURE_TRANSMITTER"] + ["engine_surge_failure"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "engine_surge_failure", + ["mm"] = 0, + }, -- end of ["engine_surge_failure"] + ["l_gen"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "l_gen", + ["mm"] = 0, + }, -- end of ["l_gen"] + ["RIGHT_WING_TANK_LEAK"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "RIGHT_WING_TANK_LEAK", + ["mm"] = 0, + }, -- end of ["RIGHT_WING_TANK_LEAK"] + ["GUN_LEFT_IN_BARREL_WORN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_LEFT_IN_BARREL_WORN", + ["mm"] = 0, + }, -- end of ["GUN_LEFT_IN_BARREL_WORN"] + ["r_gen"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "r_gen", + ["mm"] = 0, + }, -- end of ["r_gen"] + ["l_conv"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "l_conv", + ["mm"] = 0, + }, -- end of ["l_conv"] + ["AAR_47_FAILURE_SENSOR_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AAR_47_FAILURE_SENSOR_RIGHT", + ["mm"] = 0, + }, -- end of ["AAR_47_FAILURE_SENSOR_RIGHT"] + ["ROCKETS_INTERVALOMETER_SEQ"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ROCKETS_INTERVALOMETER_SEQ", + ["mm"] = 0, + }, -- end of ["ROCKETS_INTERVALOMETER_SEQ"] + ["hydro_common"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hydro_common", + ["mm"] = 0, + }, -- end of ["hydro_common"] + ["SAR_2_95"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SAR_2_95", + ["mm"] = 0, + }, -- end of ["SAR_2_95"] + ["SAR_2_101"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "SAR_2_101", + ["mm"] = 0, + }, -- end of ["SAR_2_101"] + ["BOOSTER_COIL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOOSTER_COIL", + ["mm"] = 0, + }, -- end of ["BOOSTER_COIL"] + ["INSUF_FUEL_PRES"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "INSUF_FUEL_PRES", + ["mm"] = 0, + }, -- end of ["INSUF_FUEL_PRES"] + ["FAULTY_ROCKET_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "FAULTY_ROCKET_RIGHT", + ["mm"] = 0, + }, -- end of ["FAULTY_ROCKET_RIGHT"] + ["GUN_RIGHT_IN_OPEN_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_IN_OPEN_CIRCUIT", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_IN_OPEN_CIRCUIT"] + ["COMPASS_ERRATIC_INDIACATON"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COMPASS_ERRATIC_INDIACATON", + ["mm"] = 0, + }, -- end of ["COMPASS_ERRATIC_INDIACATON"] + ["OIL_DILUTION_SOLENOID"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "OIL_DILUTION_SOLENOID", + ["mm"] = 0, + }, -- end of ["OIL_DILUTION_SOLENOID"] + ["PUMP_SEPARATOR_CLOGGED"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "PUMP_SEPARATOR_CLOGGED", + ["mm"] = 0, + }, -- end of ["PUMP_SEPARATOR_CLOGGED"] + ["LEFT_MFCD_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "LEFT_MFCD_FAILURE", + ["mm"] = 0, + }, -- end of ["LEFT_MFCD_FAILURE"] + ["BOMBS_RUST_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_RUST_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_RUST_RIGHT"] + ["CLOGGED_FUEL_STRAINER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "CLOGGED_FUEL_STRAINER", + ["mm"] = 0, + }, -- end of ["CLOGGED_FUEL_STRAINER"] + ["TURNIND_INCORRECT_SENS_VAC_HIGH"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_INCORRECT_SENS_VAC_HIGH", + ["mm"] = 0, + }, -- end of ["TURNIND_INCORRECT_SENS_VAC_HIGH"] + ["r_engine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "r_engine", + ["mm"] = 0, + }, -- end of ["r_engine"] + ["hydro_left"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "hydro_left", + ["mm"] = 0, + }, -- end of ["hydro_left"] + ["A11_CLOCK_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "A11_CLOCK_FAILURE", + ["mm"] = 0, + }, -- end of ["A11_CLOCK_FAILURE"] + ["DOORS_TV_JAMMED"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "DOORS_TV_JAMMED", + ["mm"] = 0, + }, -- end of ["DOORS_TV_JAMMED"] + ["D2_RIGHT_CYLINDER"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "D2_RIGHT_CYLINDER", + ["mm"] = 0, + }, -- end of ["D2_RIGHT_CYLINDER"] + ["UNLOAD_VALVE_NOT_UNLOAD"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "UNLOAD_VALVE_NOT_UNLOAD", + ["mm"] = 0, + }, -- end of ["UNLOAD_VALVE_NOT_UNLOAD"] + ["AN_ALR69V_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AN_ALR69V_FAILURE_TOTAL", + ["mm"] = 0, + }, -- end of ["AN_ALR69V_FAILURE_TOTAL"] + ["GMC_TOTAL_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GMC_TOTAL_FAILURE", + ["mm"] = 0, + }, -- end of ["GMC_TOTAL_FAILURE"] + ["BOMBS_ARMING_BROKEN_SOLENOID_LEFT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_BROKEN_SOLENOID_LEFT", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_BROKEN_SOLENOID_LEFT"] + ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "GUN_RIGHT_OUT_OPEN_CIRCUIT", + ["mm"] = 0, + }, -- end of ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] + ["l_engine"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "l_engine", + ["mm"] = 0, + }, -- end of ["l_engine"] + ["ROOF_AIRSPEED_INDICATOR_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ROOF_AIRSPEED_INDICATOR_FAILURE", + ["mm"] = 0, + }, -- end of ["ROOF_AIRSPEED_INDICATOR_FAILURE"] + ["AAR_47_FAILURE_SENSOR_BOTTOM"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "AAR_47_FAILURE_SENSOR_BOTTOM", + ["mm"] = 0, + }, -- end of ["AAR_47_FAILURE_SENSOR_BOTTOM"] + ["COOLANT_DEFECTIVE_IND"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "COOLANT_DEFECTIVE_IND", + ["mm"] = 0, + }, -- end of ["COOLANT_DEFECTIVE_IND"] + ["ecf"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["mm"] = 0, + }, -- end of ["ecf"] + ["JADRO_1A_FAILURE_TOTAL"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["mm"] = 0, + }, -- end of ["JADRO_1A_FAILURE_TOTAL"] + ["BOMBS_ARMING_NO_VOLATAGE_RIGHT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BOMBS_ARMING_NO_VOLATAGE_RIGHT", + ["mm"] = 0, + }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_RIGHT"] + ["IFFCC_FAILURE_GUN"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "IFFCC_FAILURE_GUN", + ["mm"] = 0, + }, -- end of ["IFFCC_FAILURE_GUN"] + ["APU_Fire"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["mm"] = 0, + }, -- end of ["APU_Fire"] + ["TURNIND_INCORRECT_SENS_DEFECTIVE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "TURNIND_INCORRECT_SENS_DEFECTIVE", + ["mm"] = 0, + }, -- end of ["TURNIND_INCORRECT_SENS_DEFECTIVE"] + }, -- end of ["failures"] +} -- end of mission diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/options b/Test Missions/miz/MOOSE_Escort_Test_Follow/options new file mode 100644 index 000000000..f17fc57c6 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/options @@ -0,0 +1,203 @@ +options = +{ + ["difficulty"] = + { + ["fuel"] = false, + ["labels"] = true, + ["easyRadar"] = false, + ["easyCommunication"] = true, + ["miniHUD"] = false, + ["setGlobal"] = true, + ["birds"] = 0, + ["optionsView"] = "optview_all", + ["permitCrash"] = true, + ["immortal"] = true, + ["avionicsLanguage"] = "native", + ["cockpitVisualRM"] = true, + ["padlock"] = true, + ["reports"] = true, + ["hideStick"] = false, + ["radio"] = true, + ["map"] = true, + ["externalViews"] = true, + ["spectatorExternalViews"] = true, + ["cockpitLanguage"] = "english", + ["tips"] = true, + ["userSnapView"] = true, + ["units"] = "metric", + ["impostors"] = "medium", + ["iconsTheme"] = "nato", + ["easyFlight"] = false, + ["weapons"] = true, + ["cockpitStatusBarAllowed"] = false, + ["geffect"] = "realistic", + }, -- end of ["difficulty"] + ["playerName"] = "Killer", + ["graphics"] = + { + ["OculusRift"] = false, + ["color"] = "32", + ["preloadRadius"] = 150000, + ["heatBlr"] = 1, + ["scenes"] = "high", + ["water"] = 2, + ["visibRange"] = "Medium", + ["treesVisibility"] = 10505, + ["aspect"] = 1.7777777777778, + ["lights"] = 2, + ["HDR"] = 1, + ["MSAA"] = 3, + ["civTraffic"] = "medium", + ["clutterMaxDistance"] = 920, + ["terrainTextures"] = "max", + ["multiMonitorSetup"] = "1camera", + ["shadowTree"] = true, + ["fullScreen"] = false, + ["disableAero"] = false, + ["DOF"] = 0, + ["clouds"] = 1, + ["flatTerrainShadows"] = 0, + ["cockpitShadows"] = true, + ["height"] = 1080, + ["width"] = 1920, + ["shadows"] = 3, + ["textures"] = 2, + ["sync"] = true, + ["LensEffects"] = 3, + ["anisotropy"] = 4, + ["TranspSSAA"] = false, + ["haze"] = 1, + ["effects"] = 3, + }, -- end of ["graphics"] + ["plugins"] = + { + ["CA"] = + { + ["kompass_options"] = 1, + ["ground_target_info"] = true, + ["ground_aim_helper"] = true, + ["ground_platform_shake"] = true, + ["ground_automatic"] = true, + }, -- end of ["CA"] + ["MiG-15bis"] = + { + ["autoLeanToAimMiG15"] = true, + ["CPLocalList"] = "chinese", + ["gunCamera"] = 0, + ["aiHelper"] = false, + }, -- end of ["MiG-15bis"] + ["A-10C"] = + { + ["CPLocalList"] = "default", + }, -- end of ["A-10C"] + ["Ka-50"] = + { + ["altTrimmingMethod"] = false, + ["Ka50RudderTrimmer"] = false, + ["CPLocalList"] = "english", + }, -- end of ["Ka-50"] + ["P-51D"] = + { + ["assistance"] = 100, + ["CPLocalList"] = "default", + ["autoRudder"] = false, + }, -- end of ["P-51D"] + ["MiG-21Bis"] = + { + ["Engine"] = false, + ["CustomCockpit"] = false, + ["Shake"] = 100, + ["Reticle"] = false, + ["Freeze"] = false, + }, -- end of ["MiG-21Bis"] + ["F-86F"] = + { + ["landSeatAdjustF86"] = true, + ["CPLocalList"] = "default", + ["NoseWheelSteeringSimpleBehaviourF86"] = true, + ["gunCamera"] = 0, + }, -- end of ["F-86F"] + ["FC3"] = + { + ["CPLocalList_F-15C"] = "default", + ["CPLocalList_MiG-29S"] = "default", + ["CPLocalList_MiG-29A"] = "default", + ["CPLocalList_Su-25"] = "default", + ["CPLocalList_A-10A"] = "default", + ["CPLocalList_Su-27"] = "chinese", + ["CPLocalList_MiG-29G"] = "default", + ["CPLocalList_Su-33"] = "default", + }, -- end of ["FC3"] + ["Mi-8MTV2"] = + { + ["altMi8TrimmingMethod"] = false, + ["Mi8AutopilotAdjustment"] = false, + ["Mi8RudderTrimmer"] = false, + ["controlHelperMi8"] = false, + ["CPLocalList"] = "default", + ["weapTooltipsMi8"] = true, + ["Mi8FOV"] = 120, + }, -- end of ["Mi-8MTV2"] + ["TF-51D"] = + { + ["assistance"] = 100, + ["CPLocalList"] = "default", + ["autoRudder"] = false, + }, -- end of ["TF-51D"] + ["FW-190D9"] = + { + ["assistance"] = 100, + ["CPLocalList"] = "default", + ["autoRudder"] = false, + }, -- end of ["FW-190D9"] + ["UH-1H"] = + { + ["UHRudderTrimmer"] = false, + ["autoPilot"] = true, + ["altUHTrimmingMethod"] = false, + ["CPLocalList"] = "default", + ["weapTooltips"] = true, + ["UHTrackIRAiming"] = true, + }, -- end of ["UH-1H"] + ["Su-25T"] = + { + ["CPLocalList"] = "default", + }, -- end of ["Su-25T"] + }, -- end of ["plugins"] + ["views"] = + { + ["cockpit"] = + { + ["mirrors"] = false, + ["reflections"] = false, + ["avionics"] = 3, + ["russianHud"] = false, + }, -- end of ["cockpit"] + }, -- end of ["views"] + ["sound"] = + { + ["hear_in_helmet"] = true, + ["headphones"] = -15, + ["cockpit"] = 0, + ["GBreathEffect"] = true, + ["gui"] = 0, + ["volume"] = 0, + ["radioSpeech"] = true, + ["music"] = -100, + ["subtitles"] = true, + ["world"] = 0, + }, -- end of ["sound"] + ["miscellaneous"] = + { + ["headmove"] = true, + ["f5_nearest_ac"] = true, + ["f11_free_camera"] = true, + ["F2_view_effects"] = 2, + ["f10_awacs"] = true, + ["Coordinate_Display"] = "Lat Long", + ["accidental_failures"] = false, + ["force_feedback_enabled"] = true, + ["synchronize_controls"] = false, + ["show_pilot_body"] = true, + }, -- end of ["miscellaneous"] +} -- end of options diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses b/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses new file mode 100644 index 000000000..68ca70eb9 --- /dev/null +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses @@ -0,0 +1,807 @@ +warehouses = +{ + ["airports"] = + { + [12] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [12] + [13] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [13] + [14] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [14] + [15] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [15] + [16] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [16] + [17] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [17] + [18] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [18] + [19] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [19] + [20] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [20] + [21] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [21] + [22] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [22] + [23] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [23] + [24] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [24] + [25] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [25] + [26] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [26] + [27] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [27] + [28] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [28] + [29] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [29] + [30] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [30] + [31] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [31] + [32] = + { + ["gasoline"] = + { + ["InitFuel"] = 100, + }, -- end of ["gasoline"] + ["unlimitedMunitions"] = true, + ["methanol_mixture"] = + { + ["InitFuel"] = 100, + }, -- end of ["methanol_mixture"] + ["OperatingLevel_Air"] = 10, + ["diesel"] = + { + ["InitFuel"] = 100, + }, -- end of ["diesel"] + ["speed"] = 16.666666, + ["size"] = 100, + ["periodicity"] = 30, + ["suppliers"] = + { + }, -- end of ["suppliers"] + ["coalition"] = "NEUTRAL", + ["jet_fuel"] = + { + ["InitFuel"] = 100, + }, -- end of ["jet_fuel"] + ["OperatingLevel_Eqp"] = 10, + ["unlimitedFuel"] = true, + ["aircrafts"] = + { + }, -- end of ["aircrafts"] + ["weapons"] = + { + }, -- end of ["weapons"] + ["OperatingLevel_Fuel"] = 10, + ["unlimitedAircrafts"] = true, + }, -- end of [32] + }, -- end of ["airports"] + ["warehouses"] = + { + }, -- end of ["warehouses"] +} -- end of warehouses From 10fbaa07f5def4e0f3cc394f204ec87bbe4620f9 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 31 Mar 2016 10:41:01 +0200 Subject: [PATCH 13/14] Escort now follows the intersecting point of the sphere around the client. --- Moose/Escort.lua | 20 ++++++++++++++++-- .../miz/MOOSE_Escort_Test_Follow.miz | Bin 40943 -> 40939 bytes 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Moose/Escort.lua b/Moose/Escort.lua index 02527a343..ea9d9d1bc 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -351,8 +351,24 @@ function ESCORT:_FollowScheduler( FollowDistance ) self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) + -- Calculate the group direction vector + local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } + + -- Calculate GH2, GH2 with the same height as CV2. + local GH2 = { x = GV2.x, y = GV2.y, z = CV2.z } + + -- Calculate the angle of GV to the orthonormal plane + local alpha = math.atan2( GV.y, GV.x ) + + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. + -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(CV2) + FollowDistance sin(alpha), z(GH2)) + local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), + y = CV2.y + FollowDistance * math.sin(alpha), + z = GH2.z + } + -- Measure distance between client and group - local CatchUpDistance = ( ( CV2.x - GV2.x )^2 + ( CV2.y - GV2.y )^2 + ( CV2.z - GV2.z )^2 ) ^ 0.5 + local CatchUpDistance = ( ( CVI.x - GV2.x )^2 + ( CVI.y - GV2.y )^2 + ( CVI.z - GV2.z )^2 ) ^ 0.5 local Distance = CatchUpDistance - FollowDistance -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome @@ -378,7 +394,7 @@ function ESCORT:_FollowScheduler( FollowDistance ) self:T( { "Client Speed, Client Time, Escort Speed, Speed, CatchUpSpeed, BreakSpeed, Distance, Time:", CS, CT, GS, Speed, CatchUpSpeed, BreakSpeed, Distance, Time } ) -- Now route the escort to the desired point with the desired speed. - self.EscortGroup:TaskRouteToVec3( CV2, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) + self.EscortGroup:TaskRouteToVec3( CVI, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) end else routines.removeFunction( self.FollowScheduler ) diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow.miz b/Test Missions/miz/MOOSE_Escort_Test_Follow.miz index e62ab61013e7f573c1cd360d736031ac24bcdb93..a7692717ed46e8caa4692233c582b2591bf28113 100644 GIT binary patch delta 13254 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 From b8c10c2f41a4b4622f91d9b5506535128f4d3039 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 1 Apr 2016 17:27:28 +0200 Subject: [PATCH 14/14] A working escort function for helicopters, first version --- Embedded/Moose_Embedded.lua | 36 +- Moose/Base.lua | 5 +- Moose/Client.lua | 21 +- Moose/Escort.lua | 268 ++++-- Moose/Group.lua | 112 ++- .../miz/MOOSE_Escort_Test_Follow.miz | Bin 40939 -> 40198 bytes .../l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua | 17 +- .../l10n/DEFAULT/dictionary | 22 +- .../miz/MOOSE_Escort_Test_Follow/mission | 800 ++++++++++++------ .../miz/MOOSE_Escort_Test_Follow/warehouses | 2 +- 10 files changed, 881 insertions(+), 402 deletions(-) diff --git a/Embedded/Moose_Embedded.lua b/Embedded/Moose_Embedded.lua index 721e46db9..0993bef6d 100644 --- a/Embedded/Moose_Embedded.lua +++ b/Embedded/Moose_Embedded.lua @@ -3683,7 +3683,7 @@ end --- Holding weapons. -- @param self -- @return #GROUP self -function GROUP:HoldFire() +function GROUP:OptionROEHoldFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3695,7 +3695,7 @@ end --- Return fire. -- @param self -- @return #GROUP self -function GROUP:ReturnFire() +function GROUP:OptionROEReturnFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3707,7 +3707,7 @@ end --- Openfire. -- @param self -- @return #GROUP self -function GROUP:OpenFire() +function GROUP:OptionROEOpenFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3719,7 +3719,7 @@ end --- Weapon free. -- @param self -- @return #GROUP self -function GROUP:WeaponFree() +function GROUP:OptionROEWeaponFree() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3731,7 +3731,7 @@ end --- No evasion on enemy threats. -- @param self -- @return #GROUP self -function GROUP:EvasionNoReaction() +function GROUP:OptionEvasionNoReaction() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3743,7 +3743,7 @@ end --- Evasion passive defense. -- @param self -- @return #GROUP self -function GROUP:EvasionPassiveDefense() +function GROUP:OptionROTPassiveDefense() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3755,7 +3755,7 @@ end --- Evade fire. -- @param self -- @return #GROUP self -function GROUP:EvasionEvadeFire() +function GROUP:OptionROTEvadeFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -3767,7 +3767,7 @@ end --- Vertical manoeuvres. -- @param self -- @return #GROUP self -function GROUP:EvasionVertical() +function GROUP:OptionROTVertical() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -11167,7 +11167,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) - self.EscortMenuEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._OptionEvasionVertical, { ParamSelf = self, } ) self.ScanForTargetsFunction = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) @@ -11194,49 +11194,49 @@ end function ESCORT._ROEHoldFire( MenuParam ) - MenuParam.ParamSelf.EscortGroup:HoldFire() + MenuParam.ParamSelf.EscortGroup:OptionROEHoldFire() MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._ROEReturnFire( MenuParam ) - MenuParam.ParamSelf.EscortGroup:ReturnFire() + MenuParam.ParamSelf.EscortGroup:OptionROEReturnFire() MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._ROEOpenFire( MenuParam ) - MenuParam.ParamSelf.EscortGroup:OpenFire() + MenuParam.ParamSelf.EscortGroup:OptionROEOpenFire() MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._ROEWeaponFree( MenuParam ) - MenuParam.ParamSelf.EscortGroup:WeaponFree() + MenuParam.ParamSelf.EscortGroup:OptionROEWeaponFree() MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._EvasionNoReaction( MenuParam ) - MenuParam.ParamSelf.EscortGroup:EvasionNoReaction() + MenuParam.ParamSelf.EscortGroup:OptionEvasionNoReaction() MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._EvasionPassiveDefense( MenuParam ) - MenuParam.ParamSelf.EscortGroup:EvasionPassiveDefense() + MenuParam.ParamSelf.EscortGroup:OptionROTPassiveDefense() MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end function ESCORT._EvasionEvadeFire( MenuParam ) - MenuParam.ParamSelf.EscortGroup:EvasionEvadeFire() + MenuParam.ParamSelf.EscortGroup:OptionROTEvadeFire() MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end -function ESCORT._EvasionVertical( MenuParam ) +function ESCORT._OptionEvasionVertical( MenuParam ) - MenuParam.ParamSelf.EscortGroup:EvasionVertical() + MenuParam.ParamSelf.EscortGroup:OptionROTVertical() MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackUnit" ):ToClient( MenuParam.ParamSelf.EscortClient ) end diff --git a/Moose/Base.lua b/Moose/Base.lua index 80f3f50e6..268156f5c 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -16,7 +16,7 @@ local _TraceClass = { --ZONE = true, --GROUP = true, --UNIT = true, - --CLIENT = true, + --CLIENT = true, --CARGO = true, --CARGO_GROUP = true, --CARGO_PACKAGE = true, @@ -25,7 +25,7 @@ local _TraceClass = { --CLEANUP = true, --MENU_CLIENT = true, --MENU_CLIENT_COMMAND = true, - ESCORT = true, + --ESCORT = true, } --- The BASE Class @@ -256,6 +256,7 @@ end -- Trace section -- Log a trace (only shown when trace is on) +-- TODO: Make trace function using variable parameters. function BASE:F( Arguments ) diff --git a/Moose/Client.lua b/Moose/Client.lua index ca8a03f21..d91618860 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -71,35 +71,44 @@ end function CLIENT:Alive( CallBack ) self:F() - self.ClientAlive = false + self.ClientAlive2 = false self.ClientCallBack = CallBack - self.AliveCheckFunction = routines.scheduleFunction( self._AliveCheckCallBack, { self }, timer.getTime() + 1, 1 ) + self.AliveCheckFunction = routines.scheduleFunction( self._AliveCheckCallBack, { self }, timer.getTime() + 1, 5 ) + + return self end --- Checks if client is alive and returns true or false. -- @param #CLIENT self -- @param #boolean Returns true if client is alive. function CLIENT:IsAlive() - self:F() + self:F( self.ClientName ) local ClientDCSGroup = self:GetDCSGroup() if ClientDCSGroup then + self:T("true") return true end + self:T( "false" ) return false end --- @param #CLIENT self function CLIENT:_AliveCheckCallBack() + self:F( { self.ClientName, self.ClientAlive2 } ) if self:IsAlive() then - if self.ClientAlive == false then + if self.ClientAlive2 == false then + self:T("Calling Callback function") self.ClientCallBack( self ) - self.ClientAlive = true - routines.removeFunction( self.AliveCheckFunction ) + self.ClientAlive2 = true + end + else + if self.ClientAlive2 == true then + self.ClientAlive2 = false end end end diff --git a/Moose/Escort.lua b/Moose/Escort.lua index ea9d9d1bc..71c76ea3b 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -8,7 +8,7 @@ -- * Report identified targets -- * Perform tasks per identified target: Report vector to target, paint target, kill target -- --- @module ESCORT +-- @module Escort -- @author FlightControl Include.File( "Routines" ) @@ -24,6 +24,9 @@ Include.File( "Zone" ) -- @field Group#GROUP EscortGroup -- @field #string EscortName -- @field #number FollowScheduler The id of the _FollowScheduler function. +-- @field #boolean ReportTargets If true, nearby targets are reported. +-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. +-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. ESCORT = { ClassName = "ESCORT", EscortName = nil, -- The Escort Name @@ -31,6 +34,9 @@ ESCORT = { EscortGroup = nil, Targets = {}, -- The identified targets FollowScheduler = nil, + ReportTargets = true, + OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE, + OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION } --- MENUPARAM type @@ -48,10 +54,9 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) local self = BASE:Inherit( self, BASE:New() ) self:F( { EscortClient, EscortGroup, EscortName } ) - self.EscortClient = EscortClient - self.EscortGroup = EscortGroup + self.EscortClient = EscortClient -- Client#CLIENT + self.EscortGroup = EscortGroup -- Group#GROUP self.EscortName = EscortName - self.ReportTargets = true self.EscortMenu = MENU_CLIENT:New( self.EscortClient, "Escort" .. self.EscortName ) @@ -88,25 +93,39 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName ) -- Reaction to Threats self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) - self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._EvasionNoReaction, { ParamSelf = self, } ) - self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._EvasionPassiveDefense, { ParamSelf = self, } ) - self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._EvasionEvadeFire, { ParamSelf = self, } ) - self.EscortMenuEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._EvasionVertical, { ParamSelf = self, } ) + self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._OptionROTNoReaction, { ParamSelf = self, } ) + self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._OptionROTPassiveDefense, { ParamSelf = self, } ) + self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._OptionROTEvadeFire, { ParamSelf = self, } ) + self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._OptionROTVertical, { ParamSelf = self, } ) -- Cancel current Task - self.EscortMenuCancelTask = MENU_CLIENT_COMMAND:New( self.EscortClient, "Cancel current task", self.EscortMenu, ESCORT._CancelCurrentTask, { ParamSelf = self, } ) + self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume Mission", self.EscortMenu ) + self.EscortMenuResumeWayPoints = {} + local TaskPoints = self:RegisterRoute() + for WayPointID, WayPoint in pairs( TaskPoints ) do + self.EscortMenuResumeWayPoints[WayPointID] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Resume from waypoint " .. WayPointID, self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } ) + end + -- Initialize the EscortGroup - self.ScanForTargetsScheduler = routines.scheduleFunction( self._ScanForTargets, { self }, timer.getTime() + 1, 30 ) + self.EscortGroup:OptionROTVertical() + self.EscortGroup:OptionROEOpenFire() + + self.EscortGroup:PushTask( EscortGroup:TaskRoute( TaskPoints ) ) + + self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) end --- @param #MENUPARAM MenuParam function ESCORT._HoldPosition( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + routines.removeFunction( self.FollowScheduler ) + EscortGroup:PushTask( EscortGroup:TaskHoldPosition( 300 ) ) MESSAGE:New( "Holding Position at ... for 5 minutes.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/TaskHoldPosition" ):ToClient( EscortClient ) end @@ -114,10 +133,13 @@ end --- @param #MENUPARAM MenuParam function ESCORT._HoldPositionNearBy( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient --MenuParam.ParamSelf.EscortGroup:TaskOrbitCircleAtVec2( MenuParam.ParamSelf.EscortClient:GetPointVec2(), 300, 30, 0 ) + + routines.removeFunction( self.FollowScheduler ) local PointFrom = {} local GroupPoint = EscortGroup:GetPointVec2() @@ -141,8 +163,7 @@ function ESCORT._HoldPositionNearBy( MenuParam ) local Points = { PointFrom, PointTo } - - EscortGroup:PushTask( EscortGroup:TaskMission( Points ) ) + EscortGroup:PushTask( EscortGroup:TaskRoute( Points ) ) MESSAGE:New( "Rejoining to your location. Please hold at your location.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/HoldPositionNearBy" ):ToClient( EscortClient ) end @@ -150,8 +171,8 @@ end function ESCORT._JoinUpAndFollow( MenuParam ) local self = MenuParam.ParamSelf - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient local Distance = MenuParam.ParamDistance @@ -167,18 +188,32 @@ end function ESCORT._ReportNearbyTargets( MenuParam ) - MenuParam.ParamSelf:T() - - MenuParam.ParamSelf.ReportTargets = MenuParam.ParamReportTargets + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + self.ReportTargets = MenuParam.ParamReportTargets + + if self.ReportTargets then + if not self.ReportTargetsScheduler then + self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) + end + else + routines.removeFunction( self.ReportTargetsScheduler ) + self.ReportTargetsScheduler = nil + end end --- @param #MENUPARAM MenuParam function ESCORT._ScanTargets30Seconds( MenuParam ) MenuParam.ParamSelf:T() - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + routines.removeFunction( self.FollowScheduler ) EscortGroup:PushTask( EscortGroup:TaskControlled( @@ -193,8 +228,11 @@ end function ESCORT._ScanTargets60Seconds( MenuParam ) MenuParam.ParamSelf:T() - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + routines.removeFunction( self.FollowScheduler ) EscortGroup:PushTask( EscortGroup:TaskControlled( @@ -208,12 +246,16 @@ end --- @param #MENUPARAM MenuParam function ESCORT._AttackTarget( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient local AttackUnit = MenuParam.ParamUnit - - EscortGroup:OpenFire() - EscortGroup:EvasionVertical() + + routines.removeFunction( self.FollowScheduler ) + self.FollowScheduler = nil + + EscortGroup:OptionROEOpenFire() + EscortGroup:OptionROTVertical() EscortGroup:PushTask( EscortGroup:TaskAttackUnit( AttackUnit ) ) MESSAGE:New( "Attacking Unit", MenuParam.ParamSelf.EscortName, 10, "ESCORT/AttackTarget" ):ToClient( EscortClient ) end @@ -221,91 +263,131 @@ end --- @param #MENUPARAM MenuParam function ESCORT._ROEHoldFire( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:HoldFire() + EscortGroup:OptionROEHoldFire() MESSAGE:New( "Holding weapons.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEHoldFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam function ESCORT._ROEReturnFire( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:ReturnFire() + EscortGroup:OptionROEReturnFire() MESSAGE:New( "Returning enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEReturnFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam function ESCORT._ROEOpenFire( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:OpenFire() + EscortGroup:OptionROEOpenFire() MESSAGE:New( "Open fire on ordered targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEOpenFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam function ESCORT._ROEWeaponFree( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:WeaponFree() + EscortGroup:OptionROEWeaponFree() MESSAGE:New( "Engaging targets.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ROEWeaponFree" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam -function ESCORT._EvasionNoReaction( MenuParam ) +function ESCORT._OptionROTNoReaction( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:EvasionNoReaction() - MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionNoReaction" ):ToClient( EscortClient ) + EscortGroup:OptionEvasionNoReaction() + MESSAGE:New( "We'll fight until death.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/OptionEvasionNoReaction" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam -function ESCORT._EvasionPassiveDefense( MenuParam ) +function ESCORT._OptionROTPassiveDefense( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:EvasionPassiveDefense() - MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionPassiveDefense" ):ToClient( EscortClient ) + EscortGroup:OptionROTPassiveDefense() + MESSAGE:New( "We will use flares, chaff and jammers.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/OptionROTPassiveDefense" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam -function ESCORT._EvasionEvadeFire( MenuParam ) +function ESCORT._OptionROTEvadeFire( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:EvasionEvadeFire() - MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionEvadeFire" ):ToClient( EscortClient ) + EscortGroup:OptionROTEvadeFire() + MESSAGE:New( "We'll evade enemy fire.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/OptionROTEvadeFire" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam -function ESCORT._EvasionVertical( MenuParam ) +function ESCORT._OptionROTVertical( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient - EscortGroup:EvasionVertical() - MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/EvasionVertical" ):ToClient( EscortClient ) + EscortGroup:OptionROTVertical() + MESSAGE:New( "We'll perform vertical evasive manoeuvres.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/OptionROTVertical" ):ToClient( EscortClient ) end --- @param #MENUPARAM MenuParam -function ESCORT._CancelCurrentTask( MenuParam ) +function ESCORT._ResumeMission( MenuParam ) - local EscortGroup = MenuParam.ParamSelf.EscortGroup - local EscortClient = MenuParam.ParamSelf.EscortClient + local self = MenuParam.ParamSelf + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + local WayPoint = MenuParam.ParamWayPoint + + routines.removeFunction( self.FollowScheduler ) + self.FollowScheduler = nil + local WayPoints = EscortGroup:GetTaskRoute() + self:T( WayPoint, WayPoints ) + + for WayPointIgnore = 1, WayPoint do + table.remove( WayPoints, 1 ) + end + EscortGroup:PopCurrentTask() - MESSAGE:New( "Cancelling with current orders, continuing our mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/CancelCurrentTask" ):ToClient( EscortClient ) + EscortGroup:PushTask( EscortGroup:TaskRoute( WayPoints ) ) + MESSAGE:New( "Resuming mission.", MenuParam.ParamSelf.EscortName, 10, "ESCORT/ResumeMission" ):ToClient( EscortClient ) +end + +function ESCORT:RegisterRoute() + + local EscortGroup = self.EscortGroup -- Group#GROUP + + local TaskPoints = EscortGroup:GetTaskRoute() + self:T( TaskPoints ) + + for TaskPointID, TaskPoint in pairs( TaskPoints ) do + self:T( TaskPointID ) + TaskPoint.task.params.tasks[#TaskPoint.task.params.tasks+1] = EscortGroup:TaskRegisterWayPoint( TaskPointID ) + self:T( TaskPoint.task.params.tasks[#TaskPoint.task.params.tasks] ) + end + + self:T( TaskPoints ) + + return TaskPoints end --- @param Escort#ESCORT self @@ -355,46 +437,49 @@ function ESCORT:_FollowScheduler( FollowDistance ) local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } -- Calculate GH2, GH2 with the same height as CV2. - local GH2 = { x = GV2.x, y = GV2.y, z = CV2.z } + local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } -- Calculate the angle of GV to the orthonormal plane - local alpha = math.atan2( GV.y, GV.x ) + local alpha = math.atan2( GV.z, GV.x ) -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. - -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(CV2) + FollowDistance sin(alpha), z(GH2)) + -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), - y = CV2.y + FollowDistance * math.sin(alpha), - z = GH2.z - } + y = GH2.y, + z = CV2.z + FollowDistance * math.sin(alpha), + } + + -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. + local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } + + -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. + -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. + -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... + local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } + + -- Now we can calculate the group destination vector GDV. + local GDV = { x = DVu.x * CS * 2 + CVI.x, y = CVI.y, z = DVu.z * CS * 2 + CVI.z } + self:T2( { "CV2:", CV2 } ) + self:T2( { "CVI:", CVI } ) + self:T2( { "GDV:", GDV } ) -- Measure distance between client and group - local CatchUpDistance = ( ( CVI.x - GV2.x )^2 + ( CVI.y - GV2.y )^2 + ( CVI.z - GV2.z )^2 ) ^ 0.5 - local Distance = CatchUpDistance - FollowDistance + local CatchUpDistance = ( ( GDV.x - GV2.x )^2 + ( GDV.y - GV2.y )^2 + ( GDV.z - GV2.z )^2 ) ^ 0.5 -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome -- the requested Distance). - local Time = 1600 / FollowDistance - local CatchUpSpeed = ( Distance / Time ) * ( CatchUpDistance / 1000 ) - - -- Follow speed required = Client Speed - Group Speed + Speed to overcome distance. - local BreakSpeed = ( GS * ( ( 1 ) / Distance ) ) - if BreakSpeed < 0 then - BreakSpeed = 0 - end + local Time = 30 + local CatchUpSpeed = ( CatchUpDistance - ( CS * 2 ) ) / Time - if BreakSpeed > CS then - BreakSpeed = CS - end - - local Speed = CS + CatchUpSpeed --- - BreakSpeed + local Speed = CS + CatchUpSpeed if Speed < 0 then Speed = 0 end - self:T( { "Client Speed, Client Time, Escort Speed, Speed, CatchUpSpeed, BreakSpeed, Distance, Time:", CS, CT, GS, Speed, CatchUpSpeed, BreakSpeed, Distance, Time } ) + self:T( { "Client Speed, Escort Speed, Speed, FlyDistance, Time:", CS, GS, Speed, Distance, Time } ) -- Now route the escort to the desired point with the desired speed. - self.EscortGroup:TaskRouteToVec3( CVI, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) + self.EscortGroup:TaskRouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) end else routines.removeFunction( self.FollowScheduler ) @@ -403,7 +488,7 @@ function ESCORT:_FollowScheduler( FollowDistance ) end -function ESCORT:_ScanForTargets() +function ESCORT:_ReportTargetsScheduler() self:F() self.Targets = {} @@ -511,6 +596,7 @@ function ESCORT:_ScanForTargets() end else - routines.removeFunction( self.ScanForTargetsScheduler ) + routines.removeFunction( self.ReportTargetsScheduler ) + self.ReportTargetsScheduler = nil end end diff --git a/Moose/Group.lua b/Moose/Group.lua index 7754f9e01..98399764c 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -26,7 +26,8 @@ GROUP = { -- @type DCSGroup -- @field id_ The ID of the group in DCS -GROUPS = {} +--- The GROUPS structure contains references to all the created GROUP instances. +local GROUPS = {} --- Create a new GROUP from a DCSGroup -- @param self @@ -44,6 +45,8 @@ function GROUP:New( DCSGroup ) else self:E( { "DCSGroup is nil or does not exist, cannot initialize GROUP!", self.DCSGroup } ) end + + GROUPS[self.GroupID] = self return self end @@ -64,6 +67,8 @@ function GROUP:NewFromName( GroupName ) self.Controller = self.DCSGroup:getController() end + GROUPS[self.GroupID] = self + return self end @@ -82,6 +87,8 @@ function GROUP:NewFromDCSUnit( DCSUnit ) self.Controller = self.DCSGroup:getController() end + GROUPS[self.GroupID] = self + return self end @@ -556,13 +563,27 @@ function GROUP:TaskEmbarkToTransportAtVec2( Point, Radius ) return DCSTask end ---- Return a Misson task to follow a given route. +--- Return a Misson task from a mission template. -- @param #GROUP self --- @param #table Points A table of Route Points. +-- @param #table TaskMission A table containing the mission task. -- @return #DCSTask -function GROUP:TaskMission( Points ) +function GROUP:TaskMission( TaskMission ) self:F( Points ) + local DCSTask + DCSTask = { id = 'Mission', params = { TaskMission, }, } + + self:T( { DCSTask } ) + return DCSTask +end + +--- Return a Misson task to follow a given route defined by Points. +-- @param #GROUP self +-- @param #table Points A table of route points. +-- @return #DCSTask +function GROUP:TaskRoute( Points ) + self:F( Points ) + local DCSTask DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } @@ -622,6 +643,33 @@ function GROUP:Route( GoPoints ) return self end +function GROUP:TaskRegisterWayPoint( WayPoint ) + + local DCSTask + + DCSTask = { id = "WrappedAction", + enabled = true, + auto = false, + number = 1, + params = + { + action = + { + id = "Script", + params = + { + command = "local MissionGroup = GROUP.FindGroup( ... ) " .. + "env.info( MissionGroup:GetName() ) " .. + "MissionGroup:RegisterWayPoint ( " .. WayPoint .. " )", + }, -- end of ["params"] + }, -- end of ["action"] + }, -- end of ["params"] + } + self:T( DCSTask ) + + return DCSTask +end + --- Route the group to a given zone. -- The group final destination point can be randomized. -- A speed can be given in km/h. @@ -678,6 +726,24 @@ function GROUP:TaskRouteToZone( Zone, Randomize, Speed, Formation ) return self end +--- Return the mission template of the group. +-- @param #GROUP self +-- @return #table The MissionTemplate +function GROUP:GetTaskMission() + self:F( self.GroupName ) + + return _Database.Groups[self.GroupName].Template +end + +--- Return the mission route of the group. +-- @param #GROUP self +-- @return #table The mission route defined by points. +function GROUP:GetTaskRoute() + self:F( self.GroupName ) + + return _Database.Groups[self.GroupName].Template.route.points +end + --- Return the route of a group by using the @{Database#DATABASE} class. -- @param #GROUP self -- @param #number Begin The route point from where the copy will start. The base route point is 0. @@ -757,7 +823,7 @@ end --- Holding weapons. -- @param #GROUP self -- @return #GROUP self -function GROUP:HoldFire() +function GROUP:OptionROEHoldFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -769,7 +835,7 @@ end --- Return fire. -- @param #GROUP self -- @return #GROUP self -function GROUP:ReturnFire() +function GROUP:OptionROEReturnFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -781,7 +847,7 @@ end --- Openfire. -- @param #GROUP self -- @return #GROUP self -function GROUP:OpenFire() +function GROUP:OptionROEOpenFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -793,7 +859,7 @@ end --- Weapon free. -- @param #GROUP self -- @return #GROUP self -function GROUP:WeaponFree() +function GROUP:OptionROEWeaponFree() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -805,7 +871,7 @@ end --- No evasion on enemy threats. -- @param #GROUP self -- @return #GROUP self -function GROUP:EvasionNoReaction() +function GROUP:OptionEvasionNoReaction() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -817,7 +883,7 @@ end --- Evasion passive defense. -- @param #GROUP self -- @return #GROUP self -function GROUP:EvasionPassiveDefense() +function GROUP:OptionROTPassiveDefense() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -829,7 +895,7 @@ end --- Evade fire. -- @param #GROUP self -- @return #GROUP self -function GROUP:EvasionEvadeFire() +function GROUP:OptionROTEvadeFire() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -841,7 +907,7 @@ end --- Vertical manoeuvres. -- @param #GROUP self -- @return #GROUP self -function GROUP:EvasionVertical() +function GROUP:OptionROTVertical() self:F( { self.GroupName } ) local Controller = self:_GetController() @@ -908,3 +974,25 @@ function GROUP:MessageToClient( Message, Duration, Client ) self:Message( Message, Duration ):ToClient( Client ) end +function GROUP:RegisterWayPoint( WayPoint ) + + self:Message( "Moving over wayPoint " .. WayPoint, 20 ):ToAll() + self.WayPoint = WayPoint +end + + + + +--- Find the created GROUP using the DCSGroup ID. If a GROUP was created with the DCSGroupID, the the GROUP instance will be returned. +-- Otherwise nil will be returned. +-- @param DCSGroup#Group Group +-- @return #GROUP +function GROUP.FindGroup( DCSGroup ) + + local self = GROUPS[DCSGroup:getID()] -- Group#GROUP + self:T( self:GetClassNameAndID() ) + return self + +end + + diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow.miz b/Test Missions/miz/MOOSE_Escort_Test_Follow.miz index a7692717ed46e8caa4692233c582b2591bf28113..9c73feb6297b46e5cc3729416100f9c18d24e758 100644 GIT binary patch delta 36808 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 M$Uz|6yrbU#06UA~WB>pF diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua index e6aaa973d..5bcce439c 100644 --- a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/MOOSE_Escort_Test_Follow.lua @@ -1,18 +1,27 @@ Include.File( "Mission" ) Include.File( "Client" ) +Include.File( "Spawn" ) Include.File( "Escort" ) do local function EventAliveHelicopter( Client ) - local EscortGroupHeli = GROUP:NewFromName( "Escort Helicopter" ) - local EscortHeli = ESCORT:New( Client, EscortGroupHeli, "Escort Test Helicopter" ) + local SpawnEscortHeli = SPAWN:New( "Escort Helicopter" ) + local EscortGroupHeli1 = SpawnEscortHeli:Spawn() + local EscortGroupHeli2 = SpawnEscortHeli:Spawn() + local EscortGroupHeli3 = SpawnEscortHeli:Spawn() + local EscortGroupHeli4 = SpawnEscortHeli:Spawn() + local EscortHeli1 = ESCORT:New( Client, EscortGroupHeli1, "Escort Alpha" ) + local EscortHeli2 = ESCORT:New( Client, EscortGroupHeli2, "Escort Bravo" ) + local EscortHeli3 = ESCORT:New( Client, EscortGroupHeli3, "Escort Delta" ) + local EscortHeli4 = ESCORT:New( Client, EscortGroupHeli4, "Escort Gamma" ) end local function EventAlivePlane( Client ) - local EscortGroupPlane = GROUP:NewFromName( "Escort Plane" ) - local EscortPlane = ESCORT:New( EscortClientPlane, EscortGroupPlane, "Escort Test Plane" ) + local SpawnEscortPlane = SPAWN:New( "Escort Plane" ) + local EscortGroupPlane = SpawnEscortPlane:Spawn() + local EscortPlane = ESCORT:New( Client, EscortGroupPlane, "Escort Test Plane" ) end local EscortClientHeli = CLIENT:New( "Lead Helicopter", "Fly around and observe the behaviour of the escort helicopter" ):Alive( EventAliveHelicopter ) diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary index a731c15a0..50ee177b8 100644 --- a/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/l10n/DEFAULT/dictionary @@ -3,23 +3,31 @@ dictionary = ["DictKey_GroupName_19"] = "Escort Plane", ["DictKey_WptName_11"] = "", ["DictKey_UnitName_20"] = "Escort Plane", - ["DictKey_GroupName_15"] = "Lead Plane", + ["DictKey_GroupName_12"] = "Escort Helicopter", + ["DictKey_WptName_30"] = "", ["DictKey_sortie_4"] = "", + ["DictKey_WptName_28"] = "", + ["DictKey_WptName_14"] = "", + ["DictKey_WptName_29"] = "", ["DictKey_WptName_23"] = "", + ["DictKey_GroupName_15"] = "Lead Plane", ["DictKey_descriptionRedTask_2"] = "", - ["DictKey_descriptionBlueTask_3"] = "", ["DictKey_GroupName_9"] = "Lead Helicopter", + ["DictKey_GroupName_31"] = "Test Attack", ["DictKey_descriptionText_1"] = "", - ["DictKey_UnitName_10"] = "Lead Helicopter", + ["DictKey_UnitName_13"] = "Escort Helicopter", + ["DictKey_UnitName_32"] = "Unit #1", + ["DictKey_WptName_21"] = "", + ["DictKey_descriptionBlueTask_3"] = "", ["DictKey_WptName_22"] = "", ["DictKey_WptName_18"] = "", - ["DictKey_WptName_14"] = "", + ["DictKey_UnitName_10"] = "Lead Helicopter", ["DictKey_WptName_17"] = "", - ["DictKey_UnitName_13"] = "Escort Helicopter", + ["DictKey_WptName_33"] = "", ["DictKey_WptName_26"] = "", ["DictKey_WptName_25"] = "", ["DictKey_UnitName_16"] = "Lead Plane", - ["DictKey_WptName_21"] = "", ["DictKey_WptName_24"] = "", - ["DictKey_GroupName_12"] = "Escort Helicopter", + ["DictKey_WptName_34"] = "", + ["DictKey_WptName_27"] = "", } -- end of dictionary diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/mission b/Test Missions/miz/MOOSE_Escort_Test_Follow/mission index 6c1f6e2bf..25ec48b82 100644 --- a/Test Missions/miz/MOOSE_Escort_Test_Follow/mission +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/mission @@ -83,7 +83,7 @@ mission = }, -- end of ["func"] }, -- end of ["red"] }, -- end of ["result"] - ["maxDictId"] = 26, + ["maxDictId"] = 34, ["groundControl"] = { ["isPilotControlVehicles"] = false, @@ -222,9 +222,9 @@ mission = }, -- end of ["needModules"] ["map"] = { - ["centerY"] = 633185.71428572, - ["zoom"] = 50000, - ["centerX"] = -286145.14285714, + ["centerY"] = 649668.57142857, + ["zoom"] = 100000, + ["centerX"] = -285813.71428571, }, -- end of ["map"] ["coalitions"] = { @@ -302,7 +302,6 @@ mission = { }, -- end of ["rules"] ["eventlist"] = "", - ["predicate"] = "triggerOnce", ["actions"] = { [1] = @@ -316,6 +315,7 @@ mission = }, -- end of ["ai_task"] }, -- end of [1] }, -- end of ["actions"] + ["predicate"] = "triggerOnce", ["comment"] = "MOOSE Load Method", }, -- end of [1] [2] = @@ -331,7 +331,6 @@ mission = }, -- end of [1] }, -- end of ["rules"] ["eventlist"] = "", - ["predicate"] = "triggerOnce", ["actions"] = { [1] = @@ -345,6 +344,7 @@ mission = }, -- end of ["ai_task"] }, -- end of [1] }, -- end of ["actions"] + ["predicate"] = "triggerOnce", ["comment"] = "MOOSE Load Dynamic", }, -- end of [2] [3] = @@ -360,7 +360,6 @@ mission = }, -- end of [1] }, -- end of ["rules"] ["eventlist"] = "", - ["predicate"] = "triggerOnce", ["actions"] = { [1] = @@ -374,6 +373,7 @@ mission = }, -- end of ["ai_task"] }, -- end of [1] }, -- end of ["actions"] + ["predicate"] = "triggerOnce", ["comment"] = "MOOSE Load Embedded", }, -- end of [3] [4] = @@ -382,7 +382,6 @@ mission = { }, -- end of ["rules"] ["eventlist"] = "", - ["predicate"] = "triggerOnce", ["actions"] = { [1] = @@ -396,6 +395,7 @@ mission = }, -- end of ["ai_task"] }, -- end of [1] }, -- end of ["actions"] + ["predicate"] = "triggerOnce", ["comment"] = "MOOSE Load Mission", }, -- end of [4] }, -- end of ["trigrules"] @@ -603,7 +603,7 @@ mission = }, -- end of [1] [2] = { - ["lateActivation"] = false, + ["lateActivation"] = true, ["tasks"] = { }, -- end of ["tasks"] @@ -612,7 +612,7 @@ mission = ["uncontrolled"] = false, ["route"] = { - ["routeRelativeTOT"] = false, + ["routeRelativeTOT"] = true, ["points"] = { [1] = @@ -643,24 +643,6 @@ mission = { ["tasks"] = { - [1] = - { - ["number"] = 1, - ["key"] = "CAS", - ["id"] = "EngageTargets", - ["enabled"] = true, - ["auto"] = true, - ["params"] = - { - ["targetTypes"] = - { - [1] = "Helicopters", - [2] = "Ground Units", - [3] = "Light armed ships", - }, -- end of ["targetTypes"] - ["priority"] = 0, - }, -- end of ["params"] - }, -- end of [1] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] @@ -681,9 +663,9 @@ mission = ["vangle"] = 0, ["steer"] = 2, }, -- end of ["properties"] - ["ETA"] = 23.784032372968, - ["y"] = 631664.28571429, - ["x"] = -285595.14285714, + ["ETA"] = 48.824518671544, + ["y"] = 634468.57142857, + ["x"] = -283642.28571428, ["name"] = "DictKey_WptName_22", ["speed"] = 138.88888888889, ["ETA_locked"] = false, @@ -714,13 +696,66 @@ mission = ["vangle"] = 0, ["steer"] = 2, }, -- end of ["properties"] - ["ETA"] = 37.530380607896, - ["y"] = 633007.14285715, - ["x"] = -284238, + ["ETA"] = 231.0526539667, + ["y"] = 659754.28571428, + ["x"] = -284642.28571428, ["name"] = "DictKey_WptName_23", ["speed"] = 138.88888888889, ["ETA_locked"] = false, ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["number"] = 1, + ["auto"] = false, + ["id"] = "WrappedAction", + ["enabled"] = true, + ["params"] = + { + ["action"] = + { + ["id"] = "SwitchWaypoint", + ["params"] = + { + ["goToWaypointIndex"] = 2, + ["fromWaypointIndex"] = 3, + }, -- end of ["params"] + }, -- end of ["action"] + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [3] + [4] = + { + ["alt"] = 13, + ["type"] = "Land", + ["action"] = "Landing", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 322.67941016458, + ["airdromeId"] = 23, + ["y"] = 647369.87369832, + ["x"] = -281713.83114196, + ["name"] = "DictKey_WptName_34", + ["speed"] = 138.88888888889, + ["ETA_locked"] = false, + ["task"] = { ["id"] = "ComboTask", ["params"] = @@ -731,7 +766,7 @@ mission = }, -- end of ["params"] }, -- end of ["task"] ["speed_locked"] = true, - }, -- end of [3] + }, -- end of [4] }, -- end of ["points"] }, -- end of ["route"] ["groupId"] = 4, @@ -747,7 +782,7 @@ mission = ["speed"] = 138.88888888889, ["type"] = "Su-25T", ["unitId"] = 4, - ["psi"] = -1.1260144038135, + ["psi"] = -1.0438895175357, ["y"] = 628607.14285715, ["x"] = -287052.28571429, ["name"] = "DictKey_UnitName_20", @@ -761,7 +796,7 @@ mission = ["chaff"] = 128, ["gun"] = 100, }, -- end of ["payload"] - ["heading"] = 1.1260144038135, + ["heading"] = 1.0438895175357, ["callsign"] = { [1] = 1, @@ -870,10 +905,10 @@ mission = ["steer"] = 2, }, -- end of ["properties"] ["ETA"] = 0, - ["y"] = 630514.28571429, - ["x"] = -283495.14285714, + ["y"] = 628382.85714286, + ["x"] = -290099.42857143, ["name"] = "DictKey_WptName_11", - ["speed"] = 55.555555555556, + ["speed"] = 27.777777777778, ["ETA_locked"] = true, ["task"] = { @@ -920,9 +955,9 @@ mission = ["vangle"] = 0, ["steer"] = 2, }, -- end of ["properties"] - ["ETA"] = 33.043857683573, - ["y"] = 630528.57142858, - ["x"] = -281659.42857143, + ["ETA"] = 243.18972185585, + ["y"] = 641840, + ["x"] = -288899.42857143, ["name"] = "DictKey_WptName_26", ["speed"] = 55.555555555556, ["ETA_locked"] = false, @@ -951,7 +986,7 @@ mission = ["livery_id"] = "us army", ["skill"] = "Client", ["ropeLength"] = 15, - ["speed"] = 55.555555555556, + ["speed"] = 27.777777777778, ["type"] = "Ka-50", ["Radio"] = { @@ -975,12 +1010,12 @@ mission = { ["channels"] = { - [15] = 0.995, + [4] = 0.591, [13] = 0.583, [7] = 0.443, - [14] = 0.283, + [1] = 0.625, [2] = 0.303, - [4] = 0.591, + [15] = 0.995, [8] = 0.215, [16] = 1.21, [9] = 0.525, @@ -990,14 +1025,14 @@ mission = [11] = 0.718, [6] = 0.803, [12] = 0.35, - [1] = 0.625, + [14] = 0.283, }, -- end of ["channels"] }, -- end of [2] }, -- end of ["Radio"] ["unitId"] = 1, - ["psi"] = -0.0077819440762977, - ["y"] = 630514.28571429, - ["x"] = -283495.14285714, + ["psi"] = -1.481859585505, + ["y"] = 628382.85714286, + ["x"] = -290099.42857143, ["name"] = "DictKey_UnitName_10", ["payload"] = { @@ -1009,7 +1044,7 @@ mission = ["chaff"] = 0, ["gun"] = 100, }, -- end of ["payload"] - ["heading"] = 0.0077819440762977, + ["heading"] = 1.481859585505, ["callsign"] = { [1] = 1, @@ -1020,8 +1055,8 @@ mission = ["onboard_num"] = "050", }, -- end of [1] }, -- end of ["units"] - ["y"] = 630514.28571429, - ["x"] = -283495.14285714, + ["y"] = 628382.85714286, + ["x"] = -290099.42857143, ["name"] = "DictKey_GroupName_9", ["communication"] = true, ["start_time"] = 0, @@ -1029,7 +1064,7 @@ mission = }, -- end of [1] [2] = { - ["lateActivation"] = false, + ["lateActivation"] = true, ["tasks"] = { }, -- end of ["tasks"] @@ -1038,7 +1073,7 @@ mission = ["uncontrolled"] = false, ["route"] = { - ["routeRelativeTOT"] = false, + ["routeRelativeTOT"] = true, ["points"] = { [1] = @@ -1057,8 +1092,8 @@ mission = ["steer"] = 2, }, -- end of ["properties"] ["ETA"] = 0, - ["y"] = 630514.28571429, - ["x"] = -283788, + ["y"] = 630782.85714286, + ["x"] = -290756.57142857, ["name"] = "DictKey_WptName_14", ["speed"] = 55.555555555556, ["ETA_locked"] = true, @@ -1069,24 +1104,6 @@ mission = { ["tasks"] = { - [1] = - { - ["number"] = 1, - ["key"] = "CAS", - ["id"] = "EngageTargets", - ["enabled"] = true, - ["auto"] = true, - ["params"] = - { - ["targetTypes"] = - { - [1] = "Helicopters", - [2] = "Ground Units", - [3] = "Light armed ships", - }, -- end of ["targetTypes"] - ["priority"] = 0, - }, -- end of ["params"] - }, -- end of [1] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] @@ -1107,11 +1124,115 @@ mission = ["vangle"] = 0, ["steer"] = 2, }, -- end of ["properties"] - ["ETA"] = 23.658540331395, - ["y"] = 630528.57142858, - ["x"] = -282473.71428571, + ["ETA"] = 73.425880995736, + ["y"] = 631182.85714286, + ["x"] = -292756.57142857, ["name"] = "DictKey_WptName_25", - ["speed"] = 55.555555555556, + ["speed"] = 27.777777777778, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["enabled"] = true, + ["auto"] = false, + ["id"] = "WrappedAction", + ["number"] = 1, + ["params"] = + { + ["action"] = + { + ["id"] = "Script", + ["params"] = + { + ["command"] = "local DCSGroup = GROUP.FindGroup( ... )\ +DCSGroup:RegisterWayPoint ( 2 )", + }, -- end of ["params"] + }, -- end of ["action"] + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [2] + [3] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 138.35636187296, + ["y"] = 632354.28571429, + ["x"] = -294128, + ["name"] = "DictKey_WptName_27", + ["speed"] = 27.777777777778, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["enabled"] = true, + ["auto"] = false, + ["id"] = "WrappedAction", + ["number"] = 1, + ["params"] = + { + ["action"] = + { + ["id"] = "Script", + ["params"] = + { + ["command"] = "local DCSGroup = GROUP.FindGroup( ... )\ +DCSGroup:RegisterWayPoint ( 3 )", + }, -- end of ["params"] + }, -- end of ["action"] + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [3] + [4] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 338.52413460414, + ["y"] = 635240, + ["x"] = -294699.42857143, + ["name"] = "DictKey_WptName_28", + ["speed"] = 27.777777777778, ["ETA_locked"] = false, ["task"] = { @@ -1124,7 +1245,91 @@ mission = }, -- end of ["params"] }, -- end of ["task"] ["speed_locked"] = true, - }, -- end of [2] + }, -- end of [4] + [5] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 513.40850223263, + ["y"] = 640097.14285714, + ["x"] = -294613.71428571, + ["name"] = "DictKey_WptName_29", + ["speed"] = 27.777777777778, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + [1] = + { + ["enabled"] = true, + ["auto"] = false, + ["id"] = "EngageTargetsInZone", + ["number"] = 1, + ["params"] = + { + ["targetTypes"] = + { + [1] = "Ground Units", + }, -- end of ["targetTypes"] + ["x"] = -288242.28571428, + ["priority"] = 0, + ["y"] = 641982.85714286, + ["zoneRadius"] = 5000, + }, -- end of ["params"] + }, -- end of [1] + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [5] + [6] = + { + ["alt"] = 500, + ["type"] = "Turning Point", + ["action"] = "Turning Point", + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["properties"] = + { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + }, -- end of ["properties"] + ["ETA"] = 467.11155297145, + ["y"] = 642132.85714286, + ["x"] = -281992.28571428, + ["name"] = "DictKey_WptName_30", + ["speed"] = 27.777777777778, + ["ETA_locked"] = false, + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [6] }, -- end of ["points"] }, -- end of ["route"] ["groupId"] = 2, @@ -1141,9 +1346,9 @@ mission = ["speed"] = 55.555555555556, ["type"] = "Ka-50", ["unitId"] = 2, - ["psi"] = -0.010869137177245, - ["y"] = 630514.28571429, - ["x"] = -283788, + ["psi"] = -2.9441970937399, + ["y"] = 630782.85714286, + ["x"] = -290756.57142857, ["name"] = "DictKey_UnitName_13", ["payload"] = { @@ -1155,7 +1360,7 @@ mission = ["chaff"] = 0, ["gun"] = 100, }, -- end of ["payload"] - ["heading"] = 0.010869137177245, + ["heading"] = 2.9441970937399, ["callsign"] = { [1] = 2, @@ -1166,8 +1371,8 @@ mission = ["onboard_num"] = "051", }, -- end of [1] }, -- end of ["units"] - ["y"] = 630514.28571429, - ["x"] = -283788, + ["y"] = 630782.85714286, + ["x"] = -290756.57142857, ["name"] = "DictKey_GroupName_12", ["communication"] = true, ["start_time"] = 0, @@ -1225,6 +1430,79 @@ mission = [7] = { ["id"] = 0, + ["vehicle"] = + { + ["group"] = + { + [1] = + { + ["visible"] = false, + ["taskSelected"] = true, + ["route"] = + { + ["spans"] = + { + }, -- end of ["spans"] + ["points"] = + { + [1] = + { + ["alt"] = 9, + ["type"] = "Turning Point", + ["ETA"] = 0, + ["alt_type"] = "BARO", + ["formation_template"] = "", + ["y"] = 641868.57142857, + ["x"] = -288928, + ["name"] = "DictKey_WptName_33", + ["ETA_locked"] = true, + ["speed"] = 5.5555555555556, + ["action"] = "Off Road", + ["task"] = + { + ["id"] = "ComboTask", + ["params"] = + { + ["tasks"] = + { + }, -- end of ["tasks"] + }, -- end of ["params"] + }, -- end of ["task"] + ["speed_locked"] = true, + }, -- end of [1] + }, -- end of ["points"] + }, -- end of ["route"] + ["groupId"] = 5, + ["tasks"] = + { + }, -- end of ["tasks"] + ["hidden"] = false, + ["units"] = + { + [1] = + { + ["type"] = "BTR-80", + ["transportable"] = + { + ["randomTransportable"] = false, + }, -- end of ["transportable"] + ["unitId"] = 5, + ["skill"] = "Average", + ["y"] = 641868.57142857, + ["x"] = -288928, + ["name"] = "DictKey_UnitName_32", + ["playerCanDrive"] = true, + ["heading"] = 0, + }, -- end of [1] + }, -- end of ["units"] + ["y"] = 641868.57142857, + ["x"] = -288928, + ["name"] = "DictKey_GroupName_31", + ["start_time"] = 0, + ["task"] = "Ground Nothing", + }, -- end of [1] + }, -- end of ["group"] + }, -- end of ["vehicle"] ["name"] = "Russia", }, -- end of [7] [8] = @@ -1255,7 +1533,7 @@ mission = ["goals"] = { }, -- end of ["goals"] - ["currentKey"] = 452, + ["currentKey"] = 1192, ["start_time"] = 43200, ["forcedOptions"] = { @@ -1703,15 +1981,15 @@ mission = ["id"] = "sas_yaw_left", ["mm"] = 0, }, -- end of ["sas_yaw_left"] - ["DEFECTIVE_MECHANISM"] = + ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "DEFECTIVE_MECHANISM", + ["id"] = "BOMBS_ARMING_NO_VOLATAGE_LEFT", ["mm"] = 0, - }, -- end of ["DEFECTIVE_MECHANISM"] + }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] ["PITOT_HEAT_ELEMENT"] = { ["hh"] = 0, @@ -1810,15 +2088,15 @@ mission = ["id"] = "asc_p", ["mm"] = 0, }, -- end of ["asc_p"] - ["sas_pitch_left"] = + ["COOLANT_SHORT_CIRCUIT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "sas_pitch_left", + ["id"] = "COOLANT_SHORT_CIRCUIT", ["mm"] = 0, - }, -- end of ["sas_pitch_left"] + }, -- end of ["COOLANT_SHORT_CIRCUIT"] ["GUN_LEFT_IN_AMMUN_FAULT"] = { ["hh"] = 0, @@ -1882,24 +2160,24 @@ mission = ["id"] = "ecm", ["mm"] = 0, }, -- end of ["ecm"] - ["TGP_FAILURE_RIGHT"] = + ["CLOCK_FAILURE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TGP_FAILURE_RIGHT", + ["id"] = "CLOCK_FAILURE", ["mm"] = 0, - }, -- end of ["TGP_FAILURE_RIGHT"] - ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] = + }, -- end of ["CLOCK_FAILURE"] + ["TURNIND_INCORRECT_SENS_VAC_HIGH"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "BOMBS_ARMING_BROKEN_WIRING_LEFT", + ["id"] = "TURNIND_INCORRECT_SENS_VAC_HIGH", ["mm"] = 0, - }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] + }, -- end of ["TURNIND_INCORRECT_SENS_VAC_HIGH"] ["OIL_RADIATOR_WIRING"] = { ["hh"] = 0, @@ -1936,15 +2214,15 @@ mission = ["id"] = "PILOT_KILLED_FAILURE", ["mm"] = 0, }, -- end of ["PILOT_KILLED_FAILURE"] - ["GUN_LEFT_CENTER_MOUNT_LOOSE"] = + ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_LEFT_CENTER_MOUNT_LOOSE", + ["id"] = "BOMBS_ARMING_BROKEN_WIRING_RIGHT", ["mm"] = 0, - }, -- end of ["GUN_LEFT_CENTER_MOUNT_LOOSE"] + }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] ["VHF_VT_BURNED_OUT"] = { ["hh"] = 0, @@ -1990,15 +2268,15 @@ mission = ["id"] = "GUN_LEFT_CENTER_BARREL_WORN", ["mm"] = 0, }, -- end of ["GUN_LEFT_CENTER_BARREL_WORN"] - ["TURNIND_POINTER_VIBRATES"] = + ["abris_software"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TURNIND_POINTER_VIBRATES", + ["id"] = "abris_software", ["mm"] = 0, - }, -- end of ["TURNIND_POINTER_VIBRATES"] + }, -- end of ["abris_software"] ["GUN_FAIL_LEFT_OUT_GUN"] = { ["hh"] = 0, @@ -2008,15 +2286,15 @@ mission = ["id"] = "GUN_FAIL_LEFT_OUT_GUN", ["mm"] = 0, }, -- end of ["GUN_FAIL_LEFT_OUT_GUN"] - ["SAR_1_101"] = + ["PUMP_FAILS"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "SAR_1_101", + ["id"] = "PUMP_FAILS", ["mm"] = 0, - }, -- end of ["SAR_1_101"] + }, -- end of ["PUMP_FAILS"] ["ROCKETS_INTERVALOMETER_WIRING"] = { ["hh"] = 0, @@ -2026,15 +2304,15 @@ mission = ["id"] = "ROCKETS_INTERVALOMETER_WIRING", ["mm"] = 0, }, -- end of ["ROCKETS_INTERVALOMETER_WIRING"] - ["GUN_RIGHT_OUT_AMMUN_FAULT"] = + ["MainReductor_LowOilPressure"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_RIGHT_OUT_AMMUN_FAULT", + ["id"] = "MainReductor_LowOilPressure", ["mm"] = 0, - }, -- end of ["GUN_RIGHT_OUT_AMMUN_FAULT"] + }, -- end of ["MainReductor_LowOilPressure"] ["GUN_RIGHT_IN_AMMUN_FAULT"] = { ["hh"] = 0, @@ -2071,15 +2349,15 @@ mission = ["id"] = "BOMBS_RUST_LEFT", ["mm"] = 0, }, -- end of ["BOMBS_RUST_LEFT"] - ["GUN_RIGHT_CENTER_BARREL_WORN"] = + ["ARN_83_ADF_DAMAGE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_RIGHT_CENTER_BARREL_WORN", + ["id"] = "ARN_83_ADF_DAMAGE", ["mm"] = 0, - }, -- end of ["GUN_RIGHT_CENTER_BARREL_WORN"] + }, -- end of ["ARN_83_ADF_DAMAGE"] ["asc"] = { ["hh"] = 0, @@ -2619,15 +2897,15 @@ mission = ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING", ["mm"] = 0, }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING"] - ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] = + ["TACH_POOR_CONNECTION"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_LEFT_CENTER_OPEN_CIRCUIT", + ["id"] = "TACH_POOR_CONNECTION", ["mm"] = 0, - }, -- end of ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] + }, -- end of ["TACH_POOR_CONNECTION"] ["GUN_RIGHT_IN_MOUNT_LOOSE"] = { ["hh"] = 0, @@ -2835,15 +3113,15 @@ mission = ["id"] = "es_damage_GeneratorLeft", ["mm"] = 0, }, -- end of ["es_damage_GeneratorLeft"] - ["SUPERCHARGER_SOLENOID"] = + ["ILS_FAILURE_ANT_GLIDESLOPE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "SUPERCHARGER_SOLENOID", + ["id"] = "ILS_FAILURE_ANT_GLIDESLOPE", ["mm"] = 0, - }, -- end of ["SUPERCHARGER_SOLENOID"] + }, -- end of ["ILS_FAILURE_ANT_GLIDESLOPE"] ["engine_chip"] = { ["hh"] = 0, @@ -2853,15 +3131,15 @@ mission = ["id"] = "engine_chip", ["mm"] = 0, }, -- end of ["engine_chip"] - ["ARN_83_TOTAL_FAILURE"] = + ["GUN_LEFT_CENTER_AMMUN_FAULT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "ARN_83_TOTAL_FAILURE", + ["id"] = "GUN_LEFT_CENTER_AMMUN_FAULT", ["mm"] = 0, - }, -- end of ["ARN_83_TOTAL_FAILURE"] + }, -- end of ["GUN_LEFT_CENTER_AMMUN_FAULT"] ["CADC_FAILURE_MACH"] = { ["hh"] = 0, @@ -2916,15 +3194,15 @@ mission = ["id"] = "laser_failure", ["mm"] = 0, }, -- end of ["laser_failure"] - ["ARN_83_ADF_DAMAGE"] = + ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "ARN_83_ADF_DAMAGE", + ["id"] = "RADAR_ALTIMETR_RIGHT_ANT_FAILURE", ["mm"] = 0, - }, -- end of ["ARN_83_ADF_DAMAGE"] + }, -- end of ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] ["AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT"] = { ["hh"] = 0, @@ -2934,42 +3212,33 @@ mission = ["id"] = "AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT", ["mm"] = 0, }, -- end of ["AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT"] - ["PUMP_FAILS"] = + ["COMPASS_ERRATIC_OPERATION"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "PUMP_FAILS", + ["id"] = "COMPASS_ERRATIC_OPERATION", ["mm"] = 0, - }, -- end of ["PUMP_FAILS"] - ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] = + }, -- end of ["COMPASS_ERRATIC_OPERATION"] + ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR", + ["id"] = "BOMBS_ARMING_BROKEN_WIRING_LEFT", ["mm"] = 0, - }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] - ["TACH_BREAK_IN_INDICATOR"] = + }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] + ["VHF_SHORTED_CTL_BOX"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TACH_BREAK_IN_INDICATOR", + ["id"] = "VHF_SHORTED_CTL_BOX", ["mm"] = 0, - }, -- end of ["TACH_BREAK_IN_INDICATOR"] - ["BATTERY_OVERHEAT"] = - { - ["hh"] = 0, - ["prob"] = 100, - ["enable"] = false, - ["mmint"] = 1, - ["id"] = "BATTERY_OVERHEAT", - ["mm"] = 0, - }, -- end of ["BATTERY_OVERHEAT"] + }, -- end of ["VHF_SHORTED_CTL_BOX"] ["CARBAIR_SHORT_CIRCUIT_LEADS"] = { ["hh"] = 0, @@ -2979,6 +3248,15 @@ mission = ["id"] = "CARBAIR_SHORT_CIRCUIT_LEADS", ["mm"] = 0, }, -- end of ["CARBAIR_SHORT_CIRCUIT_LEADS"] + ["BATTERY_OVERHEAT"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "BATTERY_OVERHEAT", + ["mm"] = 0, + }, -- end of ["BATTERY_OVERHEAT"] ["NOSE_AIRSPEED_INDICATOR_FAILURE"] = { ["hh"] = 0, @@ -2988,42 +3266,33 @@ mission = ["id"] = "NOSE_AIRSPEED_INDICATOR_FAILURE", ["mm"] = 0, }, -- end of ["NOSE_AIRSPEED_INDICATOR_FAILURE"] - ["GUN_FAIL_RIGHT_IN_GUN"] = + ["es_damage_GeneratorRight"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_FAIL_RIGHT_IN_GUN", + ["id"] = "es_damage_GeneratorRight", ["mm"] = 0, - }, -- end of ["GUN_FAIL_RIGHT_IN_GUN"] - ["abris_software"] = + }, -- end of ["es_damage_GeneratorRight"] + ["GUN_RIGHT_OUT_AMMUN_FAULT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "abris_software", + ["id"] = "GUN_RIGHT_OUT_AMMUN_FAULT", ["mm"] = 0, - }, -- end of ["abris_software"] - ["ILS_FAILURE_ANT_GLIDESLOPE"] = + }, -- end of ["GUN_RIGHT_OUT_AMMUN_FAULT"] + ["BOMBS_NO_VOLATAGE_BOTH"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "ILS_FAILURE_ANT_GLIDESLOPE", + ["id"] = "BOMBS_NO_VOLATAGE_BOTH", ["mm"] = 0, - }, -- end of ["ILS_FAILURE_ANT_GLIDESLOPE"] - ["COPILOT_KILLED_FAILURE"] = - { - ["hh"] = 0, - ["prob"] = 100, - ["enable"] = false, - ["mmint"] = 1, - ["id"] = "COPILOT_KILLED_FAILURE", - ["mm"] = 0, - }, -- end of ["COPILOT_KILLED_FAILURE"] + }, -- end of ["BOMBS_NO_VOLATAGE_BOTH"] ["CADC_FAILURE_IAS"] = { ["hh"] = 0, @@ -3033,33 +3302,42 @@ mission = ["id"] = "CADC_FAILURE_IAS", ["mm"] = 0, }, -- end of ["CADC_FAILURE_IAS"] - ["COOLANT_RADIATOR_SENSOR"] = + ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "COOLANT_RADIATOR_SENSOR", + ["id"] = "BOMBS_DAMAGE_ELINKAGE_RIGHT", ["mm"] = 0, - }, -- end of ["COOLANT_RADIATOR_SENSOR"] - ["GUN_LEFT_CENTER_AMMUN_FAULT"] = + }, -- end of ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] + ["ROOF_AIRSPEED_INDICATOR_FAILURE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_LEFT_CENTER_AMMUN_FAULT", + ["id"] = "ROOF_AIRSPEED_INDICATOR_FAILURE", ["mm"] = 0, - }, -- end of ["GUN_LEFT_CENTER_AMMUN_FAULT"] - ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] = + }, -- end of ["ROOF_AIRSPEED_INDICATOR_FAILURE"] + ["AAR_47_FAILURE_SENSOR_BOTTOM"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "BOMBS_ARMING_NO_VOLATAGE_LEFT", + ["id"] = "AAR_47_FAILURE_SENSOR_BOTTOM", ["mm"] = 0, - }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] + }, -- end of ["AAR_47_FAILURE_SENSOR_BOTTOM"] + ["DEFECTIVE_MECHANISM"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "DEFECTIVE_MECHANISM", + ["mm"] = 0, + }, -- end of ["DEFECTIVE_MECHANISM"] ["AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT"] = { ["hh"] = 0, @@ -3087,15 +3365,15 @@ mission = ["id"] = "hydro_main_irreversible_valve", ["mm"] = 0, }, -- end of ["hydro_main_irreversible_valve"] - ["TAIL_GEAR_D_LOCK"] = + ["CADC_FAILURE_DYNAMIC"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TAIL_GEAR_D_LOCK", + ["id"] = "CADC_FAILURE_DYNAMIC", ["mm"] = 0, - }, -- end of ["TAIL_GEAR_D_LOCK"] + }, -- end of ["CADC_FAILURE_DYNAMIC"] ["hud"] = { ["hh"] = 0, @@ -3168,15 +3446,15 @@ mission = ["id"] = "es_damage_MainGenerator", ["mm"] = 0, }, -- end of ["es_damage_MainGenerator"] - ["MainReductor_LowOilPressure"] = + ["RIGHT_WING_TANK_LEAK"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "MainReductor_LowOilPressure", + ["id"] = "RIGHT_WING_TANK_LEAK", ["mm"] = 0, - }, -- end of ["MainReductor_LowOilPressure"] + }, -- end of ["RIGHT_WING_TANK_LEAK"] ["IGNITION_TERM_CONNECT"] = { ["hh"] = 0, @@ -3222,24 +3500,24 @@ mission = ["id"] = "VHF_SQUELCH_RELAY", ["mm"] = 0, }, -- end of ["VHF_SQUELCH_RELAY"] - ["COMPASS_ERRATIC_OPERATION"] = + ["SAR_1_101"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "COMPASS_ERRATIC_OPERATION", + ["id"] = "SAR_1_101", ["mm"] = 0, - }, -- end of ["COMPASS_ERRATIC_OPERATION"] - ["TACAN_FAILURE_RECEIVER"] = + }, -- end of ["SAR_1_101"] + ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TACAN_FAILURE_RECEIVER", + ["id"] = "GUN_LEFT_CENTER_OPEN_CIRCUIT", ["mm"] = 0, - }, -- end of ["TACAN_FAILURE_RECEIVER"] + }, -- end of ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] ["sas_pitch_right"] = { ["hh"] = 0, @@ -3258,24 +3536,24 @@ mission = ["id"] = "BOMBS_NO_VOLATAGE_AT_RACK_LEFT", ["mm"] = 0, }, -- end of ["BOMBS_NO_VOLATAGE_AT_RACK_LEFT"] - ["TransitionalReductor_ShaveInOil"] = + ["TURNIND_POINTER_VIBRATES"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TransitionalReductor_ShaveInOil", + ["id"] = "TURNIND_POINTER_VIBRATES", ["mm"] = 0, - }, -- end of ["TransitionalReductor_ShaveInOil"] - ["TACH_POOR_CONNECTION"] = + }, -- end of ["TURNIND_POINTER_VIBRATES"] + ["TACAN_FAILURE_RECEIVER"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TACH_POOR_CONNECTION", + ["id"] = "TACAN_FAILURE_RECEIVER", ["mm"] = 0, - }, -- end of ["TACH_POOR_CONNECTION"] + }, -- end of ["TACAN_FAILURE_RECEIVER"] ["VHF_AM_RADIO_FAILURE_TOTAL"] = { ["hh"] = 0, @@ -3303,24 +3581,24 @@ mission = ["id"] = "VHF_CRYSTAL", ["mm"] = 0, }, -- end of ["VHF_CRYSTAL"] - ["COOLANT_SHORT_CIRCUIT"] = + ["GUN_FAIL_RIGHT_IN_GUN"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "COOLANT_SHORT_CIRCUIT", + ["id"] = "GUN_FAIL_RIGHT_IN_GUN", ["mm"] = 0, - }, -- end of ["COOLANT_SHORT_CIRCUIT"] - ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] = + }, -- end of ["GUN_FAIL_RIGHT_IN_GUN"] + ["sas_pitch_left"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "BOMBS_ARMING_BROKEN_WIRING_RIGHT", + ["id"] = "sas_pitch_left", ["mm"] = 0, - }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] + }, -- end of ["sas_pitch_left"] ["F2_TOP_CYLINDER"] = { ["hh"] = 0, @@ -3348,15 +3626,15 @@ mission = ["id"] = "MANIFOLD_LINE_LEAK", ["mm"] = 0, }, -- end of ["MANIFOLD_LINE_LEAK"] - ["CADC_FAILURE_DYNAMIC"] = + ["COPILOT_KILLED_FAILURE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "CADC_FAILURE_DYNAMIC", + ["id"] = "COPILOT_KILLED_FAILURE", ["mm"] = 0, - }, -- end of ["CADC_FAILURE_DYNAMIC"] + }, -- end of ["COPILOT_KILLED_FAILURE"] ["CADC_FAILURE_PRESSURE_ALT"] = { ["hh"] = 0, @@ -3375,24 +3653,24 @@ mission = ["id"] = "K14_NO_POWER_SUPPLY", ["mm"] = 0, }, -- end of ["K14_NO_POWER_SUPPLY"] - ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] = + ["COOLANT_RADIATOR_SENSOR"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "RADAR_ALTIMETR_RIGHT_ANT_FAILURE", + ["id"] = "COOLANT_RADIATOR_SENSOR", ["mm"] = 0, - }, -- end of ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] - ["es_damage_GeneratorRight"] = + }, -- end of ["COOLANT_RADIATOR_SENSOR"] + ["INSUF_FUEL_PRES"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "es_damage_GeneratorRight", + ["id"] = "INSUF_FUEL_PRES", ["mm"] = 0, - }, -- end of ["es_damage_GeneratorRight"] + }, -- end of ["INSUF_FUEL_PRES"] ["BOMBS_DAMAGE_LINKAGE_RIGHT"] = { ["hh"] = 0, @@ -3411,15 +3689,15 @@ mission = ["id"] = "fs_damage_engine_pump", ["mm"] = 0, }, -- end of ["fs_damage_engine_pump"] - ["VHF_SHORTED_CTL_BOX"] = + ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "VHF_SHORTED_CTL_BOX", + ["id"] = "GUN_RIGHT_OUT_OPEN_CIRCUIT", ["mm"] = 0, - }, -- end of ["VHF_SHORTED_CTL_BOX"] + }, -- end of ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] ["CADC_FAILURE_STATIC"] = { ["hh"] = 0, @@ -3456,51 +3734,51 @@ mission = ["id"] = "IFFCC_FAILURE_TOTAL", ["mm"] = 0, }, -- end of ["IFFCC_FAILURE_TOTAL"] - ["CLOCK_FAILURE"] = + ["UNLOAD_VALVE_NOT_UNLOAD"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "CLOCK_FAILURE", + ["id"] = "UNLOAD_VALVE_NOT_UNLOAD", ["mm"] = 0, - }, -- end of ["CLOCK_FAILURE"] - ["GUN_LEFT_OUT_AMMUN_FAULT"] = + }, -- end of ["UNLOAD_VALVE_NOT_UNLOAD"] + ["TAIL_GEAR_D_LOCK"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_LEFT_OUT_AMMUN_FAULT", + ["id"] = "TAIL_GEAR_D_LOCK", ["mm"] = 0, - }, -- end of ["GUN_LEFT_OUT_AMMUN_FAULT"] - ["BOMBS_NO_VOLATAGE_BOTH"] = + }, -- end of ["TAIL_GEAR_D_LOCK"] + ["TACH_BREAK_IN_INDICATOR"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "BOMBS_NO_VOLATAGE_BOTH", + ["id"] = "TACH_BREAK_IN_INDICATOR", ["mm"] = 0, - }, -- end of ["BOMBS_NO_VOLATAGE_BOTH"] - ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] = + }, -- end of ["TACH_BREAK_IN_INDICATOR"] + ["GMC_TOTAL_FAILURE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "BOMBS_DAMAGE_ELINKAGE_RIGHT", + ["id"] = "GMC_TOTAL_FAILURE", ["mm"] = 0, - }, -- end of ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] - ["GUN_LEFT_OUT_BARREL_WORN"] = + }, -- end of ["GMC_TOTAL_FAILURE"] + ["GUN_RIGHT_CENTER_BARREL_WORN"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_LEFT_OUT_BARREL_WORN", + ["id"] = "GUN_RIGHT_CENTER_BARREL_WORN", ["mm"] = 0, - }, -- end of ["GUN_LEFT_OUT_BARREL_WORN"] + }, -- end of ["GUN_RIGHT_CENTER_BARREL_WORN"] ["EXT_HYDRO_LEAK"] = { ["hh"] = 0, @@ -3645,15 +3923,15 @@ mission = ["id"] = "TACAN_FAILURE_TRANSMITTER", ["mm"] = 0, }, -- end of ["TACAN_FAILURE_TRANSMITTER"] - ["engine_surge_failure"] = + ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "engine_surge_failure", + ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR", ["mm"] = 0, - }, -- end of ["engine_surge_failure"] + }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] ["l_gen"] = { ["hh"] = 0, @@ -3663,15 +3941,15 @@ mission = ["id"] = "l_gen", ["mm"] = 0, }, -- end of ["l_gen"] - ["RIGHT_WING_TANK_LEAK"] = + ["TransitionalReductor_ShaveInOil"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "RIGHT_WING_TANK_LEAK", + ["id"] = "TransitionalReductor_ShaveInOil", ["mm"] = 0, - }, -- end of ["RIGHT_WING_TANK_LEAK"] + }, -- end of ["TransitionalReductor_ShaveInOil"] ["GUN_LEFT_IN_BARREL_WORN"] = { ["hh"] = 0, @@ -3690,15 +3968,15 @@ mission = ["id"] = "r_gen", ["mm"] = 0, }, -- end of ["r_gen"] - ["l_conv"] = + ["GUN_LEFT_OUT_BARREL_WORN"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "l_conv", + ["id"] = "GUN_LEFT_OUT_BARREL_WORN", ["mm"] = 0, - }, -- end of ["l_conv"] + }, -- end of ["GUN_LEFT_OUT_BARREL_WORN"] ["AAR_47_FAILURE_SENSOR_RIGHT"] = { ["hh"] = 0, @@ -3753,15 +4031,15 @@ mission = ["id"] = "BOOSTER_COIL", ["mm"] = 0, }, -- end of ["BOOSTER_COIL"] - ["INSUF_FUEL_PRES"] = + ["engine_surge_failure"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "INSUF_FUEL_PRES", + ["id"] = "engine_surge_failure", ["mm"] = 0, - }, -- end of ["INSUF_FUEL_PRES"] + }, -- end of ["engine_surge_failure"] ["FAULTY_ROCKET_RIGHT"] = { ["hh"] = 0, @@ -3834,15 +4112,15 @@ mission = ["id"] = "CLOGGED_FUEL_STRAINER", ["mm"] = 0, }, -- end of ["CLOGGED_FUEL_STRAINER"] - ["TURNIND_INCORRECT_SENS_VAC_HIGH"] = + ["GUN_LEFT_OUT_AMMUN_FAULT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "TURNIND_INCORRECT_SENS_VAC_HIGH", + ["id"] = "GUN_LEFT_OUT_AMMUN_FAULT", ["mm"] = 0, - }, -- end of ["TURNIND_INCORRECT_SENS_VAC_HIGH"] + }, -- end of ["GUN_LEFT_OUT_AMMUN_FAULT"] ["r_engine"] = { ["hh"] = 0, @@ -3888,15 +4166,14 @@ mission = ["id"] = "D2_RIGHT_CYLINDER", ["mm"] = 0, }, -- end of ["D2_RIGHT_CYLINDER"] - ["UNLOAD_VALVE_NOT_UNLOAD"] = + ["ecf"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "UNLOAD_VALVE_NOT_UNLOAD", ["mm"] = 0, - }, -- end of ["UNLOAD_VALVE_NOT_UNLOAD"] + }, -- end of ["ecf"] ["AN_ALR69V_FAILURE_TOTAL"] = { ["hh"] = 0, @@ -3906,15 +4183,6 @@ mission = ["id"] = "AN_ALR69V_FAILURE_TOTAL", ["mm"] = 0, }, -- end of ["AN_ALR69V_FAILURE_TOTAL"] - ["GMC_TOTAL_FAILURE"] = - { - ["hh"] = 0, - ["prob"] = 100, - ["enable"] = false, - ["mmint"] = 1, - ["id"] = "GMC_TOTAL_FAILURE", - ["mm"] = 0, - }, -- end of ["GMC_TOTAL_FAILURE"] ["BOMBS_ARMING_BROKEN_SOLENOID_LEFT"] = { ["hh"] = 0, @@ -3924,15 +4192,24 @@ mission = ["id"] = "BOMBS_ARMING_BROKEN_SOLENOID_LEFT", ["mm"] = 0, }, -- end of ["BOMBS_ARMING_BROKEN_SOLENOID_LEFT"] - ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] = + ["SUPERCHARGER_SOLENOID"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "GUN_RIGHT_OUT_OPEN_CIRCUIT", + ["id"] = "SUPERCHARGER_SOLENOID", ["mm"] = 0, - }, -- end of ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] + }, -- end of ["SUPERCHARGER_SOLENOID"] + ["ARN_83_TOTAL_FAILURE"] = + { + ["hh"] = 0, + ["prob"] = 100, + ["enable"] = false, + ["mmint"] = 1, + ["id"] = "ARN_83_TOTAL_FAILURE", + ["mm"] = 0, + }, -- end of ["ARN_83_TOTAL_FAILURE"] ["l_engine"] = { ["hh"] = 0, @@ -3942,24 +4219,24 @@ mission = ["id"] = "l_engine", ["mm"] = 0, }, -- end of ["l_engine"] - ["ROOF_AIRSPEED_INDICATOR_FAILURE"] = + ["GUN_LEFT_CENTER_MOUNT_LOOSE"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "ROOF_AIRSPEED_INDICATOR_FAILURE", + ["id"] = "GUN_LEFT_CENTER_MOUNT_LOOSE", ["mm"] = 0, - }, -- end of ["ROOF_AIRSPEED_INDICATOR_FAILURE"] - ["AAR_47_FAILURE_SENSOR_BOTTOM"] = + }, -- end of ["GUN_LEFT_CENTER_MOUNT_LOOSE"] + ["TGP_FAILURE_RIGHT"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, - ["id"] = "AAR_47_FAILURE_SENSOR_BOTTOM", + ["id"] = "TGP_FAILURE_RIGHT", ["mm"] = 0, - }, -- end of ["AAR_47_FAILURE_SENSOR_BOTTOM"] + }, -- end of ["TGP_FAILURE_RIGHT"] ["COOLANT_DEFECTIVE_IND"] = { ["hh"] = 0, @@ -3969,14 +4246,15 @@ mission = ["id"] = "COOLANT_DEFECTIVE_IND", ["mm"] = 0, }, -- end of ["COOLANT_DEFECTIVE_IND"] - ["ecf"] = + ["l_conv"] = { ["hh"] = 0, ["prob"] = 100, ["enable"] = false, ["mmint"] = 1, + ["id"] = "l_conv", ["mm"] = 0, - }, -- end of ["ecf"] + }, -- end of ["l_conv"] ["JADRO_1A_FAILURE_TOTAL"] = { ["hh"] = 0, diff --git a/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses b/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses index 68ca70eb9..4da4b8597 100644 --- a/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses +++ b/Test Missions/miz/MOOSE_Escort_Test_Follow/warehouses @@ -442,7 +442,7 @@ warehouses = ["suppliers"] = { }, -- end of ["suppliers"] - ["coalition"] = "NEUTRAL", + ["coalition"] = "BLUE", ["jet_fuel"] = { ["InitFuel"] = 100,