mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
196bcf39cf | ||
|
|
afec1c3a5b | ||
|
|
6025339b46 | ||
|
|
40c6cc59d3 | ||
|
|
514e568e04 | ||
|
|
2f34b0a5ed | ||
|
|
708c076885 | ||
|
|
f0e0b918af | ||
|
|
e45f5e1122 | ||
|
|
932015668b | ||
|
|
4011bc3fe6 | ||
|
|
1dcccdc434 | ||
|
|
3380ed9360 | ||
|
|
ed9c14e63d | ||
|
|
4762793adc | ||
|
|
7df3946189 | ||
|
|
d5fb75fe43 | ||
|
|
c0b32a5584 | ||
|
|
e2b1276d7b | ||
|
|
f6aea13fae | ||
|
|
646b113c55 | ||
|
|
58074f499f | ||
|
|
1483ffd7ff | ||
|
|
cdaef851a0 | ||
|
|
04068d7117 |
@@ -253,6 +253,9 @@ function AI_AIR:New( AIGroup )
|
||||
|
||||
self.IdleCount = 0
|
||||
|
||||
self.RTBSpeedMaxFactor = 0.6
|
||||
self.RTBSpeedMinFactor = 0.5
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -576,6 +579,19 @@ function AI_AIR.RTBHold( AIGroup, Fsm )
|
||||
|
||||
end
|
||||
|
||||
--- Set the min and max factors on RTB speed. Use this, if your planes are heading back to base too fast. Default values are 0.5 and 0.6.
|
||||
-- The RTB speed is calculated as the max speed of the unit multiplied by MinFactor (lower bracket) and multiplied by MaxFactor (upper bracket).
|
||||
-- A random value in this bracket is then applied in the waypoint routing generation.
|
||||
-- @param #AI_AIR self
|
||||
-- @param #number MinFactor Lower bracket factor. Defaults to 0.5.
|
||||
-- @param #number MaxFactor Upper bracket factor. Defaults to 0.6.
|
||||
-- @return #AI_AIR self
|
||||
function AI_AIR:SetRTBSpeedFactors(MinFactor,MaxFactor)
|
||||
self.RTBSpeedMaxFactor = MaxFactor or 0.6
|
||||
self.RTBSpeedMinFactor = MinFactor or 0.5
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -599,12 +615,14 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
local FromCoord = AIGroup:GetCoordinate()
|
||||
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
||||
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
||||
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+1000 -- let's set this 1000m/3000 feet above ground
|
||||
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
|
||||
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
||||
|
||||
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
||||
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
||||
self:SetRTBSpeed( RTBSpeedMax * 0.5, RTBSpeedMax * 0.6 )
|
||||
local RTBSpeedMaxFactor = self.RTBSpeedMaxFactor or 0.6
|
||||
local RTBSpeedMinFactor = self.RTBSpeedMinFactor or 0.5
|
||||
self:SetRTBSpeed( RTBSpeedMax * RTBSpeedMinFactor, RTBSpeedMax * RTBSpeedMaxFactor)
|
||||
end
|
||||
|
||||
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
--- **Core** - TACAN and other beacons.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
--
|
||||
-- * Provide beacon functionality to assist pilots.
|
||||
--
|
||||
-- ===
|
||||
@@ -14,34 +14,34 @@
|
||||
-- @image Core_Radio.JPG
|
||||
|
||||
--- *In order for the light to shine so brightly, the darkness must be present.* -- Francis Bacon
|
||||
--
|
||||
--
|
||||
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
||||
-- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon.
|
||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is
|
||||
-- attach to a cargo crate, for exemple.
|
||||
--
|
||||
-- ## AA TACAN Beacon usage
|
||||
--
|
||||
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
|
||||
-- Use @#BEACON:StopAATACAN}() to stop it.
|
||||
--
|
||||
-- There are two types of BEACONs available : the (aircraft) TACAN Beacon and the general purpose Radio Beacon.
|
||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very useful to simulate the battery time if your BEACON is
|
||||
-- attach to a cargo crate, for exemple.
|
||||
--
|
||||
-- ## Aircraft TACAN Beacon usage
|
||||
--
|
||||
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON.ActivateTACAN}() to set the beacon parameters and start the beacon.
|
||||
-- Use @{#BEACON.StopRadioBeacon}() to stop it.
|
||||
--
|
||||
-- ## General Purpose Radio Beacon usage
|
||||
--
|
||||
--
|
||||
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
|
||||
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
|
||||
-- Use @{#BEACON:StopRadioBeacon}() to stop it.
|
||||
--
|
||||
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON.RadioBeacon}() to set the beacon parameters and start the beacon.
|
||||
-- Use @{#BEACON.StopRadioBeacon}() to stop it.
|
||||
--
|
||||
-- @type BEACON
|
||||
-- @field #string ClassName Name of the class "BEACON".
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
|
||||
-- @extends Core.Base#BASE
|
||||
BEACON = {
|
||||
ClassName = "BEACON",
|
||||
ClassName = "BEACON",
|
||||
Positionable = nil,
|
||||
name = nil,
|
||||
name = nil,
|
||||
}
|
||||
|
||||
--- Beacon types supported by DCS.
|
||||
--- Beacon types supported by DCS.
|
||||
-- @type BEACON.Type
|
||||
-- @field #number NULL
|
||||
-- @field #number VOR
|
||||
@@ -65,19 +65,19 @@ BEACON = {
|
||||
-- @field #number ICLS_GLIDESLOPE
|
||||
-- @field #number NAUTICAL_HOMER
|
||||
BEACON.Type={
|
||||
NULL = 0,
|
||||
NULL = 0,
|
||||
VOR = 1,
|
||||
DME = 2,
|
||||
VOR_DME = 3,
|
||||
VOR_DME = 3,
|
||||
TACAN = 4,
|
||||
VORTAC = 5,
|
||||
VORTAC = 5,
|
||||
RSBN = 128,
|
||||
BROADCAST_STATION = 1024,
|
||||
BROADCAST_STATION = 1024,
|
||||
HOMER = 8,
|
||||
AIRPORT_HOMER = 4104,
|
||||
AIRPORT_HOMER_WITH_MARKER = 4136,
|
||||
AIRPORT_HOMER = 4104,
|
||||
AIRPORT_HOMER_WITH_MARKER = 4136,
|
||||
ILS_FAR_HOMER = 16408,
|
||||
ILS_NEAR_HOMER = 16424,
|
||||
ILS_NEAR_HOMER = 16424,
|
||||
ILS_LOCALIZER = 16640,
|
||||
ILS_GLIDESLOPE = 16896,
|
||||
PRMG_LOCALIZER = 33024,
|
||||
@@ -95,26 +95,26 @@ BEACON.Type={
|
||||
-- @field #number TACAN TACtical Air Navigation system on ground.
|
||||
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
||||
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
||||
-- @field #number VOR Very High Frequency Omnidirectional Range
|
||||
-- @field #number VOR Very High Frequency Omni-Directional Range
|
||||
-- @field #number ILS_LOCALIZER ILS localizer
|
||||
-- @field #number ILS_GLIDESLOPE ILS glide slope.
|
||||
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
||||
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
|
||||
-- @field #number BROADCAST_STATION Broadcast station.
|
||||
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omni-directional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
||||
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
||||
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
||||
-- @field #number ICLS_LOCALIZER Carrier landing system.
|
||||
-- @field #number ICLS_GLIDESLOPE Carrier landing system.
|
||||
BEACON.System={
|
||||
PAR_10 = 1,
|
||||
RSBN_5 = 2,
|
||||
TACAN = 3,
|
||||
PAR_10 = 1,
|
||||
RSBN_5 = 2,
|
||||
TACAN = 3,
|
||||
TACAN_TANKER_X = 4,
|
||||
TACAN_TANKER_Y = 5,
|
||||
VOR = 6,
|
||||
ILS_LOCALIZER = 7,
|
||||
VOR = 6,
|
||||
ILS_LOCALIZER = 7,
|
||||
ILS_GLIDESLOPE = 8,
|
||||
PRMG_LOCALIZER = 9,
|
||||
PRMG_GLIDESLOPE = 10,
|
||||
@@ -131,27 +131,28 @@ BEACON.System={
|
||||
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
||||
-- @param #BEACON self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
||||
-- @return #BEACON Beacon object or #nil if the POSITIONABLE is invalid.
|
||||
function BEACON:New( Positionable )
|
||||
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
|
||||
function BEACON:New(Positionable)
|
||||
|
||||
-- Inherit BASE.
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #BEACON
|
||||
|
||||
local self=BASE:Inherit(self, BASE:New()) --#BEACON
|
||||
|
||||
-- Debug.
|
||||
self:F( Positionable )
|
||||
|
||||
self:F(Positionable)
|
||||
|
||||
-- Set positionable.
|
||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure POSITIONABLE is valid
|
||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||
self.Positionable = Positionable
|
||||
self.name = Positionable:GetName()
|
||||
self:I( string.format( "New BEACON %s", tostring( self.name ) ) )
|
||||
self.name=Positionable:GetName()
|
||||
self:I(string.format("New BEACON %s", tostring(self.name)))
|
||||
return self
|
||||
end
|
||||
|
||||
self:E( { "The passed POSITIONABLE is invalid, no BEACON created", Positionable } )
|
||||
|
||||
self:E({"The passed positionable is invalid, no BEACON created", Positionable})
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Activates a TACAN BEACON.
|
||||
-- @param #BEACON self
|
||||
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
|
||||
@@ -161,55 +162,60 @@ end
|
||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||
-- @return #BEACON self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Let's create a TACAN Beacon for a tanker
|
||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||
--
|
||||
--
|
||||
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
||||
--
|
||||
function BEACON:ActivateTACAN( Channel, Mode, Message, Bearing, Duration )
|
||||
self:T( { channel = Channel, mode = Mode, callsign = Message, bearing = Bearing, duration = Duration } )
|
||||
|
||||
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
||||
|
||||
Mode=Mode or "Y"
|
||||
|
||||
-- Get frequency.
|
||||
local Frequency = UTILS.TACANToFrequency( Channel, Mode )
|
||||
|
||||
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
|
||||
|
||||
-- Check.
|
||||
if not Frequency then
|
||||
self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
|
||||
if not Frequency then
|
||||
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
-- Beacon type.
|
||||
local Type = BEACON.Type.TACAN
|
||||
|
||||
local Type=BEACON.Type.TACAN
|
||||
|
||||
-- Beacon system.
|
||||
local System = BEACON.System.TACAN
|
||||
|
||||
local System=BEACON.System.TACAN
|
||||
|
||||
-- Check if unit is an aircraft and set system accordingly.
|
||||
local AA = self.Positionable:IsAir()
|
||||
local AA=self.Positionable:IsAir()
|
||||
|
||||
|
||||
if AA then
|
||||
System = 5 -- NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||
-- Check if "Y" mode is selected for aircraft.
|
||||
if Mode ~= "Y" then
|
||||
self:E( { "WARNING: The POSITIONABLE you want to attach the AA TACAN Beacon is an aircraft: Mode should Y! The BEACON is not emitting.", self.Positionable } )
|
||||
if Mode=="X" then
|
||||
--self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y!", self.Positionable})
|
||||
System=BEACON.System.TACAN_TANKER_X
|
||||
else
|
||||
System=BEACON.System.TACAN_TANKER_Y
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID = self.Positionable:GetID()
|
||||
|
||||
local UnitID=self.Positionable:GetID()
|
||||
|
||||
-- Debug.
|
||||
self:I( { string.format( "BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring( self.name ), Channel, Mode, Message, tostring( Bearing ), tostring( Duration ) ) } )
|
||||
|
||||
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))})
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateBeacon( Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing )
|
||||
|
||||
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
|
||||
|
||||
-- Stop scheduler.
|
||||
if Duration then
|
||||
self.Positionable:DeactivateBeacon( Duration )
|
||||
self.Positionable:DeactivateBeacon(Duration)
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -219,27 +225,28 @@ end
|
||||
-- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon.
|
||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||
-- @return #BEACON self
|
||||
function BEACON:ActivateICLS( Channel, Callsign, Duration )
|
||||
self:F( { Channel = Channel, Callsign = Callsign, Duration = Duration } )
|
||||
|
||||
function BEACON:ActivateICLS(Channel, Callsign, Duration)
|
||||
self:F({Channel=Channel, Callsign=Callsign, Duration=Duration})
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID = self.Positionable:GetID()
|
||||
|
||||
local UnitID=self.Positionable:GetID()
|
||||
|
||||
-- Debug
|
||||
self:T2( { "ICLS BEACON started!" } )
|
||||
|
||||
self:T2({"ICLS BEACON started!"})
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateICLS( Channel, UnitID, Callsign )
|
||||
|
||||
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign)
|
||||
|
||||
-- Stop scheduler
|
||||
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
self.Positionable:DeactivateBeacon( Duration )
|
||||
self.Positionable:DeactivateBeacon(Duration)
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Activates a TACAN BEACON on an Aircraft.
|
||||
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
|
||||
-- Activates a TACAN BEACON on an Aircraft.
|
||||
-- @param #BEACON self
|
||||
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
|
||||
-- @param #string Message The Message that is going to be coded in Morse and broadcasted by the beacon
|
||||
@@ -247,57 +254,58 @@ end
|
||||
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
|
||||
-- @return #BEACON self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Let's create a TACAN Beacon for a tanker
|
||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||
--
|
||||
--
|
||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||
--
|
||||
function BEACON:AATACAN( TACANChannel, Message, Bearing, BeaconDuration )
|
||||
self:F( { TACANChannel, Message, Bearing, BeaconDuration } )
|
||||
|
||||
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||
|
||||
local IsValid = true
|
||||
|
||||
|
||||
if not self.Positionable:IsAir() then
|
||||
self:E( { "The POSITIONABLE you want to attach the AA TACAN Beacon is not an aircraft! The BEACON is not emitting", self.Positionable } )
|
||||
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable})
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
local Frequency = self:_TACANToFrequency( TACANChannel, "Y" )
|
||||
if not Frequency then
|
||||
self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
|
||||
|
||||
local Frequency = self:_TACANToFrequency(TACANChannel, "Y")
|
||||
if not Frequency then
|
||||
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing
|
||||
-- or 14 (TACAN_AA_MODE_Y) if it does not
|
||||
|
||||
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing or 14 (TACAN_AA_MODE_Y) if it does not
|
||||
local System
|
||||
if Bearing then
|
||||
System = 5
|
||||
System = BEACON.System.TACAN_TANKER_Y
|
||||
else
|
||||
System = 14
|
||||
System = BEACON.System.TACAN_AA_MODE_Y
|
||||
end
|
||||
|
||||
|
||||
if IsValid then -- Starts the BEACON
|
||||
self:T2( { "AA TACAN BEACON started !" } )
|
||||
self.Positionable:SetCommand( {
|
||||
self:T2({"AA TACAN BEACON started !"})
|
||||
self.Positionable:SetCommand({
|
||||
id = "ActivateBeacon",
|
||||
params = {
|
||||
type = 4,
|
||||
type = BEACON.Type.TACAN,
|
||||
system = System,
|
||||
callsign = Message,
|
||||
AA = true,
|
||||
frequency = Frequency,
|
||||
},
|
||||
} )
|
||||
|
||||
bearing = Bearing,
|
||||
modeChannel = "Y",
|
||||
}
|
||||
})
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New( nil, function()
|
||||
SCHEDULER:New(nil,
|
||||
function()
|
||||
self:StopAATACAN()
|
||||
end, {}, BeaconDuration )
|
||||
end, {}, BeaconDuration)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -307,19 +315,21 @@ end
|
||||
function BEACON:StopAATACAN()
|
||||
self:F()
|
||||
if not self.Positionable then
|
||||
self:E( { "Start the beacon first before stopping it!" } )
|
||||
self:E({"Start the beacon first before stoping it !"})
|
||||
else
|
||||
self.Positionable:SetCommand( {
|
||||
id = 'DeactivateBeacon',
|
||||
params = {},
|
||||
} )
|
||||
self.Positionable:SetCommand({
|
||||
id = 'DeactivateBeacon',
|
||||
params = {
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Activates a general purpose Radio Beacon
|
||||
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
||||
-- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8.
|
||||
-- They can home in on these specific frequencies :
|
||||
-- Although any frequency could be used, only a few DCS Modules can home on radio beacons at the time of writing, i.e. the Mi-8, Huey, Gazelle etc.
|
||||
-- The following e.g. can home in on these specific frequencies :
|
||||
-- * **Mi8**
|
||||
-- * R-828 -> 20-60MHz
|
||||
-- * ARKUD -> 100-150MHz (canal 1 : 114166, canal 2 : 114333, canal 3 : 114583, canal 4 : 121500, canal 5 : 123100, canal 6 : 124100) AM
|
||||
@@ -342,63 +352,64 @@ end
|
||||
--
|
||||
-- -- Set the beacon and start it
|
||||
-- UnitBeacon:RadioBeacon("MySoundFileSOS.ogg", 40, radio.modulation.FM, 20, 5*60)
|
||||
function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDuration )
|
||||
self:F( { FileName, Frequency, Modulation, Power, BeaconDuration } )
|
||||
function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDuration)
|
||||
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
|
||||
local IsValid = false
|
||||
|
||||
|
||||
-- Check the filename
|
||||
if type( FileName ) == "string" then
|
||||
if FileName:find( ".ogg" ) or FileName:find( ".wav" ) then
|
||||
if not FileName:find( "l10n/DEFAULT/" ) then
|
||||
if type(FileName) == "string" then
|
||||
if FileName:find(".ogg") or FileName:find(".wav") then
|
||||
if not FileName:find("l10n/DEFAULT/") then
|
||||
FileName = "l10n/DEFAULT/" .. FileName
|
||||
end
|
||||
IsValid = true
|
||||
end
|
||||
end
|
||||
if not IsValid then
|
||||
self:E( { "File name invalid. Maybe something wrong with the extension? ", FileName } )
|
||||
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName})
|
||||
end
|
||||
|
||||
|
||||
-- Check the Frequency
|
||||
if type( Frequency ) ~= "number" and IsValid then
|
||||
self:E( { "Frequency invalid. ", Frequency } )
|
||||
if type(Frequency) ~= "number" and IsValid then
|
||||
self:E({"Frequency invalid. ", Frequency})
|
||||
IsValid = false
|
||||
end
|
||||
Frequency = Frequency * 1000000 -- Conversion to Hz
|
||||
|
||||
|
||||
-- Check the modulation
|
||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then -- TODO: Maybe make this future proof if ED decides to add an other modulation ?
|
||||
self:E( { "Modulation is invalid. Use DCS's enum radio.modulation.", Modulation } )
|
||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ?
|
||||
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
|
||||
-- Check the Power
|
||||
if type( Power ) ~= "number" and IsValid then
|
||||
self:E( { "Power is invalid. ", Power } )
|
||||
if type(Power) ~= "number" and IsValid then
|
||||
self:E({"Power is invalid. ", Power})
|
||||
IsValid = false
|
||||
end
|
||||
Power = math.floor( math.abs( Power ) ) -- TODO: Find what is the maximum power allowed by DCS and limit power to that
|
||||
|
||||
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
||||
|
||||
if IsValid then
|
||||
self:T2( { "Activating Beacon on ", Frequency, Modulation } )
|
||||
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
||||
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
||||
trigger.action.radioTransmission( FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring( self.ID ) )
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New( nil, function()
|
||||
self:StopRadioBeacon()
|
||||
end, {}, BeaconDuration )
|
||||
end
|
||||
end
|
||||
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New( nil,
|
||||
function()
|
||||
self:StopRadioBeacon()
|
||||
end, {}, BeaconDuration)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Stops the AA TACAN BEACON
|
||||
--- Stop the Radio Beacon
|
||||
-- @param #BEACON self
|
||||
-- @return #BEACON self
|
||||
function BEACON:StopRadioBeacon()
|
||||
self:F()
|
||||
-- The unique name of the transmission is the class ID
|
||||
trigger.action.stopRadioTransmission( tostring( self.ID ) )
|
||||
trigger.action.stopRadioTransmission(tostring(self.ID))
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -406,26 +417,26 @@ end
|
||||
-- @param #BEACON self
|
||||
-- @param #number TACANChannel
|
||||
-- @param #string TACANMode
|
||||
-- @return #number Frequency
|
||||
-- @return #number Frequecy
|
||||
-- @return #nil if parameters are invalid
|
||||
function BEACON:_TACANToFrequency( TACANChannel, TACANMode )
|
||||
self:F3( { TACANChannel, TACANMode } )
|
||||
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||
self:F3({TACANChannel, TACANMode})
|
||||
|
||||
if type( TACANChannel ) ~= "number" then
|
||||
if type(TACANChannel) ~= "number" then
|
||||
if TACANMode ~= "X" and TACANMode ~= "Y" then
|
||||
return nil -- error in arguments
|
||||
end
|
||||
end
|
||||
|
||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||
-- I have no idea what it does but it seems to work
|
||||
|
||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||
-- I have no idea what it does but it seems to work
|
||||
local A = 1151 -- 'X', channel >= 64
|
||||
local B = 64 -- channel >= 64
|
||||
|
||||
local B = 64 -- channel >= 64
|
||||
|
||||
if TACANChannel < 64 then
|
||||
B = 1
|
||||
end
|
||||
|
||||
|
||||
if TACANMode == 'Y' then
|
||||
A = 1025
|
||||
if TACANChannel < 64 then
|
||||
@@ -436,6 +447,6 @@ function BEACON:_TACANToFrequency( TACANChannel, TACANMode )
|
||||
A = 962
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return (A + TACANChannel - B) * 1000000
|
||||
end
|
||||
|
||||
@@ -2769,8 +2769,11 @@ do -- COORDINATE
|
||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||
-- @param #boolean Bogey Add "Bogey" at the end if true (not yet declared hostile or friendly)
|
||||
-- @param #boolean Spades Add "Spades" at the end if true (no IFF/VID ID yet known)
|
||||
-- @param #boolean SSML Add SSML tags speaking aspect as 0 1 2 and "brah" instead of BRAA
|
||||
-- @param #boolean Angels If true, altitude is e.g. "Angels 25" (i.e., a friendly plane), else "25 thousand"
|
||||
-- @param #boolean Zeros If using SSML, be aware that Google TTS will say "oh" and not "zero" for "0"; if Zeros is set to true, "0" will be replaced with "zero"
|
||||
-- @return #string The BRAA text.
|
||||
function COORDINATE:ToStringBRAANATO(FromCoordinate,Bogey,Spades)
|
||||
function COORDINATE:ToStringBRAANATO(FromCoordinate,Bogey,Spades,SSML,Angels,Zeros)
|
||||
|
||||
-- Thanks to @Pikey
|
||||
local BRAANATO = "Merged."
|
||||
@@ -2788,25 +2791,64 @@ do -- COORDINATE
|
||||
|
||||
local alt = UTILS.Round(UTILS.MetersToFeet(self.y)/1000,0)--*1000
|
||||
|
||||
local alttext = string.format("%d thousand",alt)
|
||||
|
||||
if Angels then
|
||||
alttext = string.format("Angels %d",alt)
|
||||
end
|
||||
|
||||
if alt < 1 then
|
||||
alttext = "very low"
|
||||
end
|
||||
|
||||
local track = UTILS.BearingToCardinal(bearing) or "North"
|
||||
|
||||
if rangeNM > 3 then
|
||||
if aspect == "" then
|
||||
BRAANATO = string.format("BRA, %03d, %d miles, Angels %d, Track %s",bearing, rangeNM, alt, track)
|
||||
if SSML then -- google says "oh" instead of zero, be aware
|
||||
if Zeros then
|
||||
bearing = string.format("%03d",bearing)
|
||||
local AngleDegText = string.gsub(bearing,"%d","%1 ") -- "0 5 1 "
|
||||
AngleDegText = string.gsub(AngleDegText," $","") -- "0 5 1"
|
||||
AngleDegText = string.gsub(AngleDegText,"0","zero")
|
||||
if aspect == "" then
|
||||
BRAANATO = string.format("brah %s, %d miles, %s, Track %s", AngleDegText, rangeNM, alttext, track)
|
||||
else
|
||||
BRAANATO = string.format("brah %s, %d miles, %s, %s, Track %s", AngleDegText, rangeNM, alttext, aspect, track)
|
||||
end
|
||||
else
|
||||
if aspect == "" then
|
||||
BRAANATO = string.format("brah <say-as interpret-as='characters'>%03d</say-as>, %d miles, %s, Track %s", bearing, rangeNM, alttext, track)
|
||||
else
|
||||
BRAANATO = string.format("brah <say-as interpret-as='characters'>%03d</say-as>, %d miles, %s, %s, Track %s", bearing, rangeNM, alttext, aspect, track)
|
||||
end
|
||||
end
|
||||
if Bogey and Spades then
|
||||
BRAANATO = BRAANATO..", Bogey, Spades."
|
||||
elseif Bogey then
|
||||
BRAANATO = BRAANATO..", Bogey."
|
||||
elseif Spades then
|
||||
BRAANATO = BRAANATO..", Spades."
|
||||
else
|
||||
BRAANATO = BRAANATO.."."
|
||||
end
|
||||
else
|
||||
BRAANATO = string.format("BRAA, %03d, %d miles, Angels %d, %s, Track %s",bearing, rangeNM, alt, aspect, track)
|
||||
end
|
||||
if Bogey and Spades then
|
||||
BRAANATO = BRAANATO..", Bogey, Spades."
|
||||
elseif Bogey then
|
||||
BRAANATO = BRAANATO..", Bogey."
|
||||
elseif Spades then
|
||||
BRAANATO = BRAANATO..", Spades."
|
||||
else
|
||||
BRAANATO = BRAANATO.."."
|
||||
if aspect == "" then
|
||||
BRAANATO = string.format("BRA %03d, %d miles, %s, Track %s",bearing, rangeNM, alttext, track)
|
||||
else
|
||||
BRAANATO = string.format("BRAA %03d, %d miles, %s, %s, Track %s",bearing, rangeNM, alttext, aspect, track)
|
||||
end
|
||||
if Bogey and Spades then
|
||||
BRAANATO = BRAANATO..", Bogey, Spades."
|
||||
elseif Bogey then
|
||||
BRAANATO = BRAANATO..", Bogey."
|
||||
elseif Spades then
|
||||
BRAANATO = BRAANATO..", Spades."
|
||||
else
|
||||
BRAANATO = BRAANATO.."."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return BRAANATO
|
||||
end
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SCH%20-%20Scheduler)
|
||||
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||
--
|
||||
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||
--
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPA%20-%20Spawning)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -11210,7 +11210,7 @@ end
|
||||
|
||||
--- Get wind direction and speed at carrier position.
|
||||
-- @param #AIRBOSS self
|
||||
-- @param #number alt Altitude ASL in meters. Default 50 m.
|
||||
-- @param #number alt Altitude ASL in meters. Default 15 m.
|
||||
-- @param #boolean magnetic Direction including magnetic declination.
|
||||
-- @param Core.Point#COORDINATE coord (Optional) Coordinate at which to get the wind. Default is current carrier position.
|
||||
-- @return #number Direction the wind is blowing **from** in degrees.
|
||||
@@ -11220,8 +11220,8 @@ function AIRBOSS:GetWind( alt, magnetic, coord )
|
||||
-- Current position of the carrier or input.
|
||||
local cv = coord or self:GetCoordinate()
|
||||
|
||||
-- Wind direction and speed. By default at 50 meters ASL.
|
||||
local Wdir, Wspeed = cv:GetWind( alt or 50 )
|
||||
-- Wind direction and speed. By default at 15 meters ASL.
|
||||
local Wdir, Wspeed = cv:GetWind( alt or 15 )
|
||||
|
||||
-- Include magnetic declination.
|
||||
if magnetic then
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
-- @module Ops.CSAR
|
||||
-- @image OPS_CSAR.jpg
|
||||
|
||||
-- Date: Feb 2022
|
||||
-- Date: June 2022
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||
@@ -76,65 +76,69 @@
|
||||
--
|
||||
-- The following options are available (with their defaults). Only set the ones you want changed:
|
||||
--
|
||||
-- self.allowDownedPilotCAcontrol = false -- Set to false if you don\'t want to allow control by Combined Arms.
|
||||
-- self.allowFARPRescue = true -- allows pilots to be rescued by landing at a FARP or Airbase. Else MASH only!
|
||||
-- self.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued.
|
||||
-- self.autosmoke = false -- automatically smoke a downed pilot\'s location when a heli is near.
|
||||
-- self.autosmokedistance = 1000 -- distance for autosmoke
|
||||
-- self.coordtype = 1 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates.
|
||||
-- self.csarOncrash = false -- (WIP) If set to true, will generate a downed pilot when a plane crashes as well.
|
||||
-- self.enableForAI = false -- set to false to disable AI pilots from being rescued.
|
||||
-- self.pilotRuntoExtractPoint = true -- Downed pilot will run to the rescue helicopter up to self.extractDistance in meters.
|
||||
-- self.extractDistance = 500 -- Distance the downed pilot will start to run to the rescue helicopter.
|
||||
-- self.immortalcrew = true -- Set to true to make wounded crew immortal.
|
||||
-- self.invisiblecrew = false -- Set to true to make wounded crew insvisible.
|
||||
-- self.loadDistance = 75 -- configure distance for pilots to get into helicopter in meters.
|
||||
-- self.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes.
|
||||
-- self.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined.
|
||||
-- self.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages.
|
||||
-- self.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons.
|
||||
-- self.smokecolor = 4 -- Color of smokemarker, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue.
|
||||
-- self.useprefix = true -- Requires CSAR helicopter #GROUP names to have the prefix(es) defined below.
|
||||
-- self.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor!
|
||||
-- self.verbose = 0 -- set to > 1 for stats output for debugging.
|
||||
-- mycsar.allowDownedPilotCAcontrol = false -- Set to false if you don\'t want to allow control by Combined Arms.
|
||||
-- mycsar.allowFARPRescue = true -- allows pilots to be rescued by landing at a FARP or Airbase. Else MASH only!
|
||||
-- mycsar.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued.
|
||||
-- mycsar.autosmoke = false -- automatically smoke a downed pilot\'s location when a heli is near.
|
||||
-- mycsar.autosmokedistance = 1000 -- distance for autosmoke
|
||||
-- mycsar.coordtype = 1 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates.
|
||||
-- mycsar.csarOncrash = false -- (WIP) If set to true, will generate a downed pilot when a plane crashes as well.
|
||||
-- mycsar.enableForAI = false -- set to false to disable AI pilots from being rescued.
|
||||
-- mycsar.pilotRuntoExtractPoint = true -- Downed pilot will run to the rescue helicopter up to mycsar.extractDistance in meters.
|
||||
-- mycsar.extractDistance = 500 -- Distance the downed pilot will start to run to the rescue helicopter.
|
||||
-- mycsar.immortalcrew = true -- Set to true to make wounded crew immortal.
|
||||
-- mycsar.invisiblecrew = false -- Set to true to make wounded crew insvisible.
|
||||
-- mycsar.loadDistance = 75 -- configure distance for pilots to get into helicopter in meters.
|
||||
-- mycsar.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes.
|
||||
-- mycsar.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined.
|
||||
-- mycsar.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages.
|
||||
-- mycsar.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons.
|
||||
-- mycsar.smokecolor = 4 -- Color of smokemarker, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue.
|
||||
-- mycsar.useprefix = true -- Requires CSAR helicopter #GROUP names to have the prefix(es) defined below.
|
||||
-- mycsar.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor!
|
||||
-- mycsar.verbose = 0 -- set to > 1 for stats output for debugging.
|
||||
-- -- (added 0.1.4) limit amount of downed pilots spawned by **ejection** events
|
||||
-- self.limitmaxdownedpilots = true
|
||||
-- self.maxdownedpilots = 10
|
||||
-- mycsar.limitmaxdownedpilots = true
|
||||
-- mycsar.maxdownedpilots = 10
|
||||
-- -- (added 0.1.8) - allow to set far/near distance for approach and optionally pilot must open doors
|
||||
-- self.approachdist_far = 5000 -- switch do 10 sec interval approach mode, meters
|
||||
-- self.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
|
||||
-- self.pilotmustopendoors = false -- switch to true to enable check of open doors
|
||||
-- mycsar.approachdist_far = 5000 -- switch do 10 sec interval approach mode, meters
|
||||
-- mycsar.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
|
||||
-- mycsar.pilotmustopendoors = false -- switch to true to enable check of open doors
|
||||
-- -- (added 0.1.9)
|
||||
-- self.suppressmessages = false -- switch off all messaging if you want to do your own
|
||||
-- mycsar.suppressmessages = false -- switch off all messaging if you want to do your own
|
||||
-- -- (added 0.1.11)
|
||||
-- self.rescuehoverheight = 20 -- max height for a hovering rescue in meters
|
||||
-- self.rescuehoverdistance = 10 -- max distance for a hovering rescue in meters
|
||||
-- mycsar.rescuehoverheight = 20 -- max height for a hovering rescue in meters
|
||||
-- mycsar.rescuehoverdistance = 10 -- max distance for a hovering rescue in meters
|
||||
-- -- (added 0.1.12)
|
||||
-- -- Country codes for spawned pilots
|
||||
-- self.countryblue= country.id.USA
|
||||
-- self.countryred = country.id.RUSSIA
|
||||
-- self.countryneutral = country.id.UN_PEACEKEEPERS
|
||||
-- mycsar.countryblue= country.id.USA
|
||||
-- mycsar.countryred = country.id.RUSSIA
|
||||
-- mycsar.countryneutral = country.id.UN_PEACEKEEPERS
|
||||
--
|
||||
-- ## 2.1 Experimental Features
|
||||
--
|
||||
-- WARNING - Here\'ll be dragons!
|
||||
-- DANGER - For this to work you need to de-sanitize your mission environment (all three entries) in <DCS root>\Scripts\MissionScripting.lua
|
||||
-- Needs SRS => 1.9.6 to work (works on the **server** side of SRS)
|
||||
-- self.useSRS = false -- Set true to use FF\'s SRS integration
|
||||
-- self.SRSPath = "E:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
||||
-- self.SRSchannel = 300 -- radio channel
|
||||
-- self.SRSModulation = radio.modulation.AM -- modulation
|
||||
-- self.SRSport = 5002 -- and SRS port
|
||||
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
|
||||
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
||||
-- mycsar.SRSchannel = 300 -- radio channel
|
||||
-- mycsar.SRSModulation = radio.modulation.AM -- modulation
|
||||
-- mycsar.SRSport = 5002 -- and SRS Server port
|
||||
-- mycsar.SRSCulture = "en-GB" -- SRS voice culture
|
||||
-- mycsar.SRSVoice = nil -- SRS voice, relevant for Google TTS
|
||||
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS
|
||||
-- mycsar.SRSVolume = 1 -- Volume, between 0 and 1
|
||||
-- --
|
||||
-- self.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection --shagrat
|
||||
-- self.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
||||
-- mycsar.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection. Requires mycsar.enableForAI to be set to true. --shagrat
|
||||
-- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
||||
--
|
||||
-- ## 3. Results
|
||||
--
|
||||
-- Number of successful landings with save pilots and aggregated number of saved pilots is stored in these variables in the object:
|
||||
--
|
||||
-- self.rescues -- number of successful landings *with* saved pilots
|
||||
-- self.rescuedpilots -- aggregated number of pilots rescued from the field (of *all* players)
|
||||
-- mycsar.rescues -- number of successful landings *with* saved pilots
|
||||
-- mycsar.rescuedpilots -- aggregated number of pilots rescued from the field (of *all* players)
|
||||
--
|
||||
-- ## 4. Events
|
||||
--
|
||||
@@ -260,7 +264,7 @@ CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
||||
|
||||
--- CSAR class version.
|
||||
-- @field #string version
|
||||
CSAR.version="1.0.4e"
|
||||
CSAR.version="1.0.5"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
@@ -415,6 +419,10 @@ function CSAR:New(Coalition, Template, Alias)
|
||||
self.SRSchannel = 300 -- radio channel
|
||||
self.SRSModulation = radio.modulation.AM -- modulation
|
||||
self.SRSport = 5002 -- port
|
||||
self.SRSCulture = "en-GB"
|
||||
self.SRSVoice = nil
|
||||
self.SRSGPathToCredentials = nil
|
||||
self.SRSVolume = 1
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
@@ -861,12 +869,12 @@ function CSAR:_EventHandler(EventData)
|
||||
|
||||
-- no Player
|
||||
if self.enableForAI == false and _event.IniPlayerName == nil then
|
||||
return
|
||||
return self
|
||||
end
|
||||
|
||||
-- no event
|
||||
if _event == nil or _event.initiator == nil then
|
||||
return false
|
||||
return self
|
||||
|
||||
-- take off
|
||||
elseif _event.id == EVENTS.Takeoff then -- taken off
|
||||
@@ -874,35 +882,43 @@ function CSAR:_EventHandler(EventData)
|
||||
|
||||
local _coalition = _event.IniCoalition
|
||||
if _coalition ~= self.coalition then
|
||||
return --ignore!
|
||||
return self --ignore!
|
||||
end
|
||||
|
||||
if _event.IniGroupName then
|
||||
self.takenOff[_event.IniUnitName] = true
|
||||
end
|
||||
|
||||
return true
|
||||
return self
|
||||
|
||||
-- player enter unit
|
||||
elseif _event.id == EVENTS.PlayerEnterAircraft or _event.id == EVENTS.PlayerEnterUnit then --player entered unit
|
||||
self:T(self.lid .. " Event unit - Player Enter")
|
||||
|
||||
local _coalition = _event.IniCoalition
|
||||
self:T("Coalition = "..UTILS.GetCoalitionName(_coalition))
|
||||
if _coalition ~= self.coalition then
|
||||
return --ignore!
|
||||
return self --ignore!
|
||||
end
|
||||
|
||||
if _event.IniPlayerName then
|
||||
self.takenOff[_event.IniPlayerName] = nil
|
||||
end
|
||||
|
||||
-- jumped into flying plane?
|
||||
self:T("Taken Off: "..tostring(_event.IniUnit:InAir(true)))
|
||||
|
||||
if _event.IniUnit:InAir(true) then
|
||||
self.takenOff[_event.IniPlayerName] = true
|
||||
end
|
||||
|
||||
local _unit = _event.IniUnit
|
||||
local _group = _event.IniGroup
|
||||
if _unit:IsHelicopter() or _group:IsHelicopter() then
|
||||
self:_AddMedevacMenuItem()
|
||||
end
|
||||
|
||||
return true
|
||||
return self
|
||||
|
||||
elseif (_event.id == EVENTS.PilotDead and self.csarOncrash == false) then
|
||||
-- Pilot dead
|
||||
@@ -914,57 +930,68 @@ function CSAR:_EventHandler(EventData)
|
||||
local _group = _event.IniGroup
|
||||
|
||||
if _unit == nil then
|
||||
return -- error!
|
||||
return self -- error!
|
||||
end
|
||||
|
||||
local _coalition = _event.IniCoalition
|
||||
if _coalition ~= self.coalition then
|
||||
return --ignore!
|
||||
return self --ignore!
|
||||
end
|
||||
|
||||
-- Catch multiple events here?
|
||||
if self.takenOff[_event.IniUnitName] == true or _group:IsAirborne() then
|
||||
if self:_DoubleEjection(_unitname) then
|
||||
return
|
||||
return self
|
||||
end
|
||||
|
||||
else
|
||||
self:T(self.lid .. " Pilot has not taken off, ignore")
|
||||
end
|
||||
|
||||
return
|
||||
return self
|
||||
|
||||
elseif _event.id == EVENTS.PilotDead or _event.id == EVENTS.Ejection then
|
||||
if _event.id == EVENTS.PilotDead and self.csarOncrash == false then
|
||||
return
|
||||
return self
|
||||
end
|
||||
self:T(self.lid .. " Event unit - Pilot Ejected")
|
||||
|
||||
local _unit = _event.IniUnit
|
||||
local _unitname = _event.IniUnitName
|
||||
local _group = _event.IniGroup
|
||||
|
||||
self:T({_unit.UnitName, _unitname, _group.GroupName})
|
||||
|
||||
if _unit == nil then
|
||||
return -- error!
|
||||
self:T("Unit NIL!")
|
||||
return self -- error!
|
||||
end
|
||||
|
||||
local _coalition = _unit:GetCoalition()
|
||||
--local _coalition = _unit:GetCoalition() -- nil now for some reason
|
||||
local _coalition = _group:GetCoalition()
|
||||
if _coalition ~= self.coalition then
|
||||
return --ignore!
|
||||
self:T("Wrong coalition! Coalition = "..UTILS.GetCoalitionName(_coalition))
|
||||
return self --ignore!
|
||||
end
|
||||
|
||||
|
||||
|
||||
self:T("Airborne: "..tostring(_group:IsAirborne()))
|
||||
self:T("Taken Off: "..tostring(self.takenOff[_event.IniUnitName]))
|
||||
|
||||
if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then
|
||||
self:T(self.lid .. " Pilot has not taken off, ignore")
|
||||
return -- give up, pilot hasnt taken off
|
||||
-- return self -- give up, pilot hasnt taken off
|
||||
end
|
||||
|
||||
if self:_DoubleEjection(_unitname) then
|
||||
return
|
||||
self:T("Double Ejection!")
|
||||
return self
|
||||
end
|
||||
|
||||
-- limit no of pilots in the field.
|
||||
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
||||
return
|
||||
self:T("Maxed Downed Pilot!")
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -973,33 +1000,27 @@ function CSAR:_EventHandler(EventData)
|
||||
|
||||
local wetfeet = false
|
||||
|
||||
local surface = _unit:GetCoordinate():GetSurfaceType()
|
||||
local initdcscoord = nil
|
||||
local initcoord = nil
|
||||
--if _event.id == EVENTS.Ejection then
|
||||
initdcscoord = _event.TgtDCSUnit:getPoint()
|
||||
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
||||
self:T({initdcscoord})
|
||||
--end
|
||||
|
||||
--local surface = _unit:GetCoordinate():GetSurfaceType()
|
||||
local surface = initcoord:GetSurfaceType()
|
||||
|
||||
if surface == land.SurfaceType.WATER then
|
||||
self:T("Wet feet!")
|
||||
wetfeet = true
|
||||
end
|
||||
-- all checks passed, get going.
|
||||
if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land
|
||||
local _freq = self:_GenerateADFFrequency()
|
||||
self:_AddCsar(_coalition, _unit:GetCountry(), _unit:GetCoordinate() , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
|
||||
return true
|
||||
end
|
||||
|
||||
---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location
|
||||
elseif (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then
|
||||
self:I({EVENT=_event})
|
||||
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
||||
local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute'
|
||||
local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot"
|
||||
local _country = _event.initiator:getCountry()
|
||||
local _coalition = coalition.getCountryCoalition( _country )
|
||||
if _coalition == self.coalition then
|
||||
local _freq = self:_GenerateADFFrequency()
|
||||
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
|
||||
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location.
|
||||
|
||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||
end
|
||||
return true
|
||||
self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
|
||||
return self
|
||||
end
|
||||
|
||||
elseif _event.id == EVENTS.Land then
|
||||
self:T(self.lid .. " Landing")
|
||||
@@ -1014,12 +1035,12 @@ function CSAR:_EventHandler(EventData)
|
||||
|
||||
if _unit == nil then
|
||||
self:T(self.lid .. " Unit nil on landing")
|
||||
return -- error!
|
||||
return self -- error!
|
||||
end
|
||||
|
||||
local _coalition = _event.IniCoalition
|
||||
if _coalition ~= self.coalition then
|
||||
return --ignore!
|
||||
return self --ignore!
|
||||
end
|
||||
|
||||
self.takenOff[_event.IniUnitName] = nil
|
||||
@@ -1028,13 +1049,13 @@ function CSAR:_EventHandler(EventData)
|
||||
|
||||
if _place == nil then
|
||||
self:T(self.lid .. " Landing Place Nil")
|
||||
return -- error!
|
||||
return self -- error!
|
||||
end
|
||||
|
||||
-- anyone on board?
|
||||
if self.inTransitGroups[_event.IniUnitName] == nil then
|
||||
-- ignore
|
||||
return
|
||||
return self
|
||||
end
|
||||
|
||||
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
||||
@@ -1044,8 +1065,27 @@ function CSAR:_EventHandler(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
return self
|
||||
end
|
||||
|
||||
---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location
|
||||
if (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then
|
||||
self:T("LANDING_AFTER_EJECTION")
|
||||
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
||||
local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute'
|
||||
local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot"
|
||||
local _country = _event.initiator:getCountry()
|
||||
local _coalition = coalition.getCountryCoalition( _country )
|
||||
self:T("Country = ".._country.." Coalition = ".._coalition)
|
||||
if _coalition == self.coalition then
|
||||
local _freq = self:_GenerateADFFrequency()
|
||||
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
|
||||
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location.
|
||||
|
||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1240,7 +1280,7 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
|
||||
_maxUnits = self.max_units
|
||||
end
|
||||
if _unitsInHelicopter + 1 > _maxUnits then
|
||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, _heliName, _unitsInHelicopter, _unitsInHelicopter), self.messageTime)
|
||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, _heliName, _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -1328,7 +1368,8 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
||||
local _time = self.landedStatus[_lookupKeyHeli]
|
||||
if _time == nil then
|
||||
self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 )
|
||||
_time = self.landedStatus[_lookupKeyHeli]
|
||||
_time = self.landedStatus[_lookupKeyHeli]
|
||||
_woundedGroup:OptionAlarmStateGreen()
|
||||
self:_OrderGroupToMoveToPoint(_woundedGroup, _heliUnit:GetCoordinate())
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Wait till " .. _pilotName .. " gets in. \nETA " .. _time .. " more seconds.", self.messageTime, false)
|
||||
else
|
||||
@@ -1338,7 +1379,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
||||
--if _time <= 0 or _distance < self.loadDistance then
|
||||
if _distance < self.loadDistance + 5 or _distance <= 13 then
|
||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||
return true
|
||||
else
|
||||
self.landedStatus[_lookupKeyHeli] = nil
|
||||
@@ -1350,7 +1391,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
||||
else
|
||||
if (_distance < self.loadDistance) then
|
||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||
return true
|
||||
else
|
||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||
@@ -1392,7 +1433,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
|
||||
else
|
||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||
return true
|
||||
else
|
||||
self.hoverStatus[_lookupKeyHeli] = nil
|
||||
@@ -1451,7 +1492,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport)
|
||||
|
||||
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
|
||||
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true)
|
||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
|
||||
else
|
||||
self:_RescuePilots(_heliUnit)
|
||||
return
|
||||
@@ -1526,6 +1567,14 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
|
||||
local channel = self.SRSchannel
|
||||
local msrs = MSRS:New(path,channel,modulation)
|
||||
msrs:SetPort(self.SRSport)
|
||||
msrs:SetLabel("CSAR")
|
||||
msrs:SetCulture(self.SRSCulture)
|
||||
msrs:SetCoalition(self.coalition)
|
||||
msrs:SetVoice(self.SRSVoice)
|
||||
if self.SRSGPathToCredentials then
|
||||
msrs:SetGoogle(self.SRSGPathToCredentials)
|
||||
end
|
||||
msrs:SetVolume(self.SRSVolume)
|
||||
msrs:PlaySoundText(srstext, 2)
|
||||
end
|
||||
return self
|
||||
|
||||
@@ -722,7 +722,8 @@ do
|
||||
-- ["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
|
||||
-- ["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
|
||||
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000},
|
||||
-- ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500},
|
||||
-- ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500},
|
||||
-- ["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200},
|
||||
--
|
||||
-- ### 2.1.2 Activate and deactivate zones
|
||||
--
|
||||
@@ -870,12 +871,13 @@ do
|
||||
--
|
||||
-- ## 5. Support for Hercules mod by Anubis
|
||||
--
|
||||
-- Basic support for the Hercules mod By Anubis has been build into CTLD - that is you can load/drop/build the same objects as the helicopters.
|
||||
-- To also cover objects and troops which can be loaded from the groud crew Rearm/Refuel menu, you need to use @{#CTLD_HERCULES.New}() and link
|
||||
-- this object to your CTLD setup. In this case, do **not** use the `Hercules_Cargo.lua` or `Hercules_Cargo_CTLD.lua` which are part of the mod
|
||||
-- Basic support for the Hercules mod By Anubis has been build into CTLD - that is you can load/drop/build the same way and for the same objects as
|
||||
-- the helicopters (main method).
|
||||
-- To cover objects and troops which can be loaded from the groud crew Rearm/Refuel menu (F8), you need to use @{#CTLD_HERCULES.New}() and link
|
||||
-- this object to your CTLD setup (alternative method). In this case, do **not** use the `Hercules_Cargo.lua` or `Hercules_Cargo_CTLD.lua` which are part of the mod
|
||||
-- in your mission!
|
||||
--
|
||||
-- ### 5.1 Create an own CTLD instance and allow the usage of the Hercules mod:
|
||||
-- ### 5.1 Create an own CTLD instance and allow the usage of the Hercules mod (main method)
|
||||
--
|
||||
-- local my_ctld = CTLD:New(coalition.side.BLUE,{"Helicargo", "Hercules"},"Lufttransportbrigade I")
|
||||
--
|
||||
@@ -893,26 +895,38 @@ do
|
||||
--
|
||||
-- my_ctld.useprefix = true -- this is true by default and MUST BE ON.
|
||||
--
|
||||
-- ### 5.2 Integrate Hercules ground crew loadable objects
|
||||
--
|
||||
-- Add ground crew loadable objects to your CTLD instance like so, where `my_ctld` is the previously created CTLD instance:
|
||||
-- ### 5.2 Integrate Hercules ground crew (F8 Menu) loadable objects (alternative method)
|
||||
--
|
||||
-- Integrate to your CTLD instance like so, where `my_ctld` is a previously created CTLD instance:
|
||||
--
|
||||
-- my_ctld.enableHercules = false -- avoid dual loading via CTLD F10 and F8 ground crew
|
||||
-- local herccargo = CTLD_HERCULES:New("blue", "Hercules Test", my_ctld)
|
||||
--
|
||||
-- You also need:
|
||||
--
|
||||
-- * A template called "Infantry" for 10 Paratroopers (as set via herccargo.infantrytemplate).
|
||||
-- * Depending on what you are loading with the help of the ground crew, there are 42 more templates for the various vehicles that are loadable.
|
||||
-- You also need:
|
||||
--
|
||||
-- * A template called "Infantry" for 10 Paratroopers (as set via herccargo.infantrytemplate).
|
||||
-- * Depending on what you are loading with the help of the ground crew, there are 42 more templates for the various vehicles that are loadable.
|
||||
--
|
||||
-- There's a **quick check output in the `dcs.log`** which tells you what's there and what not.
|
||||
-- E.g.:
|
||||
-- ...Checking template for APC BTR-82A Air [24998lb] (BTR-82A) ... MISSING)
|
||||
-- ...Checking template for ART 2S9 NONA Skid [19030lb] (SAU 2-C9) ... MISSING)
|
||||
-- ...Checking template for EWR SBORKA Air [21624lb] (Dog Ear radar) ... MISSING)
|
||||
-- ...Checking template for Transport Tigr Air [15900lb] (Tigr_233036) ... OK)
|
||||
-- E.g.:
|
||||
--
|
||||
-- ...Checking template for APC BTR-82A Air [24998lb] (BTR-82A) ... MISSING)
|
||||
-- ...Checking template for ART 2S9 NONA Skid [19030lb] (SAU 2-C9) ... MISSING)
|
||||
-- ...Checking template for EWR SBORKA Air [21624lb] (Dog Ear radar) ... MISSING)
|
||||
-- ...Checking template for Transport Tigr Air [15900lb] (Tigr_233036) ... OK)
|
||||
--
|
||||
-- Expected template names are the ones in the rounded brackets.
|
||||
--
|
||||
-- ### 5.2.1 Hints
|
||||
--
|
||||
-- The script works on the EVENTS.Shot trigger, which is used by the mod when you **drop cargo from the Hercules while flying**. Unloading on the ground does
|
||||
-- not achieve anything here. If you just want to unload on the ground, use the normal Moose CTLD (see 5.1).
|
||||
--
|
||||
-- There are two ways of airdropping:
|
||||
--
|
||||
-- 1) Very low and very slow (>5m and <10m AGL) - here you can drop stuff which has "Skid" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||
-- 2) Higher up and slow (>100m AGL) - here you can drop paratroopers and cargo which has "Air" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||
--
|
||||
-- Standard transport capabilities as per the real Hercules are:
|
||||
--
|
||||
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64}, -- 19t cargo, 64 paratroopers
|
||||
@@ -4792,10 +4806,11 @@ end
|
||||
end -- end do
|
||||
|
||||
do
|
||||
--- Hercules Cargo Drop Events by Anubis Yinepu
|
||||
--- **Hercules Cargo AIR Drop Events** by Anubis Yinepu
|
||||
-- Moose CTLD OO refactoring by Applevangelist
|
||||
--
|
||||
-- This script will only work for the Herculus mod by Anubis
|
||||
-- This script will only work for the Herculus mod by Anubis, and only for **Air Dropping** cargo from the Hercules.
|
||||
-- Use the standard Moose CTLD if you want to unload on the ground.
|
||||
-- Payloads carried by pylons 11, 12 and 13 need to be declared in the Herculus_Loadout.lua file
|
||||
-- Except for Ammo pallets, this script will spawn whatever payload gets launched from pylons 11, 12 and 13
|
||||
-- Pylons 11, 12 and 13 are moveable within the Herculus cargobay area
|
||||
@@ -4883,7 +4898,7 @@ CTLD_HERCULES.Types = {
|
||||
["ART GVOZDIKA [34720lb]"] = {['name'] = "SAU Gvozdika", ['container'] = false},
|
||||
["APC MTLB Air [26400lb]"] = {['name'] = "MTLB", ['container'] = true},
|
||||
["APC MTLB Skid [26290lb]"] = {['name'] = "MTLB", ['container'] = false},
|
||||
["Generic Crate [20000lb]"] = {['name'] = "Hercules_Container_Parachute", ['container'] = true} --nothing generic in Moose CTLD
|
||||
--["Generic Crate [20000lb]"] = {['name'] = "Hercules_Container_Parachute", ['container'] = true} --nothing generic in Moose CTLD
|
||||
}
|
||||
|
||||
--- Cargo Object
|
||||
@@ -4908,7 +4923,8 @@ CTLD_HERCULES.Types = {
|
||||
-- @return #CTLD_HERCULES self
|
||||
-- @usage
|
||||
-- Integrate to your CTLD instance like so, where `my_ctld` is a previously created CTLD instance:
|
||||
--
|
||||
--
|
||||
-- my_ctld.enableHercules = false -- avoid dual loading via CTLD F10 and F8 ground crew
|
||||
-- local herccargo = CTLD_HERCULES:New("blue", "Hercules Test", my_ctld)
|
||||
--
|
||||
-- You also need:
|
||||
@@ -4922,6 +4938,14 @@ CTLD_HERCULES.Types = {
|
||||
-- ...Checking template for Transport Tigr Air [15900lb] (Tigr_233036) ... OK)
|
||||
--
|
||||
-- Expected template names are the ones in the rounded brackets.
|
||||
--
|
||||
-- HINTS
|
||||
--
|
||||
-- The script works on the EVENTS.Shot trigger, which is used by the mod when you **drop cargo from the Hercules while flying**. Unloading on the ground does
|
||||
-- not achieve anything here. If you just want to unload on the ground, use the normal Moose CTLD.
|
||||
-- There are two ways of airdropping:
|
||||
-- 1) Very low and very slow (>5m and <10m AGL) - here you can drop stuff which has "Skid" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||
-- 2) Higher up and slow (>100m AGL) - here you can drop paratroopers and cargo which has "Air" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||
function CTLD_HERCULES:New(Coalition, Alias, CtldObject)
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) -- #CTLD_HERCULES
|
||||
|
||||
@@ -96,6 +96,14 @@
|
||||
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
|
||||
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
|
||||
--
|
||||
-- **NOTE on using GOOGLE TTS with SRS:** You need to have the C# library installed in your SRS folder for Google to work.
|
||||
-- You can obtain it e.g. here: [NuGet](https://www.nuget.org/packages/Grpc.Core)
|
||||
--
|
||||
-- **Pro-Tipp** - use the command line with power shell to call DCS-SR-ExternalAudio.exe - it will tell you what is missing.
|
||||
-- and also the Google Console error, in case you have missed a step in setting up your Google TTS.
|
||||
-- E.g. `.\DCS-SR-ExternalAudio.exe -t "Text Message" -f 255 -m AM -c 2 -s 2 -z -G "Path_To_You_Google.Json"`
|
||||
-- Plays a message on 255AM for the blue coalition in-game.
|
||||
--
|
||||
-- ## Set Voice
|
||||
--
|
||||
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
|
||||
@@ -135,7 +143,7 @@ MSRS = {
|
||||
|
||||
--- MSRS class version.
|
||||
-- @field #string version
|
||||
MSRS.version="0.0.5"
|
||||
MSRS.version="0.0.6"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -718,7 +726,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
--local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT")
|
||||
|
||||
-- Command.
|
||||
local command=string.format('"%s\\%s" -f %s -m %s -c %s -p %s -n "%s"', path, exe, freqs, modus, coal, port, label)
|
||||
local command=string.format('"%s\\%s" -f %s -m %s -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
|
||||
|
||||
-- Set voice or gender/culture.
|
||||
if voice then
|
||||
|
||||
@@ -52,6 +52,7 @@ BIGSMOKEPRESET = {
|
||||
-- @field #string TheChannel The Channel map.
|
||||
-- @field #string Syria Syria map.
|
||||
-- @field #string MarianaIslands Mariana Islands map.
|
||||
-- @field #string Falklands South Atlantic map.
|
||||
DCSMAP = {
|
||||
Caucasus="Caucasus",
|
||||
NTTR="Nevada",
|
||||
@@ -59,7 +60,8 @@ DCSMAP = {
|
||||
PersianGulf="PersianGulf",
|
||||
TheChannel="TheChannel",
|
||||
Syria="Syria",
|
||||
MarianaIslands="MarianaIslands"
|
||||
MarianaIslands="MarianaIslands",
|
||||
Falklands="Falklands",
|
||||
}
|
||||
|
||||
|
||||
@@ -1347,6 +1349,7 @@ end
|
||||
-- * The Cannel Map -10 (West)
|
||||
-- * Syria +5 (East)
|
||||
-- * Mariana Islands +2 (East)
|
||||
-- * Falklands +12 (East) - note there's a LOT of deviation across the map, as we're closer to the South Pole
|
||||
-- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre
|
||||
-- @return #number Declination in degrees.
|
||||
function UTILS.GetMagneticDeclination(map)
|
||||
@@ -1369,6 +1372,8 @@ function UTILS.GetMagneticDeclination(map)
|
||||
declination=5
|
||||
elseif map==DCSMAP.MarianaIslands then
|
||||
declination=2
|
||||
elseif map==DCSMAP.Falklands then
|
||||
declination=12
|
||||
else
|
||||
declination=0
|
||||
end
|
||||
|
||||
@@ -398,6 +398,7 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Ruwayshid
|
||||
-- * AIRBASE.Syria.Sanliurfa
|
||||
-- * AIRBASE.Syria.Tal_Siman
|
||||
-- * AIRBASE.Syria.Deir_ez_Zor
|
||||
--
|
||||
--@field Syria
|
||||
AIRBASE.Syria={
|
||||
@@ -463,7 +464,7 @@ AIRBASE.Syria={
|
||||
["Ruwayshid"]="Ruwayshid",
|
||||
["Sanliurfa"]="Sanliurfa",
|
||||
["Tal_Siman"]="Tal Siman",
|
||||
["Deir_ez-Zor"] = "Deir ez-Zor",
|
||||
["Deir_ez_Zor"] = "Deir ez-Zor",
|
||||
}
|
||||
|
||||
--- Airbases of the Mariana Islands map:
|
||||
@@ -485,6 +486,29 @@ AIRBASE.MarianaIslands = {
|
||||
["Olf_Orote"] = "Olf Orote",
|
||||
}
|
||||
|
||||
--- Airbases of the South Atlantic map:
|
||||
--
|
||||
-- * AIRBASE.SouthAtlantic.Port_Stanley
|
||||
-- * AIRBASE.SouthAtlantic.Mount_Pleasant
|
||||
-- * AIRBASE.SouthAtlantic.San_Carlos_FOB
|
||||
-- * AIRBASE.SouthAtlantic.Rio_Grande
|
||||
-- * AIRBASE.SouthAtlantic.Rio_Gallegos
|
||||
-- * AIRBASE.SouthAtlantic.Ushuaia
|
||||
-- * AIRBASE.SouthAtlantic.Ushuaia_Helo_Port
|
||||
-- * AIRBASE.SouthAtlantic.Punta_Arenas
|
||||
--
|
||||
--@field MarianaIslands
|
||||
AIRBASE.SouthAtlantic={
|
||||
["Port_Stanley"]="Port Stanley",
|
||||
["Mount_Pleasant"]="Mount Pleasant",
|
||||
["San_Carlos_FOB"]="San Carlos FOB",
|
||||
["Rio_Grande"]="Rio Grande",
|
||||
["Rio_Gallegos"]="Rio Gallegos",
|
||||
["Ushuaia"]="Ushuaia",
|
||||
["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
|
||||
["Punta_Arenas"]="Punta Arenas",
|
||||
}
|
||||
|
||||
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||
-- @type AIRBASE.ParkingSpot
|
||||
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
|
||||
|
||||
@@ -715,21 +715,20 @@ function GROUP:GetDCSUnit( UnitNumber )
|
||||
|
||||
if DCSGroup then
|
||||
|
||||
local UnitFound = nil
|
||||
-- 2.7.1 dead event bug, return the first alive unit instead
|
||||
local units = DCSGroup:getUnits() or {}
|
||||
if DCSGroup.getUnit and DCSGroup:getUnit( UnitNumber ) then
|
||||
return DCSGroup:getUnit( UnitNumber )
|
||||
else
|
||||
|
||||
for _,_unit in pairs(units) do
|
||||
|
||||
local UnitFound = UNIT:Find(_unit)
|
||||
local UnitFound = nil
|
||||
-- 2.7.1 dead event bug, return the first alive unit instead
|
||||
local units = DCSGroup:getUnits() or {}
|
||||
|
||||
if UnitFound and UnitFound:IsAlive() then
|
||||
|
||||
return UnitFound
|
||||
|
||||
for _,_unit in pairs(units) do
|
||||
if _unit and _unit:isExist() then
|
||||
return _unit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1600,7 +1600,11 @@ do -- Cargo
|
||||
["Ural-4320 APA-5D"] = 10,
|
||||
["Ural-4320T"] = 14,
|
||||
["ZBD04A"] = 7, -- new by kappa
|
||||
["VAB_Mephisto"] = 8 -- new by Apple
|
||||
["VAB_Mephisto"] = 8, -- new by Apple
|
||||
["tt_KORD"] = 6, -- 2.7.1 HL/TT
|
||||
["tt_DSHK"] = 6,
|
||||
["HL_KORD"] = 6,
|
||||
["HL_DSHK"] = 6,
|
||||
}
|
||||
|
||||
local CargoBayWeightLimit = (Weights[Desc.typeName] or 0) * 95
|
||||
|
||||
@@ -61,9 +61,10 @@ Documentation on the MOOSE class hierarchy, usage guides and background informat
|
||||
|
||||
|
||||
|
||||
## [MOOSE Youtube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
|
||||
## [MOOSE Youtube Tutorials](https://youtube.com/playlist?list=PLLkY2GByvtC2ME0Q9wrKRDE6qnXJYV3iT)
|
||||
|
||||
MOOSE has a [broadcast and training channel on YouTube](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) with various channels that you can watch.
|
||||
Pene has kindly created a [tutorial series for MOOSE](https://youtube.com/playlist?list=PLLkY2GByvtC2ME0Q9wrKRDE6qnXJYV3iT)
|
||||
with various videos that you can watch.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user