Merge branch 'FF/Ops' into FF/OpsDev

This commit is contained in:
Frank 2023-02-12 11:53:42 +01:00
commit 4e280f02b6
9 changed files with 624 additions and 41 deletions

View File

@ -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))

View File

@ -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,6 +124,7 @@ 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
@ -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

View File

@ -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

View File

@ -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"
@ -710,7 +866,11 @@ function AICSAR:_CheckQueue()
-- 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()

View File

@ -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

View File

@ -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' )

View File

@ -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.

View 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

View File

@ -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