Compare commits

..

22 Commits

Author SHA1 Message Date
Applevangelist
aaf77815ca #SRS
* Added MSRSQUEUE message queue
2022-08-25 10:50:45 +02:00
Applevangelist
3f488cc091 #AIRBASE
* Added 3 new airports to the enumerator SouthAtlantic
2022-08-25 10:38:44 +02:00
Applevangelist
bdbbdfe60e #RANGE
* Added Instructor and RangeControl radio info on F10
2022-08-23 09:58:50 +02:00
Applevangelist
d15c2be2d0 Range fixes (#1764)
* Fixed some typos in self.PlayerSettings
* Fixed result messages
* Thanks for [JFG] Caponi
2022-08-22 17:03:33 +02:00
Applevangelist
73994914eb Fix for #1763 UTILS.GetOSTime() (#1765)
* Fix GetOSTime fixes #1763
2022-08-22 17:03:21 +02:00
Applevangelist
63b0dae794 Update ATC_Ground.lua (#1766)
* Make ATC_Ground work on any map
2022-08-22 17:03:02 +02:00
Engines
003e865ff7 Late break bug (#1762)
* Quick update to Airboss.lua to inluce Invincible.  Not yet tested.

* Initial quick test and calibration of the landing spot; looks good.  More testing required.

* Recompiled the Moose.lua based off the last commit.

* Removing surpurflous Moose.lua for pull request.

* There was an error with the late break paratemers on the Brit carriers causing pilots to be thrown off the pattern on the break.  Fixed, tested on Invicible, working as anticipated now.

* Removing the test Moose.lua (again).

* Fixing merge confilict

* Trying again.
2022-08-15 07:15:15 +02:00
Gavin Edwards
e3c03287b7 Engines invincible (#1758)
* Quick update to Airboss.lua to inluce Invincible.  Not yet tested.

* Initial quick test and calibration of the landing spot; looks good.  More testing required.

* Recompiled the Moose.lua based off the last commit.

* Removing surpurflous Moose.lua for pull request.
2022-08-13 21:40:53 +02:00
Applevangelist
73493c3a23 Update Unit.lua (#1751) 2022-07-31 09:17:36 +02:00
Applevangelist
562a3f6208 SET - fix for dead units 2022-07-29 08:51:23 +02:00
Applevangelist
3c5f3d6c37 UNIT - added get altitude function with AGL option 2022-07-25 08:12:28 +02:00
Applevangelist
a37d4214c0 SET - fix for left over self:I() 2022-07-22 11:06:55 +02:00
Applevangelist
636d6ce324 AIRBASE - Added 2 AFB on the Falklands Map (#1748)
--@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",
  ["Pampa_Guanaco"]="Pampa Guanaco",
  ["San_Julian"]="San Julian",
}
2022-07-22 11:02:55 +02:00
Applevangelist
eef8b362d2 Beacon - added deactivate Link4 2022-07-19 08:29:43 +02:00
Applevangelist
4ae586ebaa Controllable/Beacon - added function to switch on Link4
A2A - typo in documentation
2022-07-19 08:10:54 +02:00
rfdazzle
f6e673c2bb Fixed ATIS TTS readouts for wind direction & TACAN (#1739)
Added a substitution that takes effect when self.useSRS which converts wind direction into aviation-speak, e.g. "Zero Seven One" instead of the previous behaviour which was "Zero Seventy-One".

Updated TACAN TTS string to include the 'Ray' in 'X-Ray' when SRS is in use
2022-07-07 08:41:56 +02:00
Frank
183a60159c Update Range.lua
- Fixed bug for strafing
2022-07-01 23:05:26 +02:00
Chump
1fdf4f371d Fix for issues #1735 & #1736 (#1737)
* Update Database.lua

Remove duplicate function

* Update PseudoATC.lua

Added nil check
2022-06-26 21:11:49 +01:00
Applevangelist
f50c374d04 CSAR - hand back descriptive name as 3rd parameter on event Boarded() 2022-06-25 17:24:56 +02:00
Applevangelist
d59fc331f6 UTILS - Fix for Gazelle Door Check 2022-06-25 14:27:51 +02:00
Applevangelist
b83f478294 CSAR - fix for oncrash 2022-06-16 15:42:02 +02:00
Applevangelist
d5636f4a19 CSAR - added event "Landed" (at a friendly/neutral AFB), fix for AFB rescue 2022-06-16 13:41:44 +02:00
16 changed files with 1291 additions and 2466 deletions

View File

@@ -425,7 +425,7 @@ do -- AI_A2A_DISPATCHER
-- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromParkingHot}() will spawn new aircraft in with running engines at a parking spot at the airfield.
-- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromRunway}() will spawn new aircraft at the runway at the airfield.
--
-- **The default landing method is to spawn new aircraft directly in the air.**
-- **The default take-off method is to spawn new aircraft directly in the air.**
--
-- Use these methods to fine-tune for specific airfields that are known to create bottlenecks, or have reduced airbase efficiency.
-- The more and the longer aircraft need to taxi at an airfield, the more risk there is that:

View File

@@ -245,6 +245,33 @@ function BEACON:ActivateICLS(Channel, Callsign, Duration)
return self
end
--- Activates a LINK4 BEACON. The unit the BEACON is attached to should be an aircraft carrier supporting this system.
-- @param #BEACON self
-- @param #number Frequency LINK4 FRequency in MHz, eg 336.
-- @param #string Morse The ID 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:ActivateLink4(Frequency, Morse, Duration)
self:F({Frequency=Frequency, Morse=Morse, Duration=Duration})
-- Attached unit.
local UnitID=self.Positionable:GetID()
-- Debug
self:T2({"LINK4 BEACON started!"})
-- Start beacon.
self.Positionable:CommandActivateLink4(Frequency,UnitID,Morse)
-- Stop sheduler
if Duration then -- Schedule the stop of the BEACON if asked by the MD
self.Positionable:DeactivateLink4(Duration)
end
return self
end
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
-- Activates a TACAN BEACON on an Aircraft.
-- @param #BEACON self

View File

@@ -241,16 +241,6 @@ function DATABASE:DeleteAirbase( AirbaseName )
self.AIRBASES[AirbaseName] = nil
end
--- Finds an AIRBASE based on the AirbaseName.
-- @param #DATABASE self
-- @param #string AirbaseName
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
function DATABASE:FindAirbase( AirbaseName )
local AirbaseFound = self.AIRBASES[AirbaseName]
return AirbaseFound
end
do -- Zones
--- Finds a @{Zone} based on the zone name.

View File

@@ -1127,8 +1127,10 @@ do -- SET_GROUP
local NearestGroup = nil -- Wrapper.Group#GROUP
local ClosestDistance = nil
for ObjectID, ObjectData in pairs( self.Set ) do
local Set = self:GetAliveSet()
for ObjectID, ObjectData in pairs( Set ) do
if NearestGroup == nil then
NearestGroup = ObjectData
ClosestDistance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
@@ -5627,7 +5629,7 @@ do -- SET_ZONE
if self.Filter.Prefixes then
local MZonePrefix = false
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
self:T3( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
self:T2( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
if string.find( MZoneName, ZonePrefix, 1 ) then
MZonePrefix = true
end

File diff suppressed because it is too large Load Diff

View File

@@ -949,11 +949,14 @@ function PSEUDOATC:LocalAirports(GID, UID)
for _,airbase in pairs(airports) do
local name=airbase:getName()
local q=AIRBASE:FindByName(name):GetCoordinate()
local d=q:Get2DDistance(pos)
local a=AIRBASE:FindByName(name)
if a then
local q=a:GetCoordinate()
local d=q:Get2DDistance(pos)
-- Add to table.
table.insert(self.group[GID].player[UID].airports, {distance=d, name=name})
-- Add to table.
table.insert(self.group[GID].player[UID].airports, {distance=d, name=name})
end
end
end

View File

@@ -2381,7 +2381,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
-- Sort results table wrt number of hits.
local _sort = function( a, b )
return a.hits > b.hits
return a.roundsHit > b.roundsHit
end
table.sort( _results, _sort )
@@ -2398,7 +2398,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
-- Best result.
if _bestMsg == "" then
_bestMsg = string.format( "Hits %d - %s - %s", _result.hits, _result.zone.name, _result.text )
_bestMsg = string.format( "Hits %d - %s - %s", result.roundsHit, result.name, result.roundsQuality)
end
-- 10 runs
@@ -2443,15 +2443,15 @@ function RANGE:_DisplayStrafePitResults( _unitName )
-- Get the best result of the player.
local _best = nil
for _, _result in pairs( _results ) do
if _best == nil or _result.hits > _best.hits then
if _best == nil or _result.roundsHit > _best.roundsHit then
_best = _result
end
end
-- Add best result to table.
if _best ~= nil then
local text = string.format( "%s: Hits %i - %s - %s", _playerName, _best.hits, _best.zone.name, _best.text )
table.insert( _playerResults, { msg = text, hits = _best.hits } )
local text = string.format( "%s: Hits %i - %s - %s", _playerName, _best.roundsHit, _best.name, _best.roundsQuality )
table.insert( _playerResults, { msg = text, hits = _best.roundsHit } )
end
end
@@ -2667,6 +2667,26 @@ function RANGE:_DisplayRangeInfo( _unitname )
text = text .. string.format( "Max strafing alt AGL: %s\n", tstrafemaxalt )
text = text .. string.format( "# of strafe targets: %d\n", self.nstrafetargets )
text = text .. string.format( "# of bomb targets: %d\n", self.nbombtargets )
if self.instructor then
local alive = "N/A"
if self.instructorrelayname then
local relay = UNIT:FindByName( self.instructorrelayname )
if relay then
alive = tostring( relay:IsAlive() )
end
end
text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive )
end
if self.rangecontrol then
local alive = "N/A"
if self.rangecontrolrelayname then
local relay = UNIT:FindByName( self.rangecontrolrelayname )
if relay then
alive = tostring( relay:IsAlive() )
end
end
text = text .. string.format( "Control %.3f MHz (Relay=%s)\n", self.rangecontrolfreq, alive )
end
text = text .. texthit
text = text .. textbomb
text = text .. textdelay
@@ -3018,7 +3038,7 @@ function RANGE:_CheckInZone( _unitName )
if shots and accur then
_text = _text .. string.format( "\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur )
end
_text = _text .. string.format( "\n%s", _result.text )
_text = _text .. string.format( "\n%s", resulttext )
-- Send message.
self:_DisplayMessageToGroup( _unit, _text )
@@ -3487,7 +3507,7 @@ function RANGE:_SmokeBombImpactOnOff( unitname )
self.PlayerSettings[playername].smokebombimpact = false
text = string.format( "%s, %s, smoking impact points of bombs is now OFF.", self.rangename, playername )
else
self.PlayerSettigs[playername].smokebombimpact = true
self.PlayerSettings[playername].smokebombimpact = true
text = string.format( "%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername )
end
self:_DisplayMessageToGroup( unit, text, 5, false, true )
@@ -3508,7 +3528,7 @@ function RANGE:_SmokeBombDelayOnOff( unitname )
self.PlayerSettings[playername].delaysmoke = false
text = string.format( "%s, %s, delayed smoke of bombs is now OFF.", self.rangename, playername )
else
self.PlayerSettigs[playername].delaysmoke = true
self.PlayerSettings[playername].delaysmoke = true
text = string.format( "%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername )
end
self:_DisplayMessageToGroup( unit, text, 5, false, true )

View File

@@ -1740,6 +1740,10 @@ function ATIS:onafterBroadcast( From, Event, To )
end
-- Wind
-- Adding a space after each digit of WINDFROM to convert this to aviation-speak for TTS via SRS
if self.useSRS then
WINDFROM = string.gsub(WINDFROM,".", "%1 ")
end
if self.metric then
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
else
@@ -2197,7 +2201,7 @@ function ATIS:onafterBroadcast( From, Event, To )
-- TACAN
if self.tacan then
subtitle = string.format( "TACAN channel %dX", self.tacan )
subtitle = string.format( "TACAN channel %dX Ray", self.tacan )
if not self.useSRS then
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )

View File

@@ -33,6 +33,7 @@
-- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module]
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59)) (CV-59) [Heatblur Carrier Module]
-- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12)) (R12) [**WIP**]
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05) (R05) [**WIP**]
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**]
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6)) (LHA-6) [**WIP**]
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61) [**WIP**]
@@ -53,7 +54,7 @@
--
-- At the moment, optimized parameters are available for the F/A-18C Hornet (Lot 20) and A-4E community mod as aircraft and the USS John C. Stennis as carrier.
--
-- The AV-8B Harrier, HMS Hermes, the USS Tarawa, USS America, HMAS Canberra, and Juan Carlos I are WIP. The AV-8B harrier and the LHA's and LHD can only be used together, i.e. these ships are the only carriers the harrier is supposed to land on and
-- The AV-8B Harrier, HMS Hermes, HMS Invincible, the USS Tarawa, USS America, HMAS Canberra, and Juan Carlos I are WIP. The AV-8B harrier and the LHA's and LHD can only be used together, i.e. these ships are the only carriers the harrier is supposed to land on and
-- no other fixed wing aircraft (human or AI controlled) are supposed to land on these ships. Currently only Case I is supported. Case II/III take slightly different steps from the CVN carrier.
-- However, if no offset is used for the holding radial this provides a very close representation of the V/STOL Case III, allowing for an approach to over the deck and a vertical landing.
--
@@ -1263,7 +1264,7 @@ AIRBOSS = {
--- Aircraft types capable of landing on carrier (human+AI).
-- @type AIRBOSS.AircraftCarrier
-- @field #string AV8B AV-8B Night Harrier. Works only with the HMS Hermes, USS Tarawa, USS America, and Juan Carlos I.
-- @field #string AV8B AV-8B Night Harrier. Works only with the HMS Hermes, HMS Invincible, USS Tarawa, USS America, and Juan Carlos I.
-- @field #string A4EC A-4E Community mod.
-- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics.
-- @field #string F14A F-14A by Heatblur.
@@ -1300,6 +1301,7 @@ AIRBOSS.AircraftCarrier={
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
-- @field #string VINSON USS Carl Vinson (CVN-70) [Obsolete]
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
-- @field #string AMERICA USS America (LHA-6) [V/STOL Carrier]
-- @field #string JCARLOS Juan Carlos I (L61) [V/STOL Carrier]
@@ -1314,6 +1316,7 @@ AIRBOSS.CarrierType = {
FORRESTAL = "Forrestal",
VINSON = "VINSON",
HERMES = "HERMES81",
INVINCIBLE = "hms_invincible",
TARAWA = "LHA_Tarawa",
AMERICA = "USS America LHA-6",
JCARLOS = "L61",
@@ -1988,6 +1991,9 @@ function AIRBOSS:New( carriername, alias )
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
-- Hermes parameters.
self:_InitHermes()
elseif self.carriertype == AIRBOSS.CarrierType.INVINCIBLE then
-- Invincible parameters.
self:_InitInvincible()
elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then
-- Tarawa parameters.
self:_InitTarawa()
@@ -2090,7 +2096,7 @@ function AIRBOSS:New( carriername, alias )
-- cL:FlareYellow()
-- Carrier specific.
if self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.HERMES or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.TARAWA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.AMERICA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.JCARLOS or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.CANBERRA then
if self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.INVINCIBLE or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.HERMES or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.TARAWA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.AMERICA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.JCARLOS or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.CANBERRA then
-- Flare wires.
local w1 = stern:Translate( self.carrierparam.wire1, FB, true )
@@ -2823,7 +2829,7 @@ end
function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW)
--Check if V/STOL Carrier
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- allow a larger GSE for V/STOL operations --Pene Testing
self.gle._max=_max or 0.7
@@ -2860,7 +2866,7 @@ end
function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, RightMed, RIGHT)
--Check if V/STOL Carrier -- Pene testing
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- V/STOL Values -- allow a larger LUE for V/STOL operations
self.lue._max=_max or 1.8
@@ -4457,8 +4463,48 @@ function AIRBOSS:_InitHermes()
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks?
self.BreakLate.Zmin = -UTILS.NMToMeters( 0.25 ) -- Not more than 0.25 NM port.
self.BreakLate.Zmax = UTILS.NMToMeters( 0.5 ) -- Not more than 0.5 NM starboard.
self.BreakLate.Zmin = -UTILS.NMToMeters( 1.6 ) -- Not more than 1.6 NM port.
self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard.
self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat.
self.BreakLate.LimitXmax = nil
self.BreakLate.LimitZmin = -UTILS.NMToMeters( 0.5 ) -- 926 m port, closer than the stennis as abeam is 0.8-1.0 rather than 1.2
self.BreakLate.LimitZmax = nil
end
--- Init parameters for R05 HMS Invincible carrier.
-- @param #AIRBOSS self
function AIRBOSS:_InitInvincible()
-- Init Stennis as default.
self:_InitStennis()
-- Carrier Parameters.
self.carrierparam.sterndist = -105
self.carrierparam.deckheight = 12 -- From model viewer WL0.
-- Total size of the carrier (approx as rectangle).
self.carrierparam.totlength = 228.19
self.carrierparam.totwidthport = 20.5
self.carrierparam.totwidthstarboard = 24.5
-- Landing runway.
self.carrierparam.rwyangle = 0
self.carrierparam.rwylength = 215
self.carrierparam.rwywidth = 13
-- Wires.
self.carrierparam.wire1 = nil
self.carrierparam.wire2 = nil
self.carrierparam.wire3 = nil
self.carrierparam.wire4 = nil
-- Late break.
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks?
self.BreakLate.Zmin = -UTILS.NMToMeters( 1.6 ) -- Not more than 1.6 NM port.
self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard.
self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat.
self.BreakLate.LimitXmax = nil
self.BreakLate.LimitZmin = -UTILS.NMToMeters( 0.5 ) -- 926 m port, closer than the stennis as abeam is 0.8-1.0 rather than 1.2
@@ -6293,7 +6339,7 @@ function AIRBOSS:_GetMarshalAltitude( stack, case )
p2 = Carrier:Translate( UTILS.NMToMeters( 1.5 ), hdg )
-- Tarawa,LHA,LHD Delta patterns.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- Pattern is directly overhead the carrier.
p1 = Carrier:Translate( UTILS.NMToMeters( 1.0 ), hdg + 90 )
@@ -8132,7 +8178,7 @@ function AIRBOSS:OnEventLand( EventData )
self:T( self.lid .. text )
-- Check carrier type.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- Power "Idle".
self:RadioTransmission( self.LSORadio, self.LSOCall.IDLE, false, 1, nil, true )
@@ -8167,7 +8213,7 @@ function AIRBOSS:OnEventLand( EventData )
-- AI unit landed --
--------------------
if self.carriertype ~= AIRBOSS.CarrierType.HERMES or self.carriertype ~= AIRBOSS.CarrierType.TARAWA or self.carriertype ~= AIRBOSS.CarrierType.AMERICA or self.carriertype ~= AIRBOSS.CarrierType.JCARLOS or self.carriertype ~= AIRBOSS.CarrierType.CANBERRA then
if self.carriertype ~= AIRBOSS.CarrierType.INVINCIBLE or self.carriertype ~= AIRBOSS.CarrierType.HERMES or self.carriertype ~= AIRBOSS.CarrierType.TARAWA or self.carriertype ~= AIRBOSS.CarrierType.AMERICA or self.carriertype ~= AIRBOSS.CarrierType.JCARLOS or self.carriertype ~= AIRBOSS.CarrierType.CANBERRA then
-- Coordinate at landing event
local coord = EventData.IniUnit:GetCoordinate()
@@ -9205,7 +9251,7 @@ function AIRBOSS:_CheckForLongDownwind( playerData )
local limit = UTILS.NMToMeters( -1.6 )
-- For the tarawa, other LHA and LHD we give a bit more space.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
limit = UTILS.NMToMeters( -2.0 )
end
@@ -9292,7 +9338,7 @@ function AIRBOSS:_Ninety( playerData )
self:_PlayerHint( playerData )
-- Next step: wake.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- Harrier has no wake stop. It stays port of the boat.
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.FINAL )
else
@@ -9987,7 +10033,7 @@ function AIRBOSS:_GetSternCoord()
-- local stern=self:GetCoordinate()
-- Stern coordinate (sterndist<0). --Pene testing Case III
if self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
if case==3 then
-- CASE III V/STOL translation Due over deck approach if needed.
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
@@ -10628,7 +10674,7 @@ function AIRBOSS:_GetZoneRunwayBox()
return self.zoneRunwaybox
end
--- Get zone of primary abeam landing position of HMS Hermes, USS Tarawa, USS America and Juan Carlos. Box length 50 meters and width 30 meters.
--- Get zone of primary abeam landing position of HMS Hermes, HMS Invincible, USS Tarawa, USS America and Juan Carlos. Box length 50 meters and width 30 meters.
--- Allow for Clear to land call from LSO approaching abeam the landing spot if stable as per NATOPS 00-80T
-- @param #AIRBOSS self
@@ -10733,7 +10779,7 @@ function AIRBOSS:_GetZoneHolding( case, stack )
self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", Post:GetVec2(), self.marshalradius )
-- Delta pattern.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", self.carrier:GetVec2(), UTILS.NMToMeters( 5 ) )
end
@@ -10785,7 +10831,7 @@ function AIRBOSS:_GetZoneCommence( case, stack )
-- Three position
local Three = self:GetCoordinate():Translate( D, hdg + 275 )
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
local Dx = UTILS.NMToMeters( 2.25 )
@@ -11076,7 +11122,7 @@ function AIRBOSS:_GetAltCarrier( unit )
return h
end
--- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa, Canberrra, Juan Carlos and America we take the abeam landing spot 120 ft above and 21 ft abeam the 7.5 position, for the Juan Carlos I and HMS Hermes it is 120 ft above and 21 ft abeam the 5 position. For CASE III it is 120ft directly above the landing spot.
--- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa, Canberrra, Juan Carlos and America we take the abeam landing spot 120 ft above and 21 ft abeam the 7.5 position, for the Juan Carlos I, HMS Invincible, and HMS Hermes and Invincible it is 120 ft above and 21 ft abeam the 5 position. For CASE III it is 120ft directly above the landing spot.
-- @param #AIRBOSS self
-- @return Core.Point#COORDINATE Optimal landing coordinate.
function AIRBOSS:_GetOptLandingCoordinate()
@@ -11091,7 +11137,7 @@ function AIRBOSS:_GetOptLandingCoordinate()
local FB=self:GetFinalBearing(false)
local case=self.case
-- set Case III V/STOL abeam landing spot over deck -- Pene Testing
if self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
if case==3 then
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate())
@@ -11104,7 +11150,7 @@ function AIRBOSS:_GetOptLandingCoordinate()
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true)
--stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
-- Alitude 120 ft.
-- Atlitude 120 ft.
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
end
@@ -11142,6 +11188,13 @@ function AIRBOSS:_GetLandingSpotCoordinate()
-- Primary landing spot 5
self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
elseif self.carriertype == AIRBOSS.CarrierType.INVINCIBLE then
-- Using spot 3 as the default
local hdg = self:GetHeading()
self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
-- This location looks good.
elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then
-- Landing 100 ft abeam, 120 alt.
@@ -12083,7 +12136,7 @@ function AIRBOSS:_GS( step, n )
if n == -1 then
gp = AIRBOSS.GroovePos.IC
elseif n == 1 then
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
gp = AIRBOSS.GroovePos.AL
else
gp = AIRBOSS.GroovePos.IW
@@ -13962,7 +14015,7 @@ function AIRBOSS:_IsCarrierAircraft( unit )
-- Special case for Harrier which can only land on Tarawa, LHA and LHD.
if aircrafttype == AIRBOSS.AircraftCarrier.AV8B then
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
return true
else
return false
@@ -13970,7 +14023,7 @@ function AIRBOSS:_IsCarrierAircraft( unit )
end
-- Also only Harriers can land on the Tarawa, LHA and LHD.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if aircrafttype ~= AIRBOSS.AircraftCarrier.AV8B then
return false
end
@@ -17327,7 +17380,7 @@ function AIRBOSS:_MarkCaseZones( _unitName, flare )
end
-- Tarawa, LHA and LHD landing spots.
if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
text = text .. "\n* abeam landing stop with RED flares"
-- Abeam landing spot zone.
local ALSPT = self:_GetZoneAbeamLandingSpot()

