diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 0e53eea58..db74f8ab0 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -75,4 +75,4 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 - run: npm install linkinator - - run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" + - run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" --retry-errors --retry-errors-count 3 --retry-errors-jitter diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index b32b723c7..b5122c04e 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -261,6 +261,15 @@ EVENTS = { SimulationStart = world.event.S_EVENT_SIMULATION_START or -1, WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1, WeaponDrop = world.event.S_EVENT_WEAPON_DROP or -1, + -- Added with DCS 2.9.0 + UnitTaskTimeout = world.event.S_EVENT_UNIT_TASK_TIMEOUT or -1, + UnitTaskStage = world.event.S_EVENT_UNIT_TASK_STAGE or -1, + MacSubtaskScore = world.event.S_EVENT_MAC_SUBTASK_SCORE or -1, + MacExtraScore = world.event.S_EVENT_MAC_EXTRA_SCORE or -1, + MissionRestart = world.event.S_EVENT_MISSION_RESTART or -1, + MissionWinner = world.event.S_EVENT_MISSION_WINNER or -1, + PostponedTakeoff = world.event.S_EVENT_POSTPONED_TAKEOFF or -1, + PostponedLand = world.event.S_EVENT_POSTPONED_LAND or -1, } --- The Event structure @@ -636,6 +645,55 @@ local _EVENTMETA = { Event = "OnEventWeaponDrop", Text = "S_EVENT_WEAPON_DROP" }, + -- DCS 2.9 + [EVENTS.UnitTaskTimeout] = { + Order = 1, + Side = "I", + Event = "OnEventUnitTaskTimeout", + Text = "S_EVENT_UNIT_TASK_TIMEOUT " + }, + [EVENTS.UnitTaskStage] = { + Order = 1, + Side = "I", + Event = "OnEventUnitTaskStage", + Text = "S_EVENT_UNIT_TASK_STAGE " + }, + [EVENTS.MacSubtaskScore] = { + Order = 1, + Side = "I", + Event = "OnEventMacSubtaskScore", + Text = "S_EVENT_MAC_SUBTASK_SCORE" + }, + [EVENTS.MacExtraScore] = { + Order = 1, + Side = "I", + Event = "OnEventMacExtraScore", + Text = "S_EVENT_MAC_EXTRA_SCOREP" + }, + [EVENTS.MissionRestart] = { + Order = 1, + Side = "I", + Event = "OnEventMissionRestart", + Text = "S_EVENT_MISSION_RESTART" + }, + [EVENTS.MissionWinner] = { + Order = 1, + Side = "I", + Event = "OnEventMissionWinner", + Text = "S_EVENT_MISSION_WINNER" + }, + [EVENTS.PostponedTakeoff] = { + Order = 1, + Side = "I", + Event = "OnEventPostponedTakeoff", + Text = "S_EVENT_POSTPONED_TAKEOFF" + }, + [EVENTS.PostponedLand] = { + Order = 1, + Side = "I", + Event = "OnEventPostponedLand", + Text = "S_EVENT_POSTPONED_LAND" + }, } --- The Events structure @@ -1245,11 +1303,14 @@ function EVENT:onEvent( Event ) Event.TgtDCSUnit = Event.target if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() - Event.TgtUnitName = Event.TgtDCSUnitName - Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) - Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() - Event.TgtCategory = Event.TgtDCSUnit:getDesc().category - Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + -- Workaround for borked target info on cruise missiles + if Event.TgtDCSUnitName and Event.TgtDCSUnitName ~= "" then + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) + Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + end else Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id)) Event.TgtUnitName = Event.TgtDCSUnitName diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index ff631d18a..ce95806b1 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: Oct 2023 +-- Last Update: Nov 2023 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -799,12 +799,16 @@ do -- @param #MANTIS self -- @param Core.Set#SET_ZONE ZoneSet Set of zones to be used. Units will move around to the next (random) zone between 100m and 3000m away. -- @param #number Number Number of closest zones to be considered, defaults to 3. + -- @param #boolean Random If true, use a random coordinate inside the next zone to scoot to. + -- @param #string Formation Formation to use, defaults to "Cone". See mission editor dropdown for options. -- @return #MANTIS self - function MANTIS:AddScootZones(ZoneSet, Number) + function MANTIS:AddScootZones(ZoneSet, Number, Random, Formation) self:T(self.lid .. " AddScootZones") self.SkateZones = ZoneSet self.SkateNumber = Number or 3 - self.shootandscoot = true + self.shootandscoot = true + self.ScootRandom = Random + self.ScootFormation = Formation or "Cone" return self end @@ -1809,8 +1813,8 @@ do self.Shorad.Groupset=self.ShoradGroupSet self.Shorad.debug = self.debug end - if self.shootandscoot and self.SkateZones then - self.Shorad:AddScootZones(self.SkateZones,self.SkateNumber or 3) + if self.shootandscoot and self.SkateZones and self.Shorad then + self.Shorad:AddScootZones(self.SkateZones,self.SkateNumber or 3,self.ScootRandom,self.ScootFormation) end self:__Status(-math.random(1,10)) return self diff --git a/Moose Development/Moose/Functional/Shorad.lua b/Moose Development/Moose/Functional/Shorad.lua index 3ba433296..505e819a7 100644 --- a/Moose Development/Moose/Functional/Shorad.lua +++ b/Moose Development/Moose/Functional/Shorad.lua @@ -41,10 +41,14 @@ -- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles -- @field #number DefenseLowProb Default 70, minimum detection limit -- @field #number DefenseHighProb Default 90, maximum detection limit --- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green. --- @field #boolean shootandscoot --- @field #number SkateNumber --- @field Core.Set#SET_ZONE SkateZones +-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green +-- @field #boolean shootandscoot If true, shoot and scoot between zones +-- @field #number SkateNumber Number of zones to consider +-- @field Core.Set#SET_ZONE SkateZones Zones in this set are considered +-- @field #number minscootdist Min distance of the next zone +-- @field #number maxscootdist Max distance of the next zone +-- @field #boolean scootrandomcoord If true, use a random coordinate in the zone and not the center +-- @field #string scootformation Formation to take for scooting, e.g. "Vee" or "Cone" -- @extends Core.Base#BASE @@ -77,14 +81,15 @@ -- -- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")` -- --- ## Customize options +-- ## Customization options -- --- * SHORAD:SwitchDebug(debug) --- * SHORAD:SwitchHARMDefense(onoff) --- * SHORAD:SwitchAGMDefense(onoff) --- * SHORAD:SetDefenseLimits(low,high) --- * SHORAD:SetActiveTimer(seconds) --- * SHORAD:SetDefenseRadius(meters) +-- * myshorad:SwitchDebug(debug) +-- * myshorad:SwitchHARMDefense(onoff) +-- * myshorad:SwitchAGMDefense(onoff) +-- * myshorad:SetDefenseLimits(low,high) +-- * myshorad:SetActiveTimer(seconds) +-- * myshorad:SetDefenseRadius(meters) +-- * myshorad:AddScootZones(ZoneSet,Number,Random,Formation) -- -- @field #SHORAD SHORAD = { @@ -107,6 +112,9 @@ SHORAD = { shootandscoot = false, SkateNumber = 3, SkateZones = nil, + minscootdist = 100, + minscootdist = 3000, + scootrandomcoord = false, } ----------------------------------------------------------------------- @@ -174,7 +182,7 @@ do self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin self.UseEmOnOff = true -- Decide if we are using Emission on/off (default) or AlarmState red/green if UseEmOnOff == false then self.UseEmOnOff = UseEmOnOff end - self:I("*** SHORAD - Started Version 0.3.2") + self:I("*** SHORAD - Started Version 0.3.4") -- Set the string id for output to DCS.log file. self.lid=string.format("SHORAD %s | ", self.name) self:_InitState() @@ -219,12 +227,16 @@ do -- @param #SHORAD self -- @param Core.Set#SET_ZONE ZoneSet Set of zones to be used. Units will move around to the next (random) zone between 100m and 3000m away. -- @param #number Number Number of closest zones to be considered, defaults to 3. + -- @param #boolean Random If true, use a random coordinate inside the next zone to scoot to. + -- @param #string Formation Formation to use, defaults to "Cone". See mission editor dropdown for options. -- @return #SHORAD self - function SHORAD:AddScootZones(ZoneSet, Number) + function SHORAD:AddScootZones(ZoneSet, Number, Random, Formation) self:T(self.lid .. " AddScootZones") self.SkateZones = ZoneSet self.SkateNumber = Number or 3 - self.shootandscoot = true + self.shootandscoot = true + self.scootrandomcoord = Random + self.scootformation = Formation or "Cone" return self end @@ -613,8 +625,8 @@ do function SHORAD:onafterShootAndScoot(From,Event,To,Shorad) self:T( { From,Event,To } ) local possibleZones = {} - local mindist = 100 - local maxdist = 3000 + local mindist = self.minscootdist or 100 + local maxdist = self.maxscootdist or 3000 if Shorad and Shorad:IsAlive() then local NowCoord = Shorad:GetCoordinate() for _,_zone in pairs(self.SkateZones.Set) do @@ -630,7 +642,11 @@ do if rand == 0 then rand = 1 end self:T(self.lid .. " ShootAndScoot to zone "..rand) local ToCoordinate = possibleZones[rand]:GetCoordinate() - Shorad:RouteGroundTo(ToCoordinate,20,"Cone",1) + if self.scootrandomcoord then + ToCoordinate = possibleZones[rand]:GetRandomCoordinate(nil,nil,{land.SurfaceType.LAND,land.SurfaceType.ROAD}) + end + local formation = self.scootformation or "Cone" + Shorad:RouteGroundTo(ToCoordinate,20,formation,1) end end return self @@ -731,4 +747,4 @@ do end ----------------------------------------------------------------------- -- SHORAD end ------------------------------------------------------------------------ \ No newline at end of file +----------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 80c8d7d6e..9f0d780bd 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -24,7 +24,7 @@ -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Last Update October 2023 +-- Last Update November 2023 do @@ -741,7 +741,7 @@ do -- -- -- E.g. update unit capabilities for testing. Please stay realistic in your mission design. -- -- Make a Gazelle into a heavy truck, this type can load both crates and troops and eight of each type, up to 4000 kgs: --- my_ctld:UnitCapabilities("SA342L", true, true, 8, 8, 12, 4000) +-- my_ctld:SetUnitCapabilities("SA342L", true, true, 8, 8, 12, 4000) -- -- -- Default unit type capabilities are: -- ["SA342Mistral"] = {type="SA342Mistral", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400}, @@ -1200,14 +1200,14 @@ CTLD.CargoZoneType = { -- @field #CTLD_CARGO.Enum Type Type enumerator (for moves). --- Unit capabilities. --- @type CTLD.UnitCapabilities +-- @type CTLD.UnitTypeCapabilities -- @field #string type Unit type. -- @field #boolean crates Can transport crate. -- @field #boolean troops Can transport troops. -- @field #number cratelimit Number of crates transportable. -- @field #number trooplimit Number of troop units transportable. -- @field #number cargoweightlimit Max loadable kgs of cargo. -CTLD.UnitTypes = { +CTLD.UnitTypeCapabilities = { ["SA342Mistral"] = {type="SA342Mistral", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400}, ["SA342L"] = {type="SA342L", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 12, cargoweightlimit = 400}, ["SA342M"] = {type="SA342M", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400}, @@ -1228,7 +1228,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.41" +CTLD.version="1.0.43" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1293,6 +1293,8 @@ function CTLD:New(Coalition, Prefixes, Alias) self:AddTransition("*", "CratesDropped", "*") -- CTLD deploy event. self:AddTransition("*", "CratesBuild", "*") -- CTLD build event. self:AddTransition("*", "CratesRepaired", "*") -- CTLD repair event. + self:AddTransition("*", "CratesBuildStarted", "*") -- CTLD build event. + self:AddTransition("*", "CratesRepairStarted", "*") -- CTLD repair event. self:AddTransition("*", "Load", "*") -- CTLD load event. self:AddTransition("*", "Save", "*") -- CTLD save event. self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. @@ -1475,7 +1477,7 @@ function CTLD:New(Coalition, Prefixes, Alias) -- @param #CTLD self -- @param #number delay Delay in seconds. - --- FSM Function OnBeforeTroopsPickedUp. + --- FSM Function OnBeforeTroopsPickedUp. -- @function [parent=#CTLD] OnBeforeTroopsPickedUp -- @param #CTLD self -- @param #string From State. @@ -1627,6 +1629,46 @@ function CTLD:New(Coalition, Prefixes, Alias) -- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build. -- @return #CTLD self + --- FSM Function OnAfterCratesBuildStarted. Info event that a build has been started. + -- @function [parent=#CTLD] OnAfterCratesBuildStarted + -- @param #CTLD self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Wrapper.Group#GROUP Group Group Object. + -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @return #CTLD self + + --- FSM Function OnAfterCratesRepairStarted. Info event that a repair has been started. + -- @function [parent=#CTLD] OnAfterCratesRepairStarted + -- @param #CTLD self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Wrapper.Group#GROUP Group Group Object. + -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @return #CTLD self + + --- FSM Function OnBeforeCratesBuildStarted. Info event that a build has been started. + -- @function [parent=#CTLD] OnBeforeCratesBuildStarted + -- @param #CTLD self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Wrapper.Group#GROUP Group Group Object. + -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @return #CTLD self + + --- FSM Function OnBeforeCratesRepairStarted. Info event that a repair has been started. + -- @function [parent=#CTLD] OnBeforeCratesRepairStarted + -- @param #CTLD self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Wrapper.Group#GROUP Group Group Object. + -- @param Wrapper.Unit#UNIT Unit Unit Object. + -- @return #CTLD self + --- FSM Function OnAfterCratesRepaired. -- @function [parent=#CTLD] OnAfterCratesRepaired -- @param #CTLD self @@ -1680,7 +1722,7 @@ function CTLD:_GetUnitCapabilities(Unit) self:T(self.lid .. " _GetUnitCapabilities") local _unit = Unit -- Wrapper.Unit#UNIT local unittype = _unit:GetTypeName() - local capabilities = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities + local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities if not capabilities or capabilities == {} then -- e.g. ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0}, capabilities = {} @@ -1871,7 +1913,7 @@ function CTLD:_PreloadCrates(Group, Unit, Cargo, NumberOfCrates) local unitname = unit:GetName() -- see if this heli can load crates local unittype = unit:GetTypeName() - local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local cancrates = capabilities.crates -- #boolean local cratelimit = capabilities.cratelimit -- #number if not cancrates then @@ -2124,6 +2166,7 @@ function CTLD:_RepairObjectFromCrates(Group,Unit,Crates,Build,Number,Engineering desttimer:Start(self.repairtime - 1) local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate()) buildtimer:Start(self.repairtime) + self:__CratesRepairStarted(1,Group,Unit) else if not Engineering then self:_SendMessage("Can't repair this unit with " .. build.Name, 10, false, Group) @@ -2308,7 +2351,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack) end -- avoid crate spam - local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local canloadcratesno = capabilities.cratelimit local loaddist = self.CrateDistance or 35 local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true) @@ -2601,8 +2644,8 @@ function CTLD:_LoadCratesNearby(Group, Unit) local unitname = unit:GetName() -- see if this heli can load crates local unittype = unit:GetTypeName() - local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities - --local capabilities = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities + --local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities local cancrates = capabilities.crates -- #boolean local cratelimit = capabilities.cratelimit -- #number local grounded = not self:IsUnitInAir(Unit) @@ -2753,7 +2796,7 @@ function CTLD:_GetMaxLoadableMass(Unit) if not Unit then return 0 end local loadable = 0 local loadedmass = self:_GetUnitCargoMass(Unit) - local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local maxmass = capabilities.cargoweightlimit or 2000 -- max 2 tons loadable = maxmass - loadedmass return loadable @@ -2778,7 +2821,7 @@ function CTLD:_ListCargo(Group, Unit) self:T(self.lid .. " _ListCargo") local unitname = Unit:GetName() local unittype = Unit:GetTypeName() - local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local trooplimit = capabilities.trooplimit -- #boolean local cratelimit = capabilities.cratelimit -- #number local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo @@ -3226,6 +3269,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering) local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate()) buildtimer:Start(self.buildtime) self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group) + self:__CratesBuildStarted(1,Group,Unit) else self:_BuildObjectFromCrates(Group,Unit,build) end @@ -3536,13 +3580,19 @@ function CTLD:_RefreshF10Menus() if _group then -- get chopper capabilities local unittype = _unit:GetTypeName() - local capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitTypeCapabilities local cantroops = capabilities.troops local cancrates = capabilities.crates -- top menu local topmenu = MENU_GROUP:New(_group,"CTLD",nil) - local toptroops = MENU_GROUP:New(_group,"Manage Troops",topmenu) - local topcrates = MENU_GROUP:New(_group,"Manage Crates",topmenu) + local toptroops = nil + local topcrates = nil + if cantroops then + toptroops = MENU_GROUP:New(_group,"Manage Troops",topmenu) + end + if cancrates then + topcrates = MENU_GROUP:New(_group,"Manage Crates",topmenu) + end local listmenu = MENU_GROUP_COMMAND:New(_group,"List boarded cargo",topmenu, self._ListCargo, self, _group, _unit) local invtry = MENU_GROUP_COMMAND:New(_group,"Inventory",topmenu, self._ListInventory, self, _group, _unit) local rbcns = MENU_GROUP_COMMAND:New(_group,"List active zone beacons",topmenu, self._ListRadioBeacons, self, _group, _unit) @@ -4339,7 +4389,7 @@ end -- @param #number Trooplimit Unit can carry number of troops. Default 0. -- @param #number Length Unit lenght (in metres) for the load radius. Default 20. -- @param #number Maxcargoweight Maxmimum weight in kgs this helo can carry. Default 500. - function CTLD:UnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight) + function CTLD:SetUnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight) self:T(self.lid .. " UnitCapabilities") local unittype = nil local unit = nil @@ -4353,13 +4403,13 @@ end end local length = 20 local maxcargo = 500 - local existingcaps = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities + local existingcaps = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities if existingcaps then length = existingcaps.length or 20 maxcargo = existingcaps.cargoweightlimit or 500 end -- set capabilities - local capabilities = {} -- #CTLD.UnitCapabilities + local capabilities = {} -- #CTLD.UnitTypeCapabilities capabilities.type = unittype capabilities.crates = Cancrates or false capabilities.troops = Cantroops or false @@ -4367,10 +4417,26 @@ end capabilities.trooplimit = Trooplimit or 0 capabilities.length = Length or length capabilities.cargoweightlimit = Maxcargoweight or maxcargo - self.UnitTypes[unittype] = capabilities + self.UnitTypeCapabilities[unittype] = capabilities return self end + --- [Deprecated] - Function to add/adjust unittype capabilities. Has been replaced with `SetUnitCapabilities()` - pls use the new one going forward! + -- @param #CTLD self + -- @param #string Unittype The unittype to adjust. If passed as Wrapper.Unit#UNIT, it will search for the unit in the mission. + -- @param #boolean Cancrates Unit can load crates. Default false. + -- @param #boolean Cantroops Unit can load troops. Default false. + -- @param #number Cratelimit Unit can carry number of crates. Default 0. + -- @param #number Trooplimit Unit can carry number of troops. Default 0. + -- @param #number Length Unit lenght (in metres) for the load radius. Default 20. + -- @param #number Maxcargoweight Maxmimum weight in kgs this helo can carry. Default 500. + function CTLD:UnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight) + self:I(self.lid.."This function been replaced with `SetUnitCapabilities()` - pls use the new one going forward!") + self:SetUnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight) + return self + end + + --- (Internal) Check if a unit is hovering *in parameters*. -- @param #CTLD self -- @param Wrapper.Unit#UNIT Unit @@ -4523,7 +4589,7 @@ end local unittype = Unit:GetTypeName() local unitname = Unit:GetName() local Group = Unit:GetGroup() - local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities + local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local cancrates = capabilities.crates -- #boolean local cratelimit = capabilities.cratelimit -- #number if cancrates then diff --git a/docs/beginner/hello-world-build.md b/docs/beginner/hello-world-build.md new file mode 100644 index 000000000..fde7e63da --- /dev/null +++ b/docs/beginner/hello-world-build.md @@ -0,0 +1,9 @@ +--- +parent: Beginner +nav_order: 03 +--- + +# Create your own Hello world + +{: .warning } +> THIS DOCUMENT IS STILL WORK IN PROGRESS! diff --git a/docs/beginner/hello-world.md b/docs/beginner/hello-world.md new file mode 100644 index 000000000..48f7bcaf4 --- /dev/null +++ b/docs/beginner/hello-world.md @@ -0,0 +1,178 @@ +--- +parent: Beginner +nav_order: 02 +--- + +# Hello world mission +{: .no_toc } + +1. Table of contents +{:toc} + +## Let's see MOOSE in action + +It is tradition that the first piece of code is a very simple example on showing +a "Hello world!" to the user. We have prepared this example mission for you. So +you can download and run it. Later on we will analyze it to explain the basics +on how to add MOOSE to your own missions. + +- Download the demo mission [001-hello-world.miz] by clicking on the link. +- Put the .miz file into your Missions subfolder of your [Saved Games folder]. +- Start DCS, choose `MISSION` in the menu on the right side: + + ![dcs-menu-mission.png](../images/beginner/dcs-menu-mission.png) + +- Click on `My Missions`, choose the `hello-world` mission and click on `OK`. + + ![dcs-my-missions.png](../images/beginner/dcs-my-missions.png) + +- It is an empty mission, so skip `BRIEFING` with `START` and then `FLY`. +- You spawn as a spectator. After some seconds you will see this message in + the upper right corner: + + ![dcs-message.jpg](../images/beginner/dcs-message.jpg) + +Ok, that's all. There is nothing more to see in this mission. This is not +particularly impressive and can also be achieved using standard Lua in DCS +(i.e. without MOOSE), but we want to keep it simple at the beginning. + +{: .note } +> If the text don't show up, the mission might be corrupted. Please contact the +> team on Discord for futher instructions. + +## Let's take a look under the hood + +- Go back to the main window and open the `MISSION EDITOR`. +- Choose `open mission` navigate to `My Missions` and open 001-hello-world.miz. +- On the left side activate `TRIGGERS`: + + ![dcs-triggers-toolbar.png](../images/beginner/dcs-triggers-toolbar.png) + +- On the right side the `TRIGGERS` dialog opens with a lot of options. +- First take a look at the available triggers: + + ![dcs-triggers-mission-start.png](../images/beginner/dcs-triggers-mission-start.png) + +- You will see two: + - One in yellow with type `4 MISSION START` and name `Load MOOSE` and + - one in green with type `1 ONCE` and name `Load Mission Script`. + +### Execution of Moose + +- Click on the yellow one to show all of it options. + +- In the middle part the `CONDITIONS` will be shown. + For this trigger there are no conditions configured. + + ![dcs-triggers-mission-start-conditions.png](../images/beginner/dcs-triggers-mission-start-conditions.png) + + {: .important } + > The trigger type `4 MISSION START` does not support `CONDITIONS`.
+ > So `CONDITIONS` must left blank when using it.
+ > **If you add a condition the trigger will never be executed!** + +- On the right side the `ACTIONS` will be shown: + + ![dcs-triggers-mission-start-actions.png](../images/beginner/dcs-triggers-mission-start-actions.png) + +- A `DO SCRIPT FILE` is configured, which executes the file `Moose_.lua` + +{: .highlight } +> This is the execution of the Moose framework included in the mission as one single file.
+> The difference between `Moose_.lua` and `Moose.lua` will be explained later.
+> This doesn't matter at this time. + +{: .important } +> The trigger `4 MISSION START` will be executed **before** the mission is started!
+> This is important, because Moose **must** be executed before other scripts, that want to use Moose! + +### Execution of the mission script + +- Now move back to the left `TRIGGERS` area and click on the green trigger
+ `1 ONCE (Load Mission Script ...)` + + ![dcs-triggers-once.png](../images/beginner/dcs-triggers-once.png) + +- The configured options will be shown.
+ In the middle part the `CONDITIONS` will be shown.
+ For this trigger there is one condition configured: + + ![dcs-triggers-once-conditions.png](../images/beginner/dcs-triggers-once-conditions.png) + +- The combination of `1 ONCE` with `TIME MORE(1)` will ensure, that the mission + script is executed 1 second after the mission is started. + +- On the right side the `ACTIONS` will be shown: + + ![dcs-triggers-once-actions.png](../images/beginner/dcs-triggers-once-actions.png) + +- A `DO SCRIPT FILE` is configured, which executes the file `001-hello-world.lua`. + +{: .highlight } +> This is the execution of the mission script, which you will create in the future. + +{: .important } +> Most important is the fact, that the mission script (`001-hello-world.lua`) +> is executed **after** `Moose_.lua`, because the mission script needs the +> classes defined in `Moose_.lua`. And they are only available when `Moose_.lua` +> is executed before the mission script. + +### Inspect the code of the mission script + +The file `001-hello-world.lua` consists of following code: + +```lua +-- +-- Simple example mission to show the very basics of MOOSE +-- +MESSAGE:New( "Hello World! This messages is printed by MOOSE", 35, "INFO" ):ToAll() +``` + +- The first three lines starting with `--` are comments and will be ignored. + +- Line 4 is the one with the "magic": + + - With `MESSAGE` we use the class [Core.Message]. + +The part before the dot (Core) is the section where the class is placed. +It is important for the Moose programmes to have a structure where the classes +are placed. But in the code itself it is not used. + +#### What is a class? + +{: .highlight } +> In object-oriented programming, a class is an extensible program-code-template +> for creating objects, providing initial values for state (member variables) +> and implementations of behavior (member functions or methods).
+> *Source [Wikipedia:Class]{:target="_blank"}* + +After the class name we call a method of that class. We do this with semicolon +followed by the name of the method and a pair of round brackets. +Here we call the method `New`, which creates a new MESSAGE object. + +We give it three parameters within the round brackets, which are divided by commas: +1. The text we want to show: `"Hello World! ..."` +1. The time in seconds the messages should be visible: `35` +1. And the type of message: `"INFO"` + +- With `New` the MESSAGE object is created, but the message is still not printed + to the screen. +- This is done by `:ToAll()`. Another method of [Core.Message] which sends the + message to all players, no matter if they belong to the RED or BLUE coalition. + +If you you want to read more about [Core.Message] click on the link. +The page with all the Methods and Fields is very long and this might be +daunting, but for the copy and paste approach, you won't need it often. + +And if you want to learn how to use more of that stuff, you will become +compftable in filtering these informations fast. + +## Next step + +Now it is time to [create your own Hello world] mission. + +[Saved Games folder]: ../beginner/tipps-and-tricks.md#find-the-saved-games-folder +[hello-world demo mission]: https://raw.githubusercontent.com/FlightControl-Master/MOOSE_MISSIONS/master/Core/Message/001-hello-world.miz +[Core.Message]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Core.Message.html +[Wikipedia:Class]: https://en.wikipedia.org/wiki/Class_(computer_programming) +[create your own Hello world]: hello-world-build.md diff --git a/docs/beginner/introduction.md b/docs/beginner/introduction.md new file mode 100644 index 000000000..38e3334cd --- /dev/null +++ b/docs/beginner/introduction.md @@ -0,0 +1,106 @@ +--- +parent: Beginner +nav_order: 01 +--- +# Introduction +{: .no_toc } + +1. Table of contents +{:toc} + +This very short chapter is for people identifying as a consumer of MOOSE and not +wishing to learn to script. This is a condensed FAQ and set of links to get you +up and running. It specifically avoids any complexity. + +## What is MOOSE? + +[DCS] has included a [Simulator Scripting Engine] (short SSE). This SSE gives +mission designers access to objects in the game using [Lua] scripts. + +**M**ission **O**bject **O**riented **S**cripting **E**nvironment, is a +scripting framework written in [Lua] that attempts to make the scripting of +missions within DCS easier, simpler and shorter than with the standard methods. + +MOOSE is over 5 MB of code, with as many words as the Bible and the core of it +was written over several years by one person. + +MOOSE is the brain-child of an talented programmer with the alias FlightControl. +If you want to know more about this topic, check out FC’s [MOOSE for Dummies] +videos on YouTube. + +{: .note } +> We recommend video playback at 1.5x speed, as FC speaks slowly and distinctly. + +## What is Lua? + +[Lua] is a lightweight, programming language designed primarily to be embedded +in applications. It's main advantages are: + +- It is fast, +- it is portabel (Windows, Linux, MacOS), +- it is easy to use. + +[Lua] is embedded in DCS, so we can use it without any modifacation to the game. + +## What is are scripts, frameworks and classes? + +A script is a set of instructions in plain text read by a computer and processed +on the fly. Scripts do not need to be compiled before execution, unlike exe +files. + +A framework is a structure that you can build software (or in this case missions) +on. It serves as a foundation, so you're not starting entirely from scratch. +It takes a lot of work off your hands because someone else has thought about it +and provides ready-made building blocks for many situations. + +These building blocks are called classes in object oriented programming. + +## What can MOOSE do for me? + +Whilst MOOSE can be used to write customised [Lua] scripts, you are probably not +caring for learning [Lua] right now. Instead you can use a MOOSE script written +by someone else by just copy and paste it. You can configure the basic settings +of the classes to fit your needs in your mission. + +Here are a few suggestions for well-known and popular classes: + +- [Ops.Airboss] manages recoveries of human pilots and AI aircraft on aircraft + carriers. +- [Functional.RAT] creates random airtraffic in your missions. +- [Functional.Range] (which counts hits on targets so you can practice), +- [Functional.Fox] to practice to evade missiles without being destroyed. +- and many more! + +You will need to look through examples to know what functionallity you want to +add to your missions. + +## What if I don’t want to learn scripting? + +The good news for you: You don't need to become a professional [Lua] programmer +to use MOOSE. As explained already, you can copy and paste the code from example +missions. You need some basics how to add triggers in the mission editor. But we +will cover this later. + +If you want to modify the behaviour of the classes slightly, some basics about +the [Lua] synthax (the rules how to write the code) will help you to avoid +errors. + +The more customizations you want to make, the more knowledge about [Lua] you +will need. But you can learn this step by step. + +## Next step + +We will start with a very simple demonstartion of MOOSE in the next section +[Hello world mission]. + +[DCS]: https://www.digitalcombatsimulator.com/en/ +[Simulator Scripting Engine]: https://wiki.hoggitworld.com/view/Simulator_Scripting_Engine_Documentation +[Lua]: https://www.lua.org/ +[MOOSE for Dummies]: https://www.youtube.com/watch?v=ZqvdUFhKX4o&list=PL7ZUrU4zZUl04jBoOSX_rmqE6cArquhM4&index=2&t=618s + +[Ops.Airboss]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Ops.Airboss.html +[Functional.RAT]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.RAT.html +[Functional.Range]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Range.html +[Functional.Fox]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html + +[Hello world mission]: hello-world.md diff --git a/docs/beginner/tipps-and-tricks.md b/docs/beginner/tipps-and-tricks.md index 3fa2d8bc2..3ea1bd781 100644 --- a/docs/beginner/tipps-and-tricks.md +++ b/docs/beginner/tipps-and-tricks.md @@ -25,5 +25,30 @@ It depends on the platform and the version you choosed to install: - If you changed the installation folder of the Standalone version, right click on the game icon, open Properties and click on `Open File Location`. +## Find the Saved Games folder + +DCS creates a folder to store all user specific configuration and data. +This folder can be found in your userprofile as subfolder of `Saved Games`. + +The easiest way to find it, is to open search and paste the text below into it +and press Enter: + +```%userprofile%\Saved Games``` + +{: .note } +> The text will work even if your Windows is installed with another language, +> e.g. German. This is really usefull. + +Depending on the DCS version you will find one of the following folders: + +- DCS +- DCS.openbeta + +{: .note } +> It is good idea to add the folder to the quick access area in the windows +> explorer. You will use it very often! + +For MOOSE users the folders `Missions`, `Logs` and `Config` are most important! + [DCS World Steam Edition]: https://store.steampowered.com/app/223750/DCS_World_Steam_Edition/ [DCS World Standalone installer]: https://www.digitalcombatsimulator.com/en/downloads/world/ diff --git a/docs/images/beginner/dcs-menu-mission.png b/docs/images/beginner/dcs-menu-mission.png new file mode 100644 index 000000000..0c69f781a Binary files /dev/null and b/docs/images/beginner/dcs-menu-mission.png differ diff --git a/docs/images/beginner/dcs-message.jpg b/docs/images/beginner/dcs-message.jpg new file mode 100644 index 000000000..e07a88fdb Binary files /dev/null and b/docs/images/beginner/dcs-message.jpg differ diff --git a/docs/images/beginner/dcs-my-missions.png b/docs/images/beginner/dcs-my-missions.png new file mode 100644 index 000000000..f99f9ccd0 Binary files /dev/null and b/docs/images/beginner/dcs-my-missions.png differ diff --git a/docs/images/beginner/dcs-triggers-mission-start-actions-conf.png b/docs/images/beginner/dcs-triggers-mission-start-actions-conf.png new file mode 100644 index 000000000..b205bdf2e Binary files /dev/null and b/docs/images/beginner/dcs-triggers-mission-start-actions-conf.png differ diff --git a/docs/images/beginner/dcs-triggers-mission-start-actions.png b/docs/images/beginner/dcs-triggers-mission-start-actions.png new file mode 100644 index 000000000..06ed821fc Binary files /dev/null and b/docs/images/beginner/dcs-triggers-mission-start-actions.png differ diff --git a/docs/images/beginner/dcs-triggers-mission-start-conditions.png b/docs/images/beginner/dcs-triggers-mission-start-conditions.png new file mode 100644 index 000000000..d051b07cd Binary files /dev/null and b/docs/images/beginner/dcs-triggers-mission-start-conditions.png differ diff --git a/docs/images/beginner/dcs-triggers-mission-start-conf.png b/docs/images/beginner/dcs-triggers-mission-start-conf.png new file mode 100644 index 000000000..67d323e77 Binary files /dev/null and b/docs/images/beginner/dcs-triggers-mission-start-conf.png differ diff --git a/docs/images/beginner/dcs-triggers-mission-start.png b/docs/images/beginner/dcs-triggers-mission-start.png new file mode 100644 index 000000000..60b0bef27 Binary files /dev/null and b/docs/images/beginner/dcs-triggers-mission-start.png differ diff --git a/docs/images/beginner/dcs-triggers-once-actions.png b/docs/images/beginner/dcs-triggers-once-actions.png new file mode 100644 index 000000000..b93b1a65b Binary files /dev/null and b/docs/images/beginner/dcs-triggers-once-actions.png differ diff --git a/docs/images/beginner/dcs-triggers-once-conditions.png b/docs/images/beginner/dcs-triggers-once-conditions.png new file mode 100644 index 000000000..7bc4799a7 Binary files /dev/null and b/docs/images/beginner/dcs-triggers-once-conditions.png differ diff --git a/docs/images/beginner/dcs-triggers-once-conf.png b/docs/images/beginner/dcs-triggers-once-conf.png new file mode 100644 index 000000000..fd45b5761 Binary files /dev/null and b/docs/images/beginner/dcs-triggers-once-conf.png differ diff --git a/docs/images/beginner/dcs-triggers-once.png b/docs/images/beginner/dcs-triggers-once.png new file mode 100644 index 000000000..b15125839 Binary files /dev/null and b/docs/images/beginner/dcs-triggers-once.png differ diff --git a/docs/images/beginner/dcs-triggers-toolbar.png b/docs/images/beginner/dcs-triggers-toolbar.png new file mode 100644 index 000000000..08af0b49f Binary files /dev/null and b/docs/images/beginner/dcs-triggers-toolbar.png differ