From 6799cd776e95d41d1e949b4aca19a7163e28d7b9 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 15 Sep 2017 16:17:08 +0200 Subject: [PATCH 01/10] RAT documentation update --- docs/Documentation/Designate.html | 1 + docs/Documentation/Detection.html | 4 +- docs/Documentation/Fsm.html | 3 +- docs/Documentation/Movement.html | 4 - docs/Documentation/Positionable.html | 1 - docs/Documentation/Rat.html | 277 ++++++++++++++++++++++++++- docs/Documentation/Settings.html | 2 +- docs/Documentation/Spawn.html | 14 +- docs/Documentation/SpawnStatic.html | 1 + docs/Documentation/Task_Cargo.html | 3 +- 10 files changed, 287 insertions(+), 23 deletions(-) diff --git a/docs/Documentation/Designate.html b/docs/Documentation/Designate.html index ff349e1b5..8ecc57ea8 100644 --- a/docs/Documentation/Designate.html +++ b/docs/Documentation/Designate.html @@ -1151,6 +1151,7 @@ function below will use the range 1-7 just in case

+ DESIGNATE.LaserCodes diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index db832f4d5..da950516a 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2460,7 +2460,6 @@ The index of the DetectedItem.

- #number DETECTION_BASE.DetectedItemCount @@ -2474,7 +2473,6 @@ The index of the DetectedItem.

- #number DETECTION_BASE.DetectedItemMax @@ -4052,7 +4050,7 @@ Return false to cancel Transition.

- #number + DETECTION_BASE.RefreshTimeInterval diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index dc67c7520..b58946d17 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -1599,7 +1599,7 @@ A string defining the start state.

- + #string FSM._StartState @@ -1898,7 +1898,6 @@ A string defining the start state.

- FSM.current diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index 3123488df..dfb86750e 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -228,7 +228,6 @@ on defined intervals (currently every minute).

- #number MOVEMENT.AliveUnits @@ -237,9 +236,6 @@ on defined intervals (currently every minute).

- -

Contains the counter how many units are currently alive

-
diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index 35cac07a2..e531312d4 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -1974,7 +1974,6 @@ The height in meters to add to the altitude of the positionable.

- Core.Spot#SPOT POSITIONABLE.Spot diff --git a/docs/Documentation/Rat.html b/docs/Documentation/Rat.html index 41cd88aa0..93e33ac5f 100644 --- a/docs/Documentation/Rat.html +++ b/docs/Documentation/Rat.html @@ -223,6 +223,12 @@ RAT.FLuser

Flight level set by users explicitly.

+ + + + RAT:Livery(skins) + +

Set livery of aircraft.

@@ -283,6 +289,12 @@ RAT:SetCoalition(friendly)

Set the friendly coalitions from which the airports can be used as departure or destination.

+ + + + RAT:SetCruiseAltitude(alt) + +

Set cruising altitude.

@@ -325,6 +337,12 @@ RAT:SetFLmin(height)

Set min flight level.

+ + + + RAT:SetMaCruiseAltitude(alt) + +

Set max cruising altitude above sea level.

@@ -337,6 +355,12 @@ RAT:SetMaxDistance(dist)

Set maximum distance between departure and destination.

+ + + + RAT:SetMinCruiseAltitude(alt) + +

Set min cruising altitude above sea level.

@@ -408,7 +432,7 @@ RAT.Tinactive -

Time in seconds after which inactive units will be destroyed. Default is 180 seconds.

+

Time in seconds after which inactive units will be destroyed. Default is 300 seconds.

@@ -493,6 +517,12 @@ RAT:_InitAircraft(DCSgroup)

Initialize basic parameters of the aircraft based on its (template) group in the mission editor.

+ + + + RAT:_MinDistance(alpha, beta, h) + +

Calculate min distance between departure and destination for given minimum flight level and climb/decent rates

@@ -739,12 +769,24 @@ RAT.friendly

Possible departure/destination airport: all=blue+red+neutral, same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red.

+ + + + RAT:has_value(tab, val) + +

Utility function which checks if table contains a specific value.

RAT.id

Some ID to identify who we are in output of the DCS.log file.

+ + + + RAT.livery + +

Livery of the aircraft set by user.

@@ -775,6 +817,12 @@ RAT.ngroups

Number of groups to be spawned in total.

+ + + + RAT.onboard_num + + @@ -829,6 +877,12 @@ RAT.rot

ROT of spawned groups, default is no reaction. Possible: "noreaction", "passive", "evade".

+ + + + RAT.skill + +

Skill of AI.

@@ -902,7 +956,7 @@
  • A specific departure and/or destination airport can be chosen.
  • -
  • Valid coalitions can be set, e.g. only red, blue or neutral, all three �colours�.
  • +
  • Valid coalitions can be set, e.g. only red, blue or neutral, all three "colours".
  • It is possible to start in air within a zone defined in the mission editor or within a zone above an airport of the map.
