diff --git a/Moose Development/Maths/Scoring.xlsx b/Moose Development/Maths/Scoring.xlsx new file mode 100644 index 000000000..aea394565 Binary files /dev/null and b/Moose Development/Maths/Scoring.xlsx differ diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index c866dd48b..8b6b51cba 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -1,4 +1,4 @@ ---- Single-Player:**No** / Mulit-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- **AI Balancing will replace in multi player missions +--- Single-Player:**No** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- **AI Balancing will replace in multi player missions -- non-occupied human slots with AI groups, in order to provide an engaging simulation environment, -- even when there are hardly any players in the mission.** -- @@ -116,6 +116,7 @@ function AI_BALANCER:New( SetClient, SpawnAI ) -- Inherits from BASE local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER + -- TODO: Define the OnAfterSpawned event self:SetStartState( "None" ) self:AddTransition( "*", "Monitor", "Monitoring" ) self:AddTransition( "*", "Spawn", "Spawning" ) @@ -179,15 +180,17 @@ function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) -- OK, Spawn a new group from the default SpawnAI object provided. local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP - AIGroup:E( "Spawning new AIGroup" ) - --TODO: need to rework UnitName thing ... - - SetGroup:Add( ClientName, AIGroup ) - self.SpawnQueue[ClientName] = nil - - -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. - -- Mission designers can catch this event to bind further actions to the AIGroup. - self:Spawned( AIGroup ) + if AIGroup then + AIGroup:E( "Spawning new AIGroup" ) + --TODO: need to rework UnitName thing ... + + SetGroup:Add( ClientName, AIGroup ) + self.SpawnQueue[ClientName] = nil + + -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. + -- Mission designers can catch this event to bind further actions to the AIGroup. + self:Spawned( AIGroup ) + end end --- @param #AI_BALANCER self diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index a34cc3997..c76c79c66 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -1,4 +1,4 @@ ---- Single-Player:**Yes** / Mulit-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Air** -- **Execute Combat Air Patrol (CAP).** +--- Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Air** -- **Execute Combat Air Patrol (CAP).** -- -- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG) -- diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index a7b18b8e0..c8cf9f0a7 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -1,4 +1,4 @@ ---- Single-Player:**Yes** / Mulit-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Air** -- +--- Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Air** -- -- **Provide Close Air Support to friendly ground troops.** -- -- ![Banner Image](..\Presentations\AI_CAS\Dia1.JPG) @@ -136,8 +136,8 @@ AI_CAS_ZONE = { -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO --- @param Core.Zone#ZONE EngageZone -- @return #AI_CAS_ZONE self function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index 63c6e4117..2172045f7 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -1,4 +1,4 @@ ----Single-Player:**Yes** / Mulit-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Ground** -- +---Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Ground** -- -- **Management of logical cargo objects, that can be transported from and to transportation carriers.** -- -- ![Banner Image](..\Presentations\AI_CARGO\CARGO.JPG) diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index e49b718be..8780b3ac0 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -1,4 +1,4 @@ ---- Single-Player:**Yes** / Mulit-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Air** -- +--- Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Air** -- -- **Air Patrolling or Staging.** -- -- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index a6dbb7204..90644c8fc 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -38,7 +38,7 @@ -- -- ![Objects](..\Presentations\EVENT\Dia6.JPG) -- --- For most DCS events, the above order of updating will be followed.1 +-- For most DCS events, the above order of updating will be followed. -- -- ![Objects](..\Presentations\EVENT\Dia7.JPG) -- @@ -124,6 +124,22 @@ -- -- ![Objects](..\Presentations\EVENT\Dia14.JPG) -- +-- **IMPORTANT NOTE:** Some events can involve not just UNIT objects, but also STATIC objects!!! +-- In that case the initiator or target unit fields will refer to a STATIC object! +-- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated. +-- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event. +-- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory. +-- Example code snippet: +-- +-- if Event.IniObjectCategory == Object.Category.UNIT then +-- ... +-- end +-- if Event.IniObjectCategory == Object.Category.STATIC then +-- ... +-- end +-- +-- When a static object is involved in the event, the Group and Player fields won't be populated. +-- -- ==== -- -- # **API CHANGE HISTORY** @@ -152,7 +168,8 @@ -- -- @module Event - +-- TODO: Need to update the EVENTDATA documentation with IniPlayerName and TgtPlayerName +-- TODO: Need to update the EVENTDATA documentation with IniObjectCategory and TgtObjectCategory @@ -195,23 +212,45 @@ EVENTS = { } --- The Event structure +-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event: +-- +-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event. +-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ +-- -- @type EVENTDATA --- @field id --- @field initiator --- @field target --- @field weapon --- @field IniDCSUnit --- @field IniDCSUnitName --- @field Wrapper.Unit#UNIT IniUnit --- @field #string IniUnitName --- @field IniDCSGroup --- @field IniDCSGroupName --- @field TgtDCSUnit --- @field TgtDCSUnitName --- @field Wrapper.Unit#UNIT TgtUnit --- @field #string TgtUnitName --- @field TgtDCSGroup --- @field TgtDCSGroupName +-- @field #number id The identifier of the event. +-- +-- @field Dcs.DCSUnit#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}. +-- @field Dcs.DCSObject#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). +-- @field Dcs.DCSUnit#Unit IniDCSUnit (UNIT/STATIC) The initiating @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}. +-- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name. +-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Wrapper.Unit#UNIT} of the initiator Unit object. +-- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName). +-- @field Dcs.DCSGroup#Group IniDCSGroup (UNIT) The initiating {Dcs.DCSGroup#Group}. +-- @field #string IniDCSGroupName (UNIT) The initiating Group name. +-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object. +-- @field #string IniGroupName (UNIT) The initiating GROUP name (same as IniDCSGroupName). +-- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot. +-- @field Dcs.DCScoalition#coalition.side IniCoalition (UNIT) The coalition of the initiator. +-- @field Dcs.DCSUnit#Unit.Category IniCategory (UNIT) The category of the initiator. +-- @field #string IniTypeName (UNIT) The type name of the initiator. +-- +-- @field Dcs.DCSUnit#Unit target (UNIT/STATIC) The target @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}. +-- @field Dcs.DCSObject#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). +-- @field Dcs.DCSUnit#Unit TgtDCSUnit (UNIT/STATIC) The target @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}. +-- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name. +-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Wrapper.Unit#UNIT} of the target Unit object. +-- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName). +-- @field Dcs.DCSGroup#Group TgtDCSGroup (UNIT) The target {Dcs.DCSGroup#Group}. +-- @field #string TgtDCSGroupName (UNIT) The target Group name. +-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Wrapper.Group#GROUP} of the target Group object. +-- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName). +-- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot. +-- @field Dcs.DCScoalition#coalition.side TgtCoalition (UNIT) The coalition of the target. +-- @field Dcs.DCSUnit#Unit.Category TgtCategory (UNIT) The category of the target. +-- @field #string TgtTypeName (UNIT) The type name of the target. +-- +-- @field weapon The weapon used during the event. -- @field Weapon -- @field WeaponName -- @field WeaponTgtDCSUnit @@ -598,25 +637,59 @@ function EVENT:onEvent( Event ) end if self and self.Events and self.Events[Event.id] then - if Event.initiator and Event.initiator:getCategory() == Object.Category.UNIT then - Event.IniDCSUnit = Event.initiator - Event.IniDCSGroup = Event.IniDCSUnit:getGroup() - Event.IniDCSUnitName = Event.IniDCSUnit:getName() - Event.IniUnitName = Event.IniDCSUnitName - Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName ) - if not Event.IniUnit then - -- Unit can be a CLIENT. Most likely this will be the case ... - Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true ) + + + if Event.initiator then + + Event.IniObjectCategory = Event.initiator:getCategory() + + if Event.IniObjectCategory == Object.Category.UNIT then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniDCSGroup = Event.IniDCSUnit:getGroup() + Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName ) + if not Event.IniUnit then + -- Unit can be a CLIENT. Most likely this will be the case ... + Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true ) + end + Event.IniDCSGroupName = "" + if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then + Event.IniDCSGroupName = Event.IniDCSGroup:getName() + Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) + self:E( { IniGroup = Event.IniGroup } ) + end + Event.IniPlayerName = Event.IniDCSUnit:getPlayerName() + Event.IniCoalition = Event.IniDCSUnit:getCoalition() + Event.IniTypeName = Event.IniDCSUnit:getTypeName() + Event.IniCategory = Event.IniDCSUnit:getDesc().category end - Event.IniDCSGroupName = "" - if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then - Event.IniDCSGroupName = Event.IniDCSGroup:getName() - Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) - self:E( { IniGroup = Event.IniGroup } ) + + if Event.IniObjectCategory == Object.Category.STATIC then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniUnit = STATIC:FindByName( Event.IniDCSUnitName ) + Event.IniCoalition = Event.IniDCSUnit:getCoalition() + Event.IniCategory = Event.IniDCSUnit:getDesc().category + Event.IniTypeName = Event.IniDCSUnit:getTypeName() + end + + if Event.IniObjectCategory == Object.Category.SCENERY then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator ) + Event.IniCategory = Event.IniDCSUnit:getDesc().category + Event.IniTypeName = Event.IniDCSUnit:getTypeName() end end + if Event.target then - if Event.target and Event.target:getCategory() == Object.Category.UNIT then + + Event.TgtObjectCategory = Event.target:getCategory() + + if Event.TgtObjectCategory == Object.Category.UNIT then Event.TgtDCSUnit = Event.target Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup() Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() @@ -626,8 +699,32 @@ function EVENT:onEvent( Event ) if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then Event.TgtDCSGroupName = Event.TgtDCSGroup:getName() end + Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName() + Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + end + + if Event.TgtObjectCategory == Object.Category.STATIC then + Event.TgtDCSUnit = Event.target + Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName ) + Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + end + + if Event.TgtObjectCategory == Object.Category.SCENERY then + Event.TgtDCSUnit = Event.target + Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target ) + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() end end + if Event.weapon then Event.Weapon = Event.weapon Event.WeaponName = Event.Weapon:getTypeName() diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 08ea61bdc..d263245e9 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -182,6 +182,20 @@ function MESSAGE:ToCoalition( CoalitionSide ) return self end +--- Sends a MESSAGE to a Coalition if the given Condition is true. +-- @param #MESSAGE self +-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. +-- @return #MESSAGE +function MESSAGE:ToCoalitionIf( CoalitionSide, Condition ) + self:F( CoalitionSide ) + + if Condition and Condition == true then + self:ToCoalition( CoalitionSide ) + end + + return self +end + --- Sends a MESSAGE to all players. -- @param #MESSAGE self -- @return #MESSAGE @@ -194,10 +208,24 @@ 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:F() + self:F() - self:ToCoalition( coalition.side.RED ) - self:ToCoalition( coalition.side.BLUE ) + self:ToCoalition( coalition.side.RED ) + self:ToCoalition( coalition.side.BLUE ) + + return self +end + + +--- Sends a MESSAGE to all players if the given Condition is true. +-- @param #MESSAGE self +-- @return #MESSAGE +function MESSAGE:ToAllIf( Condition ) + + if Condition and Condition == true then + self:ToCoalition( coalition.side.RED ) + self:ToCoalition( coalition.side.BLUE ) + end return self end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index cfb27e42f..02554aae8 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -7,13 +7,42 @@ -- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. -- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums. -- --- 1.1) POINT_VEC3 constructor --- --------------------------- +-- ## 1.1) POINT_VEC3 constructor +-- -- A new POINT_VEC3 instance can be created with: -- -- * @{Point#POINT_VEC3.New}(): a 3D point. -- * @{Point#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCSTypes#Vec3}. --- +-- +-- ## 1.2) Smoke, flare, explode, illuminate +-- +-- At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods: +-- +-- ### 1.2.1) Smoke +-- +-- * @{#POINT_VEC3.Smoke}(): To smoke the point in a certain color. +-- * @{#POINT_VEC3.SmokeBlue}(): To smoke the point in blue. +-- * @{#POINT_VEC3.SmokeRed}(): To smoke the point in red. +-- * @{#POINT_VEC3.SmokeOrange}(): To smoke the point in orange. +-- * @{#POINT_VEC3.SmokeWhite}(): To smoke the point in white. +-- * @{#POINT_VEC3.SmokeGreen}(): To smoke the point in green. +-- +-- ### 1.2.2) Flare +-- +-- * @{#POINT_VEC3.Flare}(): To flare the point in a certain color. +-- * @{#POINT_VEC3.FlareRed}(): To flare the point in red. +-- * @{#POINT_VEC3.FlareYellow}(): To flare the point in yellow. +-- * @{#POINT_VEC3.FlareWhite}(): To flare the point in white. +-- * @{#POINT_VEC3.FlareGreen}(): To flare the point in green. +-- +-- ### 1.2.3) Explode +-- +-- * @{#POINT_VEC3.Explosion}(): To explode the point with a certain intensity. +-- +-- ### 1.2.4) Illuminate +-- +-- * @{#POINT_VEC3.IlluminationBomb}(): To illuminate the point. +-- -- -- 2) @{Point#POINT_VEC2} class, extends @{Point#POINT_VEC3} -- ========================================================= @@ -38,9 +67,12 @@ -- -- Hereby the change log: -- --- 2017-02-18: POINT_VEC3:**NewFromVec2( Vec2, LandHeightAdd )** added. +-- 2017-03-03: POINT\_VEC3:**Explosion( ExplosionIntensity )** added. +-- 2017-03-03: POINT\_VEC3:**IlluminationBomb()** added. -- --- 2016-08-12: POINT_VEC3:**Translate( Distance, Angle )** added. +-- 2017-02-18: POINT\_VEC3:**NewFromVec2( Vec2, LandHeightAdd )** added. +-- +-- 2016-08-12: POINT\_VEC3:**Translate( Distance, Angle )** added. -- -- 2016-08-06: Made PointVec3 and Vec3, PointVec2 and Vec2 terminology used in the code consistent. -- @@ -501,6 +533,21 @@ function POINT_VEC3:RoutePointGround( Speed, Formation ) return RoutePoint end +--- Creates an explosion at the point of a certain intensity. +-- @param #POINT_VEC3 self +-- @param #number ExplosionIntensity +function POINT_VEC3:Explosion( ExplosionIntensity ) + self:F2( { ExplosionIntensity } ) + trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) +end + +--- Creates an illumination bomb at the point. +-- @param #POINT_VEC3 self +function POINT_VEC3:IlluminationBomb() + self:F2() + trigger.action.illuminationBomb( self:GetVec3() ) +end + --- Smokes the point in a color. -- @param #POINT_VEC3 self diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 739e12737..81ceaf3f1 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -64,7 +64,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr -- Initialize the ObjectSchedulers array, which is a weakly coupled table. -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) + self.ObjectSchedulers = self.ObjectSchedulers or {} -- setmetatable( {}, { __mode = "v" } ) if Scheduler.MasterObject then self.ObjectSchedulers[self.CallID] = Scheduler diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 87ce48bce..3fbe7a8ef 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -35,8 +35,8 @@ -- -- ## 1.2) Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}: -- --- * @{#ZONE_BASE.IsPointVec2InZone}(): Returns if a @{Point#POINT_VEC2} is within the zone. --- * @{#ZONE_BASE.IsPointVec3InZone}(): Returns if a @{Point#POINT_VEC3} is within the zone. +-- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a Vec2 is within the zone. +-- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a Vec3 is within the zone. -- -- ## 1.3) A zone has a probability factor that can be set to randomize a selection between zones: -- @@ -145,21 +145,28 @@ -- -- Hereby the change log: -- --- 2017-02-18: ZONE_POLYGON_BASE:**GetRandomPointVec2()** added. +-- 2017-02-28: ZONE\_BASE:**IsVec2InZone()** replaces ZONE\_BASE:_IsPointVec2InZone()_. +-- 2017-02-28: ZONE\_BASE:**IsVec3InZone()** replaces ZONE\_BASE:_IsPointVec3InZone()_. +-- 2017-02-28: ZONE\_RADIUS:**IsVec2InZone()** replaces ZONE\_RADIUS:_IsPointVec2InZone()_. +-- 2017-02-28: ZONE\_RADIUS:**IsVec3InZone()** replaces ZONE\_RADIUS:_IsPointVec3InZone()_. +-- 2017-02-28: ZONE\_POLYGON:**IsVec2InZone()** replaces ZONE\_POLYGON:_IsPointVec2InZone()_. +-- 2017-02-28: ZONE\_POLYGON:**IsVec3InZone()** replaces ZONE\_POLYGON:_IsPointVec3InZone()_. -- --- 2017-02-18: ZONE_POLYGON_BASE:**GetRandomPointVec3()** added. +-- 2017-02-18: ZONE\_POLYGON_BASE:**GetRandomPointVec2()** added. -- --- 2017-02-18: ZONE_RADIUS:**GetRandomPointVec3( inner, outer )** added. +-- 2017-02-18: ZONE\_POLYGON_BASE:**GetRandomPointVec3()** added. -- --- 2017-02-18: ZONE_RADIUS:**GetRandomPointVec2( inner, outer )** added. +-- 2017-02-18: ZONE\_RADIUS:**GetRandomPointVec3( inner, outer )** added. -- --- 2016-08-15: ZONE_BASE:**GetName()** added. +-- 2017-02-18: ZONE\_RADIUS:**GetRandomPointVec2( inner, outer )** added. -- --- 2016-08-15: ZONE_BASE:**SetZoneProbability( ZoneProbability )** added. +-- 2016-08-15: ZONE\_BASE:**GetName()** added. -- --- 2016-08-15: ZONE_BASE:**GetZoneProbability()** added. +-- 2016-08-15: ZONE\_BASE:**SetZoneProbability( ZoneProbability )** added. -- --- 2016-08-15: ZONE_BASE:**GetZoneMaybe()** added. +-- 2016-08-15: ZONE\_BASE:**GetZoneProbability()** added. +-- +-- 2016-08-15: ZONE\_BASE:**GetZoneMaybe()** added. -- -- === -- @@ -212,7 +219,7 @@ end -- @param #ZONE_BASE self -- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. -- @return #boolean true if the location is within the zone. -function ZONE_BASE:IsPointVec2InZone( Vec2 ) +function ZONE_BASE:IsVec2InZone( Vec2 ) self:F2( Vec2 ) return false @@ -222,10 +229,10 @@ end -- @param #ZONE_BASE self -- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. -- @return #boolean true if the point is within the zone. -function ZONE_BASE:IsPointVec3InZone( Vec3 ) +function ZONE_BASE:IsVec3InZone( Vec3 ) self:F2( Vec3 ) - local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } ) + local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) return InZone end @@ -514,7 +521,7 @@ end -- @param #ZONE_RADIUS self -- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. -- @return #boolean true if the location is within the zone. -function ZONE_RADIUS:IsPointVec2InZone( Vec2 ) +function ZONE_RADIUS:IsVec2InZone( Vec2 ) self:F2( Vec2 ) local ZoneVec2 = self:GetVec2() @@ -532,10 +539,10 @@ end -- @param #ZONE_RADIUS self -- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. -- @return #boolean true if the point is within the zone. -function ZONE_RADIUS:IsPointVec3InZone( Vec3 ) +function ZONE_RADIUS:IsVec3InZone( Vec3 ) self:F2( Vec3 ) - local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } ) + local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) return InZone end @@ -854,7 +861,7 @@ end -- @param #ZONE_POLYGON_BASE self -- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. -- @return #boolean true if the location is within the zone. -function ZONE_POLYGON_BASE:IsPointVec2InZone( Vec2 ) +function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 ) self:F2( Vec2 ) local Next @@ -896,7 +903,7 @@ function ZONE_POLYGON_BASE:GetRandomVec2() while Vec2Found == false do Vec2 = { x = math.random( BS.x1, BS.x2 ), y = math.random( BS.y1, BS.y2 ) } self:T2( Vec2 ) - if self:IsPointVec2InZone( Vec2 ) then + if self:IsVec2InZone( Vec2 ) then Vec2Found = true end end diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index e2a6a5f46..c77a3088a 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -1,10 +1,185 @@ ---- Scoring system for MOOSE. --- This scoring class calculates the hits and kills that players make within a simulation session. --- Scoring is calculated using a defined algorithm. --- With a small change in MissionScripting.lua, the scoring can also be logged in a CSV file, that can then be uploaded --- to a database or a BI tool to publish the scoring results to the player community. +--- Single-Player:**Yes** / Multi-Player:**Yes** / Core:**Yes** -- **Administer the scoring of player achievements, +-- and create a CSV file logging the scoring events for use at team or squadron websites.** +-- +-- ![Banner Image](..\Presentations\SCORING\Dia1.JPG) +-- +-- === +-- +-- # 1) @{Scoring#SCORING} class, extends @{Base#BASE} +-- +-- The @{#SCORING} class administers the scoring of player achievements, +-- and creates a CSV file logging the scoring events and results for use at team or squadron websites. +-- +-- SCORING automatically calculates the threat level of the objects hit and destroyed by players, +-- which can be @{Unit}, @{Static) and @{Scenery} objects. +-- +-- Positive score points are granted when enemy or neutral targets are destroyed. +-- Negative score points or penalties are given when a friendly target is hit or destroyed. +-- This brings a lot of dynamism in the scoring, where players need to take care to inflict damage on the right target. +-- By default, penalties weight heavier in the scoring, to ensure that players don't commit fratricide. +-- The total score of the player is calculated by **adding the scores minus the penalties**. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia4.JPG) +-- +-- The score value is calculated based on the **threat level of the player** and the **threat level of the target**. +-- A calculated score takes the threat level of the target divided by a balanced threat level of the player unit. +-- As such, if the threat level of the target is high, and the player threat level is low, a higher score will be given than +-- if the threat level of the player would be high too. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia5.JPG) +-- +-- When multiple players hit the same target, and finally succeed in destroying the target, then each player who contributed to the target +-- destruction, will receive a score. This is important for targets that require significant damage before it can be destroyed, like +-- ships or heavy planes. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia13.JPG) +-- +-- Optionally, the score values can be **scaled** by a **scale**. Specific scales can be set for positive cores or negative penalties. +-- The default range of the scores granted is a value between 0 and 10. The default range of penalties given is a value between 0 and 30. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia7.JPG) +-- +-- **Additional scores** can be granted to **specific objects**, when the player(s) destroy these objects. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia9.JPG) +-- +-- Various @{Zone}s can be defined for which scores are also granted when objects in that @{Zone} are destroyed. +-- This is **specifically useful** to designate **scenery targets on the map** that will generate points when destroyed. +-- +-- With a small change in MissionScripting.lua, the scoring results can also be logged in a **CSV file**. +-- These CSV files can be used to: +-- +-- * Upload scoring to a database or a BI tool to publish the scoring results to the player community. +-- * Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results. +-- * Share scoring amoung players after the mission to discuss mission results. +-- +-- Scores can be **reported**. **Menu options** are automatically added to **each player group** when a player joins a client slot or a CA unit. +-- Use the radio menu F10 to consult the scores while running the mission. +-- Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission. +-- +-- ## 1.1) Set the destroy score or penalty scale +-- +-- Score scales can be set for scores granted when enemies or friendlies are destroyed. +-- Use the method @{#SCORING.SetScaleDestroyScore}() to set the scale of enemy destroys (positive destroys). +-- Use the method @{#SCORING.SetScaleDestroyPenalty}() to set the scale of friendly destroys (negative destroys). +-- +-- local Scoring = SCORING:New( "Scoring File" ) +-- Scoring:SetScaleDestroyScore( 10 ) +-- Scoring:SetScaleDestroyPenalty( 40 ) +-- +-- The above sets the scale for valid scores to 10. So scores will be given in a scale from 0 to 10. +-- The penalties will be given in a scale from 0 to 40. +-- +-- ## 1.2) Define special targets that will give extra scores. +-- +-- Special targets can be set that will give extra scores to the players when these are destroyed. +-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Unit}s. +-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s. +-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Group}s. +-- +-- local Scoring = SCORING:New( "Scoring File" ) +-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 ) +-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 ) +-- +-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed. +-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over. +-- For example, this can be done as follows: +-- +-- Scoring:RemoveUnitScore( UNIT:FindByName( "Unit #001" ) ) +-- +-- +-- +-- ## 1.3) Define destruction zones that will give extra scores. +-- +-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points. +-- Use the method @{#SCORING.AddZoneScore}() to add a @{Zone} for additional scoring. +-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Zone} for additional scoring. +-- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Zone#ZONE_UNIT}, +-- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points. +-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone}, +-- just large enough around that building. +-- +-- ## 1.4) Add extra Goal scores upon an event or a condition. +-- +-- A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens. +-- Use the method @{#SCORING.AddGoalScore}() to add a score for a Player at any time in your mission. +-- +-- ## 1.5) Configure fratricide level. +-- +-- When a player commits too much damage to friendlies, his penalty score will reach a certain level. +-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked. +-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. +-- +-- ## 1.6) Penalty score when a player changes the coalition. +-- +-- When a player changes the coalition, he can receive a penalty score. +-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition. +-- By default, the penalty for changing coalition is the default penalty scale. +-- +-- ## 1.8) Define output CSV files. +-- +-- The CSV file is given the name of the string given in the @{#SCORING.New}{} constructor, followed by the .csv extension. +-- The file is incrementally saved in the **\\Saved Games\\DCS\\Logs** folder, and has a time stamp indicating each mission run. +-- See the following example: +-- +-- local ScoringFirstMission = SCORING:New( "FirstMission" ) +-- local ScoringSecondMission = SCORING:New( "SecondMission" ) +-- +-- The above documents that 2 Scoring objects are created, ScoringFirstMission and ScoringSecondMission. +-- +-- ## 1.9) Configure messages. +-- +-- When players hit or destroy targets, messages are sent. +-- Various methods exist to configure: +-- +-- * Which messages are sent upon the event. +-- * Which audience receives the message. +-- +-- ### 1.9.1) Configure the messages sent upon the event. +-- +-- Use the following methods to configure when to send messages. By default, all messages are sent. +-- +-- * @{#SCORING.SetMessagesHit}(): Configure to send messages after a target has been hit. +-- * @{#SCORING.SetMessagesDestroy}(): Configure to send messages after a target has been destroyed. +-- * @{#SCORING.SetMessagesAddon}(): Configure to send messages for additional score, after a target has been destroyed. +-- * @{#SCORING.SetMessagesZone}(): Configure to send messages for additional score, after a target has been destroyed within a given zone. +-- +-- ### 1.9.2) Configure the audience of the messages. +-- +-- Use the following methods to configure the audience of the messages. By default, the messages are sent to all players in the mission. +-- +-- * @{#SCORING.SetMessagesToAll}(): Configure to send messages to all players. +-- * @{#SCORING.SetMessagesToCoalition}(): Configure to send messages to only those players within the same coalition as the player. +-- +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-02-26: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **Wingthor (TAW)**: Testing & Advice. +-- * **Dutch-Baron (TAW)**: Testing & Advice. +-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing and Advice. +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- -- @module Scoring --- @author FlightControl --- The Scoring class @@ -42,7 +217,7 @@ local _SCORINGCategory = function SCORING:New( GameName ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, BASE:New() ) -- #SCORING if GameName then self.GameName = GameName @@ -51,172 +226,340 @@ function SCORING:New( GameName ) end + -- Additional Object scores + self.ScoringObjects = {} + + -- Additional Zone scores. + self.ScoringZones = {} + + -- Configure Messages + self:SetMessagesToAll() + self:SetMessagesHit( true ) + self:SetMessagesDestroy( true ) + self:SetMessagesScore( true ) + self:SetMessagesZone( true ) + + -- Scales + self:SetScaleDestroyScore( 10 ) + self:SetScaleDestroyPenalty( 30 ) + + -- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked). + self:SetFratricide( self.ScaleDestroyPenalty * 3 ) + + -- Default penalty when a player changes coalition. + self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty ) + + -- Event handlers self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Hit, self._EventOnHit ) + self:HandleEvent( EVENTS.PlayerEnterUnit ) + self:HandleEvent( EVENTS.PlayerLeaveUnit ) - --self.SchedulerId = routines.scheduleFunction( SCORING._FollowPlayersScheduled, { self }, 0, 5 ) - self.SchedulerId = SCHEDULER:New( self, self._FollowPlayersScheduled, {}, 0, 5 ) - - self:ScoreMenu() - - self:OpenCSV( GameName) + -- Create the CSV file. + self:OpenCSV( GameName ) return self end ---- Creates a score radio menu. Can be accessed using Radio -> F10. +--- Set the scale for scoring valid destroys (enemy destroys). +-- A default calculated score is a value between 1 and 10. +-- The scale magnifies the scores given to the players. -- @param #SCORING self --- @return #SCORING self -function SCORING:ScoreMenu() - self.Menu = MENU_MISSION:New( 'Scoring' ) - self.AllScoresMenu = MENU_MISSION_COMMAND:New( 'Score All Active Players', self.Menu, SCORING.ReportScoreAll, self ) - --- = COMMANDMENU:New('Your Current Score', ReportScore, SCORING.ReportScorePlayer, self ) +-- @param #number Scale The scale of the score given. +function SCORING:SetScaleDestroyScore( Scale ) + + self.ScaleDestroyScore = Scale + return self end ---- Follows new players entering Clients within the DCSRTE. --- TODO: Need to see if i can catch this also with an event. It will eliminate the schedule ... -function SCORING:_FollowPlayersScheduled() - self:F3( "_FollowPlayersScheduled" ) +--- Set the scale for scoring penalty destroys (friendly destroys). +-- A default calculated penalty is a value between 1 and 10. +-- The scale magnifies the scores given to the players. +-- @param #SCORING self +-- @param #number Scale The scale of the score given. +-- @return #SCORING +function SCORING:SetScaleDestroyPenalty( Scale ) - local ClientUnit = 0 - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) } - local unitId - local unitData - local AlivePlayerUnits = {} + self.ScaleDestroyPenalty = Scale + + return self +end - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - self:T3( { "_FollowPlayersScheduled", CoalitionData } ) - for UnitId, UnitData in pairs( CoalitionData ) do - self:_AddPlayerFromUnit( UnitData ) - end +--- Add a @{Unit} for additional scoring when the @{Unit} is destroyed. +-- Note that if there was already a @{Unit} declared within the scoring with the same name, +-- then the old @{Unit} will be replaced with the new @{Unit}. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddUnitScore( ScoreUnit, Score ) + + local UnitName = ScoreUnit:GetName() + + self.ScoringObjects[UnitName] = Score + + return self +end + +--- Removes a @{Unit} for additional scoring when the @{Unit} is destroyed. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given. +-- @return #SCORING +function SCORING:RemoveUnitScore( ScoreUnit ) + + local UnitName = ScoreUnit:GetName() + + self.ScoringObjects[UnitName] = nil + + return self +end + +--- Add a @{Static} for additional scoring when the @{Static} is destroyed. +-- Note that if there was already a @{Static} declared within the scoring with the same name, +-- then the old @{Static} will be replaced with the new @{Static}. +-- @param #SCORING self +-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddStaticScore( ScoreStatic, Score ) + + local StaticName = ScoreStatic:GetName() + + self.ScoringObjects[StaticName] = Score + + return self +end + +--- Removes a @{Static} for additional scoring when the @{Static} is destroyed. +-- @param #SCORING self +-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given. +-- @return #SCORING +function SCORING:RemoveStaticScore( ScoreStatic ) + + local StaticName = ScoreStatic:GetName() + + self.ScoringObjects[StaticName] = nil + + return self +end + + +--- Specify a special additional score for a @{Group}. +-- @param #SCORING self +-- @param Wrapper.Group#GROUP ScoreGroup The @{Group} for which each @{Unit} a Score is given. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddScoreGroup( ScoreGroup, Score ) + + local ScoreUnits = ScoreGroup:GetUnits() + + for ScoreUnitID, ScoreUnit in pairs( ScoreUnits ) do + local UnitName = ScoreUnit:GetName() + self.ScoringObjects[UnitName] = Score end - return true + return self end - ---- Track DEAD or CRASH events for the scoring. +--- Add a @{Zone} to define additional scoring when any object is destroyed in that zone. +-- Note that if a @{Zone} with the same name is already within the scoring added, the @{Zone} (type) and Score will be replaced! +-- This allows for a dynamic destruction zone evolution within your mission. -- @param #SCORING self --- @param Core.Event#EVENTDATA Event -function SCORING:_EventOnDeadOrCrash( Event ) - self:F( { Event } ) +-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters. +-- Note that a zone can be a polygon or a moving zone. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddZoneScore( ScoreZone, Score ) - local TargetUnit = nil - local TargetGroup = nil - local TargetUnitName = "" - local TargetGroupName = "" - local TargetPlayerName = "" - local TargetCoalition = nil - local TargetCategory = nil - local TargetType = nil - local TargetUnitCoalition = nil - local TargetUnitCategory = nil - local TargetUnitType = nil + local ZoneName = ScoreZone:GetName() - if Event.IniDCSUnit then - - TargetUnit = Event.IniDCSUnit - TargetUnitName = Event.IniDCSUnitName - TargetGroup = Event.IniDCSGroup - TargetGroupName = Event.IniDCSGroupName - TargetPlayerName = TargetUnit:getPlayerName() - - TargetCoalition = TargetUnit:getCoalition() - --TargetCategory = TargetUnit:getCategory() - TargetCategory = TargetUnit:getDesc().category -- Workaround - TargetType = TargetUnit:getTypeName() - - TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] - TargetUnitCategory = _SCORINGCategory[TargetCategory] - TargetUnitType = TargetType - - self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) - end - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Something got killed" ) - - -- Some variables - local InitUnitName = PlayerData.UnitName - local InitUnitType = PlayerData.UnitType - local InitCoalition = PlayerData.UnitCoalition - local InitCategory = PlayerData.UnitCategory - local InitUnitCoalition = _SCORINGCoalition[InitCoalition] - local InitUnitCategory = _SCORINGCategory[InitCategory] - - self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } ) - - -- What is he hitting? - if TargetCategory then - if PlayerData and PlayerData.Hit and PlayerData.Hit[TargetCategory] and PlayerData.Hit[TargetCategory][TargetUnitName] then -- Was there a hit for this unit for this player before registered??? - if not PlayerData.Kill[TargetCategory] then - PlayerData.Kill[TargetCategory] = {} - end - if not PlayerData.Kill[TargetCategory][TargetType] then - PlayerData.Kill[TargetCategory][TargetType] = {} - PlayerData.Kill[TargetCategory][TargetType].Score = 0 - PlayerData.Kill[TargetCategory][TargetType].ScoreKill = 0 - PlayerData.Kill[TargetCategory][TargetType].Penalty = 0 - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = 0 - end - - if InitCoalition == TargetCoalition then - PlayerData.Penalty = PlayerData.Penalty + 25 - PlayerData.Kill[TargetCategory][TargetType].Penalty = PlayerData.Kill[TargetCategory][TargetType].Penalty + 25 - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = PlayerData.Kill[TargetCategory][TargetType].PenaltyKill + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' killed a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Penalty: -" .. PlayerData.Kill[TargetCategory][TargetType].Penalty .. - ". Score Total:" .. PlayerData.Score - PlayerData.Penalty, - 5 ):ToAll() - self:ScoreCSV( PlayerName, "KILL_PENALTY", 1, -125, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - else - PlayerData.Score = PlayerData.Score + 10 - PlayerData.Kill[TargetCategory][TargetType].Score = PlayerData.Kill[TargetCategory][TargetType].Score + 10 - PlayerData.Kill[TargetCategory][TargetType].ScoreKill = PlayerData.Kill[TargetCategory][TargetType].ScoreKill + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' killed an enemy " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - PlayerData.Kill[TargetCategory][TargetType].ScoreKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Score .. - ". Score Total:" .. PlayerData.Score - PlayerData.Penalty, - 5 ):ToAll() - self:ScoreCSV( PlayerName, "KILL_SCORE", 1, 10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - end - end - end - end - end + self.ScoringZones[ZoneName] = {} + self.ScoringZones[ZoneName].ScoreZone = ScoreZone + self.ScoringZones[ZoneName].Score = Score + + return self end +--- Remove a @{Zone} for additional scoring. +-- The scoring will search if any @{Zone} is added with the given name, and will remove that zone from the scoring. +-- This allows for a dynamic destruction zone evolution within your mission. +-- @param #SCORING self +-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters. +-- Note that a zone can be a polygon or a moving zone. +-- @return #SCORING +function SCORING:RemoveZoneScore( ScoreZone ) + + local ZoneName = ScoreZone:GetName() + + self.ScoringZones[ZoneName] = nil + + return self +end + + +--- Configure to send messages after a target has been hit. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesHit( OnOff ) + + self.MessagesHit = OnOff + return self +end + +--- If to send messages after a target has been hit. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesHit() + + return self.MessagesHit +end + +--- Configure to send messages after a target has been destroyed. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesDestroy( OnOff ) + + self.MessagesDestroy = OnOff + return self +end + +--- If to send messages after a target has been destroyed. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesDestroy() + + return self.MessagesDestroy +end + +--- Configure to send messages after a target has been destroyed and receives additional scores. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesScore( OnOff ) + + self.MessagesScore = OnOff + return self +end + +--- If to send messages after a target has been destroyed and receives additional scores. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesScore() + + return self.MessagesScore +end + +--- Configure to send messages after a target has been hit in a zone, and additional score is received. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesZone( OnOff ) + + self.MessagesZone = OnOff + return self +end + +--- If to send messages after a target has been hit in a zone, and additional score is received. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesZone() + + return self.MessagesZone +end + +--- Configure to send messages to all players. +-- @param #SCORING self +-- @return #SCORING +function SCORING:SetMessagesToAll() + + self.MessagesAudience = 1 + return self +end + +--- If to send messages to all players. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesToAll() + + return self.MessagesAudience == 1 +end + +--- Configure to send messages to only those players within the same coalition as the player. +-- @param #SCORING self +-- @return #SCORING +function SCORING:SetMessagesToCoalition() + + self.MessagesAudience = 2 + return self +end + +--- If to send messages to only those players within the same coalition as the player. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesToCoalition() + + return self.MessagesAudience == 2 +end + + +--- When a player commits too much damage to friendlies, his penalty score will reach a certain level. +-- Use this method to define the level when a player gets kicked. +-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. +-- @param #SCORING self +-- @param #number Fratricide The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked. +-- @return #SCORING +function SCORING:SetFratricide( Fratricide ) + + self.Fratricide = Fratricide + return self +end + + +--- When a player changes the coalition, he can receive a penalty score. +-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition. +-- By default, the penalty for changing coalition is the default penalty scale. +-- @param #SCORING self +-- @param #number CoalitionChangePenalty The amount of penalty that is given. +-- @return #SCORING +function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty ) + + self.CoalitionChangePenalty = CoalitionChangePenalty + return self +end --- Add a new player entering a Unit. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT UnitData function SCORING:_AddPlayerFromUnit( UnitData ) self:F( UnitData ) - if UnitData and UnitData:isExist() then - local UnitName = UnitData:getName() - local PlayerName = UnitData:getPlayerName() - local UnitDesc = UnitData:getDesc() + if UnitData:IsAlive() then + local UnitName = UnitData:GetName() + local PlayerName = UnitData:GetPlayerName() + local UnitDesc = UnitData:GetDesc() local UnitCategory = UnitDesc.category - local UnitCoalition = UnitData:getCoalition() - local UnitTypeName = UnitData:getTypeName() + local UnitCoalition = UnitData:GetCoalition() + local UnitTypeName = UnitData:GetTypeName() self:T( { PlayerName, UnitName, UnitCategory, UnitCoalition, UnitTypeName } ) if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ... self.Players[PlayerName] = {} self.Players[PlayerName].Hit = {} - self.Players[PlayerName].Kill = {} + self.Players[PlayerName].Destroy = {} self.Players[PlayerName].Mission = {} -- for CategoryID, CategoryName in pairs( SCORINGCategory ) do -- self.Players[PlayerName].Hit[CategoryID] = {} - -- self.Players[PlayerName].Kill[CategoryID] = {} + -- self.Players[PlayerName].Destroy[CategoryID] = {} -- end self.Players[PlayerName].HitPlayers = {} - self.Players[PlayerName].HitUnits = {} self.Players[PlayerName].Score = 0 self.Players[PlayerName].Penalty = 0 self.Players[PlayerName].PenaltyCoalition = 0 @@ -234,26 +577,26 @@ function SCORING:_AddPlayerFromUnit( UnitData ) 2 ):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() ) + UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() ) end end self.Players[PlayerName].UnitName = UnitName self.Players[PlayerName].UnitCoalition = UnitCoalition self.Players[PlayerName].UnitCategory = UnitCategory self.Players[PlayerName].UnitType = UnitTypeName + self.Players[PlayerName].UNIT = UnitData - if self.Players[PlayerName].Penalty > 100 then + if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then if self.Players[PlayerName].PenaltyWarning < 1 then - MESSAGE:New( "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than 150, you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, + MESSAGE:New( "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 ):ToAll() self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1 end end - if self.Players[PlayerName].Penalty > 150 then - ClientGroup = GROUP:NewFromDCSUnit( UnitData ) - ClientGroup:Destroy() + if self.Players[PlayerName].Penalty > self.Fratricide then + UnitData:Destroy() MESSAGE:New( "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", 10 ):ToAll() @@ -263,6 +606,37 @@ function SCORING:_AddPlayerFromUnit( UnitData ) end +--- Add a goal score for a player. +-- The method takes the PlayerUnit for which the Goal score needs to be set. +-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal. +-- A free text can be given that is shown to the players. +-- The Score can be both positive and negative. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc. +-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel). +-- @param #string Text A free text that is shown to the players. +-- @param #number Score The score can be both positive or negative ( Penalty ). +function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score ) + + local PlayerName = PlayerUnit:GetPlayerName() + + self:E( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } ) + + -- PlayerName can be nil, if the Unit with the player crashed or due to another reason. + if PlayerName then + local PlayerData = self.Players[PlayerName] + + PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 } + PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score + PlayerData.Score = PlayerData.Score + Score + + MESSAGE:New( Text, 30 ):ToAll() + + self:ScoreCSV( PlayerName, "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() ) + end +end + + --- Registers Scores the players completing a Mission Task. -- @param #SCORING self -- @param Tasking.Mission#MISSION Mission @@ -331,6 +705,34 @@ function SCORING:_AddMissionScore( Mission, Text, Score ) end end + +--- Handles the OnPlayerEnterUnit event for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:OnEventPlayerEnterUnit( Event ) + if Event.IniUnit then + self:_AddPlayerFromUnit( Event.IniUnit ) + local Menu = MENU_GROUP:New( Event.IniGroup, 'Scoring' ) + local ReportGroupSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, Event.IniGroup ) + local ReportGroupDetailed = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, Event.IniGroup ) + local ReportToAllSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, Event.IniGroup ) + self:SetState( Event.IniUnit, "ScoringMenu", Menu ) + end +end + +--- Handles the OnPlayerLeaveUnit event for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:OnEventPlayerLeaveUnit( Event ) + if Event.IniUnit then + local Menu = self:GetState( Event.IniUnit, "ScoringMenu" ) -- Core.Menu#MENU_GROUP + if Menu then + Menu:Remove() + end + end +end + + --- Handles the OnHit event for the scoring. -- @param #SCORING self -- @param Core.Event#EVENTDATA Event @@ -338,6 +740,7 @@ function SCORING:_EventOnHit( Event ) self:F( { Event } ) local InitUnit = nil + local InitUNIT = nil local InitUnitName = "" local InitGroup = nil local InitGroupName = "" @@ -351,10 +754,11 @@ function SCORING:_EventOnHit( Event ) local InitUnitType = nil local TargetUnit = nil + local TargetUNIT = nil local TargetUnitName = "" local TargetGroup = nil local TargetGroupName = "" - local TargetPlayerName = "" + local TargetPlayerName = nil local TargetCoalition = nil local TargetCategory = nil @@ -366,16 +770,18 @@ function SCORING:_EventOnHit( Event ) if Event.IniDCSUnit then InitUnit = Event.IniDCSUnit + InitUNIT = Event.IniUnit InitUnitName = Event.IniDCSUnitName InitGroup = Event.IniDCSGroup InitGroupName = Event.IniDCSGroupName - InitPlayerName = InitUnit:getPlayerName() + InitPlayerName = Event.IniPlayerName - InitCoalition = InitUnit:getCoalition() + InitCoalition = Event.IniCoalition --TODO: Workaround Client DCS Bug --InitCategory = InitUnit:getCategory() - InitCategory = InitUnit:getDesc().category - InitType = InitUnit:getTypeName() + --InitCategory = InitUnit:getDesc().category + InitCategory = Event.IniCategory + InitType = Event.IniTypeName InitUnitCoalition = _SCORINGCoalition[InitCoalition] InitUnitCategory = _SCORINGCategory[InitCategory] @@ -388,16 +794,18 @@ function SCORING:_EventOnHit( Event ) if Event.TgtDCSUnit then TargetUnit = Event.TgtDCSUnit + TargetUNIT = Event.TgtUnit TargetUnitName = Event.TgtDCSUnitName TargetGroup = Event.TgtDCSGroup TargetGroupName = Event.TgtDCSGroupName - TargetPlayerName = TargetUnit:getPlayerName() + TargetPlayerName = Event.TgtPlayerName - TargetCoalition = TargetUnit:getCoalition() + TargetCoalition = Event.TgtCoalition --TODO: Workaround Client DCS Bug --TargetCategory = TargetUnit:getCategory() - TargetCategory = TargetUnit:getDesc().category - TargetType = TargetUnit:getTypeName() + --TargetCategory = TargetUnit:getDesc().category + TargetCategory = Event.TgtCategory + TargetType = Event.TgtTypeName TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] TargetUnitCategory = _SCORINGCategory[TargetCategory] @@ -407,279 +815,682 @@ function SCORING:_EventOnHit( Event ) end if InitPlayerName ~= nil then -- It is a player that is hitting something - self:_AddPlayerFromUnit( InitUnit ) + self:_AddPlayerFromUnit( InitUNIT ) if self.Players[InitPlayerName] then -- This should normally not happen, but i'll test it anyway. if TargetPlayerName ~= nil then -- It is a player hitting another player ... - self:_AddPlayerFromUnit( TargetUnit ) - self.Players[InitPlayerName].HitPlayers = self.Players[InitPlayerName].HitPlayers + 1 - end + self:_AddPlayerFromUnit( TargetUNIT ) + end - self:T( "Hitting Something" ) - -- What is he hitting? - if TargetCategory then - if not self.Players[InitPlayerName].Hit[TargetCategory] then - self.Players[InitPlayerName].Hit[TargetCategory] = {} + self:T( "Hitting Something" ) + + -- What is he hitting? + if TargetCategory then + + -- A target got hit, score it. + -- Player contains the score data from self.Players[InitPlayerName] + local Player = self.Players[InitPlayerName] + + -- Ensure there is a hit table per TargetCategory and TargetUnitName. + Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {} + Player.Hit[TargetCategory][TargetUnitName] = Player.Hit[TargetCategory][TargetUnitName] or {} + + -- PlayerHit contains the score counters and data per unit that was hit. + local PlayerHit = Player.Hit[TargetCategory][TargetUnitName] + + PlayerHit.Score = PlayerHit.Score or 0 + PlayerHit.Penalty = PlayerHit.Penalty or 0 + PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0 + PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0 + PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0 + PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT + + -- Only grant hit scores if there was more than one second between the last hit. + if timer.getTime() - PlayerHit.TimeStamp > 1 then + PlayerHit.TimeStamp = timer.getTime() + + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + + -- Ensure there is a Player to Player hit reference table. + Player.HitPlayers[TargetPlayerName] = true + end + + local Score = 0 + + if InitCoalition then -- A coalition object was hit. + if InitCoalition == TargetCoalition then + Player.Penalty = Player.Penalty + 10 + PlayerHit.Penalty = PlayerHit.Penalty + 10 + PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 + + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit a friendly target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + end + self:ScoreCSV( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + else + Player.Score = Player.Score + 1 + PlayerHit.Score = PlayerHit.Score + 1 + PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit an enemy target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + end + self:ScoreCSV( InitPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + end + else -- A scenery object was hit. + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit a scenery object.", + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + self:ScoreCSV( InitPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) + end + end end - if not self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName] then - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName] = {} - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = 0 - end - local Score = 0 - if InitCoalition == TargetCoalition then - self.Players[InitPlayerName].Penalty = self.Players[InitPlayerName].Penalty + 10 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty + 10 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit + 1 - MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit .. " times. Penalty: -" .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty .. - ". Score Total:" .. self.Players[InitPlayerName].Score - self.Players[InitPlayerName].Penalty, - 2 - ):ToAll() - self:ScoreCSV( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - else - self.Players[InitPlayerName].Score = self.Players[InitPlayerName].Score + 1 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score + 1 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit + 1 - MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit .. " times. Score: " .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score .. - ". Score Total:" .. self.Players[InitPlayerName].Score - self.Players[InitPlayerName].Penalty, - 2 - ):ToAll() - self:ScoreCSV( InitPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - end - end end elseif InitPlayerName == nil then -- It is an AI hitting a player??? end end +--- Track DEAD or CRASH events for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:_EventOnDeadOrCrash( Event ) + self:F( { Event } ) -function SCORING:ReportScoreAll() + local TargetUnit = nil + local TargetGroup = nil + local TargetUnitName = "" + local TargetGroupName = "" + local TargetPlayerName = "" + local TargetCoalition = nil + local TargetCategory = nil + local TargetType = nil + local TargetUnitCoalition = nil + local TargetUnitCategory = nil + local TargetUnitType = nil - env.info( "Hello World " ) + if Event.IniDCSUnit then - local ScoreMessage = "" - local PlayerMessage = "" + TargetUnit = Event.IniDCSUnit + TargetUnitName = Event.IniDCSUnitName + TargetGroup = Event.IniDCSGroup + TargetGroupName = Event.IniDCSGroupName + TargetPlayerName = Event.IniPlayerName - self:T( "Score Report" ) + TargetCoalition = Event.IniCoalition + --TargetCategory = TargetUnit:getCategory() + --TargetCategory = TargetUnit:getDesc().category -- Workaround + TargetCategory = Event.IniCategory + TargetType = Event.IniTypeName - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Score Player: " .. PlayerName ) + TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] + TargetUnitCategory = _SCORINGCategory[TargetCategory] + TargetUnitType = TargetType + + self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) + end + + -- Player contains the score and reference data for the player. + for PlayerName, Player in pairs( self.Players ) do + if Player then -- This should normally not happen, but i'll test it anyway. + self:T( "Something got destroyed" ) -- Some variables - local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] - local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] - local InitUnitType = PlayerData.UnitType - local InitUnitName = PlayerData.UnitName + local InitUnitName = Player.UnitName + local InitUnitType = Player.UnitType + local InitCoalition = Player.UnitCoalition + local InitCategory = Player.UnitCategory + local InitUnitCoalition = _SCORINGCoalition[InitCoalition] + local InitUnitCategory = _SCORINGCategory[InitCategory] - local PlayerScore = 0 - local PlayerPenalty = 0 + self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } ) - ScoreMessage = ":\n" + -- What is the player destroying? + if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] then -- Was there a hit for this unit for this player before registered??? + + Player.Destroy[TargetCategory] = Player.Destroy[TargetCategory] or {} + Player.Destroy[TargetCategory][TargetType] = Player.Destroy[TargetCategory][TargetType] or {} - local ScoreMessageHits = "" + -- PlayerDestroy contains the destroy score data per category and target type of the player. + local TargetDestroy = Player.Destroy[TargetCategory][TargetType] + TargetDestroy.Score = TargetDestroy.Score or 0 + TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy or 0 + TargetDestroy.Penalty = TargetDestroy.Penalty or 0 + TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy or 0 + TargetDestroy.UNIT = TargetDestroy.UNIT or Player.Hit[TargetCategory][TargetUnitName].UNIT - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( CategoryName ) - if PlayerData.Hit[CategoryID] then - local Score = 0 - local ScoreHit = 0 - local Penalty = 0 - local PenaltyHit = 0 - self:T( "Hit scores exist for player " .. PlayerName ) - for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do - Score = Score + UnitData.Score - ScoreHit = ScoreHit + UnitData.ScoreHit - Penalty = Penalty + UnitData.Penalty - PenaltyHit = UnitData.PenaltyHit + if TargetCoalition then + if InitCoalition == TargetCoalition then + local ThreatLevelTarget, ThreatTypeTarget = TargetDestroy.UNIT:GetThreatLevel() + local ThreatLevelPlayer = Player.UNIT:GetThreatLevel() / 10 + 1 + local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 ) + self:E( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } ) + + Player.Penalty = Player.Penalty + ThreatPenalty + TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty + TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1 + + if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.PenaltyDestroy .. " times. " .. + "Penalty: -" .. TargetDestroy.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed a friendly target " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.PenaltyDestroy .. " times. " .. + "Penalty: -" .. TargetDestroy.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + end + self:ScoreCSV( PlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + else + + local ThreatLevelTarget, ThreatTypeTarget = TargetDestroy.UNIT:GetThreatLevel() + local ThreatLevelPlayer = Player.UNIT:GetThreatLevel() / 10 + 1 + local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 ) + + self:E( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } ) + + Player.Score = Player.Score + ThreatScore + TargetDestroy.Score = TargetDestroy.Score + ThreatScore + TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1 + if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.ScoreDestroy .. " times. " .. + "Score: " .. TargetDestroy.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed an enemy " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.ScoreDestroy .. " times. " .. + "Score: " .. TargetDestroy.Score .. ". Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + end + self:ScoreCSV( PlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + + local UnitName = TargetDestroy.UNIT:GetName() + local Score = self.ScoringObjects[UnitName] + if Score then + Player.Score = Player.Score + Score + TargetDestroy.Score = TargetDestroy.Score + Score + MESSAGE + :New( "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() ) + self:ScoreCSV( PlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + end + + -- Check if there are Zones where the destruction happened. + for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do + self:E( { ScoringZone = ScoreZoneData } ) + local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE + local Score = ScoreZoneData.Score + if ScoreZone:IsVec2InZone( TargetDestroy.UNIT:GetVec2() ) then + Player.Score = Player.Score + Score + TargetDestroy.Score = TargetDestroy.Score + Score + MESSAGE + :New( "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. + "Total: " .. Player.Score - Player.Penalty, + 15 ) + :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) + self:ScoreCSV( PlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + end + end + end - local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) - self:T( ScoreMessageHit ) - ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty else - --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) + -- Check if there are Zones where the destruction happened. + for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do + self:E( { ScoringZone = ScoreZoneData } ) + local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE + local Score = ScoreZoneData.Score + if ScoreZone:IsVec2InZone( TargetDestroy.UNIT:GetVec2() ) then + Player.Score = Player.Score + Score + TargetDestroy.Score = TargetDestroy.Score + Score + MESSAGE + :New( "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. + "Total: " .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) + self:ScoreCSV( PlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) + end + end end end - if ScoreMessageHits ~= "" then - ScoreMessage = ScoreMessage .. " Hits: " .. ScoreMessageHits .. "\n" - end - - local ScoreMessageKills = "" - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( "Kill scores exist for player " .. PlayerName ) - if PlayerData.Kill[CategoryID] then - local Score = 0 - local ScoreKill = 0 - local Penalty = 0 - local PenaltyKill = 0 - - for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do - Score = Score + UnitData.Score - ScoreKill = ScoreKill + UnitData.ScoreKill - Penalty = Penalty + UnitData.Penalty - PenaltyKill = PenaltyKill + UnitData.PenaltyKill - end - - local ScoreMessageKill = string.format( " %s:%d ", CategoryName, Score - Penalty ) - self:T( ScoreMessageKill ) - ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill - - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageKills ~= "" then - ScoreMessage = ScoreMessage .. " Kills: " .. ScoreMessageKills .. "\n" - end - - local ScoreMessageCoalitionChangePenalties = "" - if PlayerData.PenaltyCoalition ~= 0 then - ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) - PlayerPenalty = PlayerPenalty + PlayerData.Penalty - end - if ScoreMessageCoalitionChangePenalties ~= "" then - ScoreMessage = ScoreMessage .. " Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties .. "\n" - end - - local ScoreMessageMission = "" - local ScoreMission = 0 - local ScoreTask = 0 - for MissionName, MissionData in pairs( PlayerData.Mission ) do - ScoreMission = ScoreMission + MissionData.ScoreMission - ScoreTask = ScoreTask + MissionData.ScoreTask - ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " - end - PlayerScore = PlayerScore + ScoreMission + ScoreTask - - if ScoreMessageMission ~= "" then - ScoreMessage = ScoreMessage .. " Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")\n" - end - - PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score:%d (%d Score -%d Penalties)%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage ) end end - MESSAGE:New( PlayerMessage, 30, "Player Scores" ):ToAll() end -function SCORING:ReportScorePlayer() - - env.info( "Hello World " ) +--- Produce detailed report of player hit scores. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerHits( PlayerName ) local ScoreMessage = "" - local PlayerMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 - self:T( "Score Report" ) + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Score Player: " .. PlayerName ) + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName - -- Some variables - local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] - local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] - local InitUnitType = PlayerData.UnitType - local InitUnitName = PlayerData.UnitName - - local PlayerScore = 0 - local PlayerPenalty = 0 - - ScoreMessage = "" - - local ScoreMessageHits = "" - - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( CategoryName ) - if PlayerData.Hit[CategoryID] then - local Score = 0 - local ScoreHit = 0 - local Penalty = 0 - local PenaltyHit = 0 - self:T( "Hit scores exist for player " .. PlayerName ) - for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do - Score = Score + UnitData.Score - ScoreHit = ScoreHit + UnitData.ScoreHit - Penalty = Penalty + UnitData.Penalty - PenaltyHit = UnitData.PenaltyHit - end - local ScoreMessageHit = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreHit, PenaltyHit ) - self:T( ScoreMessageHit ) - ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) + local ScoreMessageHits = "" + for CategoryID, CategoryName in pairs( _SCORINGCategory ) do + self:T( CategoryName ) + if PlayerData.Hit[CategoryID] then + self:T( "Hit scores exist for player " .. PlayerName ) + local Score = 0 + local ScoreHit = 0 + local Penalty = 0 + local PenaltyHit = 0 + for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do + Score = Score + UnitData.Score + ScoreHit = ScoreHit + UnitData.ScoreHit + Penalty = Penalty + UnitData.Penalty + PenaltyHit = UnitData.PenaltyHit end + local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) + self:T( ScoreMessageHit ) + ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit + PlayerScore = PlayerScore + Score + PlayerPenalty = PlayerPenalty + Penalty + else + --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) end - if ScoreMessageHits ~= "" then - ScoreMessage = ScoreMessage .. "\n Hits: " .. ScoreMessageHits .. " " - end - - local ScoreMessageKills = "" - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( "Kill scores exist for player " .. PlayerName ) - if PlayerData.Kill[CategoryID] then - local Score = 0 - local ScoreKill = 0 - local Penalty = 0 - local PenaltyKill = 0 - - for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do - Score = Score + UnitData.Score - ScoreKill = ScoreKill + UnitData.ScoreKill - Penalty = Penalty + UnitData.Penalty - PenaltyKill = PenaltyKill + UnitData.PenaltyKill - end - - local ScoreMessageKill = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreKill, PenaltyKill ) - self:T( ScoreMessageKill ) - ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill - - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageKills ~= "" then - ScoreMessage = ScoreMessage .. "\n Kills: " .. ScoreMessageKills .. " " - end - - local ScoreMessageCoalitionChangePenalties = "" - if PlayerData.PenaltyCoalition ~= 0 then - ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) - PlayerPenalty = PlayerPenalty + PlayerData.Penalty - end - if ScoreMessageCoalitionChangePenalties ~= "" then - ScoreMessage = ScoreMessage .. "\n Coalition: " .. ScoreMessageCoalitionChangePenalties .. " " - end - - local ScoreMessageMission = "" - local ScoreMission = 0 - local ScoreTask = 0 - for MissionName, MissionData in pairs( PlayerData.Mission ) do - ScoreMission = ScoreMission + MissionData.ScoreMission - ScoreTask = ScoreTask + MissionData.ScoreTask - ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " - end - PlayerScore = PlayerScore + ScoreMission + ScoreTask - - if ScoreMessageMission ~= "" then - ScoreMessage = ScoreMessage .. "\n Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") " - end - - PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties ):%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage ) + end + if ScoreMessageHits ~= "" then + ScoreMessage = "Hits: " .. ScoreMessageHits + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + + +--- Produce detailed report of player destroy scores. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerDestroys( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageDestroys = "" + for CategoryID, CategoryName in pairs( _SCORINGCategory ) do + if PlayerData.Destroy[CategoryID] then + self:T( "Destroy scores exist for player " .. PlayerName ) + local Score = 0 + local ScoreDestroy = 0 + local Penalty = 0 + local PenaltyDestroy = 0 + + for UnitName, UnitData in pairs( PlayerData.Destroy[CategoryID] ) do + self:E( { UnitData = UnitData } ) + if UnitData ~= {} then + Score = Score + UnitData.Score + ScoreDestroy = ScoreDestroy + UnitData.ScoreDestroy + Penalty = Penalty + UnitData.Penalty + PenaltyDestroy = PenaltyDestroy + UnitData.PenaltyDestroy + end + end + + local ScoreMessageDestroy = string.format( " %s:%d ", CategoryName, Score - Penalty ) + self:T( ScoreMessageDestroy ) + ScoreMessageDestroys = ScoreMessageDestroys .. ScoreMessageDestroy + + PlayerScore = PlayerScore + Score + PlayerPenalty = PlayerPenalty + Penalty + else + --ScoreMessageDestroys = ScoreMessageDestroys .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) + end + end + if ScoreMessageDestroys ~= "" then + ScoreMessage = "Destroys: " .. ScoreMessageDestroys + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + +--- Produce detailed report of player penalty scores because of changing the coalition. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerCoalitionChanges( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageCoalitionChangePenalties = "" + if PlayerData.PenaltyCoalition ~= 0 then + ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) + PlayerPenalty = PlayerPenalty + PlayerData.Penalty + end + if ScoreMessageCoalitionChangePenalties ~= "" then + ScoreMessage = ScoreMessage .. "Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + +--- Produce detailed report of player goal scores. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerMissions( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageGoal = "" + local ScoreGoal = 0 + local ScoreTask = 0 + for GoalName, GoalData in pairs( PlayerData.Goals ) do + ScoreGoal = ScoreGoal + GoalData.Score + ScoreMessageGoal = ScoreMessageGoal .. "'" .. GoalName .. "':" .. GoalData.Score .. "; " + end + PlayerScore = PlayerScore + ScoreGoal + + if ScoreMessageGoal ~= "" then + ScoreMessage = "Goals: " .. ScoreMessageGoal + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + +--- Produce detailed report of player penalty scores because of changing the coalition. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerMissions( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageMission = "" + local ScoreMission = 0 + local ScoreTask = 0 + for MissionName, MissionData in pairs( PlayerData.Mission ) do + ScoreMission = ScoreMission + MissionData.ScoreMission + ScoreTask = ScoreTask + MissionData.ScoreTask + ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " + end + PlayerScore = PlayerScore + ScoreMission + ScoreTask + + if ScoreMessageMission ~= "" then + ScoreMessage = "Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")" + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + + +--- Report Group Score Summary +-- @param #SCORING self +-- @param Wrapper.Group#GROUP PlayerGroup The player group. +function SCORING:ReportScoreGroupSummary( PlayerGroup ) + + local PlayerMessage = "" + + self:T( "Report Score Group Summary" ) + + local PlayerUnits = PlayerGroup:GetUnits() + for UnitID, PlayerUnit in pairs( PlayerUnits ) do + local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT + local PlayerName = PlayerUnit:GetPlayerName() + + if PlayerName then + + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + self:E( { ReportHits, ScoreHits, PenaltyHits } ) + + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) + ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys + self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) + + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) + ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges + self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) + + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) + ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals + self:E( { ReportGoals, ScoreGoals, PenaltyGoals } ) + + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) + ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions + self:E( { ReportMissions, ScoreMissions, PenaltyMissions } ) + + local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions + local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty + ) + MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + end + end + +end + +--- Report Group Score Detailed +-- @param #SCORING self +-- @param Wrapper.Group#GROUP PlayerGroup The player group. +function SCORING:ReportScoreGroupDetailed( PlayerGroup ) + + local PlayerMessage = "" + + self:T( "Report Score Group Detailed" ) + + local PlayerUnits = PlayerGroup:GetUnits() + for UnitID, PlayerUnit in pairs( PlayerUnits ) do + local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT + local PlayerName = PlayerUnit:GetPlayerName() + + if PlayerName then + + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + self:E( { ReportHits, ScoreHits, PenaltyHits } ) + + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) + ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys + self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) + + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) + ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges + self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) + + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) + ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals + self:E( { ReportGoals, ScoreGoals, PenaltyGoals } ) + + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) + ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions + self:E( { ReportMissions, ScoreMissions, PenaltyMissions } ) + + local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions + local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty, + ReportHits, + ReportDestroys, + ReportCoalitionChanges, + ReportGoals, + ReportMissions + ) + MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + end + end + +end + +--- Report all players score +-- @param #SCORING self +-- @param Wrapper.Group#GROUP PlayerGroup The player group. +function SCORING:ReportScoreAllSummary( PlayerGroup ) + + local PlayerMessage = "" + + self:T( "Report Score All Players" ) + + for PlayerName, PlayerData in pairs( self.Players ) do + + if PlayerName then + + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + self:E( { ReportHits, ScoreHits, PenaltyHits } ) + + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) + ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys + self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) + + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) + ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges + self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) + + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) + ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals + self:E( { ReportGoals, ScoreGoals, PenaltyGoals } ) + + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) + ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions + self:E( { ReportMissions, ScoreMissions, PenaltyMissions } ) + + local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions + local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty + ) + MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) end end - MESSAGE:New( PlayerMessage, 30, "Player Scores" ):ToAll() end @@ -780,21 +1591,10 @@ function SCORING:ScoreCSV( PlayerName, ScoreType, ScoreTimes, ScoreAmount, Playe PlayerUnitType = '' end - if not TargetUnitCoalition then - TargetUnitCoalition = '' - end - - if not TargetUnitCategory then - TargetUnitCategory = '' - end - - if not TargetUnitType then - TargetUnitType = '' - end - - if not TargetUnitName then - TargetUnitName = '' - end + TargetUnitCoalition = TargetUnitCoalition or "" + TargetUnitCategory = TargetUnitCategory or "" + TargetUnitType = TargetUnitType or "" + TargetUnitName = TargetUnitName or "" if lfs and io and os then self.CSVFile:write( diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index 48ceb1e74..85e2f9fbd 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -1,4 +1,4 @@ ---- Single-Player:**Yes** / Mulit-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- +--- Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- -- **Spawn groups of units dynamically in your missions.** -- -- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG) @@ -1304,10 +1304,12 @@ function SPAWN:_RandomizeTemplate( SpawnIndex ) self.SpawnGroups[SpawnIndex].SpawnTemplate.x = self.SpawnTemplate.x self.SpawnGroups[SpawnIndex].SpawnTemplate.y = self.SpawnTemplate.y self.SpawnGroups[SpawnIndex].SpawnTemplate.start_time = self.SpawnTemplate.start_time + local OldX = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[1].x + local OldY = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[1].y for UnitID = 1, #self.SpawnGroups[SpawnIndex].SpawnTemplate.units do self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].heading = self.SpawnTemplate.units[1].heading - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x = self.SpawnTemplate.units[1].x - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y = self.SpawnTemplate.units[1].y + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x = self.SpawnTemplate.units[1].x + ( self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x - OldX ) + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y = self.SpawnTemplate.units[1].y + ( self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y - OldY ) self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].alt = self.SpawnTemplate.units[1].alt end end diff --git a/Moose Development/Moose/Moose.lua b/Moose Development/Moose/Moose.lua index ed13ffe2e..3d1c4339e 100644 --- a/Moose Development/Moose/Moose.lua +++ b/Moose Development/Moose/Moose.lua @@ -27,6 +27,7 @@ Include.File( "Wrapper/Unit" ) Include.File( "Wrapper/Client" ) Include.File( "Wrapper/Static" ) Include.File( "Wrapper/Airbase" ) +Include.File( "Wrapper/Scenery" ) --- Functional Classes Include.File( "Functional/Scoring" ) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 931747909..d6c18eb1a 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -14,6 +14,7 @@ -- * @{#TASK.HasStateMachine}():Enquire if the task has a @{Fsm} -- * @{#TASK.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK}. -- * @{#TASK.UnAssignFromUnit}(): Unassign the task from a unit. +-- * @{#TASK.SetTimeOut}(): Set timer in seconds before task gets cancelled if not assigned. -- -- 1.2) Set and enquire task status (beyond the task state machine processing). -- ---------------------------------------------------------------------------- @@ -70,6 +71,7 @@ TASK = { FsmTemplate = nil, Mission = nil, CommandCenter = nil, + TimeOut = 0, } --- FSM PlayerAborted event handler prototype for TASK. @@ -163,6 +165,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType ) self:AddTransition( "*", "PlayerAborted", "*" ) self:AddTransition( "*", "PlayerDead", "*" ) self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" ) + self:AddTransition( "*", "TimeOut", "Cancelled" ) self:E( "New TASK " .. TaskName ) @@ -403,6 +406,17 @@ function TASK:UnAssignFromUnit( TaskUnit ) return self end +--- Sets the TimeOut for the @{Task}. If @{Task} stayed planned for longer than TimeOut, it gets into Cancelled status. +-- @param #TASK self +-- @param #integer Timer in seconds +-- @return #TASK self +function TASK:SetTimeOut ( Timer ) + self:F( Timer ) + self.TimeOut = Timer + self:__TimeOut( self.TimeOut ) + return self +end + --- Send a message of the @{Task} to the assigned @{Group}s. -- @param #TASK self function TASK:MessageToGroups( Message ) @@ -934,6 +948,30 @@ function TASK:onstatechange( From, Event, To ) end +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onenterPlanned( From, Event, To) + if not self.TimeOut == 0 then + self.__TimeOut( self.TimeOut ) + end +end + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onbeforeTimeOut( From, Event, To ) + if From == "Planned" then + self:RemoveMenu() + return true + end + return false +end + do -- Reporting --- Create a summary report of the Task. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 85a167b36..9b8862819 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -455,8 +455,7 @@ function GROUP:IsCompletelyInZone( Zone ) for UnitID, UnitData in pairs( self:GetUnits() ) do local Unit = UnitData -- Wrapper.Unit#UNIT - -- TODO: Rename IsPointVec3InZone to IsVec3InZone - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then + if Zone:IsVec3InZone( Unit:GetVec3() ) then else return false end @@ -474,7 +473,7 @@ function GROUP:IsPartlyInZone( Zone ) for UnitID, UnitData in pairs( self:GetUnits() ) do local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then + if Zone:IsVec3InZone( Unit:GetVec3() ) then return true end end @@ -491,7 +490,7 @@ function GROUP:IsNotInZone( Zone ) for UnitID, UnitData in pairs( self:GetUnits() ) do local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then + if Zone:IsVec3InZone( Unit:GetVec3() ) then return false end end diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index abfa0c607..edcd3ffff 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -217,10 +217,7 @@ function IDENTIFIABLE:GetCallsign() end +function IDENTIFIABLE:GetThreatLevel() - - - - - - + return 0, "Scenery" +end diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua new file mode 100644 index 000000000..c697d250e --- /dev/null +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -0,0 +1,39 @@ +--- This module contains the SCENERY class. +-- +-- 1) @{Scenery#SCENERY} class, extends @{Positionable#POSITIONABLE} +-- =============================================================== +-- Scenery objects are defined on the map. +-- The @{Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: +-- +-- * Wraps the DCS Scenery objects. +-- * Support all DCS Scenery APIs. +-- * Enhance with Scenery specific APIs not in the DCS API set. +-- +-- @module Scenery +-- @author FlightControl + + + +--- The SCENERY class +-- @type SCENERY +-- @extends Wrapper.Positionable#POSITIONABLE +SCENERY = { + ClassName = "SCENERY", +} + + +function SCENERY:Register( SceneryName, SceneryObject ) + local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) ) + self.SceneryName = SceneryName + self.SceneryObject = SceneryObject + return self +end + +function SCENERY:GetDCSObject() + return self.SceneryObject +end + +function SCENERY:GetThreatLevel() + + return 0, "Scenery" +end diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index efadcaf4d..0a4ba9c80 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -79,3 +79,8 @@ function STATIC:GetDCSObject() return nil end + +function STATIC:GetThreatLevel() + + return 1, "Static" +end \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 101174af0..ad0fc58be 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -536,45 +536,129 @@ end -- * Threat level 8: Unit is a Short Range SAM, radar guided. -- * Threat level 9: Unit is a Medium Range SAM, radar guided. -- * Threat level 10: Unit is a Long Range SAM, radar guided. +-- @param #UNIT self function UNIT:GetThreatLevel() local Attributes = self:GetDesc().attributes + self:E( Attributes ) + local ThreatLevel = 0 + local ThreatText = "" + + if self:IsGround() then - local ThreatLevels = { - "Unarmed", - "Infantry", - "Old Tanks & APCs", - "Tanks & IFVs without ATGM", - "Tanks & IFV with ATGM", - "Modern Tanks", - "AAA", - "IR Guided SAMs", - "SR SAMs", - "MR SAMs", - "LR SAMs" - } + self:E( "Ground" ) - self:T2( Attributes ) + local ThreatLevels = { + "Unarmed", + "Infantry", + "Old Tanks & APCs", + "Tanks & IFVs without ATGM", + "Tanks & IFV with ATGM", + "Modern Tanks", + "AAA", + "IR Guided SAMs", + "SR SAMs", + "MR SAMs", + "LR SAMs" + } + + + if Attributes["LR SAM"] then ThreatLevel = 10 + elseif Attributes["MR SAM"] then ThreatLevel = 9 + elseif Attributes["SR SAM"] and + not Attributes["IR Guided SAM"] then ThreatLevel = 8 + elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and + Attributes["IR Guided SAM"] then ThreatLevel = 7 + elseif Attributes["AAA"] then ThreatLevel = 6 + elseif Attributes["Modern Tanks"] then ThreatLevel = 5 + elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and + Attributes["ATGM"] then ThreatLevel = 4 + elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and + not Attributes["ATGM"] then ThreatLevel = 3 + elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2 + elseif Attributes["Infantry"] then ThreatLevel = 1 + end + + ThreatText = ThreatLevels[ThreatLevel+1] + end - if Attributes["LR SAM"] then ThreatLevel = 10 - elseif Attributes["MR SAM"] then ThreatLevel = 9 - elseif Attributes["SR SAM"] and - not Attributes["IR Guided SAM"] then ThreatLevel = 8 - elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and - Attributes["IR Guided SAM"] then ThreatLevel = 7 - elseif Attributes["AAA"] then ThreatLevel = 6 - elseif Attributes["Modern Tanks"] then ThreatLevel = 5 - elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and - Attributes["ATGM"] then ThreatLevel = 4 - elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and - not Attributes["ATGM"] then ThreatLevel = 3 - elseif Attributes["Old Tanks"] or Attributes["APC"] then ThreatLevel = 2 - elseif Attributes["Infantry"] then ThreatLevel = 1 + if self:IsAir() then + + self:E( "Air" ) + + local ThreatLevels = { + "Unarmed", + "Tanker", + "AWACS", + "Transport Helicpter", + "UAV", + "Bomber", + "Strategic Bomber", + "Attack Helicopter", + "Interceptor", + "Multirole Fighter", + "Fighter" + } + + + if Attributes["Fighters"] then ThreatLevel = 10 + elseif Attributes["Multirole fighters"] then ThreatLevel = 9 + elseif Attributes["Battleplanes"] then ThreatLevel = 8 + elseif Attributes["Attack helicopters"] then ThreatLevel = 7 + elseif Attributes["Strategic bombers"] then ThreatLevel = 6 + elseif Attributes["Bombers"] then ThreatLevel = 5 + elseif Attributes["UAVs"] then ThreatLevel = 4 + elseif Attributes["Transport helicopters"] then ThreatLevel = 3 + elseif Attributes["AWACS"] then ThreatLevel = 2 + elseif Attributes["Tankers"] then ThreatLevel = 1 + end + + ThreatText = ThreatLevels[ThreatLevel+1] + end + + if self:IsShip() then + + self:E( "Ship" ) + +--["Aircraft Carriers"] = {"Heavy armed ships",}, +--["Cruisers"] = {"Heavy armed ships",}, +--["Destroyers"] = {"Heavy armed ships",}, +--["Frigates"] = {"Heavy armed ships",}, +--["Corvettes"] = {"Heavy armed ships",}, +--["Heavy armed ships"] = {"Armed ships", "Armed Air Defence", "HeavyArmoredUnits",}, +--["Light armed ships"] = {"Armed ships","NonArmoredUnits"}, +--["Armed ships"] = {"Ships"}, +--["Unarmed ships"] = {"Ships","HeavyArmoredUnits",}, + + local ThreatLevels = { + "Unarmed ship", + "Light armed ships", + "Corvettes", + "", + "Frigates", + "", + "Cruiser", + "", + "Destroyer", + "", + "Aircraft Carrier" + } + + + if Attributes["Aircraft Carriers"] then ThreatLevel = 10 + elseif Attributes["Destroyers"] then ThreatLevel = 8 + elseif Attributes["Cruisers"] then ThreatLevel = 6 + elseif Attributes["Frigates"] then ThreatLevel = 4 + elseif Attributes["Corvettes"] then ThreatLevel = 2 + elseif Attributes["Light armed ships"] then ThreatLevel = 1 + end + + ThreatText = ThreatLevels[ThreatLevel+1] end self:T2( ThreatLevel ) - return ThreatLevel, ThreatLevels[ThreatLevel+1] + return ThreatLevel, ThreatText end @@ -589,7 +673,7 @@ function UNIT:IsInZone( Zone ) self:F2( { self.UnitName, Zone } ) if self:IsAlive() then - local IsInZone = Zone:IsPointVec3InZone( self:GetVec3() ) + local IsInZone = Zone:IsVec3InZone( self:GetVec3() ) self:T( { IsInZone } ) return IsInZone @@ -606,7 +690,7 @@ function UNIT:IsNotInZone( Zone ) self:F2( { self.UnitName, Zone } ) if self:IsAlive() then - local IsInZone = not Zone:IsPointVec3InZone( self:GetVec3() ) + local IsInZone = not Zone:IsVec3InZone( self:GetVec3() ) self:T( { IsInZone } ) return IsInZone diff --git a/Moose Mission Setup/Moose_Create.bat b/Moose Mission Setup/Moose_Create.bat index ea27cb4f9..4e3a251d4 100644 --- a/Moose Mission Setup/Moose_Create.bat +++ b/Moose Mission Setup/Moose_Create.bat @@ -65,6 +65,7 @@ COPY /b Moose.lua + %1\Wrapper\Unit.lua Moose.lua COPY /b Moose.lua + %1\Wrapper\Client.lua Moose.lua COPY /b Moose.lua + %1\Wrapper\Static.lua Moose.lua COPY /b Moose.lua + %1\Wrapper\Airbase.lua Moose.lua +COPY /b Moose.lua + %1\Wrapper\Scenery.lua Moose.lua rem Functional Classes COPY /b Moose.lua + %1\Functional\Scoring.lua Moose.lua diff --git a/Moose Presentations/LED Score Board.png b/Moose Presentations/LED Score Board.png new file mode 100644 index 000000000..673d1c74b Binary files /dev/null and b/Moose Presentations/LED Score Board.png differ diff --git a/Moose Presentations/SCORING.pptx b/Moose Presentations/SCORING.pptx new file mode 100644 index 000000000..576daef1f Binary files /dev/null and b/Moose Presentations/SCORING.pptx differ diff --git a/Moose Presentations/USER MISSIONS.pptx b/Moose Presentations/USER MISSIONS.pptx new file mode 100644 index 000000000..9fa93dbdd Binary files /dev/null and b/Moose Presentations/USER MISSIONS.pptx differ diff --git a/Moose Presentations/USER MISSIONS/Dia1.JPG b/Moose Presentations/USER MISSIONS/Dia1.JPG new file mode 100644 index 000000000..1b1131f73 Binary files /dev/null and b/Moose Presentations/USER MISSIONS/Dia1.JPG differ diff --git a/Moose Test Missions/SCO - Scoring/SCO-100 - Scoring of Statics/SCO-100 - Scoring of Statics.lua b/Moose Test Missions/SCO - Scoring/SCO-100 - Scoring of Statics/SCO-100 - Scoring of Statics.lua new file mode 100644 index 000000000..b45814d10 --- /dev/null +++ b/Moose Test Missions/SCO - Scoring/SCO-100 - Scoring of Statics/SCO-100 - Scoring of Statics.lua @@ -0,0 +1,38 @@ +--- +-- Name: SCO-100 - Scoring of Statics +-- Author: FlightControl +-- Date Created: 21 Feb 2017 +-- +-- # Situation: +-- +-- A shooting range has been setup. Fly the Ka-50 or the Su-25T to the statics located near the airport, and shoot them. +-- +-- # Test cases: +-- +-- 1. Observe the scoring granted to your flight when you hit and kill targets. + + +local HQ = GROUP:FindByName( "HQ", "Bravo HQ" ) + +local CommandCenter = COMMANDCENTER:New( HQ, "Bravo" ) + +local Scoring = SCORING:New( "Shooting Range 1" ) + +Scoring:SetMultiplierDestroyScore( 10 ) + +Scoring:SetMultiplierDestroyPenalty( 40 ) + +Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 ) + +-- Test for zone scores. + +-- This one is to test scoring on normal units. +local ShootingRangeZone = ZONE:New( "ScoringZone1" ) +Scoring:AddZoneScore( ShootingRangeZone, 200 ) + +-- This one is to test scoring on scenery. +-- Note that you can only destroy scenery with heavy weapons. +local SceneryZone = ZONE:New( "ScoringZone2" ) +Scoring:AddZoneScore( SceneryZone, 200 ) + + diff --git a/Moose Test Missions/SCO - Scoring/SCO-100 - Scoring of Statics/SCO-100 - Scoring of Statics.miz b/Moose Test Missions/SCO - Scoring/SCO-100 - Scoring of Statics/SCO-100 - Scoring of Statics.miz new file mode 100644 index 000000000..77b029cc9 Binary files /dev/null and b/Moose Test Missions/SCO - Scoring/SCO-100 - Scoring of Statics/SCO-100 - Scoring of Statics.miz differ diff --git a/Moose Test Missions/SCO - Scoring/SCO-101 - Scoring Client to Client/SCO-101 - Scoring Client to Client.lua b/Moose Test Missions/SCO - Scoring/SCO-101 - Scoring Client to Client/SCO-101 - Scoring Client to Client.lua new file mode 100644 index 000000000..704c458a4 --- /dev/null +++ b/Moose Test Missions/SCO - Scoring/SCO-101 - Scoring Client to Client/SCO-101 - Scoring Client to Client.lua @@ -0,0 +1,21 @@ +--- +-- Name: SCO-101 - Scoring Client to Client +-- Author: FlightControl +-- Date Created: 24 Feb 2017 +-- +-- # Situation: +-- +-- A shooting range has been setup to test client to client scoring. +-- +-- # Test cases: +-- +-- 1. Observe the scoring granted to your flight when you hit and kill other clients. + + +local HQ = GROUP:FindByName( "HQ", "Bravo HQ" ) + +local CommandCenter = COMMANDCENTER:New( HQ, "Lima" ) + +local Scoring = SCORING:New( "Detect Demo" ) + + diff --git a/Moose Test Missions/SCO - Scoring/SCO-101 - Scoring Client to Client/SCO-101 - Scoring Client to Client.miz b/Moose Test Missions/SCO - Scoring/SCO-101 - Scoring Client to Client/SCO-101 - Scoring Client to Client.miz new file mode 100644 index 000000000..4867aaec3 Binary files /dev/null and b/Moose Test Missions/SCO - Scoring/SCO-101 - Scoring Client to Client/SCO-101 - Scoring Client to Client.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-018 - Ground Ops - Randomize Templates/SPA-018 - Ground Ops - Randomize Templates.lua b/Moose Test Missions/SPA - Spawning/SPA-018 - Ground Ops - Randomize Templates/SPA-018 - Ground Ops - Randomize Templates.lua index b5db1d32d..4258bd86c 100644 --- a/Moose Test Missions/SPA - Spawning/SPA-018 - Ground Ops - Randomize Templates/SPA-018 - Ground Ops - Randomize Templates.lua +++ b/Moose Test Missions/SPA - Spawning/SPA-018 - Ground Ops - Randomize Templates/SPA-018 - Ground Ops - Randomize Templates.lua @@ -1,6 +1,7 @@ +--- -- Name: SPA-018 - Ground Ops - Randomize Templates -- Author: FlightControl --- Date Created: 10 January 2017 +-- Date Created: 10 Jan 2017 -- -- # Situation: -- diff --git a/Moose Test Missions/SPA - Spawning/SPA-019 - Ground Ops - Randomize Templates without Waypoints/SPA-019 - Ground Ops - Randomize Templates without Waypoints.lua b/Moose Test Missions/SPA - Spawning/SPA-019 - Ground Ops - Randomize Templates without Waypoints/SPA-019 - Ground Ops - Randomize Templates without Waypoints.lua new file mode 100644 index 000000000..e636abb57 --- /dev/null +++ b/Moose Test Missions/SPA - Spawning/SPA-019 - Ground Ops - Randomize Templates without Waypoints/SPA-019 - Ground Ops - Randomize Templates without Waypoints.lua @@ -0,0 +1,27 @@ +--- +-- Name: SPA-019 - Ground Ops - Randomize Templates with Waypoints +-- Author: FlightControl +-- Date Created: 24 Feb 2017 +-- +-- # Situation: +-- +-- At Gudauta spawn multiple ground vehicles, in a scheduled fashion. +-- +-- # Test cases: +-- +-- 1. Observe that the ground vehicles are spawned with randomized templates. +-- 2. Observe that the ground vehicles are spread around the spawning area and are not stacked upon each other. + + +-- Tests Gudauta +-- ------------- +-- Create a zone table of the 2 zones. +ZoneTable = { ZONE:New( "Zone1" ), ZONE:New( "Zone2" ) } + +TemplateTable = { "A", "B", "C" } + +Spawn_Vehicle_1 = SPAWN:New( "Spawn Vehicle 1" ) + :InitLimit( 10, 10 ) + :InitRandomizeTemplate( TemplateTable ) + :SpawnScheduled( 5, .5 ) + diff --git a/Moose Test Missions/SPA - Spawning/SPA-019 - Ground Ops - Randomize Templates without Waypoints/SPA-019 - Ground Ops - Randomize Templates without Waypoints.miz b/Moose Test Missions/SPA - Spawning/SPA-019 - Ground Ops - Randomize Templates without Waypoints/SPA-019 - Ground Ops - Randomize Templates without Waypoints.miz new file mode 100644 index 000000000..ada6016ae Binary files /dev/null and b/Moose Test Missions/SPA - Spawning/SPA-019 - Ground Ops - Randomize Templates without Waypoints/SPA-019 - Ground Ops - Randomize Templates without Waypoints.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints.lua b/Moose Test Missions/SPA - Spawning/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints.lua new file mode 100644 index 000000000..ba61228a3 --- /dev/null +++ b/Moose Test Missions/SPA - Spawning/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints.lua @@ -0,0 +1,29 @@ +--- +-- Name: SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints +-- Author: FlightControl +-- Date Created: 24 Feb 2017 +-- +-- # Situation: +-- +-- At Gudauta spawn multiple ground vehicles, in a scheduled fashion. +-- +-- # Test cases: +-- +-- 1. Observe that the ground vehicles are spawned with randomized templates. +-- 2. Observe that the ground vehicles are spread around the spawning area and are not stacked upon each other. +-- 3. Observe that the ground vehicles are spread over the random zones, and that the initial templates formations are kept. + + +-- Tests Gudauta +-- ------------- +-- Create a zone table of the 2 zones. +ZoneTable = { ZONE:New( "Zone1" ), ZONE:New( "Zone2" ) } + +TemplateTable = { "A", "B", "C" } + +Spawn_Vehicle_1 = SPAWN:New( "Spawn Vehicle 1" ) + :InitLimit( 100, 10 ) + :InitRandomizeTemplate( TemplateTable ) + :InitRandomizeZones( ZoneTable ) + :SpawnScheduled( 5, .5 ) + diff --git a/Moose Test Missions/SPA - Spawning/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints.miz b/Moose Test Missions/SPA - Spawning/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints.miz new file mode 100644 index 000000000..04f9a5156 Binary files /dev/null and b/Moose Test Missions/SPA - Spawning/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints/SPA-020 - Ground Ops - Randomize Templates in Random Zones without Waypoints.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit.miz b/Moose Test Missions/SPA - Spawning/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit.miz index 9746819a5..aad899b49 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit.miz and b/Moose Test Missions/SPA - Spawning/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit/SPA-120 - Air Ops - Scheduled Spawn with Repeat on Landing with Limit.miz differ diff --git a/README.md b/README.md index d779ca5a9..93ca78473 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ MOOSE works with DCS world 1.5. and 2.0. The goal of MOOSE is to allow mission designers to enhance their scripting with mission orchestration objects, which can be instantiated from defined classes within the framework. This will allow to write mission scripts with minimal code embedded. Of course, the richness of the framework will determine the richness of the misson scenarios. The MOOSE is a service that is produced while being consumed ... , it will evolve further as more classes are developed for the framework, and as more users are using it. -MOOSE is meant to be a one-man show, it is meant to evolve within a growing community around the framework. +MOOSE is not a one-man show, it is a collaborative effort and meant to evolve within a growing community around the framework. Within the community, key users will start supporting, documenting, explaining and even creating new classes for the framework. It is the ambition to grow this framework as a de-facto standard for mission designers to use. diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html index 0d0a13fce..b5afcb1a4 100644 --- a/docs/Documentation/AI_Balancer.html +++ b/docs/Documentation/AI_Balancer.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,7 +72,7 @@

    Module AI_Balancer

    -

    Single-Player:No / Mulit-Player:Yes / AI:Yes / Human:No / Types:All -- AI Balancing will replace in multi player missions +

    Single-Player:No / Multi-Player:Yes / AI:Yes / Human:No / Types:All -- AI Balancing will replace in multi player missions non-occupied human slots with AI groups, in order to provide an engaging simulation environment, even when there are hardly any players in the mission.

    diff --git a/docs/Documentation/AI_Cap.html b/docs/Documentation/AI_Cap.html index a2e672290..d9d91abaf 100644 --- a/docs/Documentation/AI_Cap.html +++ b/docs/Documentation/AI_Cap.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,7 +72,7 @@

    Module AI_Cap

    -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Air -- Execute Combat Air Patrol (CAP).

    +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Air -- Execute Combat Air Patrol (CAP).

    Banner Image

    diff --git a/docs/Documentation/AI_Cas.html b/docs/Documentation/AI_Cas.html index 3b11f8e58..766b7be8e 100644 --- a/docs/Documentation/AI_Cas.html +++ b/docs/Documentation/AI_Cas.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,7 +72,7 @@

    Module AI_Cas

    -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Air -- +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Air -- Provide Close Air Support to friendly ground troops.

    Banner Image

    @@ -307,7 +308,7 @@ It can be notified to go RTB through the RTB event.

    - AI_CAS_ZONE:New(PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType, EngageZone) + AI_CAS_ZONE:New(PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType)

    Creates a new AICASZONE object

    @@ -739,7 +740,7 @@ It can be notified to go RTB through the RTB event.

    -AI_CAS_ZONE:New(PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType, EngageZone) +AI_CAS_ZONE:New(PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType)
    @@ -780,13 +781,14 @@ The maximum speed of the Controllable in km/h.
  • -

    Dcs.DCSTypes#AltitudeType PatrolAltType : -The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO

    +

    Core.Zone#ZONE_BASE EngageZone : +The zone where the engage will happen.

  • -

    Core.Zone#ZONE EngageZone :

    +

    Dcs.DCSTypes#AltitudeType PatrolAltType : +The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO

  • diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index 1804d6d64..4339111c1 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,7 +72,7 @@

    Module AI_Patrol

    -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Air -- +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Air -- Air Patrolling or Staging.

    Banner Image

    diff --git a/docs/Documentation/Account.html b/docs/Documentation/Account.html index 469ffb5b0..4b98fc1ab 100644 --- a/docs/Documentation/Account.html +++ b/docs/Documentation/Account.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Airbase.html b/docs/Documentation/Airbase.html index 148977871..fa23f7c94 100644 --- a/docs/Documentation/Airbase.html +++ b/docs/Documentation/Airbase.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/AirbasePolice.html b/docs/Documentation/AirbasePolice.html index b85cf5549..27e47f5fe 100644 --- a/docs/Documentation/AirbasePolice.html +++ b/docs/Documentation/AirbasePolice.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Assign.html b/docs/Documentation/Assign.html index 52eed4a74..6cc1abe16 100644 --- a/docs/Documentation/Assign.html +++ b/docs/Documentation/Assign.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Base.html b/docs/Documentation/Base.html index 47b494f73..50090444d 100644 --- a/docs/Documentation/Base.html +++ b/docs/Documentation/Base.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 6e4a998ff..34836b383 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,7 +72,7 @@

    Module Cargo

    -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Ground --
    +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Ground --
    Management of logical cargo objects, that can be transported from and to transportation carriers.

    Banner Image

    diff --git a/docs/Documentation/CleanUp.html b/docs/Documentation/CleanUp.html index b47299090..6148fe3f1 100644 --- a/docs/Documentation/CleanUp.html +++ b/docs/Documentation/CleanUp.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Client.html b/docs/Documentation/Client.html index ce349f609..a00f673ed 100644 --- a/docs/Documentation/Client.html +++ b/docs/Documentation/Client.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/CommandCenter.html b/docs/Documentation/CommandCenter.html index 403772d3e..f0607f930 100644 --- a/docs/Documentation/CommandCenter.html +++ b/docs/Documentation/CommandCenter.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Controllable.html b/docs/Documentation/Controllable.html index 946cfb89a..fc7daf27b 100644 --- a/docs/Documentation/Controllable.html +++ b/docs/Documentation/Controllable.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Database.html b/docs/Documentation/Database.html index 99c49f976..93a9354c4 100644 --- a/docs/Documentation/Database.html +++ b/docs/Documentation/Database.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 8a75e6329..bbf38dbd0 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/DetectionManager.html b/docs/Documentation/DetectionManager.html index a32d6921c..4da79c117 100644 --- a/docs/Documentation/DetectionManager.html +++ b/docs/Documentation/DetectionManager.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Escort.html b/docs/Documentation/Escort.html index 56357f0f5..f07ad5198 100644 --- a/docs/Documentation/Escort.html +++ b/docs/Documentation/Escort.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Event.html b/docs/Documentation/Event.html index c8ab35fec..a555f4eba 100644 --- a/docs/Documentation/Event.html +++ b/docs/Documentation/Event.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -115,7 +116,7 @@ in the correct processing order.

    Objects

    -

    For most DCS events, the above order of updating will be followed.1

    +

    For most DCS events, the above order of updating will be followed.

    Objects

    @@ -206,6 +207,23 @@ There are basically 4 main categories of information stored in the EVENTDATA str

    Objects

    +

    IMPORTANT NOTE: Some events can involve not just UNIT objects, but also STATIC objects!!! +In that case the initiator or target unit fields will refer to a STATIC object! +In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated. +The fields IniObjectCategory and TgtObjectCategory contain the indicator which kind of object is involved in the event. +You can use the enumerator Object.Category.UNIT and Object.Category.STATIC to check on IniObjectCategory and TgtObjectCategory. +Example code snippet:

    + +
     if Event.IniObjectCategory == Object.Category.UNIT then
    +  ...
    + end
    + if Event.IniObjectCategory == Object.Category.STATIC then
    +  ...
    + end 
    +
    + +

    When a static object is involved in the event, the Group and Player fields won't be populated.

    +

    API CHANGE HISTORY

    @@ -391,81 +409,182 @@ YYYY-MM-DD: CLASS:NewFunction( Params ) added

    Type EVENTDATA

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -489,25 +608,28 @@ YYYY-MM-DD: CLASS:NewFunction( Params ) added

    EVENTDATA.IniCategory +
      (UNIT) The category of the initiator.
    +
    +
    EVENTDATA.IniCoalition +
     (UNIT) The coalition of the initiator.
    +
    +
    EVENTDATA.IniDCSGroup - +
      (UNIT) The initiating {Dcs.DCSGroup#Group}.
    +
    EVENTDATA.IniDCSGroupName - +

    (UNIT) The initiating Group name.

    EVENTDATA.IniDCSUnit - +
       (UNIT/STATIC) The initiating <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    EVENTDATA.IniDCSUnitName - +

    (UNIT/STATIC) The initiating Unit name.

    EVENTDATA.IniGroup +
         (UNIT) The initiating MOOSE wrapper <a href="Wrapper.Group.html##(GROUP)">Wrapper.Group#GROUP</a> of the initiator Group object.
    +
    +
    EVENTDATA.IniGroupName +
     (UNIT) The initiating GROUP name (same as IniDCSGroupName).
    +
    +
    EVENTDATA.IniObjectCategory +

    (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).

    +
    EVENTDATA.IniPlayerName +
    (UNIT) The name of the initiating player in case the Unit is a client or player slot.
    +
    +
    EVENTDATA.IniTypeName +
      (UNIT) The type name of the initiator.
    +
    EVENTDATA.IniUnit - +
          (UNIT/STATIC) The initiating MOOSE wrapper <a href="Wrapper.Unit.html##(UNIT)">Wrapper.Unit#UNIT</a> of the initiator Unit object.
    +
    EVENTDATA.IniUnitName - +
      (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).
    +
    +
    EVENTDATA.TgtCategory +
      (UNIT) The category of the target.
    +
    +
    EVENTDATA.TgtCoalition +
     (UNIT) The coalition of the target.
    +
    EVENTDATA.TgtDCSGroup - +
      (UNIT) The target {Dcs.DCSGroup#Group}.
    +
    EVENTDATA.TgtDCSGroupName - +

    (UNIT) The target Group name.

    EVENTDATA.TgtDCSUnit - +
       (UNIT/STATIC) The target <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    EVENTDATA.TgtDCSUnitName +

    (UNIT/STATIC) The target Unit name.

    +
    EVENTDATA.TgtGroup +
         (UNIT) The target MOOSE wrapper <a href="Wrapper.Group.html##(GROUP)">Wrapper.Group#GROUP</a> of the target Group object.
    +
    +
    EVENTDATA.TgtGroupName +
     (UNIT) The target GROUP name (same as TgtDCSGroupName).
    +
    +
    EVENTDATA.TgtObjectCategory +
      (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).
    +
    +
    EVENTDATA.TgtPlayerName +
    (UNIT) The name of the target player in case the Unit is a client or player slot.
    +
    +
    EVENTDATA.TgtTypeName +
      (UNIT) The type name of the target.
    +
    EVENTDATA.TgtUnit - +
          (UNIT/STATIC) The target MOOSE wrapper <a href="Wrapper.Unit.html##(UNIT)">Wrapper.Unit#UNIT</a> of the target Unit object.
    +
    EVENTDATA.TgtUnitName - +
      (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).
    +
    EVENTDATA.id +

    The identifier of the event.

    EVENTDATA.initiator - +
        (UNIT/STATIC/SCENERY) The initiating <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    EVENTDATA.target - +
           (UNIT/STATIC) The target <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    EVENTDATA.weapon - +

    The weapon used during the event.

    @@ -1325,71 +1447,179 @@ The self instance of the class for which the event is.

    Type EVENTDATA

    -

    The Event structure

    +

    The Event structure +Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:

    + +
      +
    • A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
    • +
    + + +
      +
    • A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ +
    • +

    Field(s)

    + Dcs.DCSUnit#Unit.Category + +EVENTDATA.IniCategory + +
    +
    + +
      (UNIT) The category of the initiator.
    +
    + +
    +
    +
    +
    + + Dcs.DCScoalition#coalition.side + +EVENTDATA.IniCoalition + +
    +
    + +
     (UNIT) The coalition of the initiator.
    +
    + +
    +
    +
    +
    + + Dcs.DCSGroup#Group EVENTDATA.IniDCSGroup
    - +
      (UNIT) The initiating {Dcs.DCSGroup#Group}.
    +
    + #string EVENTDATA.IniDCSGroupName
    - +

    (UNIT) The initiating Group name.

    + Dcs.DCSUnit#Unit EVENTDATA.IniDCSUnit
    - +
       (UNIT/STATIC) The initiating <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    + #string EVENTDATA.IniDCSUnitName
    - +

    (UNIT/STATIC) The initiating Unit name.

    - + Wrapper.Group#GROUP EVENTDATA.IniGroup
    +
         (UNIT) The initiating MOOSE wrapper <a href="Wrapper.Group.html##(GROUP)">Wrapper.Group#GROUP</a> of the initiator Group object.
    +
    + +
    +
    +
    +
    + + #string + +EVENTDATA.IniGroupName + +
    +
    + +
     (UNIT) The initiating GROUP name (same as IniDCSGroupName).
    +
    + +
    +
    +
    +
    + + Dcs.DCSObject#Object.Category + +EVENTDATA.IniObjectCategory + +
    +
    + +

    (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).

    + +
    +
    +
    +
    + + #string + +EVENTDATA.IniPlayerName + +
    +
    + +
    (UNIT) The name of the initiating player in case the Unit is a client or player slot.
    +
    + +
    +
    +
    +
    + + #string + +EVENTDATA.IniTypeName + +
    +
    + +
      (UNIT) The type name of the initiator.
    +
    @@ -1404,7 +1634,8 @@ The self instance of the class for which the event is.

    - +
          (UNIT/STATIC) The initiating MOOSE wrapper <a href="Wrapper.Unit.html##(UNIT)">Wrapper.Unit#UNIT</a> of the initiator Unit object.
    +
    @@ -1418,58 +1649,171 @@ The self instance of the class for which the event is.

    - +
      (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).
    +
    + Dcs.DCSUnit#Unit.Category + +EVENTDATA.TgtCategory + +
    +
    + +
      (UNIT) The category of the target.
    +
    + +
    +
    +
    +
    + + Dcs.DCScoalition#coalition.side + +EVENTDATA.TgtCoalition + +
    +
    + +
     (UNIT) The coalition of the target.
    +
    + +
    +
    +
    +
    + + Dcs.DCSGroup#Group EVENTDATA.TgtDCSGroup
    - +
      (UNIT) The target {Dcs.DCSGroup#Group}.
    +
    + #string EVENTDATA.TgtDCSGroupName
    - +

    (UNIT) The target Group name.

    + Dcs.DCSUnit#Unit EVENTDATA.TgtDCSUnit
    - +
       (UNIT/STATIC) The target <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    + #string EVENTDATA.TgtDCSUnitName
    +

    (UNIT/STATIC) The target Unit name.

    + +
    +
    +
    +
    + + Wrapper.Group#GROUP + +EVENTDATA.TgtGroup + +
    +
    + +
         (UNIT) The target MOOSE wrapper <a href="Wrapper.Group.html##(GROUP)">Wrapper.Group#GROUP</a> of the target Group object.
    +
    + +
    +
    +
    +
    + + #string + +EVENTDATA.TgtGroupName + +
    +
    + +
     (UNIT) The target GROUP name (same as TgtDCSGroupName).
    +
    + +
    +
    +
    +
    + + Dcs.DCSObject#Object.Category + +EVENTDATA.TgtObjectCategory + +
    +
    + +
      (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).
    +
    + +
    +
    +
    +
    + + #string + +EVENTDATA.TgtPlayerName + +
    +
    + +
    (UNIT) The name of the target player in case the Unit is a client or player slot.
    +
    + +
    +
    +
    +
    + + #string + +EVENTDATA.TgtTypeName + +
    +
    + +
      (UNIT) The type name of the target.
    +
    @@ -1484,7 +1828,8 @@ The self instance of the class for which the event is.

    - +
          (UNIT/STATIC) The target MOOSE wrapper <a href="Wrapper.Unit.html##(UNIT)">Wrapper.Unit#UNIT</a> of the target Unit object.
    +
    @@ -1498,7 +1843,8 @@ The self instance of the class for which the event is.

    - +
      (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).
    +
    @@ -1544,12 +1890,14 @@ The self instance of the class for which the event is.

    + #number EVENTDATA.id
    +

    The identifier of the event.

    @@ -1557,26 +1905,30 @@ The self instance of the class for which the event is.

    + Dcs.DCSUnit#Unit EVENTDATA.initiator
    - +
        (UNIT/STATIC/SCENERY) The initiating <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    + Dcs.DCSUnit#Unit EVENTDATA.target
    - +
           (UNIT/STATIC) The target <a href="Dcs.DCSUnit.html##(Unit)">Dcs.DCSUnit#Unit</a> or <a href="Dcs.DCSStaticObject.html##(StaticObject)">Dcs.DCSStaticObject#StaticObject</a>.
    +
    @@ -1589,7 +1941,7 @@ The self instance of the class for which the event is.

    - +

    The weapon used during the event.

    diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index 16ce970e5..ca46b6637 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Group.html b/docs/Documentation/Group.html index ab7723b8a..72af7618d 100644 --- a/docs/Documentation/Group.html +++ b/docs/Documentation/Group.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Identifiable.html b/docs/Documentation/Identifiable.html index c249503c9..8a521c0f9 100644 --- a/docs/Documentation/Identifiable.html +++ b/docs/Documentation/Identifiable.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -164,6 +165,12 @@ IDENTIFIABLE:GetName()

    Returns DCS Identifiable object name.

    + + + + IDENTIFIABLE:GetThreatLevel() + + @@ -398,6 +405,19 @@ The DCS Identifiable is not existing or alive.

    + + +
    +
    + + +IDENTIFIABLE:GetThreatLevel() + +
    +
    + + +
    diff --git a/docs/Documentation/MOVEMENT.html b/docs/Documentation/MOVEMENT.html index 6fe2427d0..12f09c4ec 100644 --- a/docs/Documentation/MOVEMENT.html +++ b/docs/Documentation/MOVEMENT.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Menu.html b/docs/Documentation/Menu.html index 590c587d8..57a2dc811 100644 --- a/docs/Documentation/Menu.html +++ b/docs/Documentation/Menu.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Message.html b/docs/Documentation/Message.html index ddc1305de..1577b95de 100644 --- a/docs/Documentation/Message.html +++ b/docs/Documentation/Message.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -133,6 +134,12 @@ To send messages, you need to use the To functions.

    MESSAGE:ToAll()

    Sends a MESSAGE to all players.

    + + + + MESSAGE:ToAllIf(Condition) + +

    Sends a MESSAGE to all players if the given Condition is true.

    @@ -151,6 +158,12 @@ To send messages, you need to use the To functions.

    MESSAGE:ToCoalition(CoalitionSide)

    Sends a MESSAGE to a Coalition.

    + + + + MESSAGE:ToCoalitionIf(CoalitionSide, Condition) + +

    Sends a MESSAGE to a Coalition if the given Condition is true.

    @@ -309,6 +322,32 @@ or MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) MessageAll:ToAll() + +
    +
    +
    + + +MESSAGE:ToAllIf(Condition) + +
    +
    + +

    Sends a MESSAGE to all players if the given Condition is true.

    + +

    Parameter

    +
      +
    • + +

      Condition :

      + +
    • +
    +

    Return value

    + +

    #MESSAGE:

    + +
    @@ -418,6 +457,38 @@ or 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 ) + +
    +
    +
    + + +MESSAGE:ToCoalitionIf(CoalitionSide, Condition) + +
    +
    + +

    Sends a MESSAGE to a Coalition if the given Condition is true.

    + +

    Parameters

    +
      +
    • + +

      CoalitionSide : +needs to be filled out by the defined structure of the standard scripting engine coalition.side.

      + +
    • +
    • + +

      Condition :

      + +
    • +
    +

    Return value

    + +

    #MESSAGE:

    + +
    diff --git a/docs/Documentation/MissileTrainer.html b/docs/Documentation/MissileTrainer.html index 6c6665ba2..6c7b0853d 100644 --- a/docs/Documentation/MissileTrainer.html +++ b/docs/Documentation/MissileTrainer.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Mission.html b/docs/Documentation/Mission.html index 101b239ae..f5e92651f 100644 --- a/docs/Documentation/Mission.html +++ b/docs/Documentation/Mission.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Object.html b/docs/Documentation/Object.html index 750a4df83..ae8b003b8 100644 --- a/docs/Documentation/Object.html +++ b/docs/Documentation/Object.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Point.html b/docs/Documentation/Point.html index 91876b43e..2fbbea2c7 100644 --- a/docs/Documentation/Point.html +++ b/docs/Documentation/Point.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -82,6 +83,7 @@ In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums.

    1.1) POINT_VEC3 constructor

    +

    A new POINT_VEC3 instance can be created with:

    +

    1.2) Smoke, flare, explode, illuminate

    + +

    At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods:

    + +

    1.2.1) Smoke

    + + + +

    1.2.2) Flare

    + + + +

    1.2.3) Explode

    + + + +

    1.2.4) Illuminate

    + + +

    2) Point#POINT_VEC2 class, extends Point#POINT_VEC3

    The Point#POINT_VEC2 class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified.

    @@ -114,6 +153,9 @@ In order to keep the credibility of the the author, I want to emphasize that the

    Hereby the change log:

    +

    2017-03-03: POINT_VEC3:Explosion( ExplosionIntensity ) added.
    +2017-03-03: POINT_VEC3:IlluminationBomb() added.

    +

    2017-02-18: POINT_VEC3:NewFromVec2( Vec2, LandHeightAdd ) added.

    2016-08-12: POINT_VEC3:Translate( Distance, Angle ) added.

    @@ -251,6 +293,12 @@ In order to keep the credibility of the the author, I want to emphasize that the POINT_VEC3.ClassName + + + + POINT_VEC3:Explosion(ExplosionIntensity) + +

    Creates an explosion at the point of a certain intensity.

    @@ -383,6 +431,12 @@ In order to keep the credibility of the the author, I want to emphasize that the POINT_VEC3:GetZ()

    Return the z coordinate of the POINT_VEC3.

    + + + + POINT_VEC3:IlluminationBomb() + +

    Creates an illumination bomb at the point.

    @@ -998,6 +1052,27 @@ The new calculated POINT_VEC2.

    + +
    +
    +
    + + +POINT_VEC3:Explosion(ExplosionIntensity) + +
    +
    + +

    Creates an explosion at the point of a certain intensity.

    + +

    Parameter

    +
      +
    • + +

      #number ExplosionIntensity :

      + +
    • +
    @@ -1536,6 +1611,19 @@ The z coodinate.

    + +POINT_VEC3:IlluminationBomb() + +
    +
    + +

    Creates an illumination bomb at the point.

    + +
    +
    +
    +
    + POINT_VEC3:IsMetric() diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index 1c2380097..93943636f 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Process_JTAC.html b/docs/Documentation/Process_JTAC.html index e9edf0979..7b075d55f 100644 --- a/docs/Documentation/Process_JTAC.html +++ b/docs/Documentation/Process_JTAC.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Process_Pickup.html b/docs/Documentation/Process_Pickup.html index bf2924a3e..01d6c1246 100644 --- a/docs/Documentation/Process_Pickup.html +++ b/docs/Documentation/Process_Pickup.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Route.html b/docs/Documentation/Route.html index f4f2b8eeb..188d2dd9a 100644 --- a/docs/Documentation/Route.html +++ b/docs/Documentation/Route.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Scenery.html b/docs/Documentation/Scenery.html new file mode 100644 index 000000000..f7258b5b4 --- /dev/null +++ b/docs/Documentation/Scenery.html @@ -0,0 +1,220 @@ + + + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    Module Scenery

    + +

    This module contains the SCENERY class.

    + + + +

    1) Scenery#SCENERY class, extends Positionable#POSITIONABLE

    +

    Scenery objects are defined on the map. +The Scenery#SCENERY class is a wrapper class to handle the DCS Scenery objects:

    + +
      +
    • Wraps the DCS Scenery objects.
    • +
    • Support all DCS Scenery APIs.
    • +
    • Enhance with Scenery specific APIs not in the DCS API set.
    • +
    + + +

    Global(s)

    + + + + + +
    SCENERY + +
    +

    Type SCENERY

    + + + + + + + + + + + + + + + + + +
    SCENERY.ClassName + +
    SCENERY:GetDCSObject() + +
    SCENERY:GetThreatLevel() + +
    SCENERY:Register(SceneryName, SceneryObject) + +
    + +

    Global(s)

    +
    +
    + + #SCENERY + +SCENERY + +
    +
    + + + +
    +
    +

    Type Scenery

    + +

    Type SCENERY

    + +

    The SCENERY class

    + +

    Field(s)

    +
    +
    + + #string + +SCENERY.ClassName + +
    +
    + + + +
    +
    +
    +
    + + +SCENERY:GetDCSObject() + +
    +
    + + + +
    +
    +
    +
    + + +SCENERY:GetThreatLevel() + +
    +
    + + + +
    +
    +
    +
    + + +SCENERY:Register(SceneryName, SceneryObject) + +
    +
    + + + +

    Parameters

    +
      +
    • + +

      SceneryName :

      + +
    • +
    • + +

      SceneryObject :

      + +
    • +
    +
    +
    + +
    + +
    + + diff --git a/docs/Documentation/ScheduleDispatcher.html b/docs/Documentation/ScheduleDispatcher.html index 15111f577..78cfd02be 100644 --- a/docs/Documentation/ScheduleDispatcher.html +++ b/docs/Documentation/ScheduleDispatcher.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -341,8 +342,7 @@ Nothing of this code should be modified without testing it thoroughly.

    -

    Initialize the ObjectSchedulers array, which is a weakly coupled table. - If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.

    +

    setmetatable( {}, { __mode = "v" } )

    diff --git a/docs/Documentation/Scheduler.html b/docs/Documentation/Scheduler.html index e6b02c81e..e6fea02b4 100644 --- a/docs/Documentation/Scheduler.html +++ b/docs/Documentation/Scheduler.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Scoring.html b/docs/Documentation/Scoring.html index ec7e0292d..d24225f13 100644 --- a/docs/Documentation/Scoring.html +++ b/docs/Documentation/Scoring.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,22 +72,210 @@

    Module Scoring

    -

    Scoring system for MOOSE.

    +

    Single-Player:Yes / Multi-Player:Yes / Core:Yes -- Administer the scoring of player achievements, +and create a CSV file logging the scoring events for use at team or squadron websites.

    + +

    Banner Image

    + +
    + +

    1) Scoring#SCORING class, extends Base#BASE

    + +

    The #SCORING class administers the scoring of player achievements, +and creates a CSV file logging the scoring events and results for use at team or squadron websites.

    -

    This scoring class calculates the hits and kills that players make within a simulation session. -Scoring is calculated using a defined algorithm. -With a small change in MissionScripting.lua, the scoring can also be logged in a CSV file, that can then be uploaded -to a database or a BI tool to publish the scoring results to the player community.

    + +

    SCORING automatically calculates the threat level of the objects hit and destroyed by players, +which can be Unit, Static objects.

    + +

    Positive score points are granted when enemy or neutral targets are destroyed. +Negative score points or penalties are given when a friendly target is hit or destroyed. +This brings a lot of dynamism in the scoring, where players need to take care to inflict damage on the right target. +By default, penalties weight heavier in the scoring, to ensure that players don't commit fratricide. +The total score of the player is calculated by adding the scores minus the penalties.

    + +

    Banner Image

    + +

    The score value is calculated based on the threat level of the player and the threat level of the target. +A calculated score takes the threat level of the target divided by a balanced threat level of the player unit.
    +As such, if the threat level of the target is high, and the player threat level is low, a higher score will be given than +if the threat level of the player would be high too.

    + +

    Banner Image

    + +

    When multiple players hit the same target, and finally succeed in destroying the target, then each player who contributed to the target +destruction, will receive a score. This is important for targets that require significant damage before it can be destroyed, like +ships or heavy planes.

    + +

    Banner Image

    + +

    Optionally, the score values can be scaled by a scale. Specific scales can be set for positive cores or negative penalties. +The default range of the scores granted is a value between 0 and 10. The default range of penalties given is a value between 0 and 30.

    + +

    Banner Image

    + +

    Additional scores can be granted to specific objects, when the player(s) destroy these objects.

    + +

    Banner Image

    + +

    Various Zones can be defined for which scores are also granted when objects in that Zone are destroyed. +This is specifically useful to designate scenery targets on the map that will generate points when destroyed.

    + +

    With a small change in MissionScripting.lua, the scoring results can also be logged in a CSV file.
    +These CSV files can be used to:

    + +
      +
    • Upload scoring to a database or a BI tool to publish the scoring results to the player community.
    • +
    • Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results.
    • +
    • Share scoring amoung players after the mission to discuss mission results.
    • +
    + +

    Scores can be reported. Menu options are automatically added to each player group when a player joins a client slot or a CA unit. +Use the radio menu F10 to consult the scores while running the mission. +Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission.

    + +

    1.1) Set the destroy score or penalty scale

    + +

    Score scales can be set for scores granted when enemies or friendlies are destroyed. +Use the method SCORING.SetScaleDestroyScore() to set the scale of enemy destroys (positive destroys). +Use the method SCORING.SetScaleDestroyPenalty() to set the scale of friendly destroys (negative destroys).

    + +
     local Scoring = SCORING:New( "Scoring File" )
    + Scoring:SetScaleDestroyScore( 10 )
    + Scoring:SetScaleDestroyPenalty( 40 )
    +
    + +

    The above sets the scale for valid scores to 10. So scores will be given in a scale from 0 to 10. +The penalties will be given in a scale from 0 to 40.

    + +

    1.2) Define special targets that will give extra scores.

    + +

    Special targets can be set that will give extra scores to the players when these are destroyed. +Use the methods SCORING.AddUnitScore() and SCORING.RemoveUnitScore() to specify a special additional score for a specific Units.
    +Use the methods SCORING.AddStaticScore() and SCORING.RemoveStaticScore() to specify a special additional score for a specific Statics.
    +Use the method SCORING.SetGroupGroup() to specify a special additional score for a specific Groups.

    + +
     local Scoring = SCORING:New( "Scoring File" )
    + Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
    + Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 )
    +
    + +

    The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed. +Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over. +For example, this can be done as follows:

    + +
     Scoring:RemoveUnitScore( UNIT:FindByName( "Unit #001" ) )
    +
    + + + +

    1.3) Define destruction zones that will give extra scores.

    + +

    Define zones of destruction. Any object destroyed within the zone of the given category will give extra points. +Use the method SCORING.AddZoneScore() to add a Zone for additional scoring.
    +Use the method SCORING.RemoveZoneScore() to remove a Zone for additional scoring.
    +There are interesting variations that can be achieved with this functionality. For example, if the Zone is a Zone#ZONE_UNIT, +then the zone is a moving zone, and anything destroyed within that Zone will generate points. +The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a Zone, +just large enough around that building.

    + +

    1.4) Add extra Goal scores upon an event or a condition.

    + +

    A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens. +Use the method SCORING.AddGoalScore() to add a score for a Player at any time in your mission.

    + +

    1.5) Configure fratricide level.

    + +

    When a player commits too much damage to friendlies, his penalty score will reach a certain level. +Use the method SCORING.SetFratricide() to define the level when a player gets kicked.
    +By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score.

    + +

    1.6) Penalty score when a player changes the coalition.

    + +

    When a player changes the coalition, he can receive a penalty score. +Use the method SCORING.SetCoalitionChangePenalty() to define the penalty when a player changes coalition. +By default, the penalty for changing coalition is the default penalty scale.

    + +

    1.8) Define output CSV files.

    + +

    The CSV file is given the name of the string given in the SCORING.New{} constructor, followed by the .csv extension. +The file is incrementally saved in the **\Saved Games\DCS\Logs** folder, and has a time stamp indicating each mission run. +See the following example:

    + +
    local ScoringFirstMission = SCORING:New( "FirstMission" )
    +local ScoringSecondMission = SCORING:New( "SecondMission" )
    +
    + +

    The above documents that 2 Scoring objects are created, ScoringFirstMission and ScoringSecondMission.

    + +

    1.9) Configure messages.

    + +

    When players hit or destroy targets, messages are sent. +Various methods exist to configure:

    + +
      +
    • Which messages are sent upon the event.
    • +
    • Which audience receives the message.
    • +
    + +

    1.9.1) Configure the messages sent upon the event.

    + +

    Use the following methods to configure when to send messages. By default, all messages are sent.

    + + + +

    1.9.2) Configure the audience of the messages.

    + +

    Use the following methods to configure the audience of the messages. By default, the messages are sent to all players in the mission.

    + + + + +
    + +

    API CHANGE HISTORY

    + +

    The underlying change log documents the API changes. Please read this carefully. The following notation is used:

    + +
      +
    • Added parts are expressed in bold type face.
    • +
    • Removed parts are expressed in italic type face.
    • +
    + +

    Hereby the change log:

    + +

    2017-02-26: Initial class and API.

    + +
    + +

    AUTHORS and CONTRIBUTIONS

    + +

    Contributions:

    + +
      +
    • Wingthor (TAW): Testing & Advice.
    • +
    • Dutch-Baron (TAW): Testing & Advice.
    • +
    • **Whisper: Testing and Advice.
    • +
    + +

    Authors:

    + +
      +
    • FlightControl: Concept, Design & Programming.
    • +
    +

    Global(s)

    - - - - + + + + @@ -226,6 +233,19 @@ Name of the DCS Static as defined within the Mission Editor.

    + +
    +
    + + +STATIC:GetThreatLevel() + +
    +
    + + +
    diff --git a/docs/Documentation/Task.html b/docs/Documentation/Task.html index 13ca897b7..cc7c6163d 100644 --- a/docs/Documentation/Task.html +++ b/docs/Documentation/Task.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -88,6 +89,7 @@
  • TASK.HasStateMachine():Enquire if the task has a Fsm
  • TASK.AssignToUnit(): Assign a task to a unit. (Needs to be implemented in the derived classes from #TASK.
  • TASK.UnAssignFromUnit(): Unassign the task from a unit.
  • +
  • TASK.SetTimeOut(): Set timer in seconds before task gets cancelled if not assigned.
  • 1.2) Set and enquire task status (beyond the task state machine processing).

    @@ -511,6 +513,12 @@ Use the method TASK.AddScore() to add scores whe
    + + + + @@ -595,6 +603,12 @@ Use the method TASK.AddScore() to add scores whe + + + + @@ -643,6 +657,12 @@ Use the method TASK.AddScore() to add scores whe + + + + @@ -661,6 +681,12 @@ Use the method TASK.AddScore() to add scores whe + + + + @@ -1993,6 +2019,36 @@ self

    + +TASK:SetTimeOut(Timer) + +
    +
    + +

    Sets the TimeOut for the Task.

    + + +

    If Task stayed planned for longer than TimeOut, it gets into Cancelled status.

    + +

    Parameter

    +
      +
    • + +

      #integer Timer : +in seconds

      + +
    • +
    +

    Return value

    + +

    #TASK: +self

    + +
    +
    +
    +
    + TASK:SetType(TaskType) @@ -2200,6 +2256,20 @@ Fsm#FSM_PROCESS

    + +
    +
    +
    + + + +TASK.TimeOut + +
    +
    + + +
    @@ -2355,6 +2425,37 @@ self

    + +TASK:onbeforeTimeOut(Event, From, To) + +
    +
    + +

    FSM function for a TASK

    + +

    Parameters

    +
      +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    +
    +
    +
    +
    + TASK:onenterAborted(From, Event, To) @@ -2448,6 +2549,37 @@ self

    + +TASK:onenterPlanned(Event, From, To) + +
    +
    + +

    FSM function for a TASK

    + +

    Parameters

    +
      +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    +
    +
    +
    +
    + TASK:onenterSuccess(Event, From, To) @@ -2508,6 +2640,8 @@ self

    +

    Type integer

    + diff --git a/docs/Documentation/Task_A2G.html b/docs/Documentation/Task_A2G.html index 892111aba..d3718c2c3 100644 --- a/docs/Documentation/Task_A2G.html +++ b/docs/Documentation/Task_A2G.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Task_PICKUP.html b/docs/Documentation/Task_PICKUP.html index 10b5479bd..16565d8d4 100644 --- a/docs/Documentation/Task_PICKUP.html +++ b/docs/Documentation/Task_PICKUP.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Task_SEAD.html b/docs/Documentation/Task_SEAD.html index 9e10ea662..b4befe7f4 100644 --- a/docs/Documentation/Task_SEAD.html +++ b/docs/Documentation/Task_SEAD.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Unit.html b/docs/Documentation/Unit.html index 20dc60691..27a770ddb 100644 --- a/docs/Documentation/Unit.html +++ b/docs/Documentation/Unit.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Utils.html b/docs/Documentation/Utils.html index ce2722695..86500945d 100644 --- a/docs/Documentation/Utils.html +++ b/docs/Documentation/Utils.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index 416e0c6b3..95d2db900 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -74,7 +75,7 @@
    + + + + @@ -334,7 +341,17 @@ following a given priority.

    @@ -358,7 +375,7 @@ following a given priority.

    ClientGroup - -
    SCORING @@ -115,9 +304,33 @@ to a database or a BI tool to publish the scoring results to the player communit

    Type SCORING

    - + + + + + + + + + + + + + + + + + @@ -139,7 +352,85 @@ to a database or a BI tool to publish the scoring results to the player communit - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -148,6 +439,18 @@ to a database or a BI tool to publish the scoring results to the player communit + + + + + + + + @@ -163,21 +466,81 @@ to a database or a BI tool to publish the scoring results to the player communit - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -187,13 +550,19 @@ to a database or a BI tool to publish the scoring results to the player communit - + - + + + + + @@ -202,6 +571,66 @@ to a database or a BI tool to publish the scoring results to the player communit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -232,12 +661,6 @@ to a database or a BI tool to publish the scoring results to the player communit - - - -
    SCORING.AllScoresMenuSCORING:AddGoalScore(PlayerUnit, GoalTag, Text, Score) - +

    Add a goal score for a player.

    +
    SCORING:AddScoreGroup(ScoreGroup, Score) +

    Specify a special additional score for a Group.

    +
    SCORING:AddStaticScore(ScoreStatic, Score) +

    Add a Static for additional scoring when the Static is destroyed.

    +
    SCORING:AddUnitScore(ScoreUnit, Score) +

    Add a Unit for additional scoring when the Unit is destroyed.

    +
    SCORING:AddZoneScore(ScoreZone, Score) +

    Add a Zone to define additional scoring when any object is destroyed in that zone.

    SCORING.MenuSCORING.CoalitionChangePenalty + +
    SCORING.Fratricide + +
    SCORING.GameName + +
    SCORING:IfMessagesDestroy() +

    If to send messages after a target has been destroyed.

    +
    SCORING:IfMessagesHit() +

    If to send messages after a target has been hit.

    +
    SCORING:IfMessagesScore() +

    If to send messages after a target has been destroyed and receives additional scores.

    +
    SCORING:IfMessagesToAll() +

    If to send messages to all players.

    +
    SCORING:IfMessagesToCoalition() +

    If to send messages to only those players within the same coalition as the player.

    +
    SCORING:IfMessagesZone() +

    If to send messages after a target has been hit in a zone, and additional score is received.

    +
    SCORING.MessagesAudience + +
    SCORING.MessagesDestroy + +
    SCORING.MessagesHit + +
    SCORING.MessagesScore + +
    SCORING.MessagesZone SCORING:New(GameName)

    Creates a new SCORING object to administer the scoring achieved by players.

    +
    SCORING:OnEventPlayerEnterUnit(Event) +

    Handles the OnPlayerEnterUnit event for the scoring.

    +
    SCORING:OnEventPlayerLeaveUnit(Event) +

    Handles the OnPlayerLeaveUnit event for the scoring.

    SCORING:ReportScoreAll()SCORING:RemoveStaticScore(ScoreStatic) - +

    Removes a Static for additional scoring when the Static is destroyed.

    SCORING:ReportScorePlayer()SCORING:RemoveUnitScore(ScoreUnit) - +

    Removes a Unit for additional scoring when the Unit is destroyed.

    +
    SCORING:RemoveZoneScore(ScoreZone) +

    Remove a Zone for additional scoring.

    +
    SCORING:ReportDetailedPlayerCoalitionChanges(PlayerName) +

    Produce detailed report of player penalty scores because of changing the coalition.

    +
    SCORING:ReportDetailedPlayerDestroys(PlayerName) +

    Produce detailed report of player destroy scores.

    +
    SCORING:ReportDetailedPlayerHits(PlayerName) +

    Produce detailed report of player hit scores.

    +
    SCORING:ReportDetailedPlayerMissions(PlayerName) +

    Produce detailed report of player goal scores.

    +
    SCORING:ReportScoreAllSummary(PlayerGroup) +

    Report all players score

    +
    SCORING:ReportScoreGroupDetailed(PlayerGroup) +

    Report Group Score Detailed

    +
    SCORING:ReportScoreGroupSummary(PlayerGroup) +

    Report Group Score Summary

    SCORING.RunTime +
    SCORING.ScaleDestroyPenalty + +
    SCORING.ScaleDestroyScore +
    SCORING:ScoreMenu()SCORING.ScoringCSV -

    Creates a score radio menu.

    +
    SCORING.ScoringCSVSCORING.ScoringObjects + +
    SCORING.ScoringZones SCORING:SecondsToClock(sSeconds) +
    SCORING:SetCoalitionChangePenalty(CoalitionChangePenalty) +

    When a player changes the coalition, he can receive a penalty score.

    +
    SCORING:SetFratricide(Fratricide) +

    When a player commits too much damage to friendlies, his penalty score will reach a certain level.

    +
    SCORING:SetMessagesDestroy(OnOff) +

    Configure to send messages after a target has been destroyed.

    +
    SCORING:SetMessagesHit(OnOff) +

    Configure to send messages after a target has been hit.

    +
    SCORING:SetMessagesScore(OnOff) +

    Configure to send messages after a target has been destroyed and receives additional scores.

    +
    SCORING:SetMessagesToAll() +

    Configure to send messages to all players.

    +
    SCORING:SetMessagesToCoalition() +

    Configure to send messages to only those players within the same coalition as the player.

    +
    SCORING:SetMessagesZone(OnOff) +

    Configure to send messages after a target has been hit in a zone, and additional score is received.

    +
    SCORING:SetScaleDestroyPenalty(Scale) +

    Set the scale for scoring penalty destroys (friendly destroys).

    +
    SCORING:SetScaleDestroyScore(Scale) +

    Set the scale for scoring valid destroys (enemy destroys).

    SCORING:_EventOnHit(Event)

    Handles the OnHit event for the scoring.

    -
    SCORING:_FollowPlayersScheduled() -

    Follows new players entering Clients within the DCSRTE.

    @@ -246,20 +669,6 @@ to a database or a BI tool to publish the scoring results to the player communit
    - - -ClientGroup - -
    -
    - - - -
    -
    -
    -
    - #SCORING SCORING @@ -323,13 +732,190 @@ to a database or a BI tool to publish the scoring results to the player communit
    - - -SCORING.AllScoresMenu + +SCORING:AddGoalScore(PlayerUnit, GoalTag, Text, Score)
    +

    Add a goal score for a player.

    + + +

    The method takes the PlayerUnit for which the Goal score needs to be set. +The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal. +A free text can be given that is shown to the players. +The Score can be both positive and negative.

    + +

    Parameters

    +
      +
    • + +

      Wrapper.Unit#UNIT PlayerUnit : +The Unit of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc.

      + +
    • +
    • + +

      #string GoalTag : +The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel).

      + +
    • +
    • + +

      #string Text : +A free text that is shown to the players.

      + +
    • +
    • + +

      #number Score : +The score can be both positive or negative ( Penalty ).

      + +
    • +
    +
    +
    +
    +
    + + +SCORING:AddScoreGroup(ScoreGroup, Score) + +
    +
    + +

    Specify a special additional score for a Group.

    + +

    Parameters

    + +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:AddStaticScore(ScoreStatic, Score) + +
    +
    + +

    Add a Static for additional scoring when the Static is destroyed.

    + + +

    Note that if there was already a Static declared within the scoring with the same name, +then the old Static will be replaced with the new Static.

    + +

    Parameters

    +
      +
    • + +

      Wrapper.Static#UNIT ScoreStatic : +The Static for which the Score needs to be given.

      + +
    • +
    • + +

      #number Score : +The Score value.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:AddUnitScore(ScoreUnit, Score) + +
    +
    + +

    Add a Unit for additional scoring when the Unit is destroyed.

    + + +

    Note that if there was already a Unit declared within the scoring with the same name, +then the old Unit will be replaced with the new Unit.

    + +

    Parameters

    +
      +
    • + +

      Wrapper.Unit#UNIT ScoreUnit : +The Unit for which the Score needs to be given.

      + +
    • +
    • + +

      #number Score : +The Score value.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:AddZoneScore(ScoreZone, Score) + +
    +
    + +

    Add a Zone to define additional scoring when any object is destroyed in that zone.

    + + +

    Note that if a Zone with the same name is already within the scoring added, the Zone (type) and Score will be replaced! +This allows for a dynamic destruction zone evolution within your mission.

    + +

    Parameters

    +
      +
    • + +

      Core.Zone#ZONE_BASE ScoreZone : +The Zone which defines the destruction score perimeters. +Note that a zone can be a polygon or a moving zone.

      + +
    • +
    • + +

      #number Score : +The Score value.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    @@ -379,8 +965,214 @@ to a database or a BI tool to publish the scoring results to the player communit
    - -SCORING.Menu + +SCORING.CoalitionChangePenalty + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.Fratricide + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.GameName + +
    +
    + + + +
    +
    +
    +
    + + +SCORING:IfMessagesDestroy() + +
    +
    + +

    If to send messages after a target has been destroyed.

    + +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +SCORING:IfMessagesHit() + +
    +
    + +

    If to send messages after a target has been hit.

    + +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +SCORING:IfMessagesScore() + +
    +
    + +

    If to send messages after a target has been destroyed and receives additional scores.

    + +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +SCORING:IfMessagesToAll() + +
    +
    + +

    If to send messages to all players.

    + +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +SCORING:IfMessagesToCoalition() + +
    +
    + +

    If to send messages to only those players within the same coalition as the player.

    + +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +SCORING:IfMessagesZone() + +
    +
    + +

    If to send messages after a target has been hit in a zone, and additional score is received.

    + +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + #number + +SCORING.MessagesAudience + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.MessagesDestroy + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.MessagesHit + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.MessagesScore + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.MessagesZone
    @@ -423,6 +1215,48 @@ ScoringObject = SCORING:New( "Gori Valley" )
    + +SCORING:OnEventPlayerEnterUnit(Event) + +
    +
    + +

    Handles the OnPlayerEnterUnit event for the scoring.

    + +

    Parameter

    + +
    +
    +
    +
    + + +SCORING:OnEventPlayerLeaveUnit(Event) + +
    +
    + +

    Handles the OnPlayerLeaveUnit event for the scoring.

    + +

    Parameter

    + +
    +
    +
    +
    + SCORING:OpenCSV(ScoringCSV) @@ -467,12 +1301,26 @@ ScoringObject:OpenCSV( "Player Scores" )
    - -SCORING:ReportScoreAll() + +SCORING:RemoveStaticScore(ScoreStatic)
    +

    Removes a Static for additional scoring when the Static is destroyed.

    + +

    Parameter

    + +

    Return value

    + +

    #SCORING:

    @@ -480,8 +1328,242 @@ ScoringObject:OpenCSV( "Player Scores" )
    - -SCORING:ReportScorePlayer() + +SCORING:RemoveUnitScore(ScoreUnit) + +
    +
    + +

    Removes a Unit for additional scoring when the Unit is destroyed.

    + +

    Parameter

    + +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:RemoveZoneScore(ScoreZone) + +
    +
    + +

    Remove a Zone for additional scoring.

    + + +

    The scoring will search if any Zone is added with the given name, and will remove that zone from the scoring. +This allows for a dynamic destruction zone evolution within your mission.

    + +

    Parameter

    +
      +
    • + +

      Core.Zone#ZONE_BASE ScoreZone : +The Zone which defines the destruction score perimeters. +Note that a zone can be a polygon or a moving zone.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:ReportDetailedPlayerCoalitionChanges(PlayerName) + +
    +
    + +

    Produce detailed report of player penalty scores because of changing the coalition.

    + +

    Parameter

    +
      +
    • + +

      #string PlayerName : +The name of the player.

      + +
    • +
    +

    Return value

    + +

    #string: +The report.

    + +
    +
    +
    +
    + + +SCORING:ReportDetailedPlayerDestroys(PlayerName) + +
    +
    + +

    Produce detailed report of player destroy scores.

    + +

    Parameter

    +
      +
    • + +

      #string PlayerName : +The name of the player.

      + +
    • +
    +

    Return value

    + +

    #string: +The report.

    + +
    +
    +
    +
    + + +SCORING:ReportDetailedPlayerHits(PlayerName) + +
    +
    + +

    Produce detailed report of player hit scores.

    + +

    Parameter

    +
      +
    • + +

      #string PlayerName : +The name of the player.

      + +
    • +
    +

    Return value

    + +

    #string: +The report.

    + +
    +
    +
    +
    + + +SCORING:ReportDetailedPlayerMissions(PlayerName) + +
    +
    + +

    Produce detailed report of player goal scores.

    + +

    Parameter

    +
      +
    • + +

      #string PlayerName : +The name of the player.

      + +
    • +
    +

    Return value

    + +

    #string: +The report.

    + +
    +
    +
    +
    + + +SCORING:ReportScoreAllSummary(PlayerGroup) + +
    +
    + +

    Report all players score

    + +

    Parameter

    + +
    +
    +
    +
    + + +SCORING:ReportScoreGroupDetailed(PlayerGroup) + +
    +
    + +

    Report Group Score Detailed

    + +

    Parameter

    + +
    +
    +
    +
    + + +SCORING:ReportScoreGroupSummary(PlayerGroup) + +
    +
    + +

    Report Group Score Summary

    + +

    Parameter

    + +
    +
    +
    +
    + + + +SCORING.RunTime
    @@ -494,8 +1576,22 @@ ScoringObject:OpenCSV( "Player Scores" )
    - -SCORING.RunTime + +SCORING.ScaleDestroyPenalty + +
    +
    + + + +
    +
    +
    +
    + + + +SCORING.ScaleDestroyScore
    @@ -595,27 +1691,6 @@ The type of the target unit.

    #SCORING: self

    -
    -
    -
    -
    - - -SCORING:ScoreMenu() - -
    -
    - -

    Creates a score radio menu.

    - - -

    Can be accessed using Radio -> F10.

    - -

    Return value

    - -

    #SCORING: -self

    -
    @@ -630,6 +1705,40 @@ self

    +
    +
    +
    +
    + + + +SCORING.ScoringObjects + +
    +
    + + + + +

    Additional Object scores

    + +
    +
    +
    +
    + + + +SCORING.ScoringZones + +
    +
    + + + + +

    Additional Zone scores.

    +
    @@ -656,6 +1765,269 @@ self

    + +SCORING:SetCoalitionChangePenalty(CoalitionChangePenalty) + +
    +
    + +

    When a player changes the coalition, he can receive a penalty score.

    + + +

    Use the method SCORING.SetCoalitionChangePenalty() to define the penalty when a player changes coalition. +By default, the penalty for changing coalition is the default penalty scale.

    + +

    Parameter

    +
      +
    • + +

      #number CoalitionChangePenalty : +The amount of penalty that is given.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetFratricide(Fratricide) + +
    +
    + +

    When a player commits too much damage to friendlies, his penalty score will reach a certain level.

    + + +

    Use this method to define the level when a player gets kicked.
    +By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score.

    + +

    Parameter

    +
      +
    • + +

      #number Fratricide : +The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetMessagesDestroy(OnOff) + +
    +
    + +

    Configure to send messages after a target has been destroyed.

    + +

    Parameter

    +
      +
    • + +

      #boolean OnOff : +If true is given, the messages are sent.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetMessagesHit(OnOff) + +
    +
    + +

    Configure to send messages after a target has been hit.

    + +

    Parameter

    +
      +
    • + +

      #boolean OnOff : +If true is given, the messages are sent.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetMessagesScore(OnOff) + +
    +
    + +

    Configure to send messages after a target has been destroyed and receives additional scores.

    + +

    Parameter

    +
      +
    • + +

      #boolean OnOff : +If true is given, the messages are sent.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetMessagesToAll() + +
    +
    + +

    Configure to send messages to all players.

    + +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetMessagesToCoalition() + +
    +
    + +

    Configure to send messages to only those players within the same coalition as the player.

    + +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetMessagesZone(OnOff) + +
    +
    + +

    Configure to send messages after a target has been hit in a zone, and additional score is received.

    + +

    Parameter

    +
      +
    • + +

      #boolean OnOff : +If true is given, the messages are sent.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetScaleDestroyPenalty(Scale) + +
    +
    + +

    Set the scale for scoring penalty destroys (friendly destroys).

    + + +

    A default calculated penalty is a value between 1 and 10. +The scale magnifies the scores given to the players.

    + +

    Parameter

    +
      +
    • + +

      #number Scale : +The scale of the score given.

      + +
    • +
    +

    Return value

    + +

    #SCORING:

    + + +
    +
    +
    +
    + + +SCORING:SetScaleDestroyScore(Scale) + +
    +
    + +

    Set the scale for scoring valid destroys (enemy destroys).

    + + +

    A default calculated score is a value between 1 and 10. +The scale magnifies the scores given to the players.

    + +

    Parameter

    +
      +
    • + +

      #number Scale : +The scale of the score given.

      + +
    • +
    +
    +
    +
    +
    + SCORING:_AddMissionScore(Mission, PlayerUnit, Text, Score) @@ -740,7 +2112,7 @@ self

    @@ -786,22 +2158,6 @@ self

    - -
    -
    -
    - - -SCORING:_FollowPlayersScheduled() - -
    -
    - -

    Follows new players entering Clients within the DCSRTE.

    - - -

    TODO: Need to see if i can catch this also with an event. It will eliminate the schedule ...

    -
    diff --git a/docs/Documentation/Sead.html b/docs/Documentation/Sead.html index 021db2d57..f0fd344db 100644 --- a/docs/Documentation/Sead.html +++ b/docs/Documentation/Sead.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Set.html b/docs/Documentation/Set.html index b67fea497..f807c3237 100644 --- a/docs/Documentation/Set.html +++ b/docs/Documentation/Set.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Smoke.html b/docs/Documentation/Smoke.html index 821a9ea9a..6702e3e2c 100644 --- a/docs/Documentation/Smoke.html +++ b/docs/Documentation/Smoke.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 7723371a8..9a836ef50 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -71,7 +72,7 @@

    Module Spawn

    -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:All --
    +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:All --
    Spawn groups of units dynamically in your missions.

    Banner Image

    @@ -1758,6 +1759,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.

    +
    @@ -2232,7 +2236,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxGroups @@ -2249,7 +2253,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxUnitsAlive @@ -2528,7 +2532,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
    - + #boolean SPAWN.SpawnUnControlled diff --git a/docs/Documentation/Static.html b/docs/Documentation/Static.html index 410ec8e61..c05f4004d 100644 --- a/docs/Documentation/Static.html +++ b/docs/Documentation/Static.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • @@ -133,6 +134,12 @@ If the DCS Static object does not exist or is nil, the STATIC methods will retur
    STATIC:GetDCSObject() +
    STATIC:GetThreatLevel() +
    TASK:SetStateMachine(TaskUnit, Fsm)

    Add a FiniteStateMachine to Task with key TaskUnit

    +
    TASK:SetTimeOut(Timer) +

    Sets the TimeOut for the Task.

    TASK.TaskType +
    TASK.TimeOut +
    TASK:onafterReplan(From, Event, To)

    FSM function for a TASK

    +
    TASK:onbeforeTimeOut(Event, From, To) +

    FSM function for a TASK

    TASK:onenterFailed(From, Event, To)

    FSM function for a TASK

    +
    TASK:onenterPlanned(Event, From, To) +

    FSM function for a TASK

    AI_Balancer -

    Single-Player:No / Mulit-Player:Yes / AI:Yes / Human:No / Types:All -- AI Balancing will replace in multi player missions +

    Single-Player:No / Multi-Player:Yes / AI:Yes / Human:No / Types:All -- AI Balancing will replace in multi player missions non-occupied human slots with AI groups, in order to provide an engaging simulation environment, even when there are hardly any players in the mission.

    @@ -91,7 +92,7 @@ CLIENTS in a SET_CLIENT collection, which are not occupied by human players.

    AI_Cap -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Air -- Execute Combat Air Patrol (CAP).

    +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Air -- Execute Combat Air Patrol (CAP).

    Banner Image

    @@ -106,7 +107,7 @@ and automatically engage any airborne enemies that are within a certain range or
    AI_Cas -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Air -- +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Air -- Provide Close Air Support to friendly ground troops.

    Banner Image

    @@ -121,7 +122,7 @@ and automatically engage any airborne enemies that are within a certain range or
    AI_Patrol -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Air -- +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Air -- Air Patrolling or Staging.

    Banner Image

    @@ -166,7 +167,7 @@ and automatically engage any airborne enemies that are within a certain range or
    Cargo -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:Ground --
    +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:Ground --
    Management of logical cargo objects, that can be transported from and to transportation carriers.

    Banner Image

    @@ -317,6 +318,12 @@ following a given priority.

    Route

    (SP) (MP) (FSM) Route AI or players through waypoints or to zones.

    +
    Scenery +

    This module contains the SCENERY class.

    Scoring -

    Scoring system for MOOSE.

    +

    Single-Player:Yes / Multi-Player:Yes / Core:Yes -- Administer the scoring of player achievements, +and create a CSV file logging the scoring events for use at team or squadron websites.

    + +

    Banner Image

    + +
    + +

    1) Scoring#SCORING class, extends Base#BASE

    + +

    The #SCORING class administers the scoring of player achievements, +and creates a CSV file logging the scoring events and results for use at team or squadron websites.

    Spawn -

    Single-Player:Yes / Mulit-Player:Yes / AI:Yes / Human:No / Types:All --
    +

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:All --
    Spawn groups of units dynamically in your missions.

    Banner Image

    diff --git a/docs/Documentation/routines.html b/docs/Documentation/routines.html index 7c828c35d..ba89d2875 100644 --- a/docs/Documentation/routines.html +++ b/docs/Documentation/routines.html @@ -50,6 +50,7 @@
  • Process_JTAC
  • Process_Pickup
  • Route
  • +
  • Scenery
  • ScheduleDispatcher
  • Scheduler
  • Scoring
  • diff --git a/docs/Presentations/SCORING.pptx b/docs/Presentations/SCORING.pptx new file mode 100644 index 000000000..511f83f82 Binary files /dev/null and b/docs/Presentations/SCORING.pptx differ diff --git a/docs/Presentations/SCORING/Dia1.JPG b/docs/Presentations/SCORING/Dia1.JPG new file mode 100644 index 000000000..d1b418574 Binary files /dev/null and b/docs/Presentations/SCORING/Dia1.JPG differ diff --git a/docs/Presentations/SCORING/Dia10.JPG b/docs/Presentations/SCORING/Dia10.JPG new file mode 100644 index 000000000..ff450950b Binary files /dev/null and b/docs/Presentations/SCORING/Dia10.JPG differ diff --git a/docs/Presentations/SCORING/Dia11.JPG b/docs/Presentations/SCORING/Dia11.JPG new file mode 100644 index 000000000..3814c3d85 Binary files /dev/null and b/docs/Presentations/SCORING/Dia11.JPG differ diff --git a/docs/Presentations/SCORING/Dia12.JPG b/docs/Presentations/SCORING/Dia12.JPG new file mode 100644 index 000000000..9228bac57 Binary files /dev/null and b/docs/Presentations/SCORING/Dia12.JPG differ diff --git a/docs/Presentations/SCORING/Dia13.JPG b/docs/Presentations/SCORING/Dia13.JPG new file mode 100644 index 000000000..2e4a6114b Binary files /dev/null and b/docs/Presentations/SCORING/Dia13.JPG differ diff --git a/docs/Presentations/SCORING/Dia14.JPG b/docs/Presentations/SCORING/Dia14.JPG new file mode 100644 index 000000000..f98caa5e1 Binary files /dev/null and b/docs/Presentations/SCORING/Dia14.JPG differ diff --git a/docs/Presentations/SCORING/Dia2.JPG b/docs/Presentations/SCORING/Dia2.JPG new file mode 100644 index 000000000..51ad11dd5 Binary files /dev/null and b/docs/Presentations/SCORING/Dia2.JPG differ diff --git a/docs/Presentations/SCORING/Dia3.JPG b/docs/Presentations/SCORING/Dia3.JPG new file mode 100644 index 000000000..1518e6a24 Binary files /dev/null and b/docs/Presentations/SCORING/Dia3.JPG differ diff --git a/docs/Presentations/SCORING/Dia4.JPG b/docs/Presentations/SCORING/Dia4.JPG new file mode 100644 index 000000000..ab7571f24 Binary files /dev/null and b/docs/Presentations/SCORING/Dia4.JPG differ diff --git a/docs/Presentations/SCORING/Dia5.JPG b/docs/Presentations/SCORING/Dia5.JPG new file mode 100644 index 000000000..44ba79cdd Binary files /dev/null and b/docs/Presentations/SCORING/Dia5.JPG differ diff --git a/docs/Presentations/SCORING/Dia6.JPG b/docs/Presentations/SCORING/Dia6.JPG new file mode 100644 index 000000000..983ebc9e8 Binary files /dev/null and b/docs/Presentations/SCORING/Dia6.JPG differ diff --git a/docs/Presentations/SCORING/Dia7.JPG b/docs/Presentations/SCORING/Dia7.JPG new file mode 100644 index 000000000..c7daf51c2 Binary files /dev/null and b/docs/Presentations/SCORING/Dia7.JPG differ diff --git a/docs/Presentations/SCORING/Dia8.JPG b/docs/Presentations/SCORING/Dia8.JPG new file mode 100644 index 000000000..b993827f2 Binary files /dev/null and b/docs/Presentations/SCORING/Dia8.JPG differ diff --git a/docs/Presentations/SCORING/Dia9.JPG b/docs/Presentations/SCORING/Dia9.JPG new file mode 100644 index 000000000..c1ccceba7 Binary files /dev/null and b/docs/Presentations/SCORING/Dia9.JPG differ diff --git a/docs/README.md b/docs/README.md index 8b0e62149..eacd0bba7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -205,6 +205,8 @@ MOOSE Functional Classes provide various functions that are useful in mission de * [DETECTION](Documentation/Detection.html): Detect other units using the available sensors of the detection unit. The DETECTION_BASE derived classes will provide different methods how the sets of detected objects are built. +* [SCORING](Documentation/Scoring.html): Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites. + ## 7.4) MOOSE AI Controlling Classes MOOSE AI Controlling Classes provide mechanisms to control AI over long lasting processes.