View File

@@ -165,7 +165,7 @@
--
-- The pilot has been boarded to the helicopter. Use e.g. `function my_csar:OnAfterBoarded(...)` to link into this event:
--
-- function my_csar:OnAfterBoarded(from, event, to, heliname, groupname)
-- function my_csar:OnAfterBoarded(from, event, to, heliname, groupname, description)
-- ... your code here ...
-- end
--
@@ -264,7 +264,7 @@ CSAR.AircraftType["AH-64D_BLK_II"] = 2
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.5"
CSAR.version="1.0.6"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -333,6 +333,7 @@ function CSAR:New(Coalition, Template, Alias)
self:AddTransition("*", "Status", "*") -- CSAR status update.
self:AddTransition("*", "PilotDown", "*") -- Downed Pilot added
self:AddTransition("*", "Approach", "*") -- CSAR heli closing in.
self:AddTransition("*", "Landed", "*") -- CSAR heli landed
self:AddTransition("*", "Boarded", "*") -- Pilot boarded.
self:AddTransition("*", "Returning", "*") -- CSAR able to return to base.
self:AddTransition("*", "Rescued", "*") -- Pilot at MASH.
@@ -474,7 +475,16 @@ function CSAR:New(Coalition, Template, Alias)
-- @param #string Heliname Name of the helicopter group.
-- @param #string Woundedgroupname Name of the downed pilot\'s group.
--- On After "Boarded" event. Downed pilot boarded heli.
--- On After "Landed" event. Heli landed at an airbase.
-- @function [parent=#CSAR] OnAfterLanded
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string HeliName Name of the #UNIT which has landed.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the heli landed.
--- On After "Boarded" event. Downed pilot boarded heli.
-- @function [parent=#CSAR] OnAfterBoarded
-- @param #CSAR self
-- @param #string From From state.
@@ -482,6 +492,7 @@ function CSAR:New(Coalition, Template, Alias)
-- @param #string To To state.
-- @param #string Heliname Name of the helicopter group.
-- @param #string Woundedgroupname Name of the downed pilot\'s group.
-- @param #string Description Descriptive name of the group.
--- On After "Returning" event. Heli can return home with downed pilot(s).
-- @function [parent=#CSAR] OnAfterReturning
@@ -1002,11 +1013,15 @@ function CSAR:_EventHandler(EventData)
local initdcscoord = nil
local initcoord = nil
--if _event.id == EVENTS.Ejection then
if _event.id == EVENTS.Ejection then
initdcscoord = _event.TgtDCSUnit:getPoint()
initcoord = COORDINATE:NewFromVec3(initdcscoord)
self:T({initdcscoord})
--end
else
initdcscoord = _event.IniDCSUnit:getPoint()
initcoord = COORDINATE:NewFromVec3(initdcscoord)
self:T({initdcscoord})
end
--local surface = _unit:GetCoordinate():GetSurfaceType()
local surface = initcoord:GetSurfaceType()
@@ -1038,15 +1053,17 @@ function CSAR:_EventHandler(EventData)
return self -- error!
end
local _coalition = _event.IniCoalition
--local _coalition = _event.IniCoalition
local _coalition = _event.IniGroup:GetCoalition()
if _coalition ~= self.coalition then
self:T(self.lid .. " Wrong coalition")
return self --ignore!
end
self.takenOff[_event.IniUnitName] = nil
local _place = _event.Place -- Wrapper.Airbase#AIRBASE
if _place == nil then
self:T(self.lid .. " Landing Place Nil")
return self -- error!
@@ -1059,6 +1076,7 @@ function CSAR:_EventHandler(EventData)
end
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
self:__Landed(2,_event.IniUnitName, _place)
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
else
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
@@ -1185,7 +1203,7 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
self.heliVisibleMessage[_lookupKeyHeli] = nil
self.heliCloseMessage[_lookupKeyHeli] = nil
self.landedStatus[_lookupKeyHeli] = nil
self:T("...helinunit nil!")
self:T("...heliunit nil!")
return
end
@@ -1281,7 +1299,7 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
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,false,false,true)
return true
return self
end
local found,downedgrouptable = self:_CheckNameInDownedPilots(_woundedGroupName)
@@ -1300,9 +1318,9 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", _heliName, _pilotName), self.messageTime,true,true)
self:__Boarded(5,_heliName,_woundedGroupName)
self:__Boarded(5,_heliName,_woundedGroupName,grouptable.desc)
return true
return self
end
--- (Internal) Move group to destination.
@@ -1378,24 +1396,24 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
end
--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
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
return true
return false
else
self.landedStatus[_lookupKeyHeli] = nil
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
return false
return true
end
end
end
else
if (_distance < self.loadDistance) then
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
return true
return false
else
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
return false
return true
end
end
end
@@ -1432,18 +1450,19 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
if _time > 0 then
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
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
return true
return false
else
self.hoverStatus[_lookupKeyHeli] = nil
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
return false
return true
end
end
_reset = false
else
self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true)
return false
end
end
@@ -2075,7 +2094,7 @@ end
-- @param #string To To state.
function CSAR:onafterStart(From, Event, To)
self:T({From, Event, To})
self:I(self.lid .. "Started.")
self:I(self.lid .. "Started ("..self.version..")")
-- event handler
self:HandleEvent(EVENTS.Takeoff, self._EventHandler)
self:HandleEvent(EVENTS.Land, self._EventHandler)
@@ -2275,6 +2294,18 @@ function CSAR:onbeforePilotDown(From, Event, To, Group, Frequency, Leadername, C
self:T({From, Event, To, Group, Frequency, Leadername, CoordinatesText})
return self
end
--- (Internal) Function called before Landed() event.
-- @param #CSAR self.
-- @param #string From From state.
-- @param #string Event Event triggered.
-- @param #string To To state.
-- @param #string HeliName Name of the #UNIT which has landed.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the heli landed.
function CSAR:onbeforeLanded(From, Event, To, HeliName, Airbase)
self:T({From, Event, To, HeliName, Airbase})
return self
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- End Ops.CSAR
--------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -52,8 +52,6 @@
--
-- ===
--
-- ![Banner Image](..\Presentations\ATIS\ATIS_Main.png)
--
-- # The MSRS Concept
--
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
@@ -143,7 +141,7 @@ MSRS = {
--- MSRS class version.
-- @field #string version
MSRS.version="0.0.6"
MSRS.version="0.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -181,7 +179,7 @@ function MSRS:New(PathToSRS, Frequency, Modulation, Volume)
self:SetCoalition()
self:SetLabel()
self:SetVolume()
self.lid = string.format("%s-%s | ",self.name,self.version)
self.lid = string.format("%s-%s | ", self.name, self.version)
if not io or not os then
self:E(self.lid.."***** ERROR - io or os NOT desanitized! MSRS will not work!")
@@ -455,19 +453,8 @@ function MSRS:PlaySoundFile(Soundfile, Delay)
-- Append file.
command=command..' --file="'..tostring(soundfile)..'"'
-- Execute command.
self:_ExecCommand(command)
--[[
command=command.." > bla.txt"
-- Debug output.
self:I(string.format("MSRS PlaySoundfile command=%s", command))
-- Execute SRS command.
local x=os.execute(command)
]]
end
@@ -493,16 +480,6 @@ function MSRS:PlaySoundText(SoundText, Delay)
-- Execute command.
self:_ExecCommand(command)
--[[
command=command.." > bla.txt"
-- Debug putput.
self:I(string.format("MSRS PlaySoundfile command=%s", command))
-- Execute SRS command.
local x=os.execute(command)
]]
end
@@ -529,37 +506,48 @@ function MSRS:PlayText(Text, Delay)
-- Execute command.
self:_ExecCommand(command)
--[[
-- Check that length of command is max 255 chars or os.execute() will not work!
if string.len(command)>255 then
-- Create a tmp file.
local filename = os.getenv('TMP') .. "\\MSRS-"..STTS.uuid()..".bat"
local script = io.open(filename, "w+")
script:write(command.." && exit")
script:close()
-- Play command.
command=string.format("\"%s\"", filename)
-- Play file in 0.05 seconds
timer.scheduleFunction(os.execute, command, timer.getTime()+0.05)
-- Remove file in 1 second.
timer.scheduleFunction(os.remove, filename, timer.getTime()+1)
else
-- Debug output.
self:I(string.format("MSRS Text command=%s", command))
end
-- Execute SRS command.
local x=os.execute(command)
return self
end
--- Play text message via STTS with explicitly specified options.
-- @param #MSRS self
-- @param #string Text Text message.
-- @param #number Delay Delay in seconds, before the message is played.
-- @param #table Frequencies Radio frequencies.
-- @param #table Modulations Radio modulations.
-- @param #string Gender Gender.
-- @param #string Culture Culture.
-- @param #string Voice Voice.
-- @param #number Volume Volume.
-- @param #string Label Label.
-- @return #MSRS self
function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
else
-- Ensure table.
if Frequencies and type(Frequencies)~="table" then
Frequencies={Frequencies}
end
-- Ensure table.
if Modulations and type(Modulations)~="table" then
Modulations={Modulations}
end
-- Get command line.
local command=self:_GetCommand(Frequencies, Modulations, nil, Gender, Voice, Culture, Volume, nil, nil, Label)
-- Append text.
command=command..string.format(" --text=\"%s\"", tostring(Text))
end
-- Execute command.
self:_ExecCommand(command)
]]
end
return self
@@ -760,6 +748,353 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
return command
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Manages radio transmissions.
--
-- The purpose of the MSRSQUEUE class is to manage SRS text-to-speech (TTS) messages using the MSRS class.
-- This can be used to submit multiple TTS messages and the class takes care that they are transmitted one after the other (and not overlapping).
--
-- @type MSRSQUEUE
-- @field #string ClassName Name of the class "MSRSQUEUE".
-- @field #string lid ID for dcs.log.
-- @field #table queue The queue of transmissions.
-- @field #string alias Name of the radio queue.
-- @field #number dt Time interval in seconds for checking the radio queue.
-- @field #number Tlast Time (abs) when the last transmission finished.
-- @field #boolean checking If `true`, the queue update function is scheduled to be called again.
-- @extends Core.Base#BASE
MSRSQUEUE = {
ClassName = "MSRSQUEUE",
Debugmode = nil,
lid = nil,
queue = {},
alias = nil,
dt = nil,
Tlast = nil,
checking = nil,
}
--- Radio queue transmission data.
-- @type MSRSQUEUE.Transmission
-- @field #string text Text to be transmitted.
-- @field Sound.SRS#MSRS msrs MOOSE SRS object.
-- @field #number duration Duration in seconds.
-- @field #table subgroups Groups to send subtitle to.
-- @field #string subtitle Subtitle of the transmission.
-- @field #number subduration Duration of the subtitle being displayed.
-- @field #number frequency Frequency.
-- @field #number modulation Modulation.
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
-- @field #boolean isplaying If true, transmission is currently playing.
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
-- @field #number interval Interval in seconds before next transmission.
--- Create a new MSRSQUEUE object for a given radio frequency/modulation.
-- @param #MSRSQUEUE self
-- @param #string alias (Optional) Name of the radio queue.
-- @return #MSRSQUEUE self The MSRSQUEUE object.
function MSRSQUEUE:New(alias)
-- Inherit base
local self=BASE:Inherit(self, BASE:New()) --#MSRSQUEUE
self.alias=alias or "My Radio"
self.dt=1.0
self.lid=string.format("MSRSQUEUE %s | ", self.alias)
return self
end
--- Clear the radio queue.
-- @param #MSRSQUEUE self
-- @return #MSRSQUEUE self The MSRSQUEUE object.
function MSRSQUEUE:Clear()
self:I(self.lid.."Clearning MSRSQUEUE")
self.queue={}
return self
end
--- Add a transmission to the radio queue.
-- @param #MSRSQUEUE self
-- @param #MSRSQUEUE.Transmission transmission The transmission data table.
-- @return #MSRSQUEUE self
function MSRSQUEUE:AddTransmission(transmission)
-- Init.
transmission.isplaying=false
transmission.Tstarted=nil
-- Add to queue.
table.insert(self.queue, transmission)
-- Start checking.
if not self.checking then
self:_CheckRadioQueue()
end
return self
end
--- Create a new transmission and add it to the radio queue.
-- @param #MSRSQUEUE self
-- @param #string text Text to play.
-- @param #number duration Duration in seconds the file lasts. Default is determined by number of characters of the text message.
-- @param Sound.SRS#MSRS msrs MOOSE SRS object.
-- @param #number tstart Start time (abs) seconds. Default now.
-- @param #number interval Interval in seconds after the last transmission finished.
-- @param #table subgroups Groups that should receive the subtiltle.
-- @param #string subtitle Subtitle displayed when the message is played.
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
-- @param #number frequency Radio frequency if other than MSRS default.
-- @param #number modulation Radio modulation if other then MSRS default.
-- @return #MSRSQUEUE.Transmission Radio transmission table.
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation)
-- Sanity checks.
if not text then
self:E(self.lid.."ERROR: No text specified.")
return nil
end
if type(text)~="string" then
self:E(self.lid.."ERROR: Text specified is NOT a string.")
return nil
end
-- Create a new transmission object.
local transmission={} --#MSRSQUEUE.Transmission
transmission.text=text
transmission.duration=duration or STTS.getSpeechTime(text)
transmission.msrs=msrs
transmission.Tplay=tstart or timer.getAbsTime()
transmission.subtitle=subtitle
transmission.interval=interval or 0
transmission.frequency=frequency
transmission.modulation=modulation
transmission.subgroups=subgroups
if transmission.subtitle then
transmission.subduration=subduration or transmission.duration
else
transmission.subduration=0 --nil
end
-- Add transmission to queue.
self:AddTransmission(transmission)
return transmission
end
--- Broadcast radio message.
-- @param #MSRSQUEUE self
-- @param #MSRSQUEUE.Transmission transmission The transmission.
function MSRSQUEUE:Broadcast(transmission)
if transmission.frequency then
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, Gender, Culture, Voice, Volume, Label)
else
transmission.msrs:PlayText(transmission.text)
end
local function texttogroup(gid)
-- Text to group.
trigger.action.outTextForGroup(gid, transmission.subtitle, transmission.subduration, true)
end
if transmission.subgroups and #transmission.subgroups>0 then
for _,_group in pairs(transmission.subgroups) do
local group=_group --Wrapper.Group#GROUP
if group and group:IsAlive() then
local gid=group:GetID()
self:ScheduleOnce(4, texttogroup, gid)
end
end
end
end
--- Calculate total transmission duration of all transmission in the queue.
-- @param #MSRSQUEUE self
-- @return #number Total transmission duration.
function MSRSQUEUE:CalcTransmisstionDuration()
local Tnow=timer.getAbsTime()
local T=0
for _,_transmission in pairs(self.queue) do
local transmission=_transmission --#MSRSQUEUE.Transmission
if transmission.isplaying then
-- Playing for dt seconds.
local dt=Tnow-transmission.Tstarted
T=T+transmission.duration-dt
else
T=T+transmission.duration
end
end
return T
end
--- Check radio queue for transmissions to be broadcasted.
-- @param #MSRSQUEUE self
-- @param #number delay Delay in seconds before checking.
function MSRSQUEUE:_CheckRadioQueue(delay)
-- Transmissions in queue.
local N=#self.queue
-- Debug info.
self:T2(self.lid..string.format("Check radio queue %s: delay=%.3f sec, N=%d, checking=%s", self.alias, delay or 0, N, tostring(self.checking)))
if delay and delay>0 then
-- Delayed call.
self:ScheduleOnce(delay, MSRSQUEUE._CheckRadioQueue, self)
-- Checking on.
self.checking=true
else
-- Check if queue is empty.
if N==0 then
-- Debug info.
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
-- Queue is now empty. Nothing to else to do. We start checking again, if a transmission is added.
self.checking=false
return
end
-- Get current abs time.
local time=timer.getAbsTime()
-- Checking on.
self.checking=true
-- Set dt.
local dt=self.dt
local playing=false
local next=nil --#MSRSQUEUE.Transmission
local remove=nil
for i,_transmission in ipairs(self.queue) do
local transmission=_transmission --#MSRSQUEUE.Transmission
-- Check if transmission time has passed.
if time>=transmission.Tplay then
-- Check if transmission is currently playing.
if transmission.isplaying then
-- Check if transmission is finished.
if time>=transmission.Tstarted+transmission.duration then
-- Transmission over.
transmission.isplaying=false
-- Remove ith element in queue.
remove=i
-- Store time last transmission finished.
self.Tlast=time
else -- still playing
-- Transmission is still playing.
playing=true
dt=transmission.duration-(time-transmission.Tstarted)
end
else -- not playing yet
local Tlast=self.Tlast
if transmission.interval==nil then
-- Not playing ==> this will be next.
if next==nil then
next=transmission
end
else
if Tlast==nil or time-Tlast>=transmission.interval then
next=transmission
else
end
end
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
if next or Tlast then
break
end
end
else
-- Transmission not due yet.
end
end
-- Found a new transmission.
if next~=nil and not playing then
-- Debug info.
self:T(self.lid..string.format("Broadcasting text=\"%s\" at T=%.3f", next.text, time))
-- Call SRS.
self:Broadcast(next)
next.isplaying=true
next.Tstarted=time
dt=next.duration
end
-- Remove completed call from queue.
if remove then
-- Remove from queue.
table.remove(self.queue, remove)
N=N-1
-- Check if queue is empty.
if #self.queue==0 then
-- Debug info.
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
self.checking=false
return
end
end
-- Check queue.
self:_CheckRadioQueue(dt)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -1724,11 +1724,17 @@ end
--- Get OS time. Needs os to be desanitized!
-- @return #number Os time in seconds.
function UTILS.GetOSTime()
if os then
return os.clock()
end
return nil
if os then
local ts = 0
local t = os.date("*t")
local s = t.sec
local m = t.min * 60
local h = t.hour * 3600
ts = s+m+h
return ts
else
return nil
end
end
--- Shuffle a table accoring to Fisher Yeates algorithm
@@ -1782,71 +1788,68 @@ end
--@return #boolean Outcome - true if a (loading door) is open, false if not, nil if none exists.
function UTILS.IsLoadingDoorOpen( unit_name )
local ret_val = false
local unit = Unit.getByName(unit_name)
if unit ~= nil then
local type_name = unit:getTypeName()
BASE:T("TypeName = ".. type_name)
if type_name == "Mi-8MT" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) < 0 then
if type_name == "Mi-8MT" and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) < 0) then
BASE:T(unit_name .. " Cargo doors are open or cargo door not present")
ret_val = true
return true
end
if type_name == "Mi-24P" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 then
if type_name == "Mi-24P" and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1) then
BASE:T(unit_name .. " a side door is open")
ret_val = true
return true
end
if type_name == "UH-1H" and unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1 then
if type_name == "UH-1H" and (unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1) then
BASE:T(unit_name .. " a side door is open ")
ret_val = true
return true
end
if string.find(type_name, "SA342" ) and (unit:getDrawArgumentValue(34) == 1) then
BASE:T(unit_name .. " front door(s) are open or doors removed")
return true
end
if string.find(type_name, "SA342" ) and unit:getDrawArgumentValue(34) == 1 or unit:getDrawArgumentValue(38) == 1 then
BASE:T(unit_name .. " front door(s) are open")
ret_val = true
end
if string.find(type_name, "Hercules") and unit:getDrawArgumentValue(1215) == 1 and unit:getDrawArgumentValue(1216) == 1 then
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1215) == 1 and unit:getDrawArgumentValue(1216) == 1) then
BASE:T(unit_name .. " rear doors are open")
ret_val = true
return true
end
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1220) == 1 or unit:getDrawArgumentValue(1221) == 1) then
BASE:T(unit_name .. " para doors are open")
ret_val = true
return true
end
if string.find(type_name, "Hercules") and unit:getDrawArgumentValue(1217) == 1 then
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1217) == 1) then
BASE:T(unit_name .. " side door is open")
ret_val = true
return true
end
if string.find(type_name, "Bell-47") then -- bell aint got no doors so always ready to load injured soldiers
BASE:T(unit_name .. " door is open")
ret_val = true
return true
end
if string.find(type_name, "UH-60L") and (unit:getDrawArgumentValue(401) == 1) or (unit:getDrawArgumentValue(402) == 1) then
if string.find(type_name, "UH-60L") and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then
BASE:T(unit_name .. " cargo door is open")
ret_val = true
return true
end
if string.find(type_name, "UH-60L" ) and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(400) == 1 then
if string.find(type_name, "UH-60L" ) and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(400) == 1 ) then
BASE:T(unit_name .. " front door(s) are open")
ret_val = true
return true
end
if type_name == "AH-64D_BLK_II" then
BASE:T(unit_name .. " front door(s) are open")
ret_val = true -- no doors on this one ;)
return true -- no doors on this one ;)
end
if ret_val == false then
BASE:T(unit_name .. " all doors are closed")
end
return ret_val
return false
end -- nil

