mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'FF/Ops' into FF/OpsDev
This commit is contained in:
commit
4e280f02b6
@ -417,10 +417,14 @@ do -- Zones and Pathlines
|
|||||||
for objectID, objectData in pairs(layerData.objects or {}) do
|
for objectID, objectData in pairs(layerData.objects or {}) do
|
||||||
|
|
||||||
-- Check for polygon which has at least 4 points (we would need 3 but the origin seems to be there twice)
|
-- Check for polygon which has at least 4 points (we would need 3 but the origin seems to be there twice)
|
||||||
if objectData.polygonMode and objectData.polygonMode=="free" and objectData.points and #objectData.points>=4 then
|
if objectData.polygonMode and (objectData.polygonMode=="free") and objectData.points and #objectData.points>=4 then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Drawing: Polygon free
|
||||||
|
---
|
||||||
|
|
||||||
-- Name of the zone.
|
-- Name of the zone.
|
||||||
local ZoneName=objectData.name or "Unknown Drawing"
|
local ZoneName=objectData.name or "Unknown free Polygon Drawing"
|
||||||
|
|
||||||
-- Reference point. All other points need to be translated by this.
|
-- Reference point. All other points need to be translated by this.
|
||||||
local vec2={x=objectData.mapX, y=objectData.mapY}
|
local vec2={x=objectData.mapX, y=objectData.mapY}
|
||||||
@ -443,7 +447,48 @@ do -- Zones and Pathlines
|
|||||||
table.remove(points, #points)
|
table.remove(points, #points)
|
||||||
|
|
||||||
-- Debug output
|
-- Debug output
|
||||||
self:I(string.format("Register ZONE: %s (Polygon drawing with %d vertices)", ZoneName, #points))
|
self:I(string.format("Register ZONE: %s (Polygon (free) drawing with %d vertices)", ZoneName, #points))
|
||||||
|
|
||||||
|
-- Create new polygon zone.
|
||||||
|
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, points)
|
||||||
|
|
||||||
|
-- Set color.
|
||||||
|
Zone:SetColor({1, 0, 0}, 0.15)
|
||||||
|
|
||||||
|
-- Store in DB.
|
||||||
|
self.ZONENAMES[ZoneName] = ZoneName
|
||||||
|
|
||||||
|
-- Add zone.
|
||||||
|
self:AddZone(ZoneName, Zone)
|
||||||
|
|
||||||
|
-- Check for polygon which has at least 4 points (we would need 3 but the origin seems to be there twice)
|
||||||
|
elseif objectData.polygonMode and objectData.polygonMode=="rect" then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Drawing: Polygon rect
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Name of the zone.
|
||||||
|
local ZoneName=objectData.name or "Unknown rect Polygon Drawing"
|
||||||
|
|
||||||
|
-- Reference point (center of the rectangle).
|
||||||
|
local vec2={x=objectData.mapX, y=objectData.mapY}
|
||||||
|
|
||||||
|
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
||||||
|
local w=objectData.width
|
||||||
|
local h=objectData.height
|
||||||
|
|
||||||
|
-- Create points from center using with and height (width for y and height for x is a bit confusing, but this is how ED implemented it).
|
||||||
|
local points={}
|
||||||
|
points[1]={x=vec2.x-h/2, y=vec2.y+w/2} --Upper left
|
||||||
|
points[2]={x=vec2.x+h/2, y=vec2.y+w/2} --Upper right
|
||||||
|
points[3]={x=vec2.x+h/2, y=vec2.y-w/2} --Lower right
|
||||||
|
points[4]={x=vec2.x-h/2, y=vec2.y-w/2} --Lower left
|
||||||
|
|
||||||
|
--local coord=COORDINATE:NewFromVec2(vec2):MarkToAll("MapX, MapY")
|
||||||
|
|
||||||
|
-- Debug output
|
||||||
|
self:I(string.format("Register ZONE: %s (Polygon (rect) drawing with %d vertices)", ZoneName, #points))
|
||||||
|
|
||||||
-- Create new polygon zone.
|
-- Create new polygon zone.
|
||||||
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, points)
|
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, points)
|
||||||
@ -459,6 +504,10 @@ do -- Zones and Pathlines
|
|||||||
|
|
||||||
elseif objectData.lineMode and (objectData.lineMode=="segments" or objectData.lineMode=="segment" or objectData.lineMode=="free") and objectData.points and #objectData.points>=2 then
|
elseif objectData.lineMode and (objectData.lineMode=="segments" or objectData.lineMode=="segment" or objectData.lineMode=="free") and objectData.points and #objectData.points>=2 then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Drawing: Line (segments, segment or free)
|
||||||
|
---
|
||||||
|
|
||||||
-- Name of the zone.
|
-- Name of the zone.
|
||||||
local Name=objectData.name or "Unknown Line Drawing"
|
local Name=objectData.name or "Unknown Line Drawing"
|
||||||
|
|
||||||
@ -474,7 +523,6 @@ do -- Zones and Pathlines
|
|||||||
points[i]=UTILS.Vec2Add(point, vec2)
|
points[i]=UTILS.Vec2Add(point, vec2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Debug output
|
-- Debug output
|
||||||
self:I(string.format("Register PATHLINE: %s (Line drawing with %d points)", Name, #points))
|
self:I(string.format("Register PATHLINE: %s (Line drawing with %d points)", Name, #points))
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
-- ### Author: **Applevangelist**
|
-- ### Author: **Applevangelist**
|
||||||
--
|
--
|
||||||
-- Date: 5 May 2021
|
-- Date: 5 May 2021
|
||||||
-- Last Update: Sep 2022
|
-- Last Update: Feb 2023
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
---
|
---
|
||||||
@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
|||||||
ClassName = "MARKEROPS",
|
ClassName = "MARKEROPS",
|
||||||
Tag = "mytag",
|
Tag = "mytag",
|
||||||
Keywords = {},
|
Keywords = {},
|
||||||
version = "0.1.0",
|
version = "0.1.1",
|
||||||
debug = false,
|
debug = false,
|
||||||
Casesensitive = true,
|
Casesensitive = true,
|
||||||
}
|
}
|
||||||
@ -124,7 +124,8 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
|||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
-- @param #number idx DCS Marker ID
|
||||||
|
|
||||||
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||||
-- @param #MARKEROPS_BASE self
|
-- @param #MARKEROPS_BASE self
|
||||||
@ -172,7 +173,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
|||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
if self:_MatchTag(Eventtext) then
|
if self:_MatchTag(Eventtext) then
|
||||||
local matchtable = self:_MatchKeywords(Eventtext)
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
self:MarkChanged(Eventtext,matchtable,coord)
|
self:MarkChanged(Eventtext,matchtable,coord,Event.idx)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||||
|
|||||||
@ -23,17 +23,36 @@
|
|||||||
-- @field #table points List of 3D points defining the path.
|
-- @field #table points List of 3D points defining the path.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- *When nothing goes right... Go left!*
|
--- *The shortest distance between two points is a straight line.* -- Archimedes
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # The PATHLINE Concept
|
-- # The PATHLINE Concept
|
||||||
--
|
--
|
||||||
-- List of points defining a path from A to B.
|
-- List of points defining a path from A to B. The pathline can consist of multiple points. Each point holds the information of its position, the surface type, the land height
|
||||||
|
-- and the water depth (if over sea).
|
||||||
--
|
--
|
||||||
-- Line drawings created in the mission editor are automatically registered as pathlines and stored in the MOOSE database.
|
-- Line drawings created in the mission editor are automatically registered as pathlines and stored in the MOOSE database.
|
||||||
-- They can be accessed with the @{#PATHLINE.FindByName) function.
|
-- They can be accessed with the @{#PATHLINE.FindByName) function.
|
||||||
--
|
--
|
||||||
|
-- # Constructor
|
||||||
|
--
|
||||||
|
-- The @{PATHLINE.New) function creates a new PATHLINE object. This does not hold any points. Points can be added with the @{#PATHLINE.AddPointFromVec2} and @{#PATHLINE.AddPointFromVec3}
|
||||||
|
--
|
||||||
|
-- For a given table of 2D or 3D positions, a new PATHLINE object can be created with the @{#PATHLINE.NewFromVec2Array} or @{#PATHLINE.NewFromVec3Array}, respectively.
|
||||||
|
--
|
||||||
|
-- # Line Drawings
|
||||||
|
--
|
||||||
|
-- The most convenient way to create a pathline is the draw panel feature in the DCS mission editor. You can select "Line" and then "Segments", "Segment" or "Free" to draw your lines.
|
||||||
|
-- These line drawings are then automatically added to the MOOSE database as PATHLINE objects and can be retrieved with the @{#PATHLINE.FindByName) function, where the name is the one
|
||||||
|
-- you specify in the draw panel.
|
||||||
|
--
|
||||||
|
-- # Mark on F10 map
|
||||||
|
--
|
||||||
|
-- The ponints of the PATHLINE can be marked on the F10 map with the @{#PATHLINE.MarkPoints}(`true`) function. The mark points contain information of the surface type, land height and
|
||||||
|
-- water depth.
|
||||||
|
--
|
||||||
|
-- To remove the marks, use @{#PATHLINE.MarkPoints}(`false`).
|
||||||
--
|
--
|
||||||
-- @field #PATHLINE
|
-- @field #PATHLINE
|
||||||
PATHLINE = {
|
PATHLINE = {
|
||||||
@ -54,7 +73,7 @@ PATHLINE = {
|
|||||||
|
|
||||||
--- PATHLINE class version.
|
--- PATHLINE class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PATHLINE.version="0.0.1"
|
PATHLINE.version="0.1.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
-- * Dedicated MASH zone
|
-- * Dedicated MASH zone
|
||||||
-- * Some FSM functions to include in your mission scripts
|
-- * Some FSM functions to include in your mission scripts
|
||||||
-- * Limit number of available helos
|
-- * Limit number of available helos
|
||||||
|
-- * SRS voice output via TTS or soundfiles
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -20,8 +21,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **applevangelist**
|
-- ### Author: **Applevangelist**
|
||||||
-- Last Update April 2022
|
-- Last Update February 2022
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
-- @module Functional.AICSAR
|
-- @module Functional.AICSAR
|
||||||
@ -87,10 +88,11 @@
|
|||||||
-- my_aicsar.rescuezoneradius -- landing zone around downed pilot. Defaults to 200m
|
-- my_aicsar.rescuezoneradius -- landing zone around downed pilot. Defaults to 200m
|
||||||
-- my_aicsar.autoonoff -- stop operations when human helicopter pilots are around. Defaults to true.
|
-- my_aicsar.autoonoff -- stop operations when human helicopter pilots are around. Defaults to true.
|
||||||
-- my_aicsar.verbose -- text messages to own coalition about ongoing operations. Defaults to true.
|
-- my_aicsar.verbose -- text messages to own coalition about ongoing operations. Defaults to true.
|
||||||
-- my_aicsarlimithelos -- limit available number of helos going on mission (defaults to true)
|
-- my_aicsar.limithelos -- limit available number of helos going on mission (defaults to true)
|
||||||
-- my_aicsar.helonumber -- number of helos available (default: 3)
|
-- my_aicsar.helonumber -- number of helos available (default: 3)
|
||||||
|
-- my_aicsar.verbose -- boolean, set to `true`for message output on-screen
|
||||||
--
|
--
|
||||||
-- ## Radio options
|
-- ## Radio output options
|
||||||
--
|
--
|
||||||
-- Radio messages, soundfile names and (for SRS) lengths are defined in three enumerators, so you can customize, localize messages and soundfiles to your liking:
|
-- Radio messages, soundfile names and (for SRS) lengths are defined in three enumerators, so you can customize, localize messages and soundfiles to your liking:
|
||||||
--
|
--
|
||||||
@ -100,7 +102,7 @@
|
|||||||
-- EN = {
|
-- EN = {
|
||||||
-- INITIALOK = "Roger, Pilot, we hear you. Stay where you are, a helo is on the way!",
|
-- INITIALOK = "Roger, Pilot, we hear you. Stay where you are, a helo is on the way!",
|
||||||
-- INITIALNOTOK = "Sorry, Pilot. You're behind maximum operational distance! Good Luck!",
|
-- INITIALNOTOK = "Sorry, Pilot. You're behind maximum operational distance! Good Luck!",
|
||||||
-- PILOTDOWN = "Pilot down at ", -- note that this will be appended with the position
|
-- PILOTDOWN = "Mayday, mayday, mayday! Pilot down at ", -- note that this will be appended with the position in MGRS
|
||||||
-- PILOTKIA = "Pilot KIA!",
|
-- PILOTKIA = "Pilot KIA!",
|
||||||
-- HELODOWN = "CSAR Helo Down!",
|
-- HELODOWN = "CSAR Helo Down!",
|
||||||
-- PILOTRESCUED = "Pilot rescued!",
|
-- PILOTRESCUED = "Pilot rescued!",
|
||||||
@ -136,8 +138,31 @@
|
|||||||
-- },
|
-- },
|
||||||
-- }
|
-- }
|
||||||
--
|
--
|
||||||
|
-- ## Radio output via SRS and Text-To-Speech (TTS)
|
||||||
|
--
|
||||||
|
-- Radio output can be done via SRS and Text-To-Speech. No extra sound files required!
|
||||||
|
-- [Initially, Have a look at the guide on setting up SRS TTS for Moose](https://github.com/FlightControl-Master/MOOSE_GUIDES/blob/master/documents/Moose%20TTS%20Setup%20Guide.pdf).
|
||||||
|
-- The text from the `AICSAR.Messages` table above is converted on the fly to an .ogg-file, which is then played back via SRS on the selected frequency and mdulation.
|
||||||
|
-- Hint - the small black window popping up shortly is visible in Single-Player only.
|
||||||
|
--
|
||||||
|
-- To set up AICSAR for SRS TTS output, add e.g. the following to your script:
|
||||||
|
--
|
||||||
|
-- -- setup for google TTS, radio 243 AM, SRS server port 5002 with a google standard-quality voice (google cloud account required)
|
||||||
|
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\google.json")
|
||||||
|
--
|
||||||
|
-- -- alternatively for MS Desktop TTS (voices need to be installed locally first!)
|
||||||
|
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
||||||
|
--
|
||||||
|
-- -- define a different voice for the downed pilot(s)
|
||||||
|
-- my_aicsar:SetPilotTTSVoice(MSRS.Voices.Google.Standard.en_AU_Standard_D,"en-AU","male")
|
||||||
|
--
|
||||||
|
-- -- define another voice for the operator
|
||||||
|
-- my_aicsar:SetOperatorTTSVoice(MSRS.Voices.Google.Standard.en_GB_Standard_A,"en-GB","female")
|
||||||
|
--
|
||||||
|
-- ## Radio output via preproduced soundfiles
|
||||||
|
--
|
||||||
-- The easiest way to add a soundfile to your mission is to use the "Sound to..." trigger in the mission editor. This will effectively
|
-- The easiest way to add a soundfile to your mission is to use the "Sound to..." trigger in the mission editor. This will effectively
|
||||||
-- save your sound file inside of the .miz mission file.
|
-- save your sound file inside of the .miz mission file. [Example soundfiles are located on github](https://github.com/FlightControl-Master/MOOSE_SOUND/tree/master/AICSAR)
|
||||||
--
|
--
|
||||||
-- To customize or localize your texts and sounds, you can take e.g. the following approach to add a German language version:
|
-- To customize or localize your texts and sounds, you can take e.g. the following approach to add a German language version:
|
||||||
--
|
--
|
||||||
@ -147,7 +172,7 @@
|
|||||||
--
|
--
|
||||||
-- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so:
|
-- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so:
|
||||||
--
|
--
|
||||||
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",270,radio.modulation.AM,5002)
|
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",270,radio.modulation.AM,nil,5002)
|
||||||
--
|
--
|
||||||
-- or
|
-- or
|
||||||
--
|
--
|
||||||
@ -161,7 +186,7 @@
|
|||||||
-- @field #AICSAR
|
-- @field #AICSAR
|
||||||
AICSAR = {
|
AICSAR = {
|
||||||
ClassName = "AICSAR",
|
ClassName = "AICSAR",
|
||||||
version = "0.0.8",
|
version = "0.1.9",
|
||||||
lid = "",
|
lid = "",
|
||||||
coalition = coalition.side.BLUE,
|
coalition = coalition.side.BLUE,
|
||||||
template = "",
|
template = "",
|
||||||
@ -173,7 +198,7 @@ AICSAR = {
|
|||||||
pilotqueue = {},
|
pilotqueue = {},
|
||||||
pilotindex = 0,
|
pilotindex = 0,
|
||||||
helos = {},
|
helos = {},
|
||||||
verbose = true,
|
verbose = false,
|
||||||
rescuezoneradius = 200,
|
rescuezoneradius = 200,
|
||||||
rescued = {},
|
rescued = {},
|
||||||
autoonoff = true,
|
autoonoff = true,
|
||||||
@ -194,6 +219,13 @@ AICSAR = {
|
|||||||
helonumber = 3,
|
helonumber = 3,
|
||||||
gettext = nil,
|
gettext = nil,
|
||||||
locale ="en", -- default text language
|
locale ="en", -- default text language
|
||||||
|
SRSTTSRadio = false,
|
||||||
|
SRSGoogle = false,
|
||||||
|
SRSQ = nil,
|
||||||
|
SRSPilot = nil,
|
||||||
|
SRSPilotVoice = false,
|
||||||
|
SRSOperator = nil,
|
||||||
|
SRSOperatorVoice = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- TODO Messages
|
-- TODO Messages
|
||||||
@ -203,7 +235,7 @@ AICSAR.Messages = {
|
|||||||
EN = {
|
EN = {
|
||||||
INITIALOK = "Roger, Pilot, we hear you. Stay where you are, a helo is on the way!",
|
INITIALOK = "Roger, Pilot, we hear you. Stay where you are, a helo is on the way!",
|
||||||
INITIALNOTOK = "Sorry, Pilot. You're behind maximum operational distance! Good Luck!",
|
INITIALNOTOK = "Sorry, Pilot. You're behind maximum operational distance! Good Luck!",
|
||||||
PILOTDOWN = "Pilot down at ",
|
PILOTDOWN = "Mayday, mayday, mayday! Pilot down at ",
|
||||||
PILOTKIA = "Pilot KIA!",
|
PILOTKIA = "Pilot KIA!",
|
||||||
HELODOWN = "CSAR Helo Down!",
|
HELODOWN = "CSAR Helo Down!",
|
||||||
PILOTRESCUED = "Pilot rescued!",
|
PILOTRESCUED = "Pilot rescued!",
|
||||||
@ -212,7 +244,7 @@ AICSAR.Messages = {
|
|||||||
DE = {
|
DE = {
|
||||||
INITIALOK = "Copy, Pilot, wir hören Sie. Bleiben Sie, wo Sie sind!\nEin Hubschrauber sammelt Sie auf!",
|
INITIALOK = "Copy, Pilot, wir hören Sie. Bleiben Sie, wo Sie sind!\nEin Hubschrauber sammelt Sie auf!",
|
||||||
INITIALNOTOK = "Verstehe, Pilot. Sie sind zu weit weg von uns.\nViel Glück!",
|
INITIALNOTOK = "Verstehe, Pilot. Sie sind zu weit weg von uns.\nViel Glück!",
|
||||||
PILOTDOWN = "Pilot abgestürzt: ",
|
PILOTDOWN = "Mayday, mayday, mayday! Pilot abgestürzt: ",
|
||||||
PILOTKIA = "Pilot gefallen!",
|
PILOTKIA = "Pilot gefallen!",
|
||||||
HELODOWN = "CSAR Hubschrauber verloren!",
|
HELODOWN = "CSAR Hubschrauber verloren!",
|
||||||
PILOTRESCUED = "Pilot gerettet!",
|
PILOTRESCUED = "Pilot gerettet!",
|
||||||
@ -309,6 +341,9 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
|||||||
-- Radio
|
-- Radio
|
||||||
self.SRS = nil
|
self.SRS = nil
|
||||||
self.SRSRadio = false
|
self.SRSRadio = false
|
||||||
|
self.SRSTTSRadio = false
|
||||||
|
self.SRSGoogle = false
|
||||||
|
self.SRSQ = nil
|
||||||
self.SRSFrequency = 243
|
self.SRSFrequency = 243
|
||||||
self.SRSPath = "\\"
|
self.SRSPath = "\\"
|
||||||
self.SRSModulation = radio.modulation.AM
|
self.SRSModulation = radio.modulation.AM
|
||||||
@ -343,6 +378,7 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
|||||||
self:AddTransition("*", "Status", "*") -- CSAR status update.
|
self:AddTransition("*", "Status", "*") -- CSAR status update.
|
||||||
self:AddTransition("*", "PilotDown", "*") -- Pilot down
|
self:AddTransition("*", "PilotDown", "*") -- Pilot down
|
||||||
self:AddTransition("*", "PilotPickedUp", "*") -- Pilot in helo
|
self:AddTransition("*", "PilotPickedUp", "*") -- Pilot in helo
|
||||||
|
self:AddTransition("*", "PilotUnloaded", "*") -- Pilot Unloaded from helo
|
||||||
self:AddTransition("*", "PilotRescued", "*") -- Pilot Rescued
|
self:AddTransition("*", "PilotRescued", "*") -- Pilot Rescued
|
||||||
self:AddTransition("*", "PilotKIA", "*") -- Pilot dead
|
self:AddTransition("*", "PilotKIA", "*") -- Pilot dead
|
||||||
self:AddTransition("*", "HeloDown", "*") -- Helo dead
|
self:AddTransition("*", "HeloDown", "*") -- Helo dead
|
||||||
@ -404,6 +440,15 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
|
--- On after "PilotUnloaded" event.
|
||||||
|
-- @function [parent=#AICSAR] OnAfterPilotUnloaded
|
||||||
|
-- @param #AICSAR self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Ops.FlightGroup#FLIGHTGROUP Helo
|
||||||
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
|
||||||
|
|
||||||
--- On after "PilotKIA" event.
|
--- On after "PilotKIA" event.
|
||||||
-- @function [parent=#AICSAR] OnAfterPilotKIA
|
-- @function [parent=#AICSAR] OnAfterPilotKIA
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
@ -453,7 +498,7 @@ function AICSAR:InitLocalization()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Switch sound output on and use SRS
|
--- [User] Switch sound output on and use SRS output for sound files.
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||||
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
||||||
@ -464,10 +509,12 @@ end
|
|||||||
-- @return #AICSAR self
|
-- @return #AICSAR self
|
||||||
function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port)
|
function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port)
|
||||||
self:T(self.lid .. "SetSRSRadio")
|
self:T(self.lid .. "SetSRSRadio")
|
||||||
self:T(self.lid .. "SetSRSRadio to "..tostring(OnOff))
|
|
||||||
self.SRSRadio = OnOff and true
|
self.SRSRadio = OnOff and true
|
||||||
|
self.SRSTTSRadio = false
|
||||||
self.SRSFrequency = Frequency or 243
|
self.SRSFrequency = Frequency or 243
|
||||||
self.SRSPath = Path or "c:\\"
|
self.SRSPath = Path or "c:\\"
|
||||||
|
self.SRS:SetLabel("ACSR")
|
||||||
|
self.SRS:SetCoalition(self.coalition)
|
||||||
self.SRSModulation = Modulation or radio.modulation.AM
|
self.SRSModulation = Modulation or radio.modulation.AM
|
||||||
local soundpath = os.getenv('TMP') .. "\\DCS\\Mission\\l10n\\DEFAULT" -- defaults to "l10n/DEFAULT/", i.e. add messages by "Sound to..." in the ME
|
local soundpath = os.getenv('TMP') .. "\\DCS\\Mission\\l10n\\DEFAULT" -- defaults to "l10n/DEFAULT/", i.e. add messages by "Sound to..." in the ME
|
||||||
self.SRSSoundPath = SoundPath or soundpath
|
self.SRSSoundPath = SoundPath or soundpath
|
||||||
@ -479,6 +526,88 @@ function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Switch sound output on and use SRS-TTS output. The voice will be used across all outputs, unless you define an extra voice for downed pilots and/or the operator.
|
||||||
|
-- See `AICSAR:SetPilotTTSVoice()` and `AICSAR:SetOperatorTTSVoice()`
|
||||||
|
-- @param #AICSAR self
|
||||||
|
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||||
|
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
||||||
|
-- @param #number Frequency (Optional) Defaults to 243 (guard)
|
||||||
|
-- @param #number Modulation (Optional) Radio modulation. Defaults to radio.modulation.AM
|
||||||
|
-- @param #number Port (Optional) Port of the SRS, defaults to 5002.
|
||||||
|
-- @param #string Voice (Optional) The voice to be used.
|
||||||
|
-- @param #string Culture (Optional) The culture to be used, defaults to "en-GB"
|
||||||
|
-- @param #string Gender (Optional) The gender to be used, defaults to "male"
|
||||||
|
-- @param #string GoogleCredentials (Optional) Path to google credentials
|
||||||
|
-- @return #AICSAR self
|
||||||
|
function AICSAR:SetSRSTTSRadio(OnOff,Path,Frequency,Modulation,Port,Voice,Culture,Gender,GoogleCredentials)
|
||||||
|
self:T(self.lid .. "SetSRSTTSRadio")
|
||||||
|
self.SRSTTSRadio = OnOff and true
|
||||||
|
self.SRSRadio = false
|
||||||
|
self.SRSFrequency = Frequency or 243
|
||||||
|
self.SRSPath = Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||||
|
self.SRSModulation = Modulation or radio.modulation.AM
|
||||||
|
self.SRSPort = Port or 5002
|
||||||
|
if OnOff then
|
||||||
|
self.SRS = MSRS:New(Path,Frequency,Modulation,1)
|
||||||
|
self.SRS:SetPort(self.SRSPort)
|
||||||
|
self.SRS:SetCoalition(self.coalition)
|
||||||
|
self.SRS:SetLabel("ACSR")
|
||||||
|
self.SRS:SetVoice(Voice)
|
||||||
|
self.SRS:SetCulture(Culture)
|
||||||
|
self.SRS:SetGender(Gender)
|
||||||
|
if GoogleCredentials then
|
||||||
|
self.SRS:SetGoogle(GoogleCredentials)
|
||||||
|
self.SRSGoogle = true
|
||||||
|
end
|
||||||
|
self.SRSQ = MSRSQUEUE:New(self.alias)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [User] Set SRS TTS Voice of downed pilot. `AICSAR:SetSRSTTSRadio()` needs to be set first!
|
||||||
|
-- @param #AICSAR self
|
||||||
|
-- @param #string Voice The voice to be used, e.g. `MSRS.Voices.Google.Standard.en_US_Standard_J` for Google or `MSRS.Voices.Microsoft.David` for Microsoft.
|
||||||
|
-- Specific voices override culture and gender!
|
||||||
|
-- @param #string Culture (Optional) The culture to be used, defaults to "en-US"
|
||||||
|
-- @param #string Gender (Optional) The gender to be used, defaults to "male"
|
||||||
|
-- @return #AICSAR self
|
||||||
|
function AICSAR:SetPilotTTSVoice(Voice,Culture,Gender)
|
||||||
|
self:T(self.lid .. "SetPilotTTSVoice")
|
||||||
|
self.SRSPilotVoice = true
|
||||||
|
self.SRSPilot = MSRS:New(self.SRSPath,self.SRSFrequency,self.SRSModulation,1)
|
||||||
|
self.SRSPilot:SetCoalition(self.coalition)
|
||||||
|
self.SRSPilot:SetVoice(Voice)
|
||||||
|
self.SRSPilot:SetCulture(Culture or "en-US")
|
||||||
|
self.SRSPilot:SetGender(Gender or "male")
|
||||||
|
self.SRSPilot:SetLabel("PILOT")
|
||||||
|
if self.SRS.google then
|
||||||
|
self.SRSPilot:SetGoogle(self.SRS.google)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [User] Set SRS TTS Voice of the rescue operator. `AICSAR:SetSRSTTSRadio()` needs to be set first!
|
||||||
|
-- @param #AICSAR self
|
||||||
|
-- @param #string Voice The voice to be used, e.g. `MSRS.Voices.Google.Standard.en_US_Standard_J` for Google or `MSRS.Voices.Microsoft.David` for Microsoft.
|
||||||
|
-- Specific voices override culture and gender!
|
||||||
|
-- @param #string Culture (Optional) The culture to be used, defaults to "en-GB"
|
||||||
|
-- @param #string Gender (Optional) The gender to be used, defaults to "female"
|
||||||
|
-- @return #AICSAR self
|
||||||
|
function AICSAR:SetOperatorTTSVoice(Voice,Culture,Gender)
|
||||||
|
self:T(self.lid .. "SetOperatorTTSVoice")
|
||||||
|
self.SRSOperatorVoice = true
|
||||||
|
self.SRSOperator = MSRS:New(self.SRSPath,self.SRSFrequency,self.SRSModulation,1)
|
||||||
|
self.SRSOperator:SetCoalition(self.coalition)
|
||||||
|
self.SRSOperator:SetVoice(Voice)
|
||||||
|
self.SRSOperator:SetCulture(Culture or "en-GB")
|
||||||
|
self.SRSOperator:SetGender(Gender or "female")
|
||||||
|
self.SRSPilot:SetLabel("RESCUE")
|
||||||
|
if self.SRS.google then
|
||||||
|
self.SRSOperator:SetGoogle(self.SRS.google)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Switch sound output on and use normale (DCS) radio
|
--- [User] Switch sound output on and use normale (DCS) radio
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||||
@ -545,13 +674,25 @@ function AICSAR:OnEventLandingAfterEjection(EventData)
|
|||||||
-- Mayday Message
|
-- Mayday Message
|
||||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||||
local text = ""
|
local text = ""
|
||||||
|
local setting = {}
|
||||||
|
setting.MGRS_Accuracy = self.MGRS_Accuracy
|
||||||
|
local location = _LandingPos:ToStringMGRS(setting)
|
||||||
|
local msgtxt = Text..location.."!"
|
||||||
|
location = string.gsub(location,"MGRS ","")
|
||||||
|
location = string.gsub(location,"%s+","")
|
||||||
|
location = string.gsub(location,"([%a%d])","%1;") -- "0 5 1 "
|
||||||
|
location = string.gsub(location,"0","zero")
|
||||||
|
location = string.gsub(location,"9","niner")
|
||||||
|
location = "MGRS;"..location
|
||||||
|
if self.SRSGoogle then
|
||||||
|
location = string.format("<say-as interpret-as='characters'>%s</say-as>",location)
|
||||||
|
end
|
||||||
|
text = Text .. location .. "!"
|
||||||
|
local ttstext = Text .. location .. "! Repeat! "..location
|
||||||
if _coalition == self.coalition then
|
if _coalition == self.coalition then
|
||||||
if self.verbose then
|
if self.verbose then
|
||||||
local setting = {}
|
MESSAGE:New(msgtxt,15,"AICSAR"):ToCoalition(self.coalition)
|
||||||
setting.MGRS_Accuracy = self.MGRS_Accuracy
|
-- MESSAGE:New(msgtxt,15,"AICSAR"):ToLog()
|
||||||
local location = _LandingPos:ToStringMGRS(setting)
|
|
||||||
text = Text .. location .. "!"
|
|
||||||
MESSAGE:New(text,15,"AICSAR"):ToCoalition(self.coalition)
|
|
||||||
end
|
end
|
||||||
if self.SRSRadio then
|
if self.SRSRadio then
|
||||||
local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength)
|
local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength)
|
||||||
@ -559,6 +700,12 @@ function AICSAR:OnEventLandingAfterEjection(EventData)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
|
elseif self.SRSTTSRadio then
|
||||||
|
if self.SRSPilotVoice then
|
||||||
|
self.SRSQ:NewTransmission(ttstext,nil,self.SRSPilot,nil,1)
|
||||||
|
else
|
||||||
|
self.SRSQ:NewTransmission(ttstext,nil,self.SRS,nil,1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -634,6 +781,10 @@ function AICSAR:_InitMission(Pilot,Index)
|
|||||||
self:__HeloDown(2,Helo,Index)
|
self:__HeloDown(2,Helo,Index)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function AICHeloUnloaded(Helo,OpsGroup)
|
||||||
|
self:__PilotUnloaded(2,Helo,OpsGroup)
|
||||||
|
end
|
||||||
|
|
||||||
function helo:OnAfterLoadingDone(From,Event,To)
|
function helo:OnAfterLoadingDone(From,Event,To)
|
||||||
AICPickedUp(helo,helo:GetCargoGroups(),Index)
|
AICPickedUp(helo,helo:GetCargoGroups(),Index)
|
||||||
end
|
end
|
||||||
@ -642,6 +793,10 @@ function AICSAR:_InitMission(Pilot,Index)
|
|||||||
AICHeloDead(helo,Index)
|
AICHeloDead(helo,Index)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function helo:OnAfterUnloaded(From,Event,To,OpsGroupCargo)
|
||||||
|
AICHeloUnloaded(helo,OpsGroupCargo)
|
||||||
|
end
|
||||||
|
|
||||||
self.helos[Index] = helo
|
self.helos[Index] = helo
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -652,7 +807,7 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP Pilot The pilot to be rescued.
|
-- @param Wrapper.Group#GROUP Pilot The pilot to be rescued.
|
||||||
-- @return #boolean outcome
|
-- @return #boolean outcome
|
||||||
function AICSAR:_CheckInMashZone(Pilot)
|
function AICSAR:_CheckInMashZone(Pilot)
|
||||||
self:T(self.lid .. "_CheckQueue")
|
self:T(self.lid .. "_CheckInMashZone")
|
||||||
if Pilot:IsInZone(self.farpzone) then
|
if Pilot:IsInZone(self.farpzone) then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
@ -696,8 +851,9 @@ end
|
|||||||
|
|
||||||
--- [Internal] Check pilot queue for next mission
|
--- [Internal] Check pilot queue for next mission
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
|
||||||
-- @return #AICSAR self
|
-- @return #AICSAR self
|
||||||
function AICSAR:_CheckQueue()
|
function AICSAR:_CheckQueue(OpsGroup)
|
||||||
self:T(self.lid .. "_CheckQueue")
|
self:T(self.lid .. "_CheckQueue")
|
||||||
for _index, _pilot in pairs(self.pilotqueue) do
|
for _index, _pilot in pairs(self.pilotqueue) do
|
||||||
local classname = _pilot.ClassName and _pilot.ClassName or "NONE"
|
local classname = _pilot.ClassName and _pilot.ClassName or "NONE"
|
||||||
@ -709,8 +865,12 @@ function AICSAR:_CheckQueue()
|
|||||||
local flightgroup = self.helos[_index] -- Ops.FlightGroup#FLIGHTGROUP
|
local flightgroup = self.helos[_index] -- Ops.FlightGroup#FLIGHTGROUP
|
||||||
-- rescued?
|
-- rescued?
|
||||||
if self:_CheckInMashZone(_pilot) then
|
if self:_CheckInMashZone(_pilot) then
|
||||||
self:T("Pilot" .. _pilot.GroupName .. " rescued!")
|
self:T("Pilot" .. _pilot.GroupName .. " rescued!")
|
||||||
_pilot:Destroy(false)
|
if OpsGroup then
|
||||||
|
OpsGroup:Despawn(10)
|
||||||
|
else
|
||||||
|
_pilot:Destroy(true,10)
|
||||||
|
end
|
||||||
self.pilotqueue[_index] = nil
|
self.pilotqueue[_index] = nil
|
||||||
self.rescued[_index] = true
|
self.rescued[_index] = true
|
||||||
self:__PilotRescued(2)
|
self:__PilotRescued(2)
|
||||||
@ -767,7 +927,7 @@ end
|
|||||||
-- @return #AICSAR self
|
-- @return #AICSAR self
|
||||||
function AICSAR:onafterStatus(From, Event, To)
|
function AICSAR:onafterStatus(From, Event, To)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
self:_CheckQueue()
|
--self:_CheckQueue()
|
||||||
self:_CheckHelos()
|
self:_CheckHelos()
|
||||||
self:__Status(30)
|
self:__Status(30)
|
||||||
return self
|
return self
|
||||||
@ -814,6 +974,12 @@ function AICSAR:onafterPilotDown(From, Event, To, Coordinate, InReach)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
|
elseif self.SRSTTSRadio then
|
||||||
|
if self.SRSOperatorVoice then
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRSOperator,nil,1)
|
||||||
|
else
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRS,nil,1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("INITIALNOTOK",self.locale)
|
local text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("INITIALNOTOK",self.locale)
|
||||||
@ -828,8 +994,15 @@ function AICSAR:onafterPilotDown(From, Event, To, Coordinate, InReach)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
|
elseif self.SRSTTSRadio then
|
||||||
|
if self.SRSOperatorVoice then
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRSOperator,nil,1)
|
||||||
|
else
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRS,nil,1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
self:_CheckQueue()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -851,7 +1024,9 @@ function AICSAR:onafterPilotKIA(From, Event, To)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
end
|
elseif self.SRSTTSRadio then
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRS,nil,1)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -875,6 +1050,12 @@ function AICSAR:onafterHeloDown(From, Event, To, Helo, Index)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
|
elseif self.SRSTTSRadio then
|
||||||
|
if self.SRSOperatorVoice then
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRSOperator,nil,1)
|
||||||
|
else
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRS,nil,1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local findex = 0
|
local findex = 0
|
||||||
local fhname = Helo:GetName()
|
local fhname = Helo:GetName()
|
||||||
@ -927,10 +1108,26 @@ function AICSAR:onafterPilotRescued(From, Event, To)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
|
elseif self.SRSTTSRadio then
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRS,nil,1)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Internal] onafterPilotUnloaded
|
||||||
|
-- @param #AICSAR self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Ops.FlightGroup#FLIGHTGROUP Helo
|
||||||
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
|
||||||
|
-- @return #AICSAR self
|
||||||
|
function AICSAR:onafterPilotUnloaded(From, Event, To, Helo, OpsGroup)
|
||||||
|
self:T({From, Event, To})
|
||||||
|
self:_CheckQueue(OpsGroup)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] onafterPilotPickedUp
|
--- [Internal] onafterPilotPickedUp
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
@ -952,6 +1149,8 @@ function AICSAR:onafterPilotPickedUp(From, Event, To, Helo, CargoTable, Index)
|
|||||||
self.SRS:PlaySoundFile(sound,2)
|
self.SRS:PlaySoundFile(sound,2)
|
||||||
elseif self.DCSRadio then
|
elseif self.DCSRadio then
|
||||||
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
self:DCSRadioBroadcast(Soundfile,Soundlength,text)
|
||||||
|
elseif self.SRSTTSRadio then
|
||||||
|
self.SRSQ:NewTransmission(text,nil,self.SRS,nil,1)
|
||||||
end
|
end
|
||||||
local findex = 0
|
local findex = 0
|
||||||
local fhname = Helo:GetName()
|
local fhname = Helo:GetName()
|
||||||
|
|||||||
@ -474,7 +474,7 @@ do -- DETECTION_BASE
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @param #table DetectedItem The DetectedItem.
|
-- @param #DetectedItem DetectedItem The DetectedItem data structure.
|
||||||
|
|
||||||
self:AddTransition( "*", "Stop", "Stopped" )
|
self:AddTransition( "*", "Stop", "Stopped" )
|
||||||
|
|
||||||
@ -2478,14 +2478,14 @@ do -- DETECTION_AREAS
|
|||||||
--- DETECTION_AREAS constructor.
|
--- DETECTION_AREAS constructor.
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||||
-- @param DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
-- @param #number DetectionZoneRange The range in meters within which targets are grouped upon the first detected target. Default 5000m.
|
||||||
-- @return #DETECTION_AREAS
|
-- @return #DETECTION_AREAS
|
||||||
function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange )
|
function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange )
|
||||||
|
|
||||||
-- Inherits from DETECTION_BASE
|
-- Inherits from DETECTION_BASE
|
||||||
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup ) )
|
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup ) )
|
||||||
|
|
||||||
self.DetectionZoneRange = DetectionZoneRange
|
self.DetectionZoneRange = DetectionZoneRange or 5000
|
||||||
|
|
||||||
self._SmokeDetectedUnits = false
|
self._SmokeDetectedUnits = false
|
||||||
self._FlareDetectedUnits = false
|
self._FlareDetectedUnits = false
|
||||||
@ -2988,4 +2988,3 @@ do -- DETECTION_AREAS
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,7 @@ __Moose.Include( 'Scripts/Moose/Wrapper/Scenery.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Static.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Static.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Unit.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Unit.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Weapon.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Weapon.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Wrapper/Net.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Cargo/Cargo.lua' )
|
__Moose.Include( 'Scripts/Moose/Cargo/Cargo.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Cargo/CargoUnit.lua' )
|
__Moose.Include( 'Scripts/Moose/Cargo/CargoUnit.lua' )
|
||||||
|
|||||||
@ -96,7 +96,7 @@ PLAYERTASK = {
|
|||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASK.version="0.1.12"
|
PLAYERTASK.version="0.1.14"
|
||||||
|
|
||||||
--- Generic task condition.
|
--- Generic task condition.
|
||||||
-- @type PLAYERTASK.Condition
|
-- @type PLAYERTASK.Condition
|
||||||
@ -3526,6 +3526,23 @@ function PLAYERTASKCONTROLLER:AddAgent(Recce)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Add agent SET_GROUP to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
|
-- @param Core.Set#SET_GROUP RecceSet SET_GROUP of agents.
|
||||||
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
|
function PLAYERTASKCONTROLLER:AddAgentSet(RecceSet)
|
||||||
|
self:T(self.lid.."AddAgentSet")
|
||||||
|
if self.Intel then
|
||||||
|
local Set = RecceSet:GetAliveSet()
|
||||||
|
for _,_Recce in pairs(Set) do
|
||||||
|
self.Intel:AddAgent(_Recce)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:E(self.lid.."*****NO detection has been set up (yet)!")
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Set up detection of STATIC objects. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Set up detection of STATIC objects. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param #boolean OnOff Set to `true`for on and `false`for off.
|
-- @param #boolean OnOff Set to `true`for on and `false`for off.
|
||||||
|
|||||||
298
Moose Development/Moose/Wrapper/Net.lua
Normal file
298
Moose Development/Moose/Wrapper/Net.lua
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
--- **Wrapper** - DCS net functions.
|
||||||
|
--
|
||||||
|
-- Encapsules **multiplayer** environment scripting functions from [net](https://wiki.hoggitworld.com/view/DCS_singleton_net)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **applevangelist**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Wrapper.Net
|
||||||
|
-- @image Utils_Profiler.jpg
|
||||||
|
|
||||||
|
do
|
||||||
|
--- The NET class
|
||||||
|
-- @type NET
|
||||||
|
-- @field #string ClassName
|
||||||
|
-- @field #string Version
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- Encapsules multiplayer environment scripting functions from [net](https://wiki.hoggitworld.com/view/DCS_singleton_net)
|
||||||
|
--
|
||||||
|
-- @field #NET
|
||||||
|
NET = {
|
||||||
|
ClassName = "NET",
|
||||||
|
Version = "0.0.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Instantiate a new NET object.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @return #NET self
|
||||||
|
function NET:New()
|
||||||
|
-- Inherit base.
|
||||||
|
local self = BASE:Inherit(self, BASE:New()) -- #NET
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Send chat message.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param #string Message Message to send
|
||||||
|
-- @param #boolean ToAll (Optional)
|
||||||
|
-- @return #NET self
|
||||||
|
function NET:SendChat(Message,ToAll)
|
||||||
|
if Message then
|
||||||
|
net.send_chat(Message, ToAll)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find the PlayerID by name
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param #string Name The player name whose ID to find
|
||||||
|
-- @return #number PlayerID or nil
|
||||||
|
function NET:GetPlayerIdByName(Name)
|
||||||
|
local playerList = self:GetPlayerList()
|
||||||
|
for i=1,#playerList do
|
||||||
|
local playerName = net.get_name(i)
|
||||||
|
if playerName == Name then
|
||||||
|
return playerList[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find the PlayerID from a CLIENT object.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @return #number PlayerID or nil
|
||||||
|
function NET:GetPlayerIDFromClient(Client)
|
||||||
|
local name = Client:GetPlayerName()
|
||||||
|
local id = self:GetPlayerIdByName(name)
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Send chat message to a specific player.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param #string Message The text message
|
||||||
|
-- @param Wrapper.Client#CLIENT ToClient Client receiving the message
|
||||||
|
-- @param Wrapper.Client#CLIENT FromClient (Optional) Client sending the message
|
||||||
|
-- @return #NET self
|
||||||
|
function NET:SendChatToPlayer(Message, ToClient, FromClient)
|
||||||
|
local PlayerId = self:GetPlayerIDFromClient(ToClient)
|
||||||
|
local FromId = self:GetPlayerIDFromClient(FromClient)
|
||||||
|
if Message and PlayerId and FromId then
|
||||||
|
net.send_chat_to(Message, tonumber(PlayerId) , tonumber(FromId))
|
||||||
|
elseif Message and PlayerId then
|
||||||
|
net.send_chat_to(Message, tonumber(PlayerId))
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Load a specific mission.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param #string Path and Mission
|
||||||
|
-- @return #boolean success
|
||||||
|
-- @usage
|
||||||
|
-- mynet:LoadMission(lfs.writeDir() .. 'Missions\\' .. 'MyTotallyAwesomeMission.miz')
|
||||||
|
function NET:LoadMission(Path)
|
||||||
|
local outcome = false
|
||||||
|
if Path then
|
||||||
|
outcome = net.load_mission(Path)
|
||||||
|
end
|
||||||
|
return outcome
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Load next mission. Returns false if at the end of list.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @return #boolean success
|
||||||
|
function NET:LoadNextMission()
|
||||||
|
local outcome = false
|
||||||
|
outcome = net.load_next_mission()
|
||||||
|
return outcome
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return a table of players currently connected to the server.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @return #table PlayerList
|
||||||
|
function NET:GetPlayerList()
|
||||||
|
local plist = nil
|
||||||
|
plist = net.get_player_list()
|
||||||
|
return plist
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the playerID of the local player. Always returns 1 for server.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @return #number ID
|
||||||
|
function NET:GetMyPlayerID()
|
||||||
|
return net.get_my_player_id()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the playerID of the server. Currently always returns 1.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @return #number ID
|
||||||
|
function NET:GetServerID()
|
||||||
|
return net.get_server_id()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return a table of attributes for a given client. If optional attribute is present, only that value is returned.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client.
|
||||||
|
-- @param #string Attribute (Optional) The attribute to obtain. List see below.
|
||||||
|
-- @return #table PlayerInfo or nil if it cannot be found
|
||||||
|
-- @usage
|
||||||
|
-- Table holds these attributes:
|
||||||
|
--
|
||||||
|
-- 'id' : playerID
|
||||||
|
-- 'name' : player name
|
||||||
|
-- 'side' : 0 - spectators, 1 - red, 2 - blue
|
||||||
|
-- 'slot' : slotID of the player or
|
||||||
|
-- 'ping' : ping of the player in ms
|
||||||
|
-- 'ipaddr': IP address of the player, SERVER ONLY
|
||||||
|
-- 'ucid' : Unique Client Identifier, SERVER ONLY
|
||||||
|
--
|
||||||
|
function NET:GetPlayerInfo(Client,Attribute)
|
||||||
|
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||||
|
if PlayerID then
|
||||||
|
return net.get_player_info(tonumber(PlayerID), Attribute)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Kicks a player from the server. Can display a message to the user.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @param #string Message (Optional) The message to send.
|
||||||
|
-- @return #boolean success
|
||||||
|
function NET:Kick(Client,Message)
|
||||||
|
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||||
|
if PlayerID and tonumber(PlayerID) ~= 1 then
|
||||||
|
return net.kick(tonumber(PlayerID), Message)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return a statistic for a given client.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @param #number StatisticID The statistic to obtain
|
||||||
|
-- @return #number Statistic or nil
|
||||||
|
-- @usage
|
||||||
|
-- StatisticIDs are:
|
||||||
|
--
|
||||||
|
-- net.PS_PING (0) - ping (in ms)
|
||||||
|
-- net.PS_CRASH (1) - number of crashes
|
||||||
|
-- net.PS_CAR (2) - number of destroyed vehicles
|
||||||
|
-- net.PS_PLANE (3) - ... planes/helicopters
|
||||||
|
-- net.PS_SHIP (4) - ... ships
|
||||||
|
-- net.PS_SCORE (5) - total score
|
||||||
|
-- net.PS_LAND (6) - number of landings
|
||||||
|
-- net.PS_EJECT (7) - of ejects
|
||||||
|
--
|
||||||
|
-- mynet:GetPlayerStatistic(Client,7) -- return number of ejects
|
||||||
|
function NET:GetPlayerStatistic(Client,StatisticID)
|
||||||
|
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||||
|
local stats = StatisticID or 0
|
||||||
|
if stats > 7 or stats < 0 then stats = 0 end
|
||||||
|
if PlayerID then
|
||||||
|
return net.get_stat(tonumber(PlayerID),stats)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return the name of a given client. Same a CLIENT:GetPlayerName().
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @return #string Name or nil if not obtainable
|
||||||
|
function NET:GetName(Client)
|
||||||
|
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||||
|
if PlayerID then
|
||||||
|
return net.get_name(tonumber(PlayerID))
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the SideId and SlotId of a given client.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @return #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
|
||||||
|
-- @return #number SlotID
|
||||||
|
function NET:GetSlot(Client)
|
||||||
|
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||||
|
if PlayerID then
|
||||||
|
local side,slot = net.get_slot(tonumber(PlayerID))
|
||||||
|
return side,slot
|
||||||
|
else
|
||||||
|
return nil,nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Force the slot for a specific client.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @param #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
|
||||||
|
-- @param #number SlotID Slot number
|
||||||
|
-- @return #boolean Success
|
||||||
|
function NET:ForceSlot(Client,SideID,SlotID)
|
||||||
|
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||||
|
if PlayerID then
|
||||||
|
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID )
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Force a client back to spectators.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param Wrapper.Client#CLIENT Client The client
|
||||||
|
-- @return #boolean Succes
|
||||||
|
function NET:ReturnToSpectators(Client)
|
||||||
|
local outcome = self:ForceSlot(Client,0)
|
||||||
|
return outcome
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Converts a lua value to a JSON string.
|
||||||
|
-- @param #string Lua Anything lua
|
||||||
|
-- @return #table Json
|
||||||
|
function NET.Lua2Json(Lua)
|
||||||
|
return net.lua2json(Lua)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Converts a JSON string to a lua value.
|
||||||
|
-- @param #string Json Anything JSON
|
||||||
|
-- @return #table Lua
|
||||||
|
function NET.Lua2Json(Json)
|
||||||
|
return net.json2lua(Json)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Executes a lua string in a given lua environment in the game.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param #string State The state in which to execute - see below.
|
||||||
|
-- @param #string DoString The lua string to be executed.
|
||||||
|
-- @return #string Output
|
||||||
|
-- @usage
|
||||||
|
-- States are:
|
||||||
|
-- 'config': the state in which $INSTALL_DIR/Config/main.cfg is executed, as well as $WRITE_DIR/Config/autoexec.cfg - used for configuration settings
|
||||||
|
-- 'mission': holds current mission
|
||||||
|
-- 'export': runs $WRITE_DIR/Scripts/Export.lua and the relevant export API
|
||||||
|
function NET:DoStringIn(State,DoString)
|
||||||
|
return net.dostring_in(State,DoString)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Write an "INFO" entry to the DCS log file, with the message Message.
|
||||||
|
-- @param #NET self
|
||||||
|
-- @param #string Message The message to be logged.
|
||||||
|
-- @return #NET self
|
||||||
|
function NET:Log(Message)
|
||||||
|
net.log(Message)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- End of NET
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
end
|
||||||
@ -30,8 +30,8 @@ Core/Timer.lua
|
|||||||
Core/Goal.lua
|
Core/Goal.lua
|
||||||
Core/Spot.lua
|
Core/Spot.lua
|
||||||
Core/TextAndSound.lua
|
Core/TextAndSound.lua
|
||||||
Core/Pathline.lua
|
|
||||||
Core/Condition.lua
|
Core/Condition.lua
|
||||||
|
Core/Pathline.lua
|
||||||
|
|
||||||
Wrapper/Object.lua
|
Wrapper/Object.lua
|
||||||
Wrapper/Identifiable.lua
|
Wrapper/Identifiable.lua
|
||||||
@ -45,6 +45,7 @@ Wrapper/Airbase.lua
|
|||||||
Wrapper/Scenery.lua
|
Wrapper/Scenery.lua
|
||||||
Wrapper/Marker.lua
|
Wrapper/Marker.lua
|
||||||
Wrapper/Weapon.lua
|
Wrapper/Weapon.lua
|
||||||
|
Wrapper/Net.lua
|
||||||
|
|
||||||
Cargo/Cargo.lua
|
Cargo/Cargo.lua
|
||||||
Cargo/CargoUnit.lua
|
Cargo/CargoUnit.lua
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user