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:
+
+ 
+
+- Click on `My Missions`, choose the `hello-world` mission and click on `OK`.
+
+ 
+
+- 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:
+
+ 
+
+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`:
+
+ 
+
+- On the right side the `TRIGGERS` dialog opens with a lot of options.
+- First take a look at the available triggers:
+
+ 
+
+- 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.
+
+ 
+
+ {: .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:
+
+ 
+
+- 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 ...)`
+
+ 
+
+- The configured options will be shown.
+ In the middle part the `CONDITIONS` will be shown.
+ For this trigger there is one condition configured:
+
+ 
+
+- 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:
+
+ 
+
+- 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