diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 7128e7afd..45af655e9 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -116,7 +116,7 @@ -- * TOR M2 -- * C-RAM -- * Silkworm (though strictly speaking this is a surface to ship missile) --- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19 +-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19, SA-21, S-300VM, S-300V4, S-400 -- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!) -- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2 -- * Other Mods: Nike @@ -283,7 +283,7 @@ MANTIS = { ClassName = "MANTIS", name = "mymantis", - version = "0.9.41", + version = "0.9.42", SAM_Templates_Prefix = "", SAM_Group = nil, EWR_Templates_Prefix = "", @@ -401,6 +401,10 @@ MANTIS.SamData = { ["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" }, ["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"}, ["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"}, + ["SA-21"] = { Range=380, Blindspot=5, Height=30, Type="Long" , Radar="92N6E"}, + ["S-300VM"] = { Range=200, Blindspot=5, Height=30, Type="Long" , Radar="9S32M"}, + ["S-300V4"] = { Range=380, Blindspot=5, Height=30, Type="Long" , Radar="9S32M"}, + ["S-400"] = { Range=250, Blindspot=5, Height=27, Type="Long" , Radar="92N6E"}, ["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" }, ["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" }, ["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" }, diff --git a/Moose Development/Moose/Ops/Cohort.lua b/Moose Development/Moose/Ops/Cohort.lua index 48f63112c..3bb75c370 100644 --- a/Moose Development/Moose/Ops/Cohort.lua +++ b/Moose Development/Moose/Ops/Cohort.lua @@ -1474,7 +1474,7 @@ function COHORT:_CheckAmmo() -- Descriptors. local Desc=weapon["desc"] - + -- Warhead. local Warhead=Desc["warhead"] diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 1f5269ce9..7edda117b 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -61,6 +61,7 @@ do -- @field #number PreviousCount -- @field #boolean CanSmoke -- @field #boolean ShowThreatDetails +-- @field #boolean PersistMe -- @extends Core.Fsm#FSM @@ -98,11 +99,12 @@ PLAYERTASK = { PreviousCount = 0, CanSmoke = true, ShowThreatDetails = true, + PersistMe = false, } --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.29" +PLAYERTASK.version="0.1.30" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -401,8 +403,17 @@ function PLAYERTASK:CanJoinTask(Group, Client) return true end +--- [User] Set this task for persistance, if persistance is enabled on the PLAYERTASKCONTROLLER instance. +-- @param #PLAYERTASK self +-- @return #PLAYERTASK self +function PLAYERTASK:EnablePersistance() + self.PersistMe = true + return self +end + --- [Internal] Add a PLAYERTASKCONTROLLER for this task -- @param #PLAYERTASK self +-- -- @param Ops.PlayerTask#PLAYERTASKCONTROLLER Controller -- @return #PLAYERTASK self function PLAYERTASK:_SetController(Controller) @@ -1088,7 +1099,6 @@ function PLAYERTASK:onafterStatus(From, Event, To) return self end - --- [Internal] On after progress call -- @param #PLAYERTASK self -- @param #string From @@ -1363,6 +1373,12 @@ do -- @field Core.ClientMenu#CLIENTMENU MenuNoTask -- @field #boolean InformationMenu Show Radio Info Menu -- @field #number TaskInfoDuration How long to show the briefing info on the screen +-- @field #table TaskPersistance Table for persistance data +-- @field #boolean TaskPersistanceSwitch Switch for persisting tasks +-- @field #string TaskPersistancePath File path for persisting tasks +-- @field #string TaskPersistanceFilename File name for persisting tasks +-- @field #table TasksPersistable List of persistable tasks +-- @field #number SceneryExplosivesAmount Kgs of TNT to explode scenery on task persistance loading -- @extends Core.Fsm#FSM --- @@ -1720,6 +1736,12 @@ PLAYERTASKCONTROLLER = { MenuNoTask = nil, InformationMenu = false, TaskInfoDuration = 30, + TaskPersistance = {}, + TaskPersistanceSwitch = false, + TaskPersistancePath = nil, + TaskPersistanceFilename = nil, + TasksPersistable = {}, + SceneryExplosivesAmount = 300, } --- @@ -1740,6 +1762,7 @@ AUFTRAG.Type.PRECISIONBOMBING = "Precision Bombing" AUFTRAG.Type.CTLD = "Combat Transport" AUFTRAG.Type.CSAR = "Combat Rescue" AUFTRAG.Type.CONQUER = "Conquer" + --- -- @type Scores PLAYERTASKCONTROLLER.Scores = { @@ -1759,6 +1782,23 @@ PLAYERTASKCONTROLLER.Scores = { [AUFTRAG.Type.CAP] = 100, [AUFTRAG.Type.CAPTUREZONE] = 100, } + +--- +-- @type TasksPersistable +PLAYERTASKCONTROLLER.TasksPersistable = { + [AUFTRAG.Type.PRECISIONBOMBING] = true, + [AUFTRAG.Type.BOMBING] = true, + [AUFTRAG.Type.ARTY] = true, +} + +--- +-- @type PersistenceData +-- @field #number ID +-- @field #string Name +-- @field #string Type +-- @field #number InitialTargets +-- @field #number Targetsleft +-- @field #boolean updated --- -- @type SeadAttributes @@ -2174,6 +2214,30 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) end +--- [User] Enable Task persistance (for specific gound target tasks) +-- @param #PLAYERTASKCONTROLLER self +-- @param #string Path Path where to save the task data +-- @param #string Filename File name under which to save the task data +-- @param #number KgsOfTNT (Optional) Explosives kgs used to remove scenery for persistence, defaults to 300 +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:EnableTaskPersistance(Path,Filename,KgsOfTNT) + self.TaskPersistanceSwitch = true + self.TaskPersistancePath = Path + self.TaskPersistanceFilename = Filename + self.SceneryExplosivesAmount = KgsOfTNT or 300 + return self +end + +--- [User] Disable Task persistance (for specific gound target tasks) +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:DisableTaskPersistance() + self.TaskPersistanceSwitch = false + self.TaskPersistancePath = nil + self.TaskPersistanceFilename = nil + return self +end + --- [User] Set or create a SCORING object for this taskcontroller -- @param #PLAYERTASKCONTROLLER self -- @param Functional.Scoring#SCORING Scoring (optional) the Scoring object @@ -2861,15 +2925,6 @@ function PLAYERTASKCONTROLLER:_GetTasksPerType() end end - --[[ - for _type,_data in pairs(tasktypes) do - self:I("Task Type: ".._type) - for _id,_task in pairs(_data) do - self:I("Task Name: ".._task.Target:GetName()) - end - end - --]] - return tasktypes end @@ -3566,9 +3621,9 @@ function PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask,Silent,TaskFilter) PlayerTask:_SetController(self) PlayerTask:SetCoalition(self.Coalition) self.TaskQueue:Push(PlayerTask) - if not Silent then - self:__TaskAdded(10,PlayerTask) - end + --if not Silent then + self:__TaskAdded(10,PlayerTask,Silent) + --end else self:E(self.lid.."***** NO valid PAYERTASK object sent!") end @@ -4765,6 +4820,128 @@ function PLAYERTASKCONTROLLER:SetSRSBroadcast(Frequency,Modulation) return self end + +--- +-- @param #PLAYERTASKCONTROLLER self +-- @param Ops.PlayerTask#PLASERTASK Task +-- @param #number TargetsLeft +function PLAYERTASKCONTROLLER:_UpdateTargetsAlive(Task,TargetsLeft) + self:T(self.lid.."_UpdateTargetsAlive") + local delta = Task.Target:CountTargets() - TargetsLeft + if delta > 0 then + self:T("Delta targets to be removed: "..delta) + local count = 0 + local targets = Task.Target:GetObjects() + for _,_object in pairs(targets or {}) do + if _object and _object.ClassName and (_object:IsInstanceOf("GROUP") or _object:IsInstanceOf("UNIT") or _object:IsInstanceOf("STATIC") or _object:IsInstanceOf("SCENERY")) then + if count < delta then + count = count + 1 + if not _object:IsInstanceOf("SCENERY") then + _object:Destroy(true) + else + _object:Explode(self.SceneryExplosivesAmount) + end + end + end + end + end + return self +end + +--- +-- @param #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:_LoadTasksPersisted() + self:T(self.lid.."_LoadTasksPersisted") + + local function MatchTask(Type,Name) + local foundtask + self.TaskQueue:ForEach( + function(_task) + local task = _task -- #PLAYERTASK + if task.Type == Type and task.Target.name and task.Target.name == Name then + foundtask = task + end + end + ) + return foundtask + end + + if lfs and io then + local ok,data = UTILS.LoadFromFile(self.TaskPersistancePath,self.TaskPersistanceFilename) + if ok == true then + table.remove(data, 1) + for _,_entry in pairs(data) do + -- "--ID;;Name;;InitialTargets;;Targetsleft;;Type\n" + local dataset = UTILS.Split(_entry,";;") + local Taskdata = {} -- #PersistenceData + Taskdata.ID = tonumber(dataset[1]) + Taskdata.Name = tostring(dataset[2]) + Taskdata.InitialTargets = tonumber(dataset[3]) + Taskdata.Targetsleft = tonumber(dataset[4]) + Taskdata.Type = tostring(dataset[5]) + Taskdata.Task = MatchTask(Taskdata.Type,Taskdata.Name) + if Taskdata.Task == nil then + self:E(self.lid.."No actual task found for "..Taskdata.Name) + else + self:T(self.lid.."Task loaded and match found for "..Taskdata.Name) + end + Taskdata.updated = Taskdata.InitialTargets == Taskdata.Targetsleft and true or false + if Taskdata.Task and Taskdata.updated == false then + self:_UpdateTargetsAlive(Taskdata.Task,Taskdata.Targetsleft) + Taskdata.updated = true + end + self.TaskPersistance[Taskdata.ID] = Taskdata + end + end + end + return self +end + +--- +-- @param #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:ClearPersistedData() + if lfs and io then + local text = "-- Data Cleared\n" + UTILS.SaveToFile(self.TaskPersistancePath,self.TaskPersistanceFilename,text) + end + return self +end + +--- +-- @param #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:_SaveTasksPersisted() + if lfs and io then + local text = "--ID;;Name;;InitialTargets;;Targetsleft;;Type\n" + for _,_data in pairs(self.TaskPersistance) do + local data = _data -- #PersistenceData + data.Targetsleft = data.Task.Target:CountTargets() -- recount + if data.Task and data.Task:IsDone() then data.Targetsleft = 0 end + local tasktext = string.format("%d;;%s;;%d;;%d;;%s\n",data.ID,data.Name,data.InitialTargets,data.Targetsleft,data.Type) + text = text..tasktext + end + UTILS.SaveToFile(self.TaskPersistancePath,self.TaskPersistanceFilename,text) + end + return self +end + +--- +-- @param #PLAYERTASKCONTROLLER self +-- @param #PLAYERTASK Task +function PLAYERTASKCONTROLLER:_AddPersistenceData(Task) + local Taskdata = {} -- #PersistenceData + if not self.TaskPersistance[Task.PlayerTaskNr] then + Taskdata.ID = Task.PlayerTaskNr + Taskdata.Name = Task.Target.name or "none" + Taskdata.InitialTargets = Task.Target:CountTargets() + Taskdata.Targetsleft = Taskdata.InitialTargets + Taskdata.Type = Task.Type + Taskdata.updated = true + Taskdata.Task = Task + self.TaskPersistance[Task.PlayerTaskNr] = Taskdata + end + return self +end + ------------------------------------------------------------------------------------------------------------------- -- FSM Functions PLAYERTASKCONTROLLER -- TODO: FSM Functions PLAYERTASKCONTROLLER @@ -4788,7 +4965,11 @@ function PLAYERTASKCONTROLLER:onafterStart(From, Event, To) self:HandleEvent(EVENTS.PilotDead, self._EventHandler) self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) self:HandleEvent(EVENTS.UnitLost, self._EventHandler) - self:SetEventPriority(5) + self:SetEventPriority(5) + -- Persistence + if self.TaskPersistanceSwitch == true then + self:_LoadTasksPersisted() + end return self end @@ -4828,6 +5009,11 @@ function PLAYERTASKCONTROLLER:onafterStatus(From, Event, To) self:I(text) end + -- Persistence + if self.TaskPersistanceSwitch == true then + self:_SaveTasksPersisted() + end + if self:GetState() ~= "Stopped" then self:__Status(-30) end @@ -4983,19 +5169,26 @@ end -- @param #string Event -- @param #string To -- @param Ops.PlayerTask#PLAYERTASK Task +-- @param #boolean Silent -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:onafterTaskAdded(From, Event, To, Task) +function PLAYERTASKCONTROLLER:onafterTaskAdded(From, Event, To, Task, Silent) self:T({From, Event, To}) self:T(self.lid.."TaskAdded") local addtxt = self.gettext:GetEntry("TASKADDED",self.locale) local taskname = string.format(addtxt, self.MenuName or self.Name, tostring(Task.Type)) - if not self.NoScreenOutput then - self:_SendMessageToClients(taskname,15) - --local m = MESSAGE:New(taskname,15,"Tasking"):ToCoalition(self.Coalition) + if not Silent then + if not self.NoScreenOutput then + self:_SendMessageToClients(taskname,15) + --local m = MESSAGE:New(taskname,15,"Tasking"):ToCoalition(self.Coalition) + end + if self.UseSRS then + taskname = string.format(addtxt, self.MenuName or self.Name, tostring(Task.TTSType)) + self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2) + end end - if self.UseSRS then - taskname = string.format(addtxt, self.MenuName or self.Name, tostring(Task.TTSType)) - self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2) + self:T(self.lid..string.format("Pers = %s | Type = %s | TypePers = %s | TaskFlag = %s",tostring(self.TaskPersistanceSwitch),tostring(Task.Type),tostring(self.TasksPersistable[Task.Type]),tostring(Task.PersistMe))) + if self.TaskPersistanceSwitch == true and self.TasksPersistable[Task.Type] == true and Task.PersistMe == true then + self:_AddPersistenceData(Task) end return self end