@@ -936,7 +990,7 @@
  • Activate the "LATE ACTIVATION" tick box. Note that this aircraft will not be spawned itself but serves a template for each RAT aircraft spawned when the mission starts.
  • -

    Voil�, your already done!

    +

    Voilà, your already done!

    Optionally, you can set a specific livery for the aircraft or give it some weapons. However, the aircraft will by default not engage any enemies. Think of them as beeing on a peaceful or ferry mission.

    @@ -1158,6 +1212,31 @@ Turn journey on=true or off=false. If no value is given switch=true.

    Flight level set by users explicitly.

    + +
    +
    +
    + + +RAT:Livery(skins) + +
    +
    + +

    Set livery of aircraft.

    + + +

    If more than one livery is specified in a table, the actually used one is chosen randomly from the selection.

    + +

    Parameter

    +
      +
    • + +

      #string skins : +Name of livery or table of names of liveries.

      + +
    • +
    @@ -1394,6 +1473,31 @@ Default is "same", so aircraft will use airports of the coalition their spawn te
    + +RAT:SetCruiseAltitude(alt) + +
    +
    + +

    Set cruising altitude.

    + + +

    This is still be checked for consitancy with selected route and prone to radomization.

    + +

    Parameter

    +
      +
    • + +

      #number alt : +Cruising altitude ASL in meters.

      + +
    • +
    +
    +
    +
    +
    + RAT:SetDeparture(names) @@ -1580,6 +1684,28 @@ Maximum FL in hundrets of feet.

    + +RAT:SetMaCruiseAltitude(alt) + +
    +
    + +

    Set max cruising altitude above sea level.

    + +

    Parameter

    +
      +
    • + +

      #number alt : +Altitude ASL in meters.

      + +
    • +
    +
    +
    +
    +
    + RAT:SetMaxCruiseSpeed(speed) @@ -1627,6 +1753,28 @@ Distance in km.

    + +RAT:SetMinCruiseAltitude(alt) + +
    +
    + +

    Set min cruising altitude above sea level.

    + +

    Parameter

    +
      +
    • + +

      #number alt : +Altitude ASL in meters.

      + +
    • +
    +
    +
    +
    +
    + RAT:SetMinDistance(dist) @@ -1890,7 +2038,7 @@ true=on, false=off.

    Set the time after which inactive groups will be destroyed.

    -

    Default is 180 seconds.

    +

    Default is 300 seconds.

    Parameter

      @@ -1913,7 +2061,7 @@ Time in seconds.

    -

    Time in seconds after which inactive units will be destroyed. Default is 180 seconds.

    +

    Time in seconds after which inactive units will be destroyed. Default is 300 seconds.

    @@ -2140,7 +2288,7 @@ Height [m] of departure airport. Note we implicitly assume that the height diffe

    Return value

    #number: - Maximal flight level in meters.

    +Maximal flight level in meters.

    @@ -2274,6 +2422,45 @@ Group of the aircraft in the mission editor.

    + +RAT:_MinDistance(alpha, beta, h) + +
    +
    + +

    Calculate min distance between departure and destination for given minimum flight level and climb/decent rates

    + +

    Parameters

    +
      +
    • + +

      #number alpha : +Angle of climb [rad].

      + +
    • +
    • + +

      #number beta : +Angle of descent [rad].

      + +
    • +
    • + +

      #number h : +min height AGL.

      + +
    • +
    +

    Return value

    + +

    #number: +Minimum distance between departure and destiantion.

    + +
    +
    +
    +
    + RAT:_ModifySpawnTemplate(waypoints) @@ -3253,6 +3440,39 @@ Waypoints for DCS task route or spawn template.

    Possible departure/destination airport: all=blue+red+neutral, same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red.

    + +
    +
    +
    + + +RAT:has_value(tab, val) + +
    +
    + +

    Utility function which checks if table contains a specific value.

    + +

    Parameters

    +
      +
    • + +

      #table tab : +Table with elements to check.

      + +
    • +
    • + +

      #string val : +The value we are looking for.

      + +
    • +
    +

    Return value

    + +

    #boolean: +True if element in the list, false otherwise.

    +
    @@ -3267,6 +3487,20 @@ Waypoints for DCS task route or spawn template.

    Some ID to identify who we are in output of the DCS.log file.

    + +
    +
    +
    + + #string + +RAT.livery + +
    +
    + +

    Livery of the aircraft set by user.

    +
    @@ -3337,6 +3571,23 @@ Waypoints for DCS task route or spawn template.

    Number of groups to be spawned in total.

    + +
    +
    +
    + + + +RAT.onboard_num + +
    +
    + + + + +

    Onboard number.

    +
    @@ -3463,6 +3714,20 @@ Waypoints for DCS task route or spawn template.

    ROT of spawned groups, default is no reaction. Possible: "noreaction", "passive", "evade".

    + +
    +
    +
    + + #string + +RAT.skill + +
    +
    + +

    Skill of AI.

    +
    diff --git a/docs/Documentation/Settings.html b/docs/Documentation/Settings.html index 274a10019..0ff600a3c 100644 --- a/docs/Documentation/Settings.html +++ b/docs/Documentation/Settings.html @@ -1241,7 +1241,7 @@ true if metric.

    - #boolean + SETTINGS.Metric diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 2a77723ca..039d0dee1 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -2192,6 +2192,9 @@ The group that was spawned. You can use this group for further actions.

    + +

    Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.

    +
    @@ -2780,6 +2783,9 @@ when nothing was spawned.

    + +

    By default, no InitLimit

    +
    @@ -2815,7 +2821,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxGroups @@ -2832,7 +2838,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxUnitsAlive @@ -3160,7 +3166,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
    - + #boolean SPAWN.SpawnUnControlled @@ -3184,7 +3190,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -

    When the first Spawn executes, all the Groups need to be made visible before start.

    +

    Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.

    diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index 487563b09..251693d35 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -437,6 +437,7 @@ ptional) The name of the new static.

    + #number SPAWNSTATIC.SpawnIndex diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 2f9cb7b3a..ce24d8062 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -553,7 +553,7 @@ based on the tasking capabilities defined in Task#TA
    - Core.Cargo#CARGO_GROUP + FSM_PROCESS.Cargo @@ -567,7 +567,6 @@ based on the tasking capabilities defined in Task#TA
    - FSM_PROCESS.DeployZone From df7ffc2a3f07ea9fd86106d95bce8a24d047fa6f Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 15 Sep 2017 17:01:15 +0200 Subject: [PATCH 02/10] Fixed detailed report following settings of player * Detailed task report now follows coordinate format settings of player. --- Moose Development/Moose/Core/Point.lua | 2 +- Moose Development/Moose/Tasking/Task.lua | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 4589d98b6..d49a2d0c4 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1072,7 +1072,7 @@ do -- COORDINATE end - if ModeA2A then + if ModeA2A == true then return self:ToStringA2A( Controllable, Settings ) else return self:ToStringA2G( Controllable, Settings ) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 4d6108705..e6a791794 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -1589,8 +1589,9 @@ function TASK:ReportDetails( ReportGroup ) Report:Add( TaskInfoIDText .. TaskInfo.TaskInfoText ) elseif type(TaskInfo) == "table" then if TaskInfoID == "Coordinates" then + local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate() local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE - Report:Add( TaskInfoIDText .. ToCoordinate:ToString() ) + Report:Add( TaskInfoIDText .. ToCoordinate:ToString( ReportGroup:GetUnit(1), nil, self ) ) else end end From 56813a800c54c72d72f5d23db28137774938ebd7 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 15 Sep 2017 19:38:19 +0200 Subject: [PATCH 03/10] Fixed the impossible bearing calculation problem * Bearing is only known of a SET_UNIT, if all units of the set are heading +/- 5 degrees in the same direction. --- Moose Development/Moose/Core/Point.lua | 4 ++-- Moose Development/Moose/Core/Set.lua | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index d49a2d0c4..58fdefccd 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -488,9 +488,9 @@ do -- COORDINATE function COORDINATE:GetHeadingText( Settings ) local Heading = self:GetHeading() if Heading then - return string.format( " heading %3.2f °", Heading ) + return string.format( " bearing %3d°", Heading ) else - return " heading cannot be determined" + return " bearing unknown" end end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 84d0763dd..c7dda4192 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1883,7 +1883,7 @@ end -- @return #number Heading Heading in degrees and speed in mps in case of moving units. function SET_UNIT:GetHeading() - local AvgHeading = nil + local HeadingSet = nil local MovingCount = 0 for UnitName, UnitData in pairs( self:GetSet() ) do @@ -1894,15 +1894,20 @@ function SET_UNIT:GetHeading() local Velocity = Coordinate:GetVelocity() if Velocity ~= 0 then local Heading = Coordinate:GetHeading() - AvgHeading = AvgHeading and ( AvgHeading + Heading ) or Heading - MovingCount = MovingCount + 1 + if HeadingSet == nil then + HeadingSet = Heading + else + local HeadingDiff = ( HeadingSet - Heading + 180 + 360 ) % 360 - 180 + HeadingDiff = math.abs( HeadingDiff ) + if HeadingDiff > 5 then + HeadingSet = nil + break + end + end end end - AvgHeading = AvgHeading and ( AvgHeading / MovingCount ) - - self:F( { AvgHeading = AvgHeading } ) - return AvgHeading + return HeadingSet end From 4edc8363e1655ba6783da380659953b0cbfd5792 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 18 Sep 2017 06:10:45 +0200 Subject: [PATCH 04/10] Urgent fixes * DESIGNATE: Messages not appearing correctly and crashing the logic is fixed. (due to a stupid typo). * TASK_A2G: Tasking is fixed. Status menus are now displayed properly. Also when the task is planned. * MENU_COMMAND: I found now why DCS is displayer "error in error handler" sometimes when a menu was selected. The error handler is DCS is bugged, so made my own one. --- Moose Development/Moose/Core/Menu.lua | 15 ++++++++++++++- Moose Development/Moose/Tasking/Mission.lua | 2 ++ Moose Development/Moose/Tasking/Task_A2G.lua | 16 ++++++++++------ .../Moose/Tasking/Task_A2G_Dispatcher.lua | 1 + Moose Development/Moose/Wrapper/Positionable.lua | 2 +- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index 20705583f..4faaa5507 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -139,11 +139,24 @@ do -- MENU_COMMAND_BASE function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments ) local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE + + -- When a menu function goes into error, DCS displays an obscure menu message. + -- This error handler catches the menu error and displays the full call stack. + local ErrorHandler = function( errmsg ) + env.info( "MOOSE error in MENU COMMAND function: " .. errmsg ) + if debug ~= nil then + env.info( debug.traceback() ) + end + return errmsg + end self:SetCommandMenuFunction( CommandMenuFunction ) self:SetCommandMenuArguments( CommandMenuArguments ) self.MenuCallHandler = function() - self.CommandMenuFunction( unpack( self.CommandMenuArguments ) ) + local function MenuFunction() + return self.CommandMenuFunction( unpack( self.CommandMenuArguments ) ) + end + local Status, Result = xpcall( MenuFunction, ErrorHandler ) end return self diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 57b52983e..86117230c 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -888,6 +888,8 @@ end -- @return #string function MISSION:ReportOverview( ReportGroup, TaskStatus ) + self:F( { TaskStatus = TaskStatus } ) + local Report = REPORT:New() -- List the name of the mission. diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 5b00b1b0d..cc4a21797 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -366,7 +366,8 @@ do -- TASK_A2G_SEAD end function TASK_A2G_SEAD:ReportOrder( ReportGroup ) - local Coordinate = self.TaskInfo.Coordinates.TaskInfoText + local Coordinate = self:GetInfo( "Coordinates" ) + --local Coordinate = self.TaskInfo.Coordinates.TaskInfoText local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) return Distance @@ -515,7 +516,8 @@ do -- TASK_A2G_BAI function TASK_A2G_BAI:ReportOrder( ReportGroup ) - local Coordinate = self.TaskInfo.Coordinates.TaskInfoText + local Coordinate = self:GetInfo( "Coordinates" ) + --local Coordinate = self.TaskInfo.Coordinates.TaskInfoText local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) return Distance @@ -630,9 +632,9 @@ do -- TASK_A2G_CAS function TASK_A2G_CAS:UpdateTaskInfo() - local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate() + local TargetCoordinate = ( self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) ) or self.TargetSetUnit:GetFirst():GetCoordinate() self:SetInfo( "Coordinates", TargetCoordinate, 0 ) - + local ThreatLevel, ThreatText if self.Detection then ThreatLevel, ThreatText = self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex ) @@ -661,8 +663,10 @@ do -- TASK_A2G_CAS end - function TASK_A2G_CAS:ReportOrder( ReportGroup ) - local Coordinate = self.TaskInfo.Coordinates.TaskInfoText + --- @param #TASK_A2G_CAS self + function TASK_A2G_CAS:ReportOrder( ReportGroup ) + + local Coordinate = self:GetInfo( "Coordinates" ) local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) return Distance diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index 8857bb4ce..7613d7cad 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -372,6 +372,7 @@ do -- TASK_A2G_DISPATCHER self.Tasks[TaskIndex] = Task Task:SetTargetZone( DetectedZone ) Task:SetDispatcher( self ) + Task:UpdateTaskInfo() Mission:AddTask( Task ) TaskReport:Add( Task:GetName() ) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index ec24b47ed..592508733 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -635,7 +635,7 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam if DCSObject:isExist() then MessageSetGroup:ForEachGroup( function( MessageGroup ) - self:GetMessageType( Message, Duration, Name ):ToGroup( MessageGroup ) + self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup ) end ) end From 9226ab9fa90bdbeaf00931c763497baeb21821d2 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 18 Sep 2017 06:15:06 +0200 Subject: [PATCH 05/10] Updated timestamp of dynamic version --- Moose Mission Setup/Moose.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 314c98d50..065517c47 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170909_1801' ) +env.info( 'Moose Generation Timestamp: 20170918_0611' ) local base = _G From ec7cc9e54757529ebe5971df53a0c5b0c7cd2f22 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 18 Sep 2017 14:50:56 +0200 Subject: [PATCH 06/10] Fixed issues with CAS and CAP * AI_CAP_ZONE: Fixed CAP engaging. * AI_CAS_ZONE: Fixed CAS engaging. --- Moose Development/Moose/AI/AI_CAP.lua | 30 ++++++++++------------ Moose Development/Moose/AI/AI_CAS.lua | 37 ++++++++++++--------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index ac5916064..e15a0dd7a 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -358,16 +358,20 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To ) end --- todo: need to fix this global function ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewEngageCapRoute( AIControllable ) +--- @param AI.AI_CAP#AI_CAP_ZONE +-- @param Wrapper.Group#GROUP EngageGroup +function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm ) - AIControllable:T( "NewEngageRoute" ) - local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_CAP_ZONE - EngageZone:__Engage( 1 ) + EngageGroup:F( { "AI_CAP_ZONE.EngageRoute:", EngageGroup:GetName() } ) + + if EngageGroup:IsAlive() then + Fsm:__Engage( 1 ) + end end + + --- @param #AI_CAP_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. @@ -503,28 +507,20 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To ) end end - --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... - self.Controllable:WayPointInitialize( EngageRoute ) - - if #AttackTasks == 0 then self:F("No targets found -> Going back to Patrolling") self:__Abort( 1 ) self:__Route( 1 ) self:SetDetectionActivated() else + + AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self ) EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) - --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... - self.Controllable:SetState( self.Controllable, "EngageZone", self ) - - self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageCapRoute" ) - self:SetDetectionDeactivated() end - --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 2 ) + Controllable:Route( EngageRoute, 0.5 ) end end diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index bd6b0e18a..a62f6d28d 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -373,12 +373,15 @@ function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To ) self:SetDetectionDeactivated() -- When not engaging, set the detection off. end ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewEngageRoute( AIControllable ) +--- @param AI.AI_CAS#AI_CAS_ZONE +-- @param Wrapper.Group#GROUP EngageGroup +function AI_CAS_ZONE.EngageRoute( EngageGroup, Fsm ) - AIControllable:T( "NewEngageRoute" ) - local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_CAS_ZONE - EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection ) + EngageGroup:F( { "AI_CAS_ZONE.EngageRoute:", EngageGroup:GetName() } ) + + if EngageGroup:IsAlive() then + Fsm:__Engage( 1, Fsm.EngageSpeed, Fsm.EngageAltitude, Fsm.EngageWeaponExpend, Fsm.EngageAttackQty, Fsm.EngageDirection ) + end end @@ -464,6 +467,9 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To, if Controllable:IsAlive() then + Controllable:OptionROEOpenFire() + Controllable:OptionROTVertical() + local EngageRoute = {} --- Calculate the current route point. @@ -485,7 +491,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To, local AttackTasks = {} - for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT self:T( DetectedUnit ) if DetectedUnit:IsAlive() then @@ -503,7 +509,8 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To, end end - EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) + AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self ) + EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks ) --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. @@ -524,20 +531,8 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To, ) EngageRoute[#EngageRoute+1] = ToTargetRoutePoint - - --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... - Controllable:WayPointInitialize( EngageRoute ) - - --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... - Controllable:SetState( Controllable, "EngageZone", self ) - - Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" ) - - --- NOW ROUTE THE GROUP! - Controllable:WayPointExecute( 1 ) - - Controllable:OptionROEOpenFire() - Controllable:OptionROTVertical() + + Controllable:Route( EngageRoute, 0.5 ) self:SetRefreshTimeInterval( 2 ) self:SetDetectionActivated() From fa14f4655ede6e7f40f8a3d00943647b8c509f7a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 20 Sep 2017 06:54:17 +0200 Subject: [PATCH 07/10] Changed message display methods --- Moose Development/Moose/Functional/Scoring.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 53ed278b1..2bfc462f5 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -668,7 +668,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score ) PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score PlayerData.Score = PlayerData.Score + Score - MESSAGE:New( self.DisplayMessagePrefix .. Text, 30 ):ToAll() + MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll() self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() ) end @@ -704,7 +704,7 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score ) PlayerData.Score = self.Players[PlayerName].Score + Score PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score - MESSAGE:New( self.DisplayMessagePrefix .. MissionName .. " : " .. Text .. " Score: " .. Score, 30 ):ToAll() + MESSAGE:NewType( self.DisplayMessagePrefix .. MissionName .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll() self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) end @@ -732,9 +732,9 @@ function SCORING:_AddMissionScore( Mission, Text, Score ) PlayerData.Score = PlayerData.Score + Score PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score - MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. + MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. Score .. " mission score!", - 60 ):ToAll() + MESSAGE.Type.Information ):ToAll() self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score ) end @@ -1522,7 +1522,7 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup ) PlayerScore, PlayerPenalty ) - MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup ) end end From a909e1ee5dec803325706bd975ebf71b90aae25f Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 20 Sep 2017 09:53:23 +0200 Subject: [PATCH 08/10] Modified message types --- .../Moose/Functional/Scoring.lua | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 2bfc462f5..40c434f33 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -608,9 +608,9 @@ function SCORING:_AddPlayerFromUnit( UnitData ) if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50 self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1 - MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. + MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.", - 2 + MESSAGE.Type.Information ):ToAll() self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() ) @@ -626,16 +626,16 @@ function SCORING:_AddPlayerFromUnit( UnitData ) if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then if self.Players[PlayerName].PenaltyWarning < 1 then - MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, - 30 + MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, + MESSAGE.Type.Information ):ToAll() self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1 end end if self.Players[PlayerName].Penalty > self.Fratricide then - MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", - 10 + MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", + MESSAGE.Type.Information ):ToAll() UnitData:GetGroup():Destroy() end @@ -902,19 +902,19 @@ function SCORING:_EventOnHit( Event ) if TargetPlayerName ~= nil then -- It is a player hitting another player ... MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, - 2 + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) else MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, - 2 + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) @@ -926,19 +926,19 @@ function SCORING:_EventOnHit( Event ) PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 if TargetPlayerName ~= nil then -- It is a player hitting another player ... MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, - 2 + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) else MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, - 2 + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) @@ -947,8 +947,8 @@ function SCORING:_EventOnHit( Event ) end else -- A scenery object was hit. MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.", - 2 + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.", + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) @@ -1008,10 +1008,10 @@ function SCORING:_EventOnHit( Event ) PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. "Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty, - 2 + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) @@ -1021,10 +1021,10 @@ function SCORING:_EventOnHit( Event ) PlayerHit.Score = PlayerHit.Score + 1 PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. "Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty, - 2 + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) @@ -1032,8 +1032,8 @@ function SCORING:_EventOnHit( Event ) end else -- A scenery object was hit. MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.", - 2 + :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.", + MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) @@ -1131,19 +1131,19 @@ function SCORING:_EventOnDeadOrCrash( Event ) if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty, - 15 + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) else MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty, - 15 + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) @@ -1165,19 +1165,19 @@ function SCORING:_EventOnDeadOrCrash( Event ) TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1 if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty, - 15 + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) else MESSAGE - :New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty, - 15 + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) @@ -1191,9 +1191,9 @@ function SCORING:_EventOnDeadOrCrash( Event ) Player.Score = Player.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score MESSAGE - :New( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. + :NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty, - 15 + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() ) @@ -1210,10 +1210,10 @@ function SCORING:_EventOnDeadOrCrash( Event ) Player.Score = Player.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score MESSAGE - :New( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + :NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty, - 15 ) + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) @@ -1232,10 +1232,10 @@ function SCORING:_EventOnDeadOrCrash( Event ) Player.Score = Player.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score MESSAGE - :New( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + :NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty, - 15 + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) @@ -1579,7 +1579,7 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup ) ReportGoals, ReportMissions ) - MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup ) end end @@ -1628,7 +1628,7 @@ function SCORING:ReportScoreAllSummary( PlayerGroup ) PlayerScore, PlayerPenalty ) - MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup ) end end From d77cbff3f8d41a9831354742e4584c302be55c3e Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Thu, 21 Sep 2017 17:18:57 +0200 Subject: [PATCH 09/10] Adding controlapi to the documentation set --- Utils/DCS_ControlAPI.txt | 565 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 Utils/DCS_ControlAPI.txt diff --git a/Utils/DCS_ControlAPI.txt b/Utils/DCS_ControlAPI.txt new file mode 100644 index 000000000..a0650d801 --- /dev/null +++ b/Utils/DCS_ControlAPI.txt @@ -0,0 +1,565 @@ +DCS Simulation Control User Scripts +==================================== + +The behaviour of the DCS can be altered using the *GameGUI.lua scripts. +You define the hooks to the DCS events, and then do what you want using the provided API. +=================================================================================================== + +When loading, DCS searches for Saved Games\DCS\Scripts\*GameGUI.lua files, +sorts them by name and then loads into the GUI Lua-state. +Each user script is loaded into an isolated environment, so the only +thing they share is the state of the simulator. + +Each script defines a set of callbacks to the DCS events and sets them with the call + DCS.setUserCallbacks(cb_table) +For each callback type the hooks of all user scripts will be called in order of loading. + +For callbacks which are supposed to returning a value, currently there are 3 of them: + onPlayerTryConnect + onPlayerTrySendChat + onPlayerTryChangeSlot +returning a value means breaking the hook call chain. +Returning nothing (or nil) means continuing the hook chain, which ends with the default allow-all handlers. + +The example user script 'testGameGUI.lua': +---------------------------------------------------------------------------------------------- +local test = {} + +function test.onPlayerTryConnect(ipaddr, name, ucid, playerID) + print('onPlayerTryConnect(%s, %s, %s, %d)', ipaddr, name, ucid, playerID) + -- if you want to gently intercept the call, allowing other user scripts to get it, + -- you better return nothing here + return true -- allow the player to connect +end + +function test.onSimulationStart() + print('Current mission is '..DCS.getMissionName()) +end + +DCS.setUserCallbacks(test) -- here we set our callbacks +---------------------------------------------------------------------------------------------- + + +The available API are documented below. +The full list of the callbacks is at the end of this document. + +In addition, all standard lua 5.1 libraries are available as well, namely: +base api, like print, etc, +math.* +table.* +string.* +io.* +os.* +debug.* + +=================================================================================================== + + + +Lua File System (lfs) API +------------------------------- +lfs.currentdir() -> string + Returns the path of the DCS install folder + +lfs.writedir() -> string + Returns the path of the current 'Saved Games\DCS' folder. + +lfs.tempdir() -> string + Returns the pat of the DCS Temp folder (AppData\Local\Temp\DCS). + +lfs.mkdir() +lfs.rmdir() +lfs.attributes() +lfs.dir() +lfs.normpath() +lfs.realpath() + + + +DCS Control API, table 'DCS.*' +------------------------------- + +DCS.setPause(bool) + Pauses/resumes the simulation. Server-side only. + +DCS.getPause() -> bool + true if simulation is paused + +DCS.stopMission() + stops current mission + +DCS.exitProcess() + Exits the DCS process. + +DCS.isMultiplayer() -> bool + True when running in the multiplayer mode. + +DCS.isServer() -> bool + True when running as a server or in the single-player mode. + +DCS.getModelTime() -> number + returns current DCS simulation time in seconds. + +DCS.getRealTime() -> number + returns current DCS real time in seconds relative to the DCS start time. + +DCS.getMissionOptions() -> table + Returns the value of 'mission.options' + +DCS.getMissionDescription() -> string + translated mission.descriptionText string + +DCS.getAvailableCoalitions() -> table { + [coalition_id] = { name = "coalition name", } + ... +} + Returns a list of coalitions which have available slots. + +DCS.getAvailableSlots(coalitionID) -> array of {unitId, type, role, callsign, groupName, country} + Returns the list of available slots. + NOTE: the returned unitID is actually a slotID, which for multi-seat units is 'unitID_seatID' + +DCS.getCurrentMission() -> table with the currently loaded mission + NOTE: to get valid mission.options use DCS.getMissionOptions() + +DCS.getMissionName() -> string + Returns the name of the current mission + +DCS.getMissionFilename() -> string + Returns the file name of the current mission (returns nil when acting as a multiplayer client). + +DCS.getMissionResult(string side) -> integer [0, 100] + Gets missin result for either 'red' or 'blue' + +DCS.getUnitProperty(missionId, propertyId) -> string + propertyId: + DCS.UNIT_RUNTIME_ID, // unique within runtime mission. int + DCS.UNIT_MISSION_ID, // unique within mission file. int>0 + DCS.UNIT_NAME, // unit name, as assigned by mission designer. + DCS.UNIT_TYPE, // unit type (Ural, ZU-23, etc) + DCS.UNIT_CATEGORY, + DCS.UNIT_GROUP_MISSION_ID, // group ID, unique within mission file. int>0 + DCS.UNIT_GROUPNAME, // group name, as assigned by mission designer. + DCS.UNIT_GROUPCATEGORY, + DCS.UNIT_CALLSIGN, + DCS.UNIT_HIDDEN,// ME hiding + DCS.UNIT_COALITION,// "blue", "red" or "unknown" + DCS.UNIT_COUNTRY_ID, + DCS.UNIT_TASK, //"unit.group.task" + DCS.UNIT_PLAYER_NAME, // valid for network "humanable" units + DCS.UNIT_ROLE,//"artillery_commander", "instructor", etc + DCS.UNIT_INVISIBLE_MAP_ICON,//ME invisible map icon + +DCS.getUnitType(missionId) -> typeId + a shortcut for DCS.getUnitProperty(missionId, DCS.UNIT_TYPE) + +DCS.getUnitTypeAttribute(typeId, attr) -> string + Returns a value from Database: Objects[typeId][attr], + for example DCS.getUnitTypeAttribute("Ural", "DisplayName") + +DCS.writeDebriefing(str) + Writes a custom string to the debriefing file + +DCS.setUserCallbacks(cb_table) + Hooks the callbacks using the handlers from the provided table. + See: "GameGUI scripts" section. + + + +Logging API 'log.*' +------------------------ +Logging works as follows: +a) each log message is accompanied with 2 attributes: a subsystem, and level. +b) after each messages gets into a logger it passes (asynchronously) through + a series of output filters which decide where the message will be written to. + +Writing to log is done by: + +log.write(SUBSYSTEM_NAME, LOG_LEVEL, message, ...) + if there are any arguments after 'message', + the actual string is formed as string.format(message, ...) + + SUBSYSTEM_NAME is a string + LOG_LEVEL is one of the values, listed below + see log.set_output() + +log.set_output(log_file_name_wo_ext, rule_subsystem_name, rule_level_mask, rule_output_mode) + + the args: + log_file_name_wo_ext: resulting log will be written to $WRITE_DIR/Logs/.log + + rule_subsytem_name: the name of the subsystem whose messages to write or empty string to match all subsystems + + rule_level_mask: a sum of log-level bit flags to match messages + valid flags are: + log.ALERT + log.ERROR + log.WARNING + log.INFO + log.DEBUG + log.ALL - includes all of the above + log.TRACE - a special level which is excluded from dcs.log file + + rule_output_mode: a sum of output flags: + log.MESSAGE + log.TIME + log.MODULE - this is a 'subsystem', not a dlc + log.LEVEL + log.FULL - all of the above + +So, in order to save net.trace(msg) messages to a file, you should issue a call: + log.set_output('lua-net', 'LuaNET', log.TRACE, log.MESSAGE + log.TIME) + + This will write to a Logs/lua-net.log file + +Or, to save everything lua-network-related: + log.set_output('lua-net', 'LuaNET', log.TRACE + log.ALL, log.MESSAGE + log.TIME + log.LEVEL) + +To close the log file, you must use + log.set_output('lua-net', '', 0, 0) + +log.* API is available in the 'Saved Games\DCS\Config\autoexec.cfg' file as well so you can control log output in you local machine. + + + +Network specific API, available through the table 'net.' +---------------------------------------------------------------- + +net.log(msg) -- equivalent to log.write('LuaNET', log.INFO, msg) +net.trace(msg) -- equivalent to log.write('LuaNET', log.TRACE, msg) + +What is the difference: log() always writes to dcs.log, but may lose messages if the output rate is too high. +trace() output never appears in the dcs.log file, it must be explicitly directed to a log file. +It never loses messages when there's an active output, but it may block if output rate is higher than writing to the log file. +To control logger output you can use $WRITE_DIR/Config/autoexec.cfg file, or call this from your network script +(log.* API, see above) + + +net.dostring_in(state, string) -> string + Executes a lua-string in a given internal lua-state and returns a string result + Valid state names are: + 'config': the state in which $INSTALL_DIR/Config/main.cfg is executed, as well as $WRITE_DIR/Config/autoexec.cfg + used for configuration settings + 'mission': holds current mission + 'export': runs $WRITE_DIR/Scripts/Export.lua and the relevant export API + +net.send_chat(string message, bool all) + Send chat message. If not all, then send to my coalition (side) only. + +net.send_chat_to(string message, playerID to) + Send direct chat message to a player + Server-side only: + net.send_chat_to(string message, playerID to[, playerID from]) + +net.recv_chat(message[, int from=0]) + Receive chat message locally[, pretending it was sent by another player]. + from = 0 means from the system + +net.load_mission(miz_filename) + Loads a specified mission, temporarily overriding the server mission list. + SERVER ONLY + +net.load_next_mission() -> bool + Load the next mission from the server mission list. Returns false if list end is reached + SERVER ONLY + +net.get_player_list() -> array of playerID + Returns the list of currently connected players + +net.get_my_player_id() -> playerID + Returns the playerID of the local player. Currently always 1 for the server. + +net.get_server_id() -> playerID + Returns playerID of the server. Currently, always 1. + +net.get_player_info(playerID) -> table + Returns a table of all player attributes or nil if playerID is invalid + +net.get_player_info(playerID, attrName) -> value + Returns a value of a given attribute for the playerID. + + Currently defined attributes are: + 'id': playerID + 'name': player name + 'side': 0 - spectators, 1 - red, 2 - blue + 'slot': slotID of the player or '' + 'ping': ping of the player in ms + 'ipaddr': IP address of the player, SERVER ONLY + 'ucid': Unique Client Identifier, SERVER ONLY + +net.kick(id, message) + Kick a player. + +net.get_stat(playerID, statID) -> integer + Get statistics for player. statIDs are: + net.PS_PING (0) - ping (in ms) + net.PS_CRASH (1) - number of crashes + net.PS_CAR (2) - number of destroyed vehicles + net.PS_PLANE (3) - ... planes/helicopters + net.PS_SHIP (4) - ... ships + net.PS_SCORE (5) - total score + net.PS_LAND (6) - number of landings + net.PS_EJECT (7) - of ejects + + +net.get_name(playerID) -> string + The same as net.get_player_info(playerID, 'name') + FIXME: implement in ServMan_compat.lua ? + +net.get_slot(playerID) -> sideID, slotID + The same as: + net.get_player_info(playerID, 'side'), net.get_player_info(playerID, 'slot') + FIXME: implement in ServMan_compat.lua ? + + + +net.set_slot(sideID, slotID) + Try to set the local player's slot. Empty slotID ('') puts the player into spectators. + +net.force_player_slot(playerID, sideID, slotID) -> boolean + Forces a player to occupy a set slot. Slot '' means no slot (moves player to spectators) + SideID: 0 - spectators, 1 - red, 2 - blue + +net.set_name(playerID, name) -- OBSOLETE, works only locally + + +net.lua2json(value) -> string + Convert a Lua value to JSON string + +net.json2lua(json_string) -> value + Convert JSON string to a Lua value + + +LuaExport API 'Export.Lo*' +---------------------------------------------------------------- +See Scripts/Export.lua for the documentation. Note that all export +API functions are available here in the Export. namespace, not the global one. +In multiplayer the availability of the API on clients depends on the server setting. + +The calls to check export capabilities: + Export.LoIsObjectExportAllowed() -- returns the value of server.advanced.allow_object_export + Export.LoIsSensorExportAllowed() -- returns the value of server.advanced.allow_sensor_export + Export.LoIsOwnshipExportAllowed() -- returns the value of server.advanced.allow_ownship_export + +These calls are only available on clients when LoIsObjectExportAllowed() is true: + Export.LoGetObjectById + Export.LoGetWorldObjects + +These calls are only available on clients when LoIsSensorExportAllowed() is true: + Export.LoGetTWSInfo + Export.LoGetTargetInformation + Export.LoGetLockedTargetInformation + Export.LoGetF15_TWS_Contacts + Export.LoGetSightingSystemInfo + Export.LoGetWingTargets + +These calls are only available on clients when LoIsOwnshipExportAllowed() is true: + Export.LoGetPlayerPlaneId + Export.LoGetIndicatedAirSpeed + Export.LoGetAngleOfAttack + Export.LoGetAngleOfSideSlip + Export.LoGetAccelerationUnits + Export.LoGetVerticalVelocity + Export.LoGetADIPitchBankYaw + Export.LoGetTrueAirSpeed + Export.LoGetAltitudeAboveSeaLevel + Export.LoGetAltitudeAboveGroundLevel + Export.LoGetMachNumber + Export.LoGetRadarAltimeter + Export.LoGetMagneticYaw + Export.LoGetGlideDeviation + Export.LoGetSideDeviation + Export.LoGetSlipBallPosition + Export.LoGetBasicAtmospherePressure + Export.LoGetControlPanel_HSI + Export.LoGetEngineInfo + Export.LoGetSelfData + Export.LoGetCameraPosition + Export.LoSetCameraPosition + Export.LoSetCommand + Export.LoGetMCPState + Export.LoGetRoute + Export.LoGetNavigationInfo + Export.LoGetPayloadInfo + Export.LoGetWingInfo + Export.LoGetMechInfo + Export.LoGetRadioBeaconsStatus + Export.LoGetVectorVelocity + Export.LoGetVectorWindVelocity + Export.LoGetSnares + Export.LoGetAngularVelocity + Export.LoGetHeightWithObjects + Export.LoGetFMData + +These functions are always available: + Export.LoGetPilotName + Export.LoGetAltitude + Export.LoGetNameByType + Export.LoGeoCoordinatesToLoCoordinates + Export.LoCoordinatesToGeoCoordinates + Export.LoGetVersionInfo + Export.LoGetWindAtPoint + Export.LoGetModelTime + Export.LoGetMissionStartTime + +These are not available in the *GameGUI state: +-- Export.LoSetSharedTexture +-- Export.LoRemoveSharedTexture +-- Export.LoUpdateSharedTexture + + +------------------------------------------------------------------------------------------- +--- The Callbacks. +------------------------------------------------------------------------------------------- + +function onMissionLoadBegin() +end + +function onMissionLoadProgress(progress, message) +end + +function onMissionLoadEnd() +end + + +function onSimulationStart() +end + +function onSimulationStop() +end + +function onSimulationFrame() +end + +function onSimulationPause() +end + +function onSimulationResume() +end + + +function onGameEvent(eventName,arg1,arg2,arg3,arg4) +--"friendly_fire", playerID, weaponName, victimPlayerID +--"mission_end", winner, msg +--"kill", killerPlayerID, killerUnitType, killerSide, victimPlayerID, victimUnitType, victimSide, weaponName +--"self_kill", playerID +--"change_slot", playerID, slotID, prevSide +--"connect", playerID, name +--"disconnect", playerID, name, playerSide, reason_code +--"crash", playerID, unit_missionID +--"eject", playerID, unit_missionID +--"takeoff", playerID, unit_missionID, airdromeName +--"landing", playerID, unit_missionID, airdromeName +--"pilot_death", playerID, unit_missionID +end + +function onNetConnect(localPlayerID) +end + +function onNetMissionChanged(newMissionName) +end + +function onNetDisconnect(reason_msg, err_code) +end + +-- disconnect reason codes: + net.ERR_INVALID_ADDRESS + net.ERR_CONNECT_FAILED + net.ERR_WRONG_VERSION + net.ERR_PROTOCOL_ERROR + net.ERR_TAINTED_CLIENT + net.ERR_INVALID_PASSWORD + net.ERR_BANNED + net.ERR_BAD_CALLSIGN + + net.ERR_TIMEOUT + net.ERR_KICKED + + +function onPlayerConnect(id) +end + +function onPlayerDisconnect(id, err_code) + -- this is never called for local playerID +end + +function onPlayerStart(id) + -- a player entered the simulation + -- this is never called for local playerID +end + +function onPlayerStop(id) + -- a player left the simulation (happens right before a disconnect, if player exited by desire) + -- this is never called for local playerID +end + +function onPlayerChangeSlot(id) + -- a player successfully changed the slot + -- this will also come as onGameEvent('change_slot', playerID, slotID), + -- if allowed by server.advanced.event_Connect setting +end + + +--- These 3 functions are different from the rest: +--- 1. they are called directly from the network code, so try to make them as fast as possible +--- 2. they return a result +-- The code shows the default implementations. + +function onPlayerTryConnect(addr, name, ucid, playerID) --> true | false, "disconnect reason" + return true +end + +function onPlayerTrySendChat(playerID, msg, all) -- -> filteredMessage | "" - empty string drops the message + return msg +end + +function onPlayerTryChangeSlot(playerID, side, slotID) -- -> true | false + return true +end + + + +-- GUI callbacks +function onChatMessage(message, from) + -- this one may be useful for chat archiving +end + +function onShowRadioMenu(a_h) +end + +function onShowPool() +end + +function onShowGameMenu() +end + +function onShowBriefing() +end + +function onShowChatAll() +end + +function onShowChatTeam() +end + +function onShowChatRead() +end + +function onShowMessage(a_text, a_duration) +end + +function onTriggerMessage(message, duration, clearView) +end + +function onRadioMessage(message, duration) +end + +function onRadioCommand(command_message) +end + +=================================================================================================== + +Happy hacking! + +Sincerely, +dsb at eagle dot ru From 0df4b5fd37357f0b819f70e92dd7bf840dc913f4 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 22 Sep 2017 11:08:35 +0200 Subject: [PATCH 10/10] Fixed DISPATCHER issues with TakeoffFromRunway --- Moose Development/Moose/AI/AI_A2A.lua | 8 +++ Moose Development/Moose/AI/AI_A2A_Cap.lua | 13 +++- .../Moose/AI/AI_A2A_Dispatcher.lua | 60 +++++++++++++++---- Moose Development/Moose/AI/AI_A2A_Gci.lua | 15 ++++- Moose Development/Moose/AI/AI_A2A_Patrol.lua | 2 +- Moose Development/Moose/Core/Base.lua | 16 +++++ Moose Development/Moose/Core/Event.lua | 11 ++-- Moose Development/Moose/Functional/Spawn.lua | 12 +++- Moose Development/Moose/Wrapper/Group.lua | 4 +- 9 files changed, 119 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index fac8b4eaa..42c21731b 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -248,6 +248,7 @@ function AI_A2A:New( AIGroup ) -- @param #AI_A2A self -- @param #number Delay + self:AddTransition( "*", "Takeoff", "Airborne" ) self:AddTransition( "*", "Return", "Returning" ) self:AddTransition( "*", "Hold", "Holding" ) self:AddTransition( "*", "Home", "Home" ) @@ -263,6 +264,13 @@ function AI_A2A:New( AIGroup ) return self end +--- @param Wrapper.Group#GROUP self +-- @param Core.Event#EVENTDATA EventData +function GROUP:OnEventTakeoff( EventData, Fsm ) + Fsm:Takeoff() + self:UnHandleEvent( EVENTS.Takeoff ) +end + function AI_A2A:SetDispatcher( Dispatcher ) self.Dispatcher = Dispatcher end diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 2509721b9..7b4fb69c0 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -141,7 +141,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling self.EngageMinSpeed = EngageMinSpeed self.EngageMaxSpeed = EngageMaxSpeed - self:AddTransition( { "Patrolling", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. + self:AddTransition( { "Patrolling", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. --- OnBefore Transition Handler for Event Engage. -- @function [parent=#AI_A2A_CAP] OnBeforeEngage @@ -302,6 +302,17 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling return self end +--- onafter State Transition for Event Patrol. +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AI Group managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_A2A_CAP:onafterStart( AIGroup, From, Event, To ) + + AIGroup:HandleEvent( EVENTS.Takeoff, nil, self ) + +end --- Set the Engage Zone which defines where the AI will engage bogies. -- @param #AI_A2A_CAP self diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 4b5c1496e..040268722 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -978,6 +978,7 @@ do -- AI_A2A_DISPATCHER -- This will avoid the detection to still "know" the shot unit until the next detection. -- Otherwise, a new intercept or engage may happen for an already shot plane! + self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead ) self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead ) @@ -1360,6 +1361,8 @@ do -- AI_A2A_DISPATCHER -- @param #AI_A2A_DISPATCHER self function AI_A2A_DISPATCHER:SetDefenderTask( SquadronName, Defender, Type, Fsm, Target ) + self:F( { SquadronName = SquadronName, Defender = Defender:GetName() } ) + self.DefenderTasks[Defender] = self.DefenderTasks[Defender] or {} self.DefenderTasks[Defender].Type = Type self.DefenderTasks[Defender].Fsm = Fsm @@ -2526,15 +2529,18 @@ do -- AI_A2A_DISPATCHER DetectedSet:Flush() local DefenderTasks = self:GetDefenderTasks() - for Defender, DefenderTask in pairs( DefenderTasks ) do - local Defender = Defender -- Wrapper.Group#GROUP + for DefenderGroup, DefenderTask in pairs( DefenderTasks ) do + local Defender = DefenderGroup -- Wrapper.Group#GROUP local DefenderTaskTarget = DefenderTask.Target local DefenderSquadronName = DefenderTask.SquadronName + if DefenderTaskTarget and DefenderTaskTarget.Index == AttackerDetection.Index then local Squadron = self:GetSquadron( DefenderSquadronName ) - local SquadronOverhead = Squadron.Overhead or self.DefenderDefault.Overhead - DefenderCount = DefenderCount + Defender:GetSize() / SquadronOverhead - self:E( "Defender Group Name: " .. Defender:GetName() .. ", Size: " .. Defender:GetSize() ) + local SquadronOverhead = Squadron.Overhead or self.DefenderDefault.Overhead + + local DefenderSize = Defender:GetInitialSize() + DefenderCount = DefenderCount + DefenderSize / SquadronOverhead + self:F( "Defender Group Name: " .. Defender:GetName() .. ", Size: " .. DefenderSize ) end end @@ -2622,10 +2628,21 @@ do -- AI_A2A_DISPATCHER Fsm:SetDisengageRadius( self.DisengageRadius ) Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName ) Fsm:Start() - Fsm:__Patrol( 2 ) self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm ) + function Fsm:onafterTakeoff( Defender, From, Event, To ) + self:F({"GCI Birth", Defender:GetName()}) + --self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) + + local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) + + if Squadron then + Fsm:__Patrol( 2 ) -- Start Patrolling + end + end + function Fsm:onafterRTB( Defender, From, Event, To ) self:F({"CAP RTB", Defender:GetName()}) self:GetParent(self).onafterRTB( self, Defender, From, Event, To ) @@ -2721,7 +2738,7 @@ do -- AI_A2A_DISPATCHER local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE local AttackerCoord = AttackerUnit:GetCoordinate() local InterceptCoord = AttackerDetection.InterceptCoord - self:F({InterceptCoord = InterceptCoord}) + self:F( { InterceptCoord = InterceptCoord } ) if InterceptCoord then local InterceptDistance = SpawnCoord:Get2DDistance( InterceptCoord ) local AirbaseDistance = SpawnCoord:Get2DDistance( AttackerCoord ) @@ -2757,6 +2774,11 @@ do -- AI_A2A_DISPATCHER self:F( { Grouping = DefenderGrouping, SquadronGrouping = DefenderSquadron.Grouping, DefaultGrouping = self.DefenderDefault.Grouping } ) self:F( { DefendersCount = DefenderCount, DefendersNeeded = DefendersNeeded } ) + if DefendersNeeded > DefenderSquadron.Resources then + DefendersNeeded = DefenderSquadron.Resources + BreakLoop = true + end + while ( DefendersNeeded > 0 ) do local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN @@ -2769,14 +2791,14 @@ do -- AI_A2A_DISPATCHER local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName ) local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP - self:F( { GCIDefender = DefenderGCI:GetName() } ) + self:E( { GCIDefender = DefenderGCI:GetName() } ) DefendersNeeded = DefendersNeeded - DefenderGrouping self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping ) if DefenderGCI then - + DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed ) @@ -2786,12 +2808,24 @@ do -- AI_A2A_DISPATCHER Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold ) Fsm:SetDisengageRadius( self.DisengageRadius ) Fsm:Start() - Fsm:__Engage( 2, AttackerDetection.Set ) -- Engage on the TargetSetUnit self:SetDefenderTask( ClosestDefenderSquadronName, DefenderGCI, "GCI", Fsm, AttackerDetection ) + function Fsm:onafterTakeoff( Defender, From, Event, To ) + self:F({"GCI Birth", Defender:GetName()}) + --self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) + + local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) + local DefenderTarget = Dispatcher:GetDefenderTaskTarget( Defender ) + + if DefenderTarget then + Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit + end + end + function Fsm:onafterRTB( Defender, From, Event, To ) self:F({"GCI RTB", Defender:GetName()}) self:GetParent(self).onafterRTB( self, Defender, From, Event, To ) @@ -2920,7 +2954,11 @@ do -- AI_A2A_DISPATCHER for AIGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do local AIGroup = AIGroup -- Wrapper.Group#GROUP if not AIGroup:IsAlive() then - self:ClearDefenderTask( AIGroup ) + local DefenderTaskFsm = self:GetDefenderTaskFsm( AIGroup ) + self:E( { Defender = AIGroup:GetName(), DefenderState = DefenderTaskFsm:GetState() } ) + if not DefenderTaskFsm:Is( "Started" ) then + self:ClearDefenderTask( AIGroup ) + end else if DefenderTask.Target then local AttackerItem = Detection:GetDetectedItem( DefenderTask.Target.Index ) diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index 5d0c415c7..7791ea72d 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -134,7 +134,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed ) self.PatrolAltType = "RADIO" - self:AddTransition( { "Started", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. + self:AddTransition( { "Started", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. --- OnBefore Transition Handler for Event Engage. -- @function [parent=#AI_A2A_GCI] OnBeforeEngage @@ -295,6 +295,19 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed ) return self end +--- onafter State Transition for Event Patrol. +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AI Group managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_A2A_GCI:onafterStart( AIGroup, From, Event, To ) + + AIGroup:HandleEvent( EVENTS.Takeoff, nil, self ) + +end + + --- onafter State Transition for Event Patrol. -- @param #AI_A2A_GCI self diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index 92cd522d3..fa9888584 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -179,7 +179,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil -- defafult PatrolAltType to "RADIO" if not specified self.PatrolAltType = PatrolAltType or "RADIO" - self:AddTransition( { "Started", "Refuelling" }, "Patrol", "Patrolling" ) + self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" ) --- OnBefore Transition Handler for Event Patrol. -- @function [parent=#AI_A2A_PATROL] OnBeforePatrol diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index b3853173d..d6f61b293 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -608,6 +608,22 @@ function BASE:CreateEventCrash( EventTime, Initiator ) world.onEvent( Event ) end +--- Creation of a Takeoff Event. +-- @param #BASE self +-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. +-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +function BASE:CreateEventTakeoff( EventTime, Initiator ) + self:F( { EventTime, Initiator } ) + + local Event = { + id = world.event.S_EVENT_TAKEOFF, + time = EventTime, + initiator = Initiator, + } + + world.onEvent( Event ) +end + -- TODO: Complete Dcs.DCSTypes#Event structure. --- The main event handling function... This function captures all events generated for the class. -- @param #BASE self diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 28a4ecf26..01235b650 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -561,12 +561,13 @@ end -- @param Core.Base#BASE EventClass The self instance of the class for which the event is. -- @param EventID -- @return #EVENT -function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID ) - self:F2( GroupName ) +function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... ) + self:E( GroupName ) local Event = self:Init( EventID, EventClass ) Event.EventGroup = true Event.EventFunction = EventFunction + Event.Params = arg return self end @@ -950,7 +951,7 @@ function EVENT:onEvent( Event ) local Result, Value = xpcall( function() - return EventData.EventFunction( EventClass, Event ) + return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) ) end, ErrorHandler ) else @@ -966,14 +967,14 @@ function EVENT:onEvent( Event ) local Result, Value = xpcall( function() - return EventFunction( EventClass, Event ) + return EventFunction( EventClass, Event, unpack( EventData.Params ) ) end, ErrorHandler ) end end end else -- The EventClass is not alive anymore, we remove it from the EventHandlers... - self:RemoveEvent( EventClass, Event.id ) + --self:RemoveEvent( EventClass, Event.id ) end else diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index dfa15037d..6a99bdc11 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -1109,8 +1109,18 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude ) -- R2.2 SpawnTemplate.x = PointVec3.x SpawnTemplate.y = PointVec3.z + + local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex ) + + -- When spawned in the air, we need to generate a Takeoff Event + + if Takeoff == GROUP.Takeoff.Air then + for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do + SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 ) + end + end - return self:SpawnWithIndex( self.SpawnIndex ) + return GroupSpawned end end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 5b4bc4169..1089224be 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -1161,9 +1161,9 @@ do -- Event Handling -- @param Core.Event#EVENTS Event -- @param #function EventFunction (optional) The function to be called when the event occurs for the GROUP. -- @return #GROUP - function GROUP:HandleEvent( Event, EventFunction ) + function GROUP:HandleEvent( Event, EventFunction, ... ) - self:EventDispatcher():OnEventForGroup( self:GetName(), EventFunction, self, Event ) + self:EventDispatcher():OnEventForGroup( self:GetName(), EventFunction, self, Event, ... ) return self end