Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank 2023-11-20 13:52:16 +01:00
commit b5965bbf81
22 changed files with 515 additions and 50 deletions

View File

@ -75,4 +75,4 @@ jobs:
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
- run: npm install linkinator - 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

View File

@ -261,6 +261,15 @@ EVENTS = {
SimulationStart = world.event.S_EVENT_SIMULATION_START or -1, SimulationStart = world.event.S_EVENT_SIMULATION_START or -1,
WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1, WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1,
WeaponDrop = world.event.S_EVENT_WEAPON_DROP 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 --- The Event structure
@ -636,6 +645,55 @@ local _EVENTMETA = {
Event = "OnEventWeaponDrop", Event = "OnEventWeaponDrop",
Text = "S_EVENT_WEAPON_DROP" 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 --- The Events structure
@ -1245,11 +1303,14 @@ function EVENT:onEvent( Event )
Event.TgtDCSUnit = Event.target Event.TgtDCSUnit = Event.target
if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName -- Workaround for borked target info on cruise missiles
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) if Event.TgtDCSUnitName and Event.TgtDCSUnitName ~= "" then
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
end
else else
Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id)) Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id))
Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnitName = Event.TgtDCSUnitName

View File

@ -22,7 +22,7 @@
-- @module Functional.Mantis -- @module Functional.Mantis
-- @image Functional.Mantis.jpg -- @image Functional.Mantis.jpg
-- --
-- Last Update: Oct 2023 -- Last Update: Nov 2023
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE --- **MANTIS** class, extends Core.Base#BASE
@ -799,12 +799,16 @@ do
-- @param #MANTIS self -- @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 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 #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 -- @return #MANTIS self
function MANTIS:AddScootZones(ZoneSet, Number) function MANTIS:AddScootZones(ZoneSet, Number, Random, Formation)
self:T(self.lid .. " AddScootZones") self:T(self.lid .. " AddScootZones")
self.SkateZones = ZoneSet self.SkateZones = ZoneSet
self.SkateNumber = Number or 3 self.SkateNumber = Number or 3
self.shootandscoot = true self.shootandscoot = true
self.ScootRandom = Random
self.ScootFormation = Formation or "Cone"
return self return self
end end
@ -1809,8 +1813,8 @@ do
self.Shorad.Groupset=self.ShoradGroupSet self.Shorad.Groupset=self.ShoradGroupSet
self.Shorad.debug = self.debug self.Shorad.debug = self.debug
end end
if self.shootandscoot and self.SkateZones then if self.shootandscoot and self.SkateZones and self.Shorad then
self.Shorad:AddScootZones(self.SkateZones,self.SkateNumber or 3) self.Shorad:AddScootZones(self.SkateZones,self.SkateNumber or 3,self.ScootRandom,self.ScootFormation)
end end
self:__Status(-math.random(1,10)) self:__Status(-math.random(1,10))
return self return self

View File

