diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index ffd33255d..412e18430 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -1175,7 +1175,7 @@ function RADIOQUEUE:_CheckRadioQueue() else - if time-Tlast>=transmission.interval then + if Tlast==nil or time-Tlast>=transmission.interval then next=transmission else diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index 6594633c9..206f1e4cb 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -2204,9 +2204,8 @@ end -- end function SPAWN:GetLastAliveGroup() self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - self.SpawnIndex = self:_GetLastIndex() - for SpawnIndex = self.SpawnIndex, 1, -1 do + + for SpawnIndex = self.SpawnCount, 1, -1 do -- Added local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) if SpawnGroup and SpawnGroup:IsAlive() then self.SpawnIndex = SpawnIndex diff --git a/Moose Development/Moose/Functional/Fox.lua b/Moose Development/Moose/Functional/Fox.lua index e6fb352f4..69afa5761 100644 --- a/Moose Development/Moose/Functional/Fox.lua +++ b/Moose Development/Moose/Functional/Fox.lua @@ -76,8 +76,8 @@ -- fox=FOX:New() -- -- -- Add training zones. --- fox:AddSafeZone(ZONE:New("Training Zone Alpha") --- fox:AddSafeZone(ZONE:New("Training Zone Bravo") +-- fox:AddSafeZone(ZONE:New("Training Zone Alpha")) +-- fox:AddSafeZone(ZONE:New("Training Zone Bravo")) -- -- -- Start missile trainer. -- fox:Start() @@ -90,8 +90,8 @@ -- fox=FOX:New() -- -- -- Add training zones. --- fox:AddLaunchZone(ZONE:New("Launch Zone SA-10 Krim") --- fox:AddLaunchZone(ZONE:New("Training Zone Bravo") +-- fox:AddLaunchZone(ZONE:New("Launch Zone SA-10 Krim")) +-- fox:AddLaunchZone(ZONE:New("Training Zone Bravo")) -- -- -- Start missile trainer. -- fox:Start() @@ -189,7 +189,7 @@ FOX.MenuF10Root=nil --- FOX class version. -- @field #string version -FOX.version="0.5.0" +FOX.version="0.5.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -444,6 +444,17 @@ function FOX:SetExplosionPower(power) return self end +--- Set missile-player distance when missile is destroyed. +-- @param #FOX self +-- @param #number distance Distance in meters. Default 100 m. +-- @return #FOX self +function FOX:SetExplosionDistance(distance) + + self.explosiondist=distance or 100 + + return self +end + --- Disable F10 menu for all players. -- @param #FOX self @@ -1065,13 +1076,13 @@ function FOX:OnEventShot(EventData) end -- Debug info. - self:E(FOX.lid.."EVENT SHOT: FOX") - self:E(FOX.lid..string.format("EVENT SHOT: Ini unit = %s", tostring(EventData.IniUnitName))) - self:E(FOX.lid..string.format("EVENT SHOT: Ini group = %s", tostring(EventData.IniGroupName))) - self:E(FOX.lid..string.format("EVENT SHOT: Weapon type = %s", tostring(_weapon))) - self:E(FOX.lid..string.format("EVENT SHOT: Weapon categ = %s", tostring(weaponcategory))) - self:E(FOX.lid..string.format("EVENT SHOT: Missil categ = %s", tostring(missilecategory))) - self:E(FOX.lid..string.format("EVENT SHOT: Missil range = %s", tostring(missilerange))) + self:T2(FOX.lid.."EVENT SHOT: FOX") + self:T2(FOX.lid..string.format("EVENT SHOT: Ini unit = %s", tostring(EventData.IniUnitName))) + self:T2(FOX.lid..string.format("EVENT SHOT: Ini group = %s", tostring(EventData.IniGroupName))) + self:T2(FOX.lid..string.format("EVENT SHOT: Weapon type = %s", tostring(_weapon))) + self:T2(FOX.lid..string.format("EVENT SHOT: Weapon categ = %s", tostring(weaponcategory))) + self:T2(FOX.lid..string.format("EVENT SHOT: Missil categ = %s", tostring(missilecategory))) + self:T2(FOX.lid..string.format("EVENT SHOT: Missil range = %s", tostring(missilerange))) -- Check if fired in launch zone. diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 17f30ac98..1143b00e8 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -98,7 +98,7 @@ PSEUDOATC.id="PseudoATC | " --- PSEUDOATC version. -- @field #number version -PSEUDOATC.version="0.9.1" +PSEUDOATC.version="0.9.2" ----------------------------------------------------------------------------------------------------------------------------------------- @@ -807,8 +807,9 @@ function PSEUDOATC:ReportBR(GID, UID, position, location) -- Message text. local text=string.format("%s: Bearing %s, Range %s.", location, Bs, Rs) - -- Send message to player group. - MESSAGE:New(text, self.mdur):ToGroup(self.player[id].group) + -- Send message + self:_DisplayMessageToGroup(self.group[GID].player[UID].unit, text, self.mdur, true) + end --- Report altitude above ground level of player unit. diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index eb3009ee4..a1d716058 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -78,7 +78,7 @@ -- @field #boolean trackrockets If true (default), all rocket types are tracked and impact point to closest bombing target is evaluated. -- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated. -- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb. --- @field #boolean autosafe If true, automatically save results every X seconds. +-- @field #boolean autosave If true, automatically save results every X seconds. -- @extends Core.Base#BASE --- Enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor. @@ -340,7 +340,7 @@ RANGE.MenuF10Root=nil --- Range script version. -- @field #string version -RANGE.version="2.1.1" +RANGE.version="2.1.2" --TODO list: --TODO: Verbosity level for messages. @@ -617,19 +617,19 @@ function RANGE:SetMessageTimeDuration(time) return self end ---- Automatically safe player results to disc. +--- Automatically save player results to disc. -- @param #RANGE self -- @return #RANGE self -function RANGE:SetAutosafeOn() - self.autosafe=true +function RANGE:SetAutosaveOn() + self.autosave=true return self end ---- Switch off auto safe player results. +--- Switch off auto save player results. -- @param #RANGE self -- @return #RANGE self -function RANGE:SetAutosafeOff() - self.autosafe=false +function RANGE:SetAutosaveOff() + self.autosave=false return self end @@ -662,7 +662,7 @@ function RANGE:SetRangeRadius(radius) return self end ---- Set player setting whether bomb impact points are smoked or not +--- Set player setting whether bomb impact points are smoked or not. -- @param #RANGE self -- @param #boolean switch If true nor nil default is to smoke impact points of bombs. -- @return #RANGE self @@ -1650,7 +1650,7 @@ function RANGE:onafterStatus(From, Event, To) self:_CheckPlayers() -- Save results. - if self.autosafe then + if self.autosave then self:Save() end @@ -1725,10 +1725,10 @@ function RANGE:onafterSave(From, Event, To) end -- Path. - local path=lfs.writedir() + local path=lfs.writedir()..[[Logs\]] -- Set file name. - local filename=path..string.format("\\RANGE-%s_BombingResults.csv", self.rangename) + local filename=path..string.format("RANGE-%s_BombingResults.csv", self.rangename) -- Header line. local scores="Name,Pass,Target,Distance,Radial,Quality,Weapon,Airframe,Mission Time" @@ -1788,11 +1788,11 @@ function RANGE:onafterLoad(From, Event, To) end end - -- Path. - local path=lfs.writedir() + -- Path in DCS log file. + local path=lfs.writedir()..[[Logs\]] -- Set file name. - local filename=path..string.format("\\RANGE-%s_BombingResults.csv", self.rangename) + local filename=path..string.format("RANGE-%s_BombingResults.csv", self.rangename) -- Info message. local text=string.format("Loading player bomb results from file %s", filename) @@ -2185,15 +2185,16 @@ function RANGE:_DisplayBombTargets(_unitname) local _text="Bomb Target Locations:" for _,_bombtarget in pairs(self.bombingTargets) do - local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + local bombtarget=_bombtarget --#RANGE.BombTarget -- Coordinate of bombtarget. - local coord=self:_GetBombTargetCoordinate(_bombtarget) + local coord=self:_GetBombTargetCoordinate(bombtarget) if coord then - local mycoord=coord:ToStringA2G(_unit, _settings) - _text=_text..string.format("\n- %s: %s",_bombtarget.name or "unknown", mycoord) + local ca2g=coord:ToStringA2G(_unit, _settings) + local lldms=coord:ToStringLLDMS() + _text=_text..string.format("\n- %s: %s %s", bombtarget.name or "unknown", ca2g, lldms) end end @@ -2708,21 +2709,19 @@ function RANGE:_MarkTargetsOnMap(_unitName) self:F(_unitName) -- Get group. - local group=nil + local group=nil --Wrapper.Group#GROUP if _unitName then group=UNIT:FindByName(_unitName):GetGroup() end -- Mark bomb targets. for _,_bombtarget in pairs(self.bombingTargets) do - local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE - if _target and _target:IsAlive() then - local coord=_target:GetCoordinate() --Core.Point#COORDINATE - if group then - coord:MarkToGroup("Bomb target ".._bombtarget.name, group) - else - coord:MarkToAll("Bomb target ".._bombtarget.name) - end + local bombtarget=_bombtarget --#RANGE.BombTarget + local coord=self:_GetBombTargetCoordinate(_bombtarget) + if group then + coord:MarkToGroup(string.format("Bomb target %s:\n%s\n%s", bombtarget.name, coord:ToStringLLDMS(), coord:ToStringBULLS(group:GetCoalition())), group) + else + coord:MarkToAll(string.format("Bomb target %s", bombtarget.name)) end end @@ -2733,7 +2732,8 @@ function RANGE:_MarkTargetsOnMap(_unitName) if _target and _target:IsAlive() then local coord=_target:GetCoordinate() --Core.Point#COORDINATE if group then - coord:MarkToGroup("Strafe target ".._target:GetName(), group) + --coord:MarkToGroup("Strafe target ".._target:GetName(), group) + coord:MarkToGroup(string.format("Strafe target %s:\n%s\n%s", _target:GetName(), coord:ToStringLLDMS(), coord:ToStringBULLS(group:GetCoalition())), group) else coord:MarkToAll("Strafe target ".._target:GetName()) end diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index f6008fc46..c9518b387 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -1,9 +1,9 @@ --- **Functional** - Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites. --- +-- -- === --- +-- -- ## Features: --- +-- -- * Set the scoring scales based on threat level. -- * Positive scores and negative scores. -- * A contribution model to score achievements. @@ -14,77 +14,77 @@ -- * Score the hits and destroys of scenery. -- * Log scores into a CSV file. -- * Connect to a remote server using JSON and IP. --- +-- -- === --- +-- -- ## Missions: --- +-- -- [SCO - Scoring](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCO%20-%20Scoring) --- +-- -- === --- --- Administers the scoring of player achievements, +-- +-- Administers the scoring of player achievements, -- and creates a CSV file logging the scoring events and results for use at team or squadron websites. --- --- SCORING automatically calculates the threat level of the objects hit and destroyed by players, +-- +-- SCORING automatically calculates the threat level of the objects hit and destroyed by players, -- which can be @{Wrapper.Unit}, @{Static) and @{Scenery} objects. --- --- Positive score points are granted when enemy or neutral targets are destroyed. --- Negative score points or penalties are given when a friendly target is hit or destroyed. +-- +-- 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 +-- 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**. +-- +-- 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. +-- 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. --- +-- -- === --- +-- -- ### Authors: **FlightControl** --- +-- -- ### Contributions: --- +-- -- * **Wingthor (TAW)**: Testing & Advice. -- * **Dutch-Baron (TAW)**: Testing & Advice. -- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing and Advice. --- --- === --- +-- +-- === +-- -- @module Functional.Scoring -- @image Scoring.JPG @@ -94,89 +94,89 @@ -- @extends Core.Base#BASE --- SCORING class --- +-- -- # Constructor: --- +-- -- local Scoring = SCORING:New( "Scoring File" ) --- --- +-- +-- -- # 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.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. --- +-- -- # 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 @{Wrapper.Unit}s. --- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s. --- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s. --- +-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s. +-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s. +-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.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" ) ) --- +-- -- # 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 @{Core.Zone#ZONE_UNIT}, +-- 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 @{Core.Zone#ZONE_UNIT}, -- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points. --- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone}, +-- 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. --- +-- -- # 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. --- +-- -- # (Decommissioned) Configure fratricide level. --- +-- -- **This functionality is decomissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**. --- +-- -- 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. +-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked. -- By default, the fratricide level is the default penalty multiplier * 2 for the penalty score. --- +-- -- # 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. --- +-- By default, the penalty for changing coalition is the default penalty scale. +-- -- # 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. --- --- ### **IMPORTANT!!!* +-- +-- The above documents that 2 Scoring objects are created, ScoringFirstMission and ScoringSecondMission. +-- +-- ### **IMPORTANT!!!* -- In order to allow DCS world to write CSV files, you need to adapt a configuration file in your DCS world installation **on the server**. -- For this, browse to the **missionscripting.lua** file in your DCS world installation folder. -- For me, this installation folder is in _D:\\Program Files\\Eagle Dynamics\\DCS World\Scripts_. --- +-- -- Edit a few code lines in the MissionScripting.lua file. Comment out the lines **os**, **io** and **lfs**: --- +-- -- do -- --sanitizeModule('os') -- --sanitizeModule('io') @@ -184,44 +184,44 @@ -- require = nil -- loadlib = nil -- end --- --- When these lines are not sanitized, functions become available to check the time, and to write files to your system at the above specified location. +-- +-- When these lines are not sanitized, functions become available to check the time, and to write files to your system at the above specified location. -- Note that the MissionScripting.lua file provides a warning. So please beware of this warning as outlined by Eagle Dynamics! --- +-- -- --Sanitize Mission Scripting environment --- --This makes unavailable some unsecure functions. +-- --This makes unavailable some unsecure functions. -- --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions. -- --You can remove the code below and make availble these functions at your own risk. --- +-- -- The MOOSE designer cannot take any responsibility of any damage inflicted as a result of the de-sanitization. -- That being said, I hope that the SCORING class provides you with a great add-on to score your squad mates achievements. --- +-- -- # 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. --- +-- -- ## 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. --- +-- -- ## 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. -- -- === --- +-- -- @field #SCORING SCORING = { ClassName = "SCORING", @@ -270,29 +270,29 @@ local _SCORINGCategory = -- @param #boolean MenuOff (Optional) Done create player menus. -- @return #SCORING self -- @usage --- +-- -- -- Define a new scoring object for the mission Gori Valley. -- ScoringObject = SCORING:New( "Gori Valley" ) --- +-- function SCORING:New( GameName, FileName, MenuOff ) -- Inherits from BASE local self = BASE:Inherit( self, BASE:New() ) -- #SCORING - - if GameName then + + if GameName then self.GameName = GameName else error( "A game name must be given to register the scoring results" ) end - + if FileName then self.FileName = FileName end - - + + -- Additional Object scores self.ScoringObjects = {} - + -- Additional Zone scores. self.ScoringZones = {} @@ -302,48 +302,48 @@ function SCORING:New( GameName, FileName, MenuOff ) 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 ) - + self:SetDisplayMessagePrefix() - + -- No player menus. self.MenuOff=MenuOff - - -- Event handlers + + -- Event handlers self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Hit, self._EventOnHit ) self:HandleEvent( EVENTS.Birth ) --self:HandleEvent( EVENTS.PlayerEnterUnit ) self:HandleEvent( EVENTS.PlayerLeaveUnit ) - - -- During mission startup, especially for single player, + + -- During mission startup, especially for single player, -- iterate the database for the player that has joined, and add him to the scoring, and set the menu. -- But this can only be started one second after the mission has started, so i need to schedule this ... - self.ScoringPlayerScan = BASE:ScheduleOnce( 1, + self.ScoringPlayerScan = BASE:ScheduleOnce( 1, function() - for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do + for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do self:_AddPlayerFromUnit( PlayerUnit ) self:SetScoringMenu( PlayerUnit:GetGroup() ) end end ) - + -- Create the CSV file. self:OpenCSV( GameName, FileName ) return self - + end --- Set a prefix string that will be displayed at each scoring message sent. @@ -375,12 +375,12 @@ end function SCORING:SetScaleDestroyPenalty( Scale ) self.ScaleDestroyPenalty = Scale - + return self end --- Add a @{Wrapper.Unit} for additional scoring when the @{Wrapper.Unit} is destroyed. --- Note that if there was already a @{Wrapper.Unit} declared within the scoring with the same name, +-- Note that if there was already a @{Wrapper.Unit} declared within the scoring with the same name, -- then the old @{Wrapper.Unit} will be replaced with the new @{Wrapper.Unit}. -- @param #SCORING self -- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given. @@ -391,7 +391,7 @@ function SCORING:AddUnitScore( ScoreUnit, Score ) local UnitName = ScoreUnit:GetName() self.ScoringObjects[UnitName] = Score - + return self end @@ -404,12 +404,12 @@ 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, +-- 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. @@ -420,7 +420,7 @@ function SCORING:AddStaticScore( ScoreStatic, Score ) local StaticName = ScoreStatic:GetName() self.ScoringObjects[StaticName] = Score - + return self end @@ -433,7 +433,7 @@ function SCORING:RemoveStaticScore( ScoreStatic ) local StaticName = ScoreStatic:GetName() self.ScoringObjects[StaticName] = nil - + return self end @@ -451,7 +451,7 @@ function SCORING:AddScoreGroup( ScoreGroup, Score ) local UnitName = ScoreUnit:GetName() self.ScoringObjects[UnitName] = Score end - + return self end @@ -459,7 +459,7 @@ end -- 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.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters. +-- @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 @@ -470,7 +470,7 @@ function SCORING:AddZoneScore( ScoreZone, Score ) self.ScoringZones[ZoneName] = {} self.ScoringZones[ZoneName].ScoreZone = ScoreZone self.ScoringZones[ZoneName].Score = Score - + return self end @@ -478,7 +478,7 @@ end -- 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. +-- @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 ) @@ -486,14 +486,14 @@ 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. +-- @param #boolean OnOff If true is given, the messages are sent. -- @return #SCORING function SCORING:SetMessagesHit( OnOff ) @@ -511,7 +511,7 @@ 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. +-- @param #boolean OnOff If true is given, the messages are sent. -- @return #SCORING function SCORING:SetMessagesDestroy( OnOff ) @@ -529,7 +529,7 @@ 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. +-- @param #boolean OnOff If true is given, the messages are sent. -- @return #SCORING function SCORING:SetMessagesScore( OnOff ) @@ -547,7 +547,7 @@ 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. +-- @param #boolean OnOff If true is given, the messages are sent. -- @return #SCORING function SCORING:SetMessagesZone( OnOff ) @@ -599,10 +599,10 @@ 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. +-- 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. +-- @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 ) @@ -613,9 +613,9 @@ 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. +-- 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. +-- @param #number CoalitionChangePenalty The amount of penalty that is given. -- @return #SCORING function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty ) @@ -685,18 +685,18 @@ function SCORING:_AddPlayerFromUnit( UnitData ) "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.", MESSAGE.Type.Information ):ToAll() - + -- Write CSV. 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() ) 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 + self.Players[PlayerName].UNIT = UnitData self.Players[PlayerName].ThreatLevel = UnitThreatLevel self.Players[PlayerName].ThreatType = UnitThreatType @@ -738,15 +738,15 @@ function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score ) self:F( { PlayerName, PlayerName, GoalTag, Text, Score } ) -- PlayerName can be nil, if the Unit with the player crashed or due to another reason. - if PlayerName then + 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.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score PlayerData.Score = PlayerData.Score + Score - + MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll() - + self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil ) end end @@ -759,7 +759,7 @@ end -- A free text can be given that is shown to the players. -- The Score can be both positive and negative. -- @param #SCORING self --- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc. +-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc. -- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel). -- @param #string Text A free text that is shown to the players. -- @param #number Score The score can be both positive or negative ( Penalty ). @@ -770,15 +770,15 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score ) self:F( { 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 + 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.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score PlayerData.Score = PlayerData.Score + Score - + MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll() - + self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() ) end end @@ -798,23 +798,23 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score ) self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } ) -- PlayerName can be nil, if the Unit with the player crashed or due to another reason. - if PlayerName then + if PlayerName then local PlayerData = self.Players[PlayerName] - + if not PlayerData.Mission[MissionName] then PlayerData.Mission[MissionName] = {} PlayerData.Mission[MissionName].ScoreTask = 0 PlayerData.Mission[MissionName].ScoreMission = 0 end - + self:T( PlayerName ) self:T( PlayerData.Mission[MissionName] ) - + PlayerData.Score = self.Players[PlayerName].Score + Score PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score - + MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll() - + self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) end end @@ -832,21 +832,21 @@ function SCORING:_AddMissionGoalScore( Mission, PlayerName, Text, Score ) self:F( { Mission:GetName(), PlayerName, Text, Score } ) -- PlayerName can be nil, if the Unit with the player crashed or due to another reason. - if PlayerName then + if PlayerName then local PlayerData = self.Players[PlayerName] - + if not PlayerData.Mission[MissionName] then PlayerData.Mission[MissionName] = {} PlayerData.Mission[MissionName].ScoreTask = 0 PlayerData.Mission[MissionName].ScoreMission = 0 end - + self:T( PlayerName ) self:T( PlayerData.Mission[MissionName] ) - + PlayerData.Score = self.Players[PlayerName].Score + Score PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score - + MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, Mission:GetText(), Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll() self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score ) @@ -860,7 +860,7 @@ end -- @param #string Text -- @param #number Score function SCORING:_AddMissionScore( Mission, Text, Score ) - + local MissionName = Mission:GetName() self:F( { Mission, Text, Score } ) @@ -899,7 +899,7 @@ end -- @param #SCORING self -- @param Core.Event#EVENTDATA Event function SCORING:OnEventBirth( Event ) - + if Event.IniUnit then if Event.IniObjectCategory == 1 then local PlayerName = Event.IniUnit:GetPlayerName() @@ -1014,21 +1014,21 @@ function SCORING:_EventOnHit( Event ) end 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] --#SCORING.PlayerData - + -- 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 @@ -1037,21 +1037,21 @@ function SCORING:_EventOnHit( Event ) PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() - -- Only grant hit scores if there was more than one second between the last hit. + -- 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 - + ------------------ -- Hit Friendly -- ------------------ @@ -1059,12 +1059,12 @@ function SCORING:_EventOnHit( Event ) Player.Penalty = Player.Penalty + 10 PlayerHit.Penalty = PlayerHit.Penalty + 10 PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 - + -- Check if target was another player. if TargetPlayerName ~= nil then -- It is a player hitting another player ... MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. - TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) @@ -1072,33 +1072,33 @@ function SCORING:_EventOnHit( Event ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) else MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. - TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) end - + -- Write penalty to CSV file. self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - + else - + ---------------- -- Hit Enemey -- ---------------- - + Player.Score = Player.Score + 1 PlayerHit.Score = PlayerHit.Score + 1 PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 - + -- Check if it was a player. if TargetPlayerName ~= nil then -- It is a player hitting another player ... MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. - TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) @@ -1106,28 +1106,28 @@ function SCORING:_EventOnHit( Event ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) else MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. - TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) end - + -- Write score to CSV file. Score 1 PT. self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - + end else -- A scenery object was hit. - + MESSAGE :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.", MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) - + -- Scenery gives 0 PT. self:ScoreCSV( InitPlayerName, "", "HIT_SCORE", 1, 0, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) end @@ -1137,35 +1137,35 @@ function SCORING:_EventOnHit( Event ) elseif InitPlayerName == nil then -- It is an AI hitting a player??? end - + -- It is a weapon initiated by a player, that is hitting something -- This seems to occur only with scenery and static objects. if Event.WeaponPlayerName ~= nil then - + self:_AddPlayerFromUnit( Event.WeaponUNIT ) - + if self.Players[Event.WeaponPlayerName] 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 ) end self:T( "Hitting Scenery" ) - + -- What is he hitting? if TargetCategory then - + -- A scenery or static got hit, score it. -- Player contains the score data from self.Players[WeaponPlayerName] local Player = self.Players[Event.WeaponPlayerName] - + -- 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 @@ -1174,60 +1174,60 @@ function SCORING:_EventOnHit( Event ) PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() - -- Only grant hit scores if there was more than one second between the last hit. + -- 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() - + local Score = 0 - + if InitCoalition then -- A coalition object was hit, probably a static. if InitCoalition == TargetCoalition then - + -- TODO: Penalty according scale Player.Penalty = Player.Penalty + 10 PlayerHit.Penalty = PlayerHit.Penalty + 10 PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 - + MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. - TargetUnitCategory .. " ( " .. TargetType .. " ) " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. "Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) - + -- Minus 10 points. self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) else - - + + Player.Score = Player.Score + 1 PlayerHit.Score = PlayerHit.Score + 1 PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 - + MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. - TargetUnitCategory .. " ( " .. TargetType .. " ) " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. "Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty, MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) - + -- Score hit 1 PT. self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - + end else -- A scenery object was hit. - + MESSAGE :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.", MESSAGE.Type.Update ) :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) - + -- Scenery hit 0 PT. self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType ) end @@ -1295,10 +1295,10 @@ function SCORING:_EventOnDeadOrCrash( Event ) -- What is the player destroying? if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] and Player.Hit[TargetCategory][TargetUnitName].TimeStamp ~= 0 then -- Was there a hit for this unit for this player before registered??? - + local TargetThreatLevel = Player.Hit[TargetCategory][TargetUnitName].ThreatLevel local TargetThreatType = Player.Hit[TargetCategory][TargetUnitName].ThreatType - + Player.Destroy[TargetCategory] = Player.Destroy[TargetCategory] or {} Player.Destroy[TargetCategory][TargetType] = Player.Destroy[TargetCategory][TargetType] or {} @@ -1311,36 +1311,36 @@ function SCORING:_EventOnDeadOrCrash( Event ) if TargetCoalition then if InitCoalition == TargetCoalition then - + --- -- Hit Friendly --- - + local ThreatLevelTarget = TargetThreatLevel local ThreatTypeTarget = TargetThreatType local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1 local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 ) self:F( { 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 + + if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. - TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty, - MESSAGE.Type.Information + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) else MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. - TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty, - MESSAGE.Type.Information + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) @@ -1349,9 +1349,9 @@ function SCORING:_EventOnDeadOrCrash( Event ) -- Write CSV penalty. Destroyed = true self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - + else - + --- -- Hit Enemy --- @@ -1360,128 +1360,128 @@ function SCORING:_EventOnDeadOrCrash( Event ) local ThreatTypeTarget = TargetThreatType local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1 local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 ) - + self:F( { 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 - :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. - TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty, - MESSAGE.Type.Information + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) else MESSAGE - :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. - TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. + :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty, - MESSAGE.Type.Information + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) end - + -- Write CSV. Destroyed = true self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - + local UnitName = TargetUnit:GetName() - + -- Scoring for special objects. local Score = self.ScoringObjects[UnitName] - + if Score then - + Player.Score = Player.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score - + MESSAGE - :NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. + :NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty, - MESSAGE.Type.Information + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() ) - + -- Write CSV file. self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) Destroyed = true end - + -- Check if there are Zones where the destruction happened. for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do self:F( { ScoringZone = ScoreZoneData } ) - + local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE - + local Score = ScoreZoneData.Score - + -- Check if target is in zone. if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then Player.Score = Player.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score - + MESSAGE - :NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. - "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. + :NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty, MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) - + -- Write CSV. self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) Destroyed = true end end - + end else - + --- -- Scenery Destroyed --- - + -- Check if there are Zones where the destruction happened. for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do self:F( { ScoringZone = ScoreZoneData } ) local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE local Score = ScoreZoneData.Score if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then - + Player.Score = Player.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score - + MESSAGE - :NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. - "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. - "Total: " .. Player.Score - Player.Penalty, - MESSAGE.Type.Information + :NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. + "Total: " .. Player.Score - Player.Penalty, + MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) - + --Write CSV. Destroyed = true self:ScoreCSV( PlayerName, "", "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) end end - + end - + -- Delete now the hit cache if the target was destroyed. -- Otherwise points will be granted every time a target gets killed by the players that hit that target. -- This is only relevant for player to player destroys. if Destroyed then Player.Hit[TargetCategory][TargetUnitName].TimeStamp = 0 end - + end end end @@ -1499,7 +1499,7 @@ function SCORING:ReportDetailedPlayerHits( PlayerName ) local PlayerPenalty = 0 local PlayerData = self.Players[PlayerName] --#SCORING.PlayerData - + if PlayerData then -- This should normally not happen, but i'll test it anyway. self:T( "Score Player: " .. PlayerName ) @@ -1514,24 +1514,24 @@ function SCORING:ReportDetailedPlayerHits( PlayerName ) 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 @@ -1542,7 +1542,7 @@ function SCORING:ReportDetailedPlayerHits( PlayerName ) ScoreMessage = "Hits: " .. ScoreMessageHits end end - + return ScoreMessage, PlayerScore, PlayerPenalty end @@ -1633,7 +1633,7 @@ function SCORING:ReportDetailedPlayerCoalitionChanges( PlayerName ) ScoreMessage = ScoreMessage .. "Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties end end - + return ScoreMessage, PlayerScore, PlayerPenalty end @@ -1670,7 +1670,7 @@ function SCORING:ReportDetailedPlayerGoals( PlayerName ) ScoreMessage = "Goals: " .. ScoreMessageGoal end end - + return ScoreMessage, PlayerScore, PlayerPenalty end @@ -1708,7 +1708,7 @@ function SCORING:ReportDetailedPlayerMissions( PlayerName ) ScoreMessage = "Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")" end end - + return ScoreMessage, PlayerScore, PlayerPenalty end @@ -1726,45 +1726,45 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup ) for UnitID, PlayerUnit in pairs( PlayerUnits ) do local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT local PlayerName = PlayerUnit:GetPlayerName() - + if PlayerName then - + local Player=self.Players[PlayerName] --#SCORING.PlayerData - + if Player then - + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) - ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits self:F( { ReportHits, ScoreHits, PenaltyHits } ) - + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) - + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) - + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals self:F( { ReportGoals, ScoreGoals, PenaltyGoals } ) - + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions self:F( { ReportMissions, ScoreMissions, PenaltyMissions } ) - + local PlayerScore = Player.Score --ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions local PlayerPenalty = Player.Penalty --PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions - - PlayerMessage = - string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", - PlayerName, - PlayerScore - PlayerPenalty, - PlayerScore, + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, PlayerPenalty ) MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup ) - + end end end @@ -1784,42 +1784,42 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup ) for UnitID, PlayerUnit in pairs( PlayerUnits ) do local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT local PlayerName = PlayerUnit:GetPlayerName() - + if PlayerName then - + local Player=self.Players[PlayerName] --#SCORING.PlayerData - + if Player then - + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) - ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits self:F( { ReportHits, ScoreHits, PenaltyHits } ) - + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) - + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) - + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals self:F( { ReportGoals, ScoreGoals, PenaltyGoals } ) - + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions self:F( { ReportMissions, ScoreMissions, PenaltyMissions } ) - + local PlayerScore = Player.Score --ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions local PlayerPenalty = Player.Penalty --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, + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty, ReportHits, ReportDestroys, ReportCoalitionChanges, @@ -1843,47 +1843,47 @@ function SCORING:ReportScoreAllSummary( PlayerGroup ) self:T( { "Summary Score Report of All Players", Players = self.Players } ) for PlayerName, PlayerData in pairs( self.Players ) do - + self:T( { PlayerName = PlayerName, PlayerGroup = PlayerGroup } ) - + if PlayerName then local Player=self.Players[PlayerName] --#SCORING.PlayerData - + if Player then - + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) - ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits self:F( { ReportHits, ScoreHits, PenaltyHits } ) - + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) - + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) - + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals self:F( { ReportGoals, ScoreGoals, PenaltyGoals } ) - + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions self:F( { ReportMissions, ScoreMissions, PenaltyMissions } ) - + local PlayerScore = Player.Score --ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions local PlayerPenalty = Player.Penalty --PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions - - PlayerMessage = - string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", - PlayerName, - PlayerScore - PlayerPenalty, - PlayerScore, - PlayerPenalty + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty ) MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup ) - + end end end @@ -1901,30 +1901,30 @@ end -- ScoringObject:OpenCSV( "Player Scores" ) function SCORING:OpenCSV( ScoringCSV, FileName ) self:F( ScoringCSV ) - + if lfs and io and os then - + if ScoringCSV then - + -- File name. local fdir = lfs.writedir() .. [[Logs\]] .. ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" - + if FileName then fdir=lfs.writedir() .. [[Logs\]] .. FileName end - + if UTILS.FileExists(fdir) then self:LoadCSV(fdir) self.CSVFile, self.err = io.open( fdir, "a+" ) if not self.CSVFile then error( "Error: Cannot open CSV file in " .. lfs.writedir() ) end - + else self.CSVFile, self.err = io.open( fdir, "w+" ) if not self.CSVFile then error( "Error: Cannot open CSV file in " .. lfs.writedir() ) - end + end self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' ) end @@ -1932,7 +1932,7 @@ function SCORING:OpenCSV( ScoringCSV, FileName ) else error( "A string containing the CSV file name must be given." ) end - + else self:F( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." ) end @@ -1964,35 +1964,35 @@ function SCORING:LoadCSV(filename) -- Load asset data from file. local data=_loadfile(filename) - + if data then -- Split by line break. local results=UTILS.Split(data,"\n") - + -- Remove first header line. table.remove(results, 1) - + -- Init player scores table. self.CSVdata=self.CSVdata or {} - + -- Loop over all lines. for _,_result in pairs(results) do - + -- Parameters are separated by commata. local resultdata=UTILS.Split(_result, ",") - + -- Grade table local result={} - + --'"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition", -- "TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' - + local PlayerName=tostring(resultdata[4]) - + -- Results data. result.GameName=tostring(resultdata[1]) - result.RunTime=tostring(resultdata[2]) + result.RunTime=tostring(resultdata[2]) result.Time=tonumber(resultdata[3]) result.PlayerName=tostring(resultdata[4]) result.TargetPlayerName=tostring(resultdata[5]) @@ -2007,13 +2007,13 @@ function SCORING:LoadCSV(filename) result.TargetUnitName=tostring(resultdata[14]) result.Times=tonumber(resultdata[15]) result.Score=tonumber(resultdata[16]) - + self:E(result.Score) - + -- Create player array if necessary. self.CSVdata[result.PlayerName]=self.CSVdata[result.PlayerName] or {} - - + + -- Init player array if it does not exist. if self.Players[PlayerName] == nil then self.Players[PlayerName] = {} @@ -2025,38 +2025,38 @@ function SCORING:LoadCSV(filename) self.Players[PlayerName].Score = 0 self.Players[PlayerName].Penalty = 0 self.Players[PlayerName].PenaltyCoalition = 0 - self.Players[PlayerName].PenaltyWarning = 0 + self.Players[PlayerName].PenaltyWarning = 0 end - + local Player=self.Players[PlayerName] --#SCORING.PlayerData - + -- Restore player scores. if result.ScoreType then - - + + if result.ScoreType:find("PENALTY") then - + -- Penalty Player.Penalty=Player.Penalty+result.Score - + -- Coalition change penalty. if result.ScoreType:find("COALITION_PENALTY") then Player.PenaltyCoalition=Player.PenaltyCoalition+1 end end - + if result.ScoreType:find("SCORE") then Player.Score=Player.Score+result.Score end - + end - + self:E(string.format("Player %s score = %d %d", PlayerName, Player.Score, self.Players[PlayerName].Score)) - + --self.Players[PlayerName].Score=self.Players[PlayerName].Score+result.Score - + -- Add result to table. - table.insert(self.CSVdata[result.PlayerName], result) + table.insert(self.CSVdata[result.PlayerName], result) end end end @@ -2083,13 +2083,13 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, --write statistic information to file --local ScoreTime = self:SecondsToClock( timer.getTime() ) local ScoreTime = UTILS.SecondsToClock(timer.getAbsTime()) - + -- Player name PlayerName = PlayerName:gsub( '"', '_' ) - + -- Target NAme TargetPlayerName = TargetPlayerName or "n/a" - + TargetPlayerName = TargetPlayerName:gsub( '"', '_' ) if PlayerUnitName and PlayerUnitName ~= '' then @@ -2143,7 +2143,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, '' .. TargetUnitType .. '' .. ',' .. '' .. TargetUnitName .. '' .. ',' .. '' .. ScoreTimes .. '' .. ',' .. - '' .. ScoreAmount + '' .. ScoreAmount ) self.CSVFile:write( "\n" ) @@ -2157,4 +2157,3 @@ function SCORING:CloseCSV() self.CSVFile:close() end end - diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index e2c8c7b6d..802e22275 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -1743,7 +1743,7 @@ _WAREHOUSEDB = { --- Warehouse class version. -- @field #string version -WAREHOUSE.version="0.9.0" +WAREHOUSE.version="0.9.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: Warehouse todo list. @@ -2318,6 +2318,7 @@ function WAREHOUSE:New(warehouse, alias) -- @param #WAREHOUSE self -- @param Wrapper.Group#GROUP group the group that was spawned. -- @param #WAREHOUSE.Assetitem asset The asset that was spawned. + -- @param #WAREHOUSE.Pendingitem request The request of the spawned asset. --- Triggers the FSM event "AssetSpawned" with a delay when the warehouse has spawned an asset. -- @function [parent=#WAREHOUSE] __AssetSpawned @@ -2325,6 +2326,7 @@ function WAREHOUSE:New(warehouse, alias) -- @param #number delay Delay in seconds. -- @param Wrapper.Group#GROUP group the group that was spawned. -- @param #WAREHOUSE.Assetitem asset The asset that was spawned. + -- @param #WAREHOUSE.Pendingitem request The request of the spawned asset. --- On after "AssetSpawned" event user function. Called when the warehouse has spawned an asset. -- @function [parent=#WAREHOUSE] OnAfterAssetSpawned @@ -2334,6 +2336,7 @@ function WAREHOUSE:New(warehouse, alias) -- @param #string To To state. -- @param Wrapper.Group#GROUP group the group that was spawned. -- @param #WAREHOUSE.Assetitem asset The asset that was spawned. + -- @param #WAREHOUSE.Pendingitem request The request of the spawned asset. --- Triggers the FSM event "AssetLowFuel" when an asset runs low on fuel @@ -3096,7 +3099,7 @@ function WAREHOUSE:FindAssetInDB(group) if aid~=nil then local asset=_WAREHOUSEDB.Assets[aid] - self:E({asset=asset}) + self:T2({asset=asset}) if asset==nil then self:_ErrorMessage(string.format("ERROR: Asset for group %s not found in the data base!", group:GetName()), 0) end @@ -3149,7 +3152,7 @@ function WAREHOUSE:onafterStart(From, Event, To) end -- Mark point at road connection. if self.road then - self.road:MarkToAll(string.format("%s road connection.", self.alias), true) + self.markroad=self.road:MarkToCoalition(string.format("%s road connection.",self.alias), self:GetCoalition(), true) end -- Get the closest point on railroad wrt spawnzone of ground assets. @@ -3163,7 +3166,7 @@ function WAREHOUSE:onafterStart(From, Event, To) end -- Mark point at rail connection. if self.rail then - self.rail:MarkToAll(string.format("%s rail connection.", self.alias), true) + self.markrail=self.rail:MarkToCoalition(string.format("%s rail connection.", self.alias), self:GetCoalition(), true) end -- Handle events: @@ -4330,7 +4333,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) table.insert(_transportassets,_assetitem) -- Asset spawned FSM function. - self:__AssetSpawned(1, spawngroup, _assetitem) + self:__AssetSpawned(1, spawngroup, _assetitem, Request) end end @@ -5269,7 +5272,7 @@ function WAREHOUSE:_SpawnAssetRequest(Request) table.insert(_assets, _assetitem) -- Call FSM function. - self:__AssetSpawned(1,_group,_assetitem) + self:__AssetSpawned(1,_group,_assetitem, Request) else self:E(self.wid.."ERROR: Cargo asset could not be spawned!") end @@ -7753,14 +7756,21 @@ function WAREHOUSE:_CheckFuel() local group=_group --Wrapper.Group#GROUP if group and group:IsAlive() then - + + -- Get min fuel of group. local fuel=group:GetFuelMin() - self:T2(self.wid..string.format("Transport group %s min fuel state = %.2f %%", group:GetName(), fuel)) + -- Debug info. + self:T2(self.wid..string.format("Transport group %s min fuel state = %.2f", group:GetName(), fuel)) + -- Check if fuel is below threshold for first time. if fuel0 and not (self.detour or self.turnintowind) then + if not self.holdtimestamp then + self:E(self.lid..string.format("Carrier came to an unexpected standstill. Trying to re-route in 3 min. Speed=%.1f knots, expected=%.1f knots", speed, ExpectedSpeed)) + self.holdtimestamp=timer.getTime() + else + if holdtime>3*60 then + local coord=self:GetCoordinate():Translate(500, hdg+10) + --coord:MarkToAll("Re-route after standstill.") + self:CarrierResumeRoute(coord) + self.holdtimestamp=nil + end + end + end -- Debug info. - local text=string.format("Time %s - Status %s (case=%d) - Speed=%.1f kts - Heading=%d - WP=%d - ETA=%s - Turning=%s - Collision Warning=%s", - clock, self:GetState(), self.case, self.carrier:GetVelocityKNOTS(), hdg, self.currentwp, eta, tostring(self.turning), tostring(collision)) + local text=string.format("Time %s - Status %s (case=%d) - Speed=%.1f kts - Heading=%d - WP=%d - ETA=%s - Turning=%s - Collision Warning=%s - Detour=%s - Turn Into Wind=%s - Holdtime=%d sec", + clock, self:GetState(), self.case, speed, hdg, self.currentwp, eta, tostring(self.turning), tostring(collision), tostring(self.detour), tostring(self.turnintowind), holdtime) self:T(self.lid..text) -- Players online: @@ -13130,7 +13185,7 @@ end --- Get next waypoint of the carrier. -- @param #AIRBOSS self -- @return Core.Point#COORDINATE Coordinate of the next waypoint. --- @return #number Number of waypoint +-- @return #number Number of waypoint. function AIRBOSS:_GetNextWaypoint() -- Next waypoint. @@ -13453,14 +13508,50 @@ function AIRBOSS._ResumeRoute(group, airboss, gotocoord) -- Waypoints array. local waypoints={} + -- Current position. + local c0=group:GetCoordinate() + -- Current positon as first waypoint. - local wp0=group:GetCoordinate():WaypointGround(speedkmh) + local wp0=c0:WaypointGround(speedkmh) table.insert(waypoints, wp0) -- First goto this coordinate. if gotocoord then + + --gotocoord:MarkToAll(string.format("Goto waypoint speed=%.1f km/h", speedkmh)) + + local headingto=c0:HeadingTo(gotocoord) + + local hdg1=airboss:GetHeading() + local hdg2=c0:HeadingTo(gotocoord) + local delta=airboss:_GetDeltaHeading(hdg1, hdg2) + + --env.info(string.format("FF hdg1=%d, hdg2=%d, delta=%d", hdg1, hdg2, delta)) + + + -- Add additional turn points + if delta>90 then + + -- Turn radius 3 NM. + local turnradius=UTILS.NMToMeters(3) + + local gotocoordh=c0:Translate(turnradius, hdg1+45) + --gotocoordh:MarkToAll(string.format("Goto help waypoint 1 speed=%.1f km/h", speedkmh)) + + local wp=gotocoordh:WaypointGround(speedkmh) + table.insert(waypoints, wp) + + gotocoordh=c0:Translate(turnradius, hdg1+90) + --gotocoordh:MarkToAll(string.format("Goto help waypoint 2 speed=%.1f km/h", speedkmh)) + + wp=gotocoordh:WaypointGround(speedkmh) + table.insert(waypoints, wp) + + end + local wp1=gotocoord:WaypointGround(speedkmh) - table.insert(waypoints, wp1) + table.insert(waypoints, wp1) + end -- Debug message. @@ -13468,7 +13559,7 @@ function AIRBOSS._ResumeRoute(group, airboss, gotocoord) -- Debug message. MESSAGE:New(text,10):ToAllIf(airboss.Debug) - airboss:I(airboss.lid..text) + airboss:I(airboss.lid..text) -- Loop over all remaining waypoints. for i=Nextwp, #airboss.waypoints do @@ -13484,6 +13575,8 @@ function AIRBOSS._ResumeRoute(group, airboss, gotocoord) speed=UTILS.KnotsToKmph(10) end + --coord:MarkToAll(string.format("Resume route WP %d, speed=%.1f km/h", i, speed)) + -- Create waypoint. local wp=coord:WaypointGround(speed) @@ -15252,6 +15345,29 @@ function AIRBOSS:_AddF10Commands(_unitName) missionCommands.addCommandForGroup(gid, "Greenie Board", _resultsPath, self._DisplayScoreBoard, self, _unitName) -- F1 missionCommands.addCommandForGroup(gid, "My LSO Grades", _resultsPath, self._DisplayPlayerGrades, self, _unitName) -- F2 missionCommands.addCommandForGroup(gid, "Last Debrief", _resultsPath, self._DisplayDebriefing, self, _unitName) -- F3 + + -- F10/Airboss//F2 Kneeboard/F2 Skipper/ + if self.skipperMenu then + local _skipperPath =missionCommands.addSubMenuForGroup(gid, "Skipper", _kneeboardPath) + local _menusetspeed=missionCommands.addSubMenuForGroup(gid, "Set Speed", _skipperPath) + missionCommands.addCommandForGroup(gid, "10 knots", _menusetspeed, self._SkipperRecoverySpeed, self, _unitName, 10) + missionCommands.addCommandForGroup(gid, "15 knots", _menusetspeed, self._SkipperRecoverySpeed, self, _unitName, 15) + missionCommands.addCommandForGroup(gid, "20 knots", _menusetspeed, self._SkipperRecoverySpeed, self, _unitName, 20) + missionCommands.addCommandForGroup(gid, "25 knots", _menusetspeed, self._SkipperRecoverySpeed, self, _unitName, 25) + missionCommands.addCommandForGroup(gid, "30 knots", _menusetspeed, self._SkipperRecoverySpeed, self, _unitName, 30) + local _menusetrtime=missionCommands.addSubMenuForGroup(gid, "Set Time", _skipperPath) + missionCommands.addCommandForGroup(gid, "15 min", _menusetrtime, self._SkipperRecoveryTime, self, _unitName, 15) + missionCommands.addCommandForGroup(gid, "30 min", _menusetrtime, self._SkipperRecoveryTime, self, _unitName, 30) + missionCommands.addCommandForGroup(gid, "45 min", _menusetrtime, self._SkipperRecoveryTime, self, _unitName, 45) + missionCommands.addCommandForGroup(gid, "60 min", _menusetrtime, self._SkipperRecoveryTime, self, _unitName, 60) + missionCommands.addCommandForGroup(gid, "90 min", _menusetrtime, self._SkipperRecoveryTime, self, _unitName, 90) + missionCommands.addCommandForGroup(gid, "U-turn On/Off", _skipperPath, self._SkipperRecoveryUturn, self, _unitName) + missionCommands.addCommandForGroup(gid, "Start CASE I", _skipperPath, self._SkipperStartRecovery, self, _unitName, 1) + missionCommands.addCommandForGroup(gid, "Start CASE II", _skipperPath, self._SkipperStartRecovery, self, _unitName, 2) + missionCommands.addCommandForGroup(gid, "Start CASE III",_skipperPath, self._SkipperStartRecovery, self, _unitName, 3) + missionCommands.addCommandForGroup(gid, "Stop Recovery", _skipperPath, self._SkipperStopRecovery, self, _unitName) + end + -- F10/Airboss/