View File

@@ -496,6 +496,11 @@ AIRBASE.MarianaIslands = {
-- * AIRBASE.SouthAtlantic.Ushuaia
-- * AIRBASE.SouthAtlantic.Ushuaia_Helo_Port
-- * AIRBASE.SouthAtlantic.Punta_Arenas
-- * AIRBASE.SouthAtlantic.Pampa_Guanaco
-- * AIRBASE.SouthAtlantic.San_Julian
-- * AIRBASE.SouthAtlantic.Puerto_Williams
-- * AIRBASE.SouthAtlantic.Puerto_Natales
-- * AIRBASE.SouthAtlantic.El_Calafate
--
--@field MarianaIslands
AIRBASE.SouthAtlantic={
@@ -507,8 +512,14 @@ AIRBASE.SouthAtlantic={
["Ushuaia"]="Ushuaia",
["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
["Punta_Arenas"]="Punta Arenas",
["Pampa_Guanaco"]="Pampa Guanaco",
["San_Julian"]="San Julian",
["Puerto_Williams"]="Puerto Williams",
["Puerto_Natales"]="Puerto Natales",
["El_Calafate"]="El Calafate",
}
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
-- @type AIRBASE.ParkingSpot
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.

View File

@@ -697,6 +697,34 @@ function CONTROLLABLE:CommandActivateICLS( Channel, UnitID, Callsign, Delay )
return self
end
--- Activate LINK4 system of the CONTROLLABLE. The controllable should be an aircraft carrier!
-- @param #CONTROLLABLE self
-- @param #number Frequency Link4 Frequency in MHz, e.g. 336
-- @param #number UnitID The DCS UNIT ID of the unit the LINK4 system is attached to. Useful if more units are in one group.
-- @param #string Callsign Morse code identification callsign.
-- @param #number Delay (Optional) Delay in seconds before the LINK4 is deactivated.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
-- Command to activate Link4 system.
local CommandActivateLink4= {
id = "ActivateLink4",
params= {
["frequency "] = Frequency*1000,
["unitId"] = UnitID,
["name"] = Callsign,
}
}
if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandActivateLink4, {self}, Delay)
else
self:SetCommand(CommandActivateLink4)
end
return self
end
--- Deactivate the active beacon of the CONTROLLABLE.
-- @param #CONTROLLABLE self
-- @param #number Delay (Optional) Delay in seconds before the beacon is deactivated.
@@ -707,7 +735,7 @@ function CONTROLLABLE:CommandDeactivateBeacon( Delay )
local CommandDeactivateBeacon = { id = 'DeactivateBeacon', params = {} }
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandActivateBeacon, { self }, Delay )
SCHEDULER:New( nil, self.CommandDeactivateBeacon, { self }, Delay )
else
self:SetCommand( CommandDeactivateBeacon )
end
@@ -733,6 +761,24 @@ function CONTROLLABLE:CommandDeactivateICLS( Delay )
return self
end
--- Deactivate the active Link4 of the CONTROLLABLE.
-- @param #CONTROLLABLE self
-- @param #number Delay (Optional) Delay in seconds before the Link4 is deactivated.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandDeactivateLink4(Delay)
-- Command to deactivate
local CommandDeactivateLink4={id='DeactivateLink4', params={}}
if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandDeactivateLink4, {self}, Delay)
else
self:SetCommand(CommandDeactivateLink4)
end
return self
end
--- Set callsign of the CONTROLLABLE. See [DCS command setCallsign](https://wiki.hoggitworld.com/view/DCS_command_setCallsign)
-- @param #CONTROLLABLE self
-- @param DCS#CALLSIGN CallName Number corresponding the the callsign identifier you wish this group to be called.

View File

@@ -537,7 +537,7 @@ function POSITIONABLE:GetBoundingRadius( MinDist )
return nil
end
--- Returns the altitude of the POSITIONABLE.
--- Returns the altitude above sea level of the POSITIONABLE.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Distance The altitude of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
@@ -779,7 +779,7 @@ function POSITIONABLE:GetRelativeVelocity( Positionable )
return UTILS.VecNorm( vtot )
end
--- Returns the POSITIONABLE height in meters.
--- Returns the POSITIONABLE height above sea level in meters.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Vec3 The height of the POSITIONABLE in meters.
-- @return #nil The POSITIONABLE is not existing or alive.

View File

@@ -178,8 +178,28 @@ function UNIT:GetDCSObject()
return nil
end
--- Returns the unit altitude above sea level in meters.
-- @param Wrapper.Unit#UNIT self
-- @param #boolean FromGround Measure from the ground or from sea level (ASL). Provide **true** for measuring from the ground (AGL). **false** or **nil** if you measure from sea level.
-- @return #number The height of the group or nil if is not existing or alive.
function UNIT:GetAltitude(FromGround)
local DCSUnit = Unit.getByName( self.UnitName )
if DCSUnit then
local altitude = 0
local point = DCSUnit:getPoint() --DCS#Vec3
altitude = point.y
if FromGround then
local land = land.getHeight( { x = point.x, y = point.z } ) or 0
altitude = altitude - land
end
return altitude
end
return nil
end
--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group.
--