@ -41,10 +41,14 @@
-- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles -- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles
-- @field #number DefenseLowProb Default 70, minimum detection limit -- @field #number DefenseLowProb Default 70, minimum detection limit
-- @field #number DefenseHighProb Default 90, maximum 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 UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green
-- @field #boolean shootandscoot -- @field #boolean shootandscoot If true, shoot and scoot between zones
-- @field #number SkateNumber -- @field #number SkateNumber Number of zones to consider
-- @field Core.Set#SET_ZONE SkateZones -- @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 -- @extends Core.Base#BASE
@ -77,14 +81,15 @@
-- --
-- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")` -- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")`
-- --
-- ## Customize options -- ## Customization options
-- --
-- * SHORAD:SwitchDebug(debug) -- * myshorad:SwitchDebug(debug)
-- * SHORAD:SwitchHARMDefense(onoff) -- * myshorad:SwitchHARMDefense(onoff)
-- * SHORAD:SwitchAGMDefense(onoff) -- * myshorad:SwitchAGMDefense(onoff)
-- * SHORAD:SetDefenseLimits(low,high) -- * myshorad:SetDefenseLimits(low,high)
-- * SHORAD:SetActiveTimer(seconds) -- * myshorad:SetActiveTimer(seconds)
-- * SHORAD:SetDefenseRadius(meters) -- * myshorad:SetDefenseRadius(meters)
-- * myshorad:AddScootZones(ZoneSet,Number,Random,Formation)
-- --
-- @field #SHORAD -- @field #SHORAD
SHORAD = { SHORAD = {
@ -107,6 +112,9 @@ SHORAD = {
shootandscoot = false, shootandscoot = false,
SkateNumber = 3, SkateNumber = 3,
SkateZones = nil, 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.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 self.UseEmOnOff = true -- Decide if we are using Emission on/off (default) or AlarmState red/green
if UseEmOnOff == false then self.UseEmOnOff = UseEmOnOff end 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. -- Set the string id for output to DCS.log file.
self.lid=string.format("SHORAD %s | ", self.name) self.lid=string.format("SHORAD %s | ", self.name)
self:_InitState() self:_InitState()
@ -219,12 +227,16 @@ do
-- @param #SHORAD self -- @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 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 #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 -- @return #SHORAD self
function SHORAD:AddScootZones(ZoneSet, Number) function SHORAD:AddScootZones(ZoneSet, Number, Random, Formation)
self:T(self.lid .. " AddScootZones") self:T(self.lid .. " AddScootZones")
self.SkateZones = ZoneSet self.SkateZones = ZoneSet
self.SkateNumber = Number or 3 self.SkateNumber = Number or 3
self.shootandscoot = true self.shootandscoot = true
self.scootrandomcoord = Random
self.scootformation = Formation or "Cone"
return self return self
end end
@ -613,8 +625,8 @@ do
function SHORAD:onafterShootAndScoot(From,Event,To,Shorad) function SHORAD:onafterShootAndScoot(From,Event,To,Shorad)
self:T( { From,Event,To } ) self:T( { From,Event,To } )
local possibleZones = {} local possibleZones = {}
local mindist = 100 local mindist = self.minscootdist or 100
local maxdist = 3000 local maxdist = self.maxscootdist or 3000
if Shorad and Shorad:IsAlive() then if Shorad and Shorad:IsAlive() then
local NowCoord = Shorad:GetCoordinate() local NowCoord = Shorad:GetCoordinate()
for _,_zone in pairs(self.SkateZones.Set) do for _,_zone in pairs(self.SkateZones.Set) do
@ -630,7 +642,11 @@ do
if rand == 0 then rand = 1 end if rand == 0 then rand = 1 end
self:T(self.lid .. " ShootAndScoot to zone "..rand) self:T(self.lid .. " ShootAndScoot to zone "..rand)
local ToCoordinate = possibleZones[rand]:GetCoordinate() 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
end end
return self return self
@ -731,4 +747,4 @@ do
end end
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- SHORAD end -- SHORAD end
----------------------------------------------------------------------- -----------------------------------------------------------------------

View File

@ -24,7 +24,7 @@
-- @module Ops.CTLD -- @module Ops.CTLD
-- @image OPS_CTLD.jpg -- @image OPS_CTLD.jpg
-- Last Update October 2023 -- Last Update November 2023
do do
@ -741,7 +741,7 @@ do
-- --
-- -- E.g. update unit capabilities for testing. Please stay realistic in your mission design. -- -- 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: -- -- 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: -- -- Default unit type capabilities are:
-- ["SA342Mistral"] = {type="SA342Mistral", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400}, -- ["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). -- @field #CTLD_CARGO.Enum Type Type enumerator (for moves).
--- Unit capabilities. --- Unit capabilities.
-- @type CTLD.UnitCapabilities -- @type CTLD.UnitTypeCapabilities
-- @field #string type Unit type. -- @field #string type Unit type.
-- @field #boolean crates Can transport crate. -- @field #boolean crates Can transport crate.
-- @field #boolean troops Can transport troops. -- @field #boolean troops Can transport troops.
-- @field #number cratelimit Number of crates transportable. -- @field #number cratelimit Number of crates transportable.
-- @field #number trooplimit Number of troop units transportable. -- @field #number trooplimit Number of troop units transportable.
-- @field #number cargoweightlimit Max loadable kgs of cargo. -- @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}, ["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}, ["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}, ["SA342M"] = {type="SA342M", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400},
@ -1228,7 +1228,7 @@ CTLD.UnitTypes = {
--- CTLD class version. --- CTLD class version.
-- @field #string version -- @field #string version
CTLD.version="1.0.41" CTLD.version="1.0.43"
--- Instantiate a new CTLD. --- Instantiate a new CTLD.
-- @param #CTLD self -- @param #CTLD self
@ -1293,6 +1293,8 @@ function CTLD:New(Coalition, Prefixes, Alias)
self:AddTransition("*", "CratesDropped", "*") -- CTLD deploy event. self:AddTransition("*", "CratesDropped", "*") -- CTLD deploy event.
self:AddTransition("*", "CratesBuild", "*") -- CTLD build event. self:AddTransition("*", "CratesBuild", "*") -- CTLD build event.
self:AddTransition("*", "CratesRepaired", "*") -- CTLD repair 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("*", "Load", "*") -- CTLD load event.
self:AddTransition("*", "Save", "*") -- CTLD save event. self:AddTransition("*", "Save", "*") -- CTLD save event.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
@ -1475,7 +1477,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
-- @param #CTLD self -- @param #CTLD self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- FSM Function OnBeforeTroopsPickedUp. --- FSM Function OnBeforeTroopsPickedUp.
-- @function [parent=#CTLD] OnBeforeTroopsPickedUp -- @function [parent=#CTLD] OnBeforeTroopsPickedUp
-- @param #CTLD self -- @param #CTLD self
-- @param #string From State. -- @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. -- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
-- @return #CTLD self -- @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. --- FSM Function OnAfterCratesRepaired.
-- @function [parent=#CTLD] OnAfterCratesRepaired -- @function [parent=#CTLD] OnAfterCratesRepaired
-- @param #CTLD self -- @param #CTLD self
@ -1680,7 +1722,7 @@ function CTLD:_GetUnitCapabilities(Unit)
self:T(self.lid .. " _GetUnitCapabilities") self:T(self.lid .. " _GetUnitCapabilities")
local _unit = Unit -- Wrapper.Unit#UNIT local _unit = Unit -- Wrapper.Unit#UNIT
local unittype = _unit:GetTypeName() local unittype = _unit:GetTypeName()
local capabilities = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
if not capabilities or capabilities == {} then if not capabilities or capabilities == {} then
-- e.g. ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0}, -- e.g. ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0},
capabilities = {} capabilities = {}
@ -1871,7 +1913,7 @@ function CTLD:_PreloadCrates(Group, Unit, Cargo, NumberOfCrates)
local unitname = unit:GetName() local unitname = unit:GetName()
-- see if this heli can load crates -- see if this heli can load crates
local unittype = unit:GetTypeName() local unittype = unit:GetTypeName()
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
local cancrates = capabilities.crates -- #boolean local cancrates = capabilities.crates -- #boolean
local cratelimit = capabilities.cratelimit -- #number local cratelimit = capabilities.cratelimit -- #number
if not cancrates then if not cancrates then
@ -2124,6 +2166,7 @@ function CTLD:_RepairObjectFromCrates(Group,Unit,Crates,Build,Number,Engineering
desttimer:Start(self.repairtime - 1) desttimer:Start(self.repairtime - 1)
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate()) local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate())
buildtimer:Start(self.repairtime) buildtimer:Start(self.repairtime)
self:__CratesRepairStarted(1,Group,Unit)
else else
if not Engineering then if not Engineering then
self:_SendMessage("Can't repair this unit with " .. build.Name, 10, false, Group) 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 end
-- avoid crate spam -- avoid crate spam
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
local canloadcratesno = capabilities.cratelimit local canloadcratesno = capabilities.cratelimit
local loaddist = self.CrateDistance or 35 local loaddist = self.CrateDistance or 35
local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true) local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true)
@ -2601,8 +2644,8 @@ function CTLD:_LoadCratesNearby(Group, Unit)
local unitname = unit:GetName() local unitname = unit:GetName()
-- see if this heli can load crates -- see if this heli can load crates
local unittype = unit:GetTypeName() local unittype = unit:GetTypeName()
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
--local capabilities = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities --local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
local cancrates = capabilities.crates -- #boolean local cancrates = capabilities.crates -- #boolean
local cratelimit = capabilities.cratelimit -- #number local cratelimit = capabilities.cratelimit -- #number
local grounded = not self:IsUnitInAir(Unit) local grounded = not self:IsUnitInAir(Unit)
@ -2753,7 +2796,7 @@ function CTLD:_GetMaxLoadableMass(Unit)
if not Unit then return 0 end if not Unit then return 0 end
local loadable = 0 local loadable = 0
local loadedmass = self:_GetUnitCargoMass(Unit) 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 local maxmass = capabilities.cargoweightlimit or 2000 -- max 2 tons
loadable = maxmass - loadedmass loadable = maxmass - loadedmass
return loadable return loadable
@ -2778,7 +2821,7 @@ function CTLD:_ListCargo(Group, Unit)
self:T(self.lid .. " _ListCargo") self:T(self.lid .. " _ListCargo")
local unitname = Unit:GetName() local unitname = Unit:GetName()
local unittype = Unit:GetTypeName() local unittype = Unit:GetTypeName()
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
local trooplimit = capabilities.trooplimit -- #boolean local trooplimit = capabilities.trooplimit -- #boolean
local cratelimit = capabilities.cratelimit -- #number local cratelimit = capabilities.cratelimit -- #number
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo 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()) local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate())
buildtimer:Start(self.buildtime) buildtimer:Start(self.buildtime)
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group) self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
self:__CratesBuildStarted(1,Group,Unit)
else else
self:_BuildObjectFromCrates(Group,Unit,build) self:_BuildObjectFromCrates(Group,Unit,build)
end end
@ -3536,13 +3580,19 @@ function CTLD:_RefreshF10Menus()
if _group then if _group then
-- get chopper capabilities -- get chopper capabilities
local unittype = _unit:GetTypeName() local unittype = _unit:GetTypeName()
local capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitCapabilities local capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitTypeCapabilities
local cantroops = capabilities.troops local cantroops = capabilities.troops
local cancrates = capabilities.crates local cancrates = capabilities.crates
-- top menu -- top menu
local topmenu = MENU_GROUP:New(_group,"CTLD",nil) local topmenu = MENU_GROUP:New(_group,"CTLD",nil)
local toptroops = MENU_GROUP:New(_group,"Manage Troops",topmenu) local toptroops = nil
local topcrates = MENU_GROUP:New(_group,"Manage Crates",topmenu) 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 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 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) 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 Trooplimit Unit can carry number of troops. Default 0.
-- @param #number Length Unit lenght (in metres) for the load radius. Default 20. -- @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. -- @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") self:T(self.lid .. " UnitCapabilities")
local unittype = nil local unittype = nil
local unit = nil local unit = nil
@ -4353,13 +4403,13 @@ end
end end
local length = 20 local length = 20
local maxcargo = 500 local maxcargo = 500
local existingcaps = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities local existingcaps = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
if existingcaps then if existingcaps then
length = existingcaps.length or 20 length = existingcaps.length or 20
maxcargo = existingcaps.cargoweightlimit or 500 maxcargo = existingcaps.cargoweightlimit or 500
end end
-- set capabilities -- set capabilities
local capabilities = {} -- #CTLD.UnitCapabilities local capabilities = {} -- #CTLD.UnitTypeCapabilities
capabilities.type = unittype capabilities.type = unittype
capabilities.crates = Cancrates or false capabilities.crates = Cancrates or false
capabilities.troops = Cantroops or false capabilities.troops = Cantroops or false
@ -4367,10 +4417,26 @@ end
capabilities.trooplimit = Trooplimit or 0 capabilities.trooplimit = Trooplimit or 0
capabilities.length = Length or length capabilities.length = Length or length
capabilities.cargoweightlimit = Maxcargoweight or maxcargo capabilities.cargoweightlimit = Maxcargoweight or maxcargo
self.UnitTypes[unittype] = capabilities self.UnitTypeCapabilities[unittype] = capabilities
return self return self
end 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*. --- (Internal) Check if a unit is hovering *in parameters*.
-- @param #CTLD self -- @param #CTLD self
-- @param Wrapper.Unit#UNIT Unit -- @param Wrapper.Unit#UNIT Unit
@ -4523,7 +4589,7 @@ end
local unittype = Unit:GetTypeName() local unittype = Unit:GetTypeName()
local unitname = Unit:GetName() local unitname = Unit:GetName()
local Group = Unit:GetGroup() local Group = Unit:GetGroup()
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
local cancrates = capabilities.crates -- #boolean local cancrates = capabilities.crates -- #boolean
local cratelimit = capabilities.cratelimit -- #number local cratelimit = capabilities.cratelimit -- #number
if cancrates then if cancrates then

View File

@ -0,0 +1,9 @@
---
parent: Beginner
nav_order: 03
---
# Create your own Hello world
{: .warning }
> THIS DOCUMENT IS STILL WORK IN PROGRESS!

View File

@ -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`. <br />
> So `CONDITIONS` must left blank when using it. <br />
> **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. <br />
> The difference between `Moose_.lua` and `Moose.lua` will be explained later. <br />
> This doesn't matter at this time.
{: .important }
> The trigger `4 MISSION START` will be executed **before** the mission is started! <br />
> 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 <br />
`1 ONCE (Load Mission Script ...)`
![dcs-triggers-once.png](../images/beginner/dcs-triggers-once.png)
- The configured options will be shown. <br />
In the middle part the `CONDITIONS` will be shown. <br />
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). <br />
> *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

View File

@ -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 FCs [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 dont 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

View File

@ -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 - If you changed the installation folder of the Standalone version, right
click on the game icon, open Properties and click on `Open File Location`. 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 Steam Edition]: https://store.steampowered.com/app/223750/DCS_World_Steam_Edition/
[DCS World Standalone installer]: https://www.digitalcombatsimulator.com/en/downloads/world/ [DCS World Standalone installer]: https://www.digitalcombatsimulator.com/en/downloads/world/

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB