mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Merge branch 'develop' into FF/Ops
This commit is contained in:
commit
1253e241ff
10
.github/workflows/gh-pages.yml
vendored
10
.github/workflows/gh-pages.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
working-directory: docs/
|
working-directory: docs/
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
id: pages
|
id: pages
|
||||||
uses: actions/configure-pages@v3
|
uses: actions/configure-pages@v4
|
||||||
- name: Build with Jekyll
|
- name: Build with Jekyll
|
||||||
# Outputs to the './_site' directory by default
|
# Outputs to the './_site' directory by default
|
||||||
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
||||||
@ -52,7 +52,7 @@ jobs:
|
|||||||
working-directory: docs/
|
working-directory: docs/
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
# Automatically uploads an artifact from the './_site' directory by default
|
# Automatically uploads an artifact from the './_site' directory by default
|
||||||
uses: actions/upload-pages-artifact@v1
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: docs/_site/
|
path: docs/_site/
|
||||||
|
|
||||||
@ -66,13 +66,13 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v1
|
uses: actions/deploy-pages@v4
|
||||||
|
|
||||||
check:
|
check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: deploy
|
needs: deploy
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
- run: npm install linkinator
|
- run: npm install linkinator
|
||||||
- run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" --retry-errors --retry-errors-count 3 --retry-errors-jitter
|
- run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" --retry-errors --retry-errors-count 3 --retry-errors-jitter
|
||||||
|
|||||||
@ -1144,6 +1144,19 @@ function BASE:TraceClassMethod( Class, Method )
|
|||||||
self:I( "Tracing method " .. Method .. " of class " .. Class )
|
self:I( "Tracing method " .. Method .. " of class " .. Class )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Serialize arguments
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param #table Arguments
|
||||||
|
-- @return #string Text
|
||||||
|
function BASE:_Serialize(Arguments)
|
||||||
|
local text = UTILS.PrintTableToLog({Arguments}, 0, true)
|
||||||
|
text = string.gsub(text,"\n","")
|
||||||
|
text = string.gsub(text,"%(%(","%(")
|
||||||
|
text = string.gsub(text,"%)%)","%)")
|
||||||
|
text = string.gsub(text,"(%s+)","")
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
--- Trace a function call. This function is private.
|
--- Trace a function call. This function is private.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
@ -1168,7 +1181,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
|||||||
if DebugInfoFrom then
|
if DebugInfoFrom then
|
||||||
LineFrom = DebugInfoFrom.currentline
|
LineFrom = DebugInfoFrom.currentline
|
||||||
end
|
end
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, BASE:_Serialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1242,7 +1255,7 @@ function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
|||||||
if DebugInfoFrom then
|
if DebugInfoFrom then
|
||||||
LineFrom = DebugInfoFrom.currentline
|
LineFrom = DebugInfoFrom.currentline
|
||||||
end
|
end
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1314,7 +1327,7 @@ function BASE:E( Arguments )
|
|||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||||
else
|
else
|
||||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -1341,39 +1354,8 @@ function BASE:I( Arguments )
|
|||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||||
else
|
else
|
||||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, BASE:_Serialize(Arguments)) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- old stuff
|
|
||||||
|
|
||||||
-- function BASE:_Destructor()
|
|
||||||
-- --self:E("_Destructor")
|
|
||||||
--
|
|
||||||
-- --self:EventRemoveAll()
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- THIS IS WHY WE NEED LUA 5.2 ...
|
|
||||||
-- function BASE:_SetDestructor()
|
|
||||||
--
|
|
||||||
-- -- TODO: Okay, this is really technical...
|
|
||||||
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
|
|
||||||
-- -- Therefore, I am parking this logic until I've properly discussed all this with the community.
|
|
||||||
--
|
|
||||||
-- local proxy = newproxy(true)
|
|
||||||
-- local proxyMeta = getmetatable(proxy)
|
|
||||||
--
|
|
||||||
-- proxyMeta.__gc = function ()
|
|
||||||
-- env.info("In __gc for " .. self:GetClassNameAndID() )
|
|
||||||
-- if self._Destructor then
|
|
||||||
-- self:_Destructor()
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- -- keep the userdata from newproxy reachable until the object
|
|
||||||
-- -- table is about to be garbage-collected - then the __gc hook
|
|
||||||
-- -- will be invoked and the destructor called
|
|
||||||
-- rawset( self, '__proxy', proxy )
|
|
||||||
--
|
|
||||||
-- end
|
|
||||||
|
|||||||
@ -8,6 +8,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/Beacon)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
||||||
--
|
--
|
||||||
-- @module Core.Beacon
|
-- @module Core.Beacon
|
||||||
@ -286,6 +290,7 @@ end
|
|||||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||||
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||||
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||||
|
self:E("This method is DEPRECATED! Please use ActivateTACAN() instead.")
|
||||||
|
|
||||||
local IsValid = true
|
local IsValid = true
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,8 @@
|
|||||||
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
|
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
|
||||||
-- @field #table CLIENTS Clients.
|
-- @field #table CLIENTS Clients.
|
||||||
-- @field #table STORAGES DCS warehouse storages.
|
-- @field #table STORAGES DCS warehouse storages.
|
||||||
|
-- @field #table STNS Used Link16 octal numbers for F16/15/18/AWACS planes.
|
||||||
|
-- @field #table SADL Used Link16 octal numbers for A10/C-II planes.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
||||||
@ -93,6 +95,8 @@ DATABASE = {
|
|||||||
OPSZONES = {},
|
OPSZONES = {},
|
||||||
PATHLINES = {},
|
PATHLINES = {},
|
||||||
STORAGES = {},
|
STORAGES = {},
|
||||||
|
STNS={},
|
||||||
|
SADL={},
|
||||||
}
|
}
|
||||||
|
|
||||||
local _DATABASECoalition =
|
local _DATABASECoalition =
|
||||||
@ -928,7 +932,7 @@ function DATABASE:Spawn( SpawnTemplate )
|
|||||||
SpawnTemplate.CountryID = nil
|
SpawnTemplate.CountryID = nil
|
||||||
SpawnTemplate.CategoryID = nil
|
SpawnTemplate.CategoryID = nil
|
||||||
|
|
||||||
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID )
|
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID, SpawnTemplate.name )
|
||||||
|
|
||||||
self:T3( SpawnTemplate )
|
self:T3( SpawnTemplate )
|
||||||
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
|
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
|
||||||
@ -1029,10 +1033,31 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
|
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
|
||||||
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if UnitTemplate.AddPropAircraft then
|
||||||
|
if UnitTemplate.AddPropAircraft.STN_L16 then
|
||||||
|
local stn = UTILS.OctalToDecimal(UnitTemplate.AddPropAircraft.STN_L16)
|
||||||
|
if stn == nil or stn < 1 then
|
||||||
|
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||||
|
else
|
||||||
|
self.STNS[stn] = UnitTemplate.name
|
||||||
|
self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if UnitTemplate.AddPropAircraft.SADL_TN then
|
||||||
|
local sadl = UTILS.OctalToDecimal(UnitTemplate.AddPropAircraft.SADL_TN)
|
||||||
|
if sadl == nil or sadl < 1 then
|
||||||
|
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||||
|
else
|
||||||
|
self.SADL[sadl] = UnitTemplate.name
|
||||||
|
self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||||
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
|
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
|
||||||
@ -1043,6 +1068,80 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get next (consecutive) free STN as octal number.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #number octal Starting octal.
|
||||||
|
-- @param #string unitname Name of the associated unit.
|
||||||
|
-- @return #number Octal
|
||||||
|
function DATABASE:GetNextSTN(octal,unitname)
|
||||||
|
local first = UTILS.OctalToDecimal(octal)
|
||||||
|
if self.STNS[first] == unitname then return octal end
|
||||||
|
local nextoctal = 77777
|
||||||
|
local found = false
|
||||||
|
if 32767-first < 10 then
|
||||||
|
first = 0
|
||||||
|
end
|
||||||
|
for i=first+1,32767 do
|
||||||
|
if self.STNS[i] == nil then
|
||||||
|
found = true
|
||||||
|
nextoctal = UTILS.DecimalToOctal(i)
|
||||||
|
self.STNS[i] = unitname
|
||||||
|
self:T("Register STN "..tostring(nextoctal).." for ".. unitname)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found then
|
||||||
|
self:E(string.format("WARNING: No next free STN past %05d found!",octal))
|
||||||
|
-- cleanup
|
||||||
|
local NewSTNS = {}
|
||||||
|
for _id,_name in pairs(self.STNS) do
|
||||||
|
if self.UNITS[_name] ~= nil then
|
||||||
|
NewSTNS[_id] = _name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.STNS = nil
|
||||||
|
self.STNS = NewSTNS
|
||||||
|
end
|
||||||
|
return nextoctal
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get next (consecutive) free SADL as octal number.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #number octal Starting octal.
|
||||||
|
-- @param #string unitname Name of the associated unit.
|
||||||
|
-- @return #number Octal
|
||||||
|
function DATABASE:GetNextSADL(octal,unitname)
|
||||||
|
local first = UTILS.OctalToDecimal(octal)
|
||||||
|
if self.SADL[first] == unitname then return octal end
|
||||||
|
local nextoctal = 7777
|
||||||
|
local found = false
|
||||||
|
if 4095-first < 10 then
|
||||||
|
first = 0
|
||||||
|
end
|
||||||
|
for i=first+1,4095 do
|
||||||
|
if self.STNS[i] == nil then
|
||||||
|
found = true
|
||||||
|
nextoctal = UTILS.DecimalToOctal(i)
|
||||||
|
self.SADL[i] = unitname
|
||||||
|
self:T("Register SADL "..tostring(nextoctal).." for ".. unitname)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found then
|
||||||
|
self:E(string.format("WARNING: No next free SADL past %04d found!",octal))
|
||||||
|
-- cleanup
|
||||||
|
local NewSTNS = {}
|
||||||
|
for _id,_name in pairs(self.SADL) do
|
||||||
|
if self.UNITS[_name] ~= nil then
|
||||||
|
NewSTNS[_id] = _name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.SADL = nil
|
||||||
|
self.SADL = NewSTNS
|
||||||
|
end
|
||||||
|
return nextoctal
|
||||||
|
end
|
||||||
|
|
||||||
--- Get group template.
|
--- Get group template.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #string GroupName Group name.
|
-- @param #string GroupName Group name.
|
||||||
|
|||||||
@ -1378,6 +1378,7 @@ function EVENT:onEvent( Event )
|
|||||||
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||||
Event.MarkText=Event.text
|
Event.MarkText=Event.text
|
||||||
Event.MarkCoalition=Event.coalition
|
Event.MarkCoalition=Event.coalition
|
||||||
|
Event.IniCoalition=Event.coalition
|
||||||
Event.MarkGroupID = Event.groupID
|
Event.MarkGroupID = Event.groupID
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
-- ### Author: **Applevangelist**
|
-- ### Author: **Applevangelist**
|
||||||
--
|
--
|
||||||
-- Date: 5 May 2021
|
-- Date: 5 May 2021
|
||||||
-- Last Update: Feb 2023
|
-- Last Update: Mar 2023
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
---
|
---
|
||||||
@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
|||||||
ClassName = "MARKEROPS",
|
ClassName = "MARKEROPS",
|
||||||
Tag = "mytag",
|
Tag = "mytag",
|
||||||
Keywords = {},
|
Keywords = {},
|
||||||
version = "0.1.1",
|
version = "0.1.3",
|
||||||
debug = false,
|
debug = false,
|
||||||
Casesensitive = true,
|
Casesensitive = true,
|
||||||
}
|
}
|
||||||
@ -114,6 +114,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 MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
|
|
||||||
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||||
@ -124,7 +126,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
|
-- @param #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
|
|
||||||
--- 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
|
||||||
@ -133,7 +136,7 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
|||||||
-- @param #string Event The Event called
|
-- @param #string Event The Event called
|
||||||
-- @param #string To The To state
|
-- @param #string To The To state
|
||||||
|
|
||||||
--- "Stop" trigger. Used to stop the function an unhandle events
|
--- "Stop" trigger. Used to stop the function an unhandle events
|
||||||
-- @function [parent=#MARKEROPS_BASE] Stop
|
-- @function [parent=#MARKEROPS_BASE] Stop
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -155,29 +158,30 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
|||||||
local text = tostring(Event.text)
|
local text = tostring(Event.text)
|
||||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||||
end
|
end
|
||||||
|
local coalition = Event.MarkCoalition
|
||||||
-- decision
|
-- decision
|
||||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||||
self:T({event="S_EVENT_MARK_ADDED", carrier=self.groupname, vec3=Event.pos})
|
self:T({event="S_EVENT_MARK_ADDED", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||||
-- Handle event
|
-- Handle event
|
||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
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:MarkAdded(Eventtext,matchtable,coord)
|
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||||
self:T({event="S_EVENT_MARK_CHANGE", carrier=self.groupname, vec3=Event.pos})
|
self:T({event="S_EVENT_MARK_CHANGE", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||||
-- Handle event.
|
-- Handle event.
|
||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
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,Event.idx)
|
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||||
self:T({event="S_EVENT_MARK_REMOVED", carrier=self.groupname, vec3=Event.pos})
|
self:T({event="S_EVENT_MARK_REMOVED", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||||
-- Hande event.
|
-- Hande event.
|
||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
@ -230,8 +234,10 @@ end
|
|||||||
-- @param #string To The To state
|
-- @param #string To The To state
|
||||||
-- @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 #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
|
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
|
||||||
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -242,8 +248,10 @@ end
|
|||||||
-- @param #string To The To state
|
-- @param #string To The To state
|
||||||
-- @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 #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
|
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
|
||||||
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1097,6 +1097,7 @@ do
|
|||||||
GroupPrefixes = nil,
|
GroupPrefixes = nil,
|
||||||
Zones = nil,
|
Zones = nil,
|
||||||
Functions = nil,
|
Functions = nil,
|
||||||
|
Alive = nil,
|
||||||
},
|
},
|
||||||
FilterMeta = {
|
FilterMeta = {
|
||||||
Coalitions = {
|
Coalitions = {
|
||||||
@ -1470,7 +1471,7 @@ do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Builds a set of groups that are only active.
|
--- Builds a set of groups that are active, ie in the mission but not yet activated (false) or actived (true).
|
||||||
-- Only the groups that are active will be included within the set.
|
-- Only the groups that are active will be included within the set.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param #boolean Active (Optional) Include only active groups to the set.
|
-- @param #boolean Active (Optional) Include only active groups to the set.
|
||||||
@ -1495,6 +1496,14 @@ do
|
|||||||
self.Filter.Active = Active
|
self.Filter.Active = Active
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Build a set of groups that are alive.
|
||||||
|
-- @param #SET_GROUP self
|
||||||
|
-- @return #SET_GROUP self
|
||||||
|
function SET_GROUP:FilterAlive()
|
||||||
|
self.Filter.Alive = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Starts the filtering.
|
--- Starts the filtering.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
@ -1993,7 +2002,16 @@ do
|
|||||||
function SET_GROUP:IsIncludeObject( MGroup )
|
function SET_GROUP:IsIncludeObject( MGroup )
|
||||||
self:F2( MGroup )
|
self:F2( MGroup )
|
||||||
local MGroupInclude = true
|
local MGroupInclude = true
|
||||||
|
|
||||||
|
if self.Filter.Alive == true then
|
||||||
|
local MGroupAlive = false
|
||||||
|
self:F( { Active = self.Filter.Active } )
|
||||||
|
if MGroup and MGroup:IsAlive() then
|
||||||
|
MGroupAlive = true
|
||||||
|
end
|
||||||
|
MGroupInclude = MGroupInclude and MGroupAlive
|
||||||
|
end
|
||||||
|
|
||||||
if self.Filter.Active ~= nil then
|
if self.Filter.Active ~= nil then
|
||||||
local MGroupActive = false
|
local MGroupActive = false
|
||||||
self:F( { Active = self.Filter.Active } )
|
self:F( { Active = self.Filter.Active } )
|
||||||
@ -2997,7 +3015,7 @@ do -- SET_UNIT
|
|||||||
local velocity = self:GetVelocity() or 0
|
local velocity = self:GetVelocity() or 0
|
||||||
Coordinate:SetHeading( heading )
|
Coordinate:SetHeading( heading )
|
||||||
Coordinate:SetVelocity( velocity )
|
Coordinate:SetVelocity( velocity )
|
||||||
self:I(UTILS.PrintTableToLog(Coordinate))
|
self:T(UTILS.PrintTableToLog(Coordinate))
|
||||||
end
|
end
|
||||||
|
|
||||||
return Coordinate
|
return Coordinate
|
||||||
@ -4521,7 +4539,7 @@ do -- SET_CLIENT
|
|||||||
if Event.IniObjectCategory == Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround() then
|
if Event.IniObjectCategory == Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround() then
|
||||||
-- CA Slot entered
|
-- CA Slot entered
|
||||||
local ObjectName, Object = self:AddInDatabase( Event )
|
local ObjectName, Object = self:AddInDatabase( Event )
|
||||||
self:I( ObjectName, UTILS.PrintTableToLog(Object) )
|
self:T( ObjectName, UTILS.PrintTableToLog(Object) )
|
||||||
if Object and self:IsIncludeObject( Object ) then
|
if Object and self:IsIncludeObject( Object ) then
|
||||||
self:Add( ObjectName, Object )
|
self:Add( ObjectName, Object )
|
||||||
end
|
end
|
||||||
|
|||||||
@ -199,6 +199,22 @@
|
|||||||
--
|
--
|
||||||
-- * @{#SPAWN.InitRepeat}() or @{#SPAWN.InitRepeatOnLanding}(): This method is used to re-spawn automatically the same group after it has landed.
|
-- * @{#SPAWN.InitRepeat}() or @{#SPAWN.InitRepeatOnLanding}(): This method is used to re-spawn automatically the same group after it has landed.
|
||||||
-- * @{#SPAWN.InitRepeatOnEngineShutDown}(): This method is used to re-spawn automatically the same group after it has landed and it shuts down the engines at the ramp.
|
-- * @{#SPAWN.InitRepeatOnEngineShutDown}(): This method is used to re-spawn automatically the same group after it has landed and it shuts down the engines at the ramp.
|
||||||
|
--
|
||||||
|
-- ### Link-16 Datalink STN and SADL IDs (limited at the moment to F15/16/18/AWACS/Tanker/B1B, but not the F15E for clients, SADL A10CII only)
|
||||||
|
--
|
||||||
|
-- *{#SPAWN.InitSTN}(): Set the STN of the first unit in the group. All other units will have consecutive STNs, provided they have not been used yet.
|
||||||
|
-- *{#SPAWN.InitSADL}(): Set the SADL of the first unit in the group. All other units will have consecutive SADLs, provided they have not been used yet.
|
||||||
|
--
|
||||||
|
-- ### Callsigns
|
||||||
|
--
|
||||||
|
-- *{#SPAWN.InitRandomizeCallsign}(): Set a random callsign name per spawn.
|
||||||
|
-- *{#SPAWN.SpawnInitCallSign}(): Set a specific callsign for a spawned group.
|
||||||
|
--
|
||||||
|
-- ### Speed
|
||||||
|
--
|
||||||
|
-- *{#SPAWN.InitSpeedMps}(): Set the initial speed on spawning in meters per second.
|
||||||
|
-- *{#SPAWN.InitSpeedKph}(): Set the initial speed on spawning in kilometers per hour.
|
||||||
|
-- *{#SPAWN.InitSpeedKnots}(): Set the initial speed on spawning in knots.
|
||||||
--
|
--
|
||||||
-- ## SPAWN **Spawn** methods
|
-- ## SPAWN **Spawn** methods
|
||||||
--
|
--
|
||||||
@ -520,7 +536,7 @@ function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPr
|
|||||||
end
|
end
|
||||||
|
|
||||||
if SpawnTemplate then
|
if SpawnTemplate then
|
||||||
self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
|
self.SpawnTemplate = UTILS.DeepCopy(SpawnTemplate) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
|
||||||
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
||||||
self.SpawnAliasPrefix = SpawnAliasPrefix or SpawnTemplatePrefix
|
self.SpawnAliasPrefix = SpawnAliasPrefix or SpawnTemplatePrefix
|
||||||
self.SpawnTemplate.name = SpawnTemplatePrefix
|
self.SpawnTemplate.name = SpawnTemplatePrefix
|
||||||
@ -724,7 +740,7 @@ end
|
|||||||
-- @param #number Country Country id as number or enumerator:
|
-- @param #number Country Country id as number or enumerator:
|
||||||
--
|
--
|
||||||
-- * @{DCS#country.id.RUSSIA}
|
-- * @{DCS#country.id.RUSSIA}
|
||||||
-- * @{DCS#county.id.USA}
|
-- * @{DCS#country.id.USA}
|
||||||
--
|
--
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
function SPAWN:InitCountry( Country )
|
function SPAWN:InitCountry( Country )
|
||||||
@ -780,6 +796,82 @@ function SPAWN:InitSkill( Skill )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Airplane - F15/16/18/AWACS/B1B/Tanker only] Set the STN Link16 starting number of the Group; each unit of the spawned group will have a consecutive STN set.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number Octal The octal number (digits 1..7, max 5 digits, i.e. 1..77777) to set the STN to. Every STN needs to be unique!
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSTN(Octal)
|
||||||
|
self:F( { Octal = Octal } )
|
||||||
|
self.SpawnInitSTN = Octal or 77777
|
||||||
|
local num = UTILS.OctalToDecimal(Octal)
|
||||||
|
if num == nil or num < 1 then
|
||||||
|
self:E("WARNING - STN "..tostring(Octal).." is not valid!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
if _DATABASE.STNS[num] ~= nil then
|
||||||
|
self:E("WARNING - STN already assigned: "..tostring(Octal).." is used for ".._DATABASE.STNS[Octal])
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane - A10-C II only] Set the SADL TN starting number of the Group; each unit of the spawned group will have a consecutive SADL set.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number Octal The octal number (digits 1..7, max 4 digits, i.e. 1..7777) to set the SADL to. Every SADL needs to be unique!
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSADL(Octal)
|
||||||
|
self:F( { Octal = Octal } )
|
||||||
|
self.SpawnInitSADL = Octal or 7777
|
||||||
|
local num = UTILS.OctalToDecimal(Octal)
|
||||||
|
if num == nil or num < 1 then
|
||||||
|
self:E("WARNING - SADL "..tostring(Octal).." is not valid!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
if _DATABASE.SADL[num] ~= nil then
|
||||||
|
self:E("WARNING - SADL already assigned: "..tostring(Octal).." is used for ".._DATABASE.SADL[Octal])
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane] Set the initial speed on spawning in meters per second. Useful when spawning in-air only.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number MPS The speed in MPS to use.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSpeedMps(MPS)
|
||||||
|
self:F( { MPS = MPS } )
|
||||||
|
if MPS == nil or tonumber(MPS)<0 then
|
||||||
|
MPS=125
|
||||||
|
end
|
||||||
|
self.InitSpeed = MPS
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane] Set the initial speed on spawning in knots. Useful when spawning in-air only.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number Knots The speed in knots to use.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSpeedKnots(Knots)
|
||||||
|
self:F( { Knots = Knots } )
|
||||||
|
if Knots == nil or tonumber(Knots)<0 then
|
||||||
|
Knots=300
|
||||||
|
end
|
||||||
|
self.InitSpeed = UTILS.KnotsToMps(Knots)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane] Set the initial speed on spawning in kilometers per hour. Useful when spawning in-air only.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number KPH The speed in KPH to use.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSpeedKph(KPH)
|
||||||
|
self:F( { KPH = KPH } )
|
||||||
|
if KPH == nil or tonumber(KPH)<0 then
|
||||||
|
KPH=UTILS.KnotsToKmph(300)
|
||||||
|
end
|
||||||
|
self.InitSpeed = UTILS.KmphToMps(KPH)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Sets the radio communication on or off. Same as checking/unchecking the COMM box in the mission editor.
|
--- Sets the radio communication on or off. Same as checking/unchecking the COMM box in the mission editor.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #number switch If true (or nil), enables the radio communication. If false, disables the radio for the spawned group.
|
-- @param #number switch If true (or nil), enables the radio communication. If false, disables the radio for the spawned group.
|
||||||
@ -1699,6 +1791,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
end
|
end
|
||||||
|
|
||||||
self.SpawnGroups[self.SpawnIndex].Spawned = true
|
self.SpawnGroups[self.SpawnIndex].Spawned = true
|
||||||
|
self.SpawnGroups[self.SpawnIndex].Group.TemplateDonor = self.SpawnTemplatePrefix
|
||||||
return self.SpawnGroups[self.SpawnIndex].Group
|
return self.SpawnGroups[self.SpawnIndex].Group
|
||||||
else
|
else
|
||||||
-- self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } )
|
-- self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } )
|
||||||
@ -3303,7 +3396,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.SpawnInitKeepUnitNames == false then
|
if self.SpawnInitKeepUnitNames == false then
|
||||||
for UnitID = 1, #SpawnTemplate.units do
|
for UnitID = 1, #SpawnTemplate.units do
|
||||||
SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID )
|
SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID )
|
||||||
@ -3311,9 +3404,17 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
for UnitID = 1, #SpawnTemplate.units do
|
for UnitID = 1, #SpawnTemplate.units do
|
||||||
local UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
|
local SpawnInitKeepUnitIFF = false
|
||||||
self:T( { UnitPrefix, Rest } )
|
if string.find(SpawnTemplate.units[UnitID].name,"#IFF_",1,true) then --Razbam IFF hack for F15E etc
|
||||||
|
SpawnInitKeepUnitIFF = true
|
||||||
|
end
|
||||||
|
local UnitPrefix, Rest
|
||||||
|
if SpawnInitKeepUnitIFF == false then
|
||||||
|
UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
|
||||||
|
self:T( { UnitPrefix, Rest } )
|
||||||
|
else
|
||||||
|
UnitPrefix=SpawnTemplate.units[UnitID].name
|
||||||
|
end
|
||||||
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
|
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
|
||||||
SpawnTemplate.units[UnitID].unitId = nil
|
SpawnTemplate.units[UnitID].unitId = nil
|
||||||
end
|
end
|
||||||
@ -3395,34 +3496,56 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
|||||||
SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex
|
SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- Speed
|
||||||
|
if self.InitSpeed then
|
||||||
|
SpawnTemplate.units[UnitID].speed = self.InitSpeed
|
||||||
|
end
|
||||||
-- Link16
|
-- Link16
|
||||||
local AddProps = SpawnTemplate.units[UnitID].AddPropAircraft
|
local AddProps = SpawnTemplate.units[UnitID].AddPropAircraft
|
||||||
if AddProps then
|
if AddProps then
|
||||||
if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
|
if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
|
||||||
-- 4 digit octal with leading 0
|
if self.SpawnInitSTN then
|
||||||
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16) ~= nil then
|
local octal = self.SpawnInitSTN
|
||||||
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
|
if UnitID > 1 then
|
||||||
local decimal = UTILS.OctalToDecimal(octal)+UnitID-1
|
octal = _DATABASE:GetNextSTN(self.SpawnInitSTN,SpawnTemplate.units[UnitID].name)
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",UTILS.DecimalToOctal(decimal))
|
end
|
||||||
else -- ED bug - chars in here
|
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",octal)
|
||||||
local STN = math.floor(UTILS.RandomGaussian(4088/2,nil,1000,4088))
|
else
|
||||||
STN = STN+UnitID-1
|
-- 5 digit octal with leading 0
|
||||||
local OSTN = UTILS.DecimalToOctal(STN)
|
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16) ~= nil then
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",OSTN)
|
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
|
||||||
|
local num = UTILS.OctalToDecimal(octal)
|
||||||
|
if _DATABASE.STNS[num] ~= nil or UnitID > 1 then -- STN taken or next unit
|
||||||
|
octal = _DATABASE:GetNextSTN(octal,SpawnTemplate.units[UnitID].name)
|
||||||
|
end
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",octal)
|
||||||
|
else -- ED bug - chars in here
|
||||||
|
local OSTN = _DATABASE:GetNextSTN(1,SpawnTemplate.units[UnitID].name)
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",OSTN)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- A10CII
|
-- A10CII
|
||||||
if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
|
if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
|
||||||
-- 3 digit octal with leading 0
|
-- 4 digit octal with leading 0
|
||||||
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN) ~= nil then
|
if self.SpawnInitSADL then
|
||||||
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
|
local octal = self.SpawnInitSADL
|
||||||
local decimal = UTILS.OctalToDecimal(octal)+UnitID-1
|
if UnitID > 1 then
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",UTILS.DecimalToOctal(decimal))
|
octal = _DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
|
||||||
else -- ED bug - chars in here
|
end
|
||||||
local STN = math.floor(UTILS.RandomGaussian(504/2,nil,100,504))
|
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",octal)
|
||||||
STN = STN+UnitID-1
|
else
|
||||||
local OSTN = UTILS.DecimalToOctal(STN)
|
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN) ~= nil then
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",OSTN)
|
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
|
||||||
|
local num = UTILS.OctalToDecimal(octal)
|
||||||
|
if _DATABASE.SADL[num] ~= nil or UnitID > 1 then -- SADL taken or next unit
|
||||||
|
octal = _DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
|
||||||
|
end
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",octal)
|
||||||
|
else -- ED bug - chars in here
|
||||||
|
local OSTN = _DATABASE:GetNextSADL(1,SpawnTemplate.units[UnitID].name)
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",OSTN)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- VoiceCallsignNumber
|
-- VoiceCallsignNumber
|
||||||
|
|||||||
@ -1,36 +1,36 @@
|
|||||||
--- **Core** - Spawn statics.
|
--- **Core** - Spawn statics.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Spawn new statics from a static already defined in the mission editor.
|
-- * Spawn new statics from a static already defined in the mission editor.
|
||||||
-- * Spawn new statics from a given template.
|
-- * Spawn new statics from a given template.
|
||||||
-- * Spawn new statics from a given type.
|
-- * Spawn new statics from a given type.
|
||||||
-- * Spawn with a custom heading and location.
|
-- * Spawn with a custom heading and location.
|
||||||
-- * Spawn within a zone.
|
-- * Spawn within a zone.
|
||||||
-- * Spawn statics linked to units, .e.g on aircraft carriers.
|
-- * Spawn statics linked to units, .e.g on aircraft carriers.
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Core/SpawnStatic)
|
|
||||||
--
|
--
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- # Demo Missions
|
||||||
|
--
|
||||||
|
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/SpawnStatic)
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
-- ## No videos yet!
|
-- ## No videos yet!
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions: **funkyfranky**
|
-- ### Contributions: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Core.SpawnStatic
|
-- @module Core.SpawnStatic
|
||||||
-- @image Core_Spawnstatic.JPG
|
-- @image Core_Spawnstatic.JPG
|
||||||
|
|
||||||
@ -58,37 +58,37 @@
|
|||||||
|
|
||||||
|
|
||||||
--- Allows to spawn dynamically new @{Wrapper.Static}s into your mission.
|
--- Allows to spawn dynamically new @{Wrapper.Static}s into your mission.
|
||||||
--
|
--
|
||||||
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
||||||
-- and "copy" these properties to create a new static object and place it at the desired coordinate.
|
-- and "copy" these properties to create a new static object and place it at the desired coordinate.
|
||||||
--
|
--
|
||||||
-- New spawned @{Wrapper.Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
-- New spawned @{Wrapper.Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
||||||
-- By default, spawned @{Wrapper.Static}s will follow a naming convention at run-time:
|
-- By default, spawned @{Wrapper.Static}s will follow a naming convention at run-time:
|
||||||
--
|
--
|
||||||
-- * Spawned @{Wrapper.Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
-- * Spawned @{Wrapper.Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
||||||
--
|
--
|
||||||
-- # SPAWNSTATIC Constructors
|
-- # SPAWNSTATIC Constructors
|
||||||
--
|
--
|
||||||
-- Firstly, we need to create a SPAWNSTATIC object that will be used to spawn new statics into the mission. There are three ways to do this.
|
-- Firstly, we need to create a SPAWNSTATIC object that will be used to spawn new statics into the mission. There are three ways to do this.
|
||||||
--
|
--
|
||||||
-- ## Use another Static
|
-- ## Use another Static
|
||||||
--
|
--
|
||||||
-- A new SPAWNSTATIC object can be created using another static by the @{#SPAWNSTATIC.NewFromStatic}() function. All parameters such as position, heading, country will be initialized
|
-- A new SPAWNSTATIC object can be created using another static by the @{#SPAWNSTATIC.NewFromStatic}() function. All parameters such as position, heading, country will be initialized
|
||||||
-- from the static.
|
-- from the static.
|
||||||
--
|
--
|
||||||
-- ## From a Template
|
-- ## From a Template
|
||||||
--
|
--
|
||||||
-- A SPAWNSTATIC object can also be created from a template table using the @{#SPAWNSTATIC.NewFromTemplate}(SpawnTemplate, CountryID) function. All parameters are taken from the template.
|
-- A SPAWNSTATIC object can also be created from a template table using the @{#SPAWNSTATIC.NewFromTemplate}(SpawnTemplate, CountryID) function. All parameters are taken from the template.
|
||||||
--
|
--
|
||||||
-- ## From a Type
|
-- ## From a Type
|
||||||
--
|
--
|
||||||
-- A very basic method is to create a SPAWNSTATIC object by just giving the type of the static. All parameters must be initialized from the InitXYZ functions described below. Otherwise default values
|
-- A very basic method is to create a SPAWNSTATIC object by just giving the type of the static. All parameters must be initialized from the InitXYZ functions described below. Otherwise default values
|
||||||
-- are used. For example, if no spawn coordinate is given, the static will be created at the origin of the map.
|
-- are used. For example, if no spawn coordinate is given, the static will be created at the origin of the map.
|
||||||
--
|
--
|
||||||
-- # Setting Parameters
|
-- # Setting Parameters
|
||||||
--
|
--
|
||||||
-- Parameters such as the spawn position, heading, country etc. can be set via :Init*XYZ* functions. Note that these functions must be given before the actual spawn command!
|
-- Parameters such as the spawn position, heading, country etc. can be set via :Init*XYZ* functions. Note that these functions must be given before the actual spawn command!
|
||||||
--
|
--
|
||||||
-- * @{#SPAWNSTATIC.InitCoordinate}(Coordinate) Sets the coordinate where the static is spawned. Statics are always spawnd on the ground.
|
-- * @{#SPAWNSTATIC.InitCoordinate}(Coordinate) Sets the coordinate where the static is spawned. Statics are always spawnd on the ground.
|
||||||
-- * @{#SPAWNSTATIC.InitHeading}(Heading) sets the orientation of the static.
|
-- * @{#SPAWNSTATIC.InitHeading}(Heading) sets the orientation of the static.
|
||||||
-- * @{#SPAWNSTATIC.InitLivery}(LiveryName) sets the livery of the static. Not all statics support this.
|
-- * @{#SPAWNSTATIC.InitLivery}(LiveryName) sets the livery of the static. Not all statics support this.
|
||||||
@ -99,17 +99,17 @@
|
|||||||
-- * @{#SPAWNSTATIC.InitLinkToUnit}(Unit, OffsetX, OffsetY, OffsetAngle) links the static to a unit, e.g. to an aircraft carrier.
|
-- * @{#SPAWNSTATIC.InitLinkToUnit}(Unit, OffsetX, OffsetY, OffsetAngle) links the static to a unit, e.g. to an aircraft carrier.
|
||||||
--
|
--
|
||||||
-- # Spawning the Statics
|
-- # Spawning the Statics
|
||||||
--
|
--
|
||||||
-- Once the SPAWNSTATIC object is created and parameters are initialized, the spawn command can be given. There are different methods where some can be used to directly set parameters
|
-- Once the SPAWNSTATIC object is created and parameters are initialized, the spawn command can be given. There are different methods where some can be used to directly set parameters
|
||||||
-- such as position and heading.
|
-- such as position and heading.
|
||||||
--
|
--
|
||||||
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
--
|
--
|
||||||
-- @field #SPAWNSTATIC SPAWNSTATIC
|
-- @field #SPAWNSTATIC SPAWNSTATIC
|
||||||
--
|
--
|
||||||
SPAWNSTATIC = {
|
SPAWNSTATIC = {
|
||||||
ClassName = "SPAWNSTATIC",
|
ClassName = "SPAWNSTATIC",
|
||||||
SpawnIndex = 0,
|
SpawnIndex = 0,
|
||||||
@ -139,9 +139,9 @@ SPAWNSTATIC = {
|
|||||||
function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
|
|
||||||
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate(SpawnTemplateName)
|
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate(SpawnTemplateName)
|
||||||
|
|
||||||
if TemplateStatic then
|
if TemplateStatic then
|
||||||
self.SpawnTemplatePrefix = SpawnTemplateName
|
self.SpawnTemplatePrefix = SpawnTemplateName
|
||||||
self.TemplateStaticUnit = UTILS.DeepCopy(TemplateStatic.units[1])
|
self.TemplateStaticUnit = UTILS.DeepCopy(TemplateStatic.units[1])
|
||||||
@ -166,11 +166,11 @@ end
|
|||||||
function SPAWNSTATIC:NewFromTemplate(SpawnTemplate, CountryID)
|
function SPAWNSTATIC:NewFromTemplate(SpawnTemplate, CountryID)
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
|
|
||||||
self.TemplateStaticUnit = UTILS.DeepCopy(SpawnTemplate)
|
self.TemplateStaticUnit = UTILS.DeepCopy(SpawnTemplate)
|
||||||
self.SpawnTemplatePrefix = SpawnTemplate.name
|
self.SpawnTemplatePrefix = SpawnTemplate.name
|
||||||
self.CountryID = CountryID or country.id.USA
|
self.CountryID = CountryID or country.id.USA
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ function SPAWNSTATIC:NewFromType(StaticType, StaticCategory, CountryID)
|
|||||||
self.InitStaticCategory=StaticCategory
|
self.InitStaticCategory=StaticCategory
|
||||||
self.CountryID=CountryID or country.id.USA
|
self.CountryID=CountryID or country.id.USA
|
||||||
self.SpawnTemplatePrefix=self.InitStaticType
|
self.SpawnTemplatePrefix=self.InitStaticType
|
||||||
|
|
||||||
self.InitStaticCoordinate=COORDINATE:New(0, 0, 0)
|
self.InitStaticCoordinate=COORDINATE:New(0, 0, 0)
|
||||||
self.InitStaticHeading=0
|
self.InitStaticHeading=0
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ function SPAWNSTATIC:InitCountry(CountryID)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Initialize name prefix statics get. This will be appended by "#0001", "#0002" etc.
|
--- Initialize name prefix statics get. This will be appended by "#0001", "#0002" etc.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string NamePrefix Name prefix of statics spawned. Will append #0001, etc to the name.
|
-- @param #string NamePrefix Name prefix of statics spawned. Will append #0001, etc to the name.
|
||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
@ -327,13 +327,13 @@ function SPAWNSTATIC:Spawn(Heading, NewName)
|
|||||||
if Heading then
|
if Heading then
|
||||||
self.InitStaticHeading=Heading
|
self.InitStaticHeading=Heading
|
||||||
end
|
end
|
||||||
|
|
||||||
if NewName then
|
if NewName then
|
||||||
self.InitStaticName=NewName
|
self.InitStaticName=NewName
|
||||||
end
|
end
|
||||||
|
|
||||||
return self:_SpawnStatic(self.TemplateStaticUnit, self.CountryID)
|
return self:_SpawnStatic(self.TemplateStaticUnit, self.CountryID)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a new @{Wrapper.Static} from a POINT_VEC2.
|
--- Creates a new @{Wrapper.Static} from a POINT_VEC2.
|
||||||
@ -347,7 +347,7 @@ function SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, NewName)
|
|||||||
local vec2={x=PointVec2:GetX(), y=PointVec2:GetY()}
|
local vec2={x=PointVec2:GetX(), y=PointVec2:GetY()}
|
||||||
|
|
||||||
local Coordinate=COORDINATE:NewFromVec2(vec2)
|
local Coordinate=COORDINATE:NewFromVec2(vec2)
|
||||||
|
|
||||||
return self:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
return self:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -362,11 +362,11 @@ function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
|||||||
|
|
||||||
-- Set up coordinate.
|
-- Set up coordinate.
|
||||||
self.InitStaticCoordinate=Coordinate
|
self.InitStaticCoordinate=Coordinate
|
||||||
|
|
||||||
if Heading then
|
if Heading then
|
||||||
self.InitStaticHeading=Heading
|
self.InitStaticHeading=Heading
|
||||||
end
|
end
|
||||||
|
|
||||||
if NewName then
|
if NewName then
|
||||||
self.InitStaticName=NewName
|
self.InitStaticName=NewName
|
||||||
end
|
end
|
||||||
@ -385,7 +385,7 @@ function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
|||||||
|
|
||||||
-- Spawn the new static at the center of the zone.
|
-- Spawn the new static at the center of the zone.
|
||||||
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||||
|
|
||||||
return Static
|
return Static
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -399,45 +399,45 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
Template=Template or {}
|
Template=Template or {}
|
||||||
|
|
||||||
local CountryID=CountryID or self.CountryID
|
local CountryID=CountryID or self.CountryID
|
||||||
|
|
||||||
if self.InitStaticType then
|
if self.InitStaticType then
|
||||||
Template.type=self.InitStaticType
|
Template.type=self.InitStaticType
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticCategory then
|
if self.InitStaticCategory then
|
||||||
Template.category=self.InitStaticCategory
|
Template.category=self.InitStaticCategory
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticCoordinate then
|
if self.InitStaticCoordinate then
|
||||||
Template.x = self.InitStaticCoordinate.x
|
Template.x = self.InitStaticCoordinate.x
|
||||||
Template.y = self.InitStaticCoordinate.z
|
Template.y = self.InitStaticCoordinate.z
|
||||||
Template.alt = self.InitStaticCoordinate.y
|
Template.alt = self.InitStaticCoordinate.y
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticHeading then
|
if self.InitStaticHeading then
|
||||||
Template.heading = math.rad(self.InitStaticHeading)
|
Template.heading = math.rad(self.InitStaticHeading)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticShape then
|
if self.InitStaticShape then
|
||||||
Template.shape_name=self.InitStaticShape
|
Template.shape_name=self.InitStaticShape
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticLivery then
|
if self.InitStaticLivery then
|
||||||
Template.livery_id=self.InitStaticLivery
|
Template.livery_id=self.InitStaticLivery
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticDead~=nil then
|
if self.InitStaticDead~=nil then
|
||||||
Template.dead=self.InitStaticDead
|
Template.dead=self.InitStaticDead
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticCargo~=nil then
|
if self.InitStaticCargo~=nil then
|
||||||
Template.canCargo=self.InitStaticCargo
|
Template.canCargo=self.InitStaticCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitStaticCargoMass~=nil then
|
if self.InitStaticCargoMass~=nil then
|
||||||
Template.mass=self.InitStaticCargoMass
|
Template.mass=self.InitStaticCargoMass
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitLinkUnit then
|
if self.InitLinkUnit then
|
||||||
Template.linkUnit=self.InitLinkUnit:GetID()
|
Template.linkUnit=self.InitLinkUnit:GetID()
|
||||||
Template.linkOffset=true
|
Template.linkOffset=true
|
||||||
@ -446,45 +446,45 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
Template.offsets.x=self.InitOffsetX
|
Template.offsets.x=self.InitOffsetX
|
||||||
Template.offsets.angle=self.InitOffsetAngle and math.rad(self.InitOffsetAngle) or 0
|
Template.offsets.angle=self.InitOffsetAngle and math.rad(self.InitOffsetAngle) or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitFarp then
|
if self.InitFarp then
|
||||||
Template.heliport_callsign_id = self.InitFarpCallsignID
|
Template.heliport_callsign_id = self.InitFarpCallsignID
|
||||||
Template.heliport_frequency = self.InitFarpFreq
|
Template.heliport_frequency = self.InitFarpFreq
|
||||||
Template.heliport_modulation = self.InitFarpModu
|
Template.heliport_modulation = self.InitFarpModu
|
||||||
Template.unitId=nil
|
Template.unitId=nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Increase spawn index counter.
|
-- Increase spawn index counter.
|
||||||
self.SpawnIndex = self.SpawnIndex + 1
|
self.SpawnIndex = self.SpawnIndex + 1
|
||||||
|
|
||||||
-- Name of the spawned static.
|
-- Name of the spawned static.
|
||||||
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
|
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
|
||||||
|
|
||||||
-- Add and register the new static.
|
-- Add and register the new static.
|
||||||
local mystatic=_DATABASE:AddStatic(Template.name)
|
local mystatic=_DATABASE:AddStatic(Template.name)
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T(Template)
|
self:T(Template)
|
||||||
|
|
||||||
-- Add static to the game.
|
-- Add static to the game.
|
||||||
local Static=nil --DCS#StaticObject
|
local Static=nil --DCS#StaticObject
|
||||||
|
|
||||||
if self.InitFarp then
|
if self.InitFarp then
|
||||||
|
|
||||||
local TemplateGroup={}
|
local TemplateGroup={}
|
||||||
TemplateGroup.units={}
|
TemplateGroup.units={}
|
||||||
TemplateGroup.units[1]=Template
|
TemplateGroup.units[1]=Template
|
||||||
|
|
||||||
TemplateGroup.visible=true
|
TemplateGroup.visible=true
|
||||||
TemplateGroup.hidden=false
|
TemplateGroup.hidden=false
|
||||||
TemplateGroup.x=Template.x
|
TemplateGroup.x=Template.x
|
||||||
TemplateGroup.y=Template.y
|
TemplateGroup.y=Template.y
|
||||||
TemplateGroup.name=Template.name
|
TemplateGroup.name=Template.name
|
||||||
|
|
||||||
self:T("Spawning FARP")
|
self:T("Spawning FARP")
|
||||||
self:T({Template=Template})
|
self:T({Template=Template})
|
||||||
self:T({TemplateGroup=TemplateGroup})
|
self:T({TemplateGroup=TemplateGroup})
|
||||||
|
|
||||||
-- ED's dirty way to spawn FARPS.
|
-- ED's dirty way to spawn FARPS.
|
||||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||||
|
|
||||||
@ -499,10 +499,10 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
world.onEvent(Event)
|
world.onEvent(Event)
|
||||||
|
|
||||||
else
|
else
|
||||||
self:T("Spawning Static")
|
self:T("Spawning Static")
|
||||||
self:T2({Template=Template})
|
self:T2({Template=Template})
|
||||||
Static=coalition.addStaticObject(CountryID, Template)
|
Static=coalition.addStaticObject(CountryID, Template)
|
||||||
end
|
end
|
||||||
|
|
||||||
return mystatic
|
return mystatic
|
||||||
end
|
end
|
||||||
|
|||||||
@ -46,6 +46,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/Zone)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions: **Applevangelist**, **FunkyFranky**, **coconutcockpit**
|
-- ### Contributions: **Applevangelist**, **FunkyFranky**, **coconutcockpit**
|
||||||
--
|
--
|
||||||
@ -326,14 +330,14 @@ function ZONE_BASE:GetRandomVec2()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||||
function ZONE_BASE:GetRandomPointVec2()
|
function ZONE_BASE:GetRandomPointVec2()
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC3} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC3} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates.
|
-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates.
|
||||||
function ZONE_BASE:GetRandomPointVec3()
|
function ZONE_BASE:GetRandomPointVec3()
|
||||||
@ -899,7 +903,8 @@ function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound )
|
|||||||
|
|
||||||
local Point = {}
|
local Point = {}
|
||||||
local Vec2 = self:GetVec2()
|
local Vec2 = self:GetVec2()
|
||||||
|
local countryID = CountryID or country.id.USA
|
||||||
|
|
||||||
Points = Points and Points or 360
|
Points = Points and Points or 360
|
||||||
|
|
||||||
local Angle
|
local Angle
|
||||||
@ -910,7 +915,7 @@ function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound )
|
|||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
|
|
||||||
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
|
local CountryName = _DATABASE.COUNTRY_NAME[countryID]
|
||||||
|
|
||||||
local Tire = {
|
local Tire = {
|
||||||
["country"] = CountryName,
|
["country"] = CountryName,
|
||||||
@ -925,7 +930,7 @@ function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound )
|
|||||||
["heading"] = 0,
|
["heading"] = 0,
|
||||||
} -- end of ["group"]
|
} -- end of ["group"]
|
||||||
|
|
||||||
local Group = coalition.addStaticObject( CountryID, Tire )
|
local Group = coalition.addStaticObject( countryID, Tire )
|
||||||
if UnBound and UnBound == true then
|
if UnBound and UnBound == true then
|
||||||
Group:destroy()
|
Group:destroy()
|
||||||
end
|
end
|
||||||
@ -1175,7 +1180,7 @@ function ZONE_RADIUS:RemoveJunk()
|
|||||||
return n
|
return n
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Count the number of different coalitions inside the zone.
|
--- Get a table of scanned units.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @return #table Table of DCS units and DCS statics inside the zone.
|
-- @return #table Table of DCS units and DCS statics inside the zone.
|
||||||
function ZONE_RADIUS:GetScannedUnits()
|
function ZONE_RADIUS:GetScannedUnits()
|
||||||
@ -1210,7 +1215,7 @@ function ZONE_RADIUS:GetScannedSetUnit()
|
|||||||
return SetUnit
|
return SetUnit
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a set of scanned units.
|
--- Get a set of scanned groups.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @return Core.Set#SET_GROUP Set of groups.
|
-- @return Core.Set#SET_GROUP Set of groups.
|
||||||
function ZONE_RADIUS:GetScannedSetGroup()
|
function ZONE_RADIUS:GetScannedSetGroup()
|
||||||
@ -1510,7 +1515,7 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
return point
|
return point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
@ -1541,7 +1546,7 @@ function ZONE_RADIUS:GetRandomVec3( inner, outer )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
@ -1985,7 +1990,7 @@ function ZONE_GROUP:GetRandomVec2()
|
|||||||
return Point
|
return Point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_GROUP self
|
-- @param #ZONE_GROUP self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
@ -2829,7 +2834,7 @@ function ZONE_POLYGON_BASE:GetRandomVec2()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone.
|
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC2}
|
-- @return @{Core.Point#POINT_VEC2}
|
||||||
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
||||||
@ -2842,7 +2847,7 @@ function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
|||||||
return PointVec2
|
return PointVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone.
|
--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC3}
|
-- @return @{Core.Point#POINT_VEC3}
|
||||||
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
||||||
@ -3830,18 +3835,18 @@ function ZONE_OVAL:GetRandomVec2()
|
|||||||
return {x=rx, y=ry}
|
return {x=rx, y=ry}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||||
function ZONE_OVAL:GetRandomPointVec2()
|
function ZONE_OVAL:GetRandomPointVec2()
|
||||||
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||||
function ZONE_OVAL:GetRandomPointVec3()
|
function ZONE_OVAL:GetRandomPointVec3()
|
||||||
return POINT_VEC2:NewFromVec3(self:GetRandomVec2())
|
return POINT_VEC3:NewFromVec3(self:GetRandomVec2())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Draw the zone on the F10 map.
|
--- Draw the zone on the F10 map.
|
||||||
@ -3981,7 +3986,7 @@ do -- ZONE_AIRBASE
|
|||||||
return ZoneVec2
|
return ZoneVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_AIRBASE self
|
-- @param #ZONE_AIRBASE self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -78,7 +78,8 @@
|
|||||||
-- ### Authors: **FlightControl**
|
-- ### Authors: **FlightControl**
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
|
-- * **Applevangelist**: Additional functionality, fixes.
|
||||||
-- * **Wingthor (TAW)**: Testing & Advice.
|
-- * **Wingthor (TAW)**: Testing & Advice.
|
||||||
-- * **Dutch-Baron (TAW)**: Testing & Advice.
|
-- * **Dutch-Baron (TAW)**: Testing & Advice.
|
||||||
-- * **Whisper**: Testing and Advice.
|
-- * **Whisper**: Testing and Advice.
|
||||||
@ -116,11 +117,13 @@
|
|||||||
-- Special targets can be set that will give extra scores to the players when these are destroyed.
|
-- Special targets can be set that will give extra scores to the players when these are destroyed.
|
||||||
-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s.
|
-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s.
|
||||||
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Wrapper.Static}s.
|
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Wrapper.Static}s.
|
||||||
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
|
-- Use the method @{#SCORING.AddScoreSetGroup}() to specify a special additional score for a specific @{Wrapper.Group}s gathered in a @{Core.Set#SET_GROUP}.
|
||||||
--
|
--
|
||||||
-- local Scoring = SCORING:New( "Scoring File" )
|
-- local Scoring = SCORING:New( "Scoring File" )
|
||||||
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
||||||
-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 )
|
-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 )
|
||||||
|
-- local GroupSet = SET_GROUP:New():FilterPrefixes("RAT"):FilterStart()
|
||||||
|
-- Scoring:AddScoreSetGroup( GroupSet, 100)
|
||||||
--
|
--
|
||||||
-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed.
|
-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed.
|
||||||
-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over.
|
-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over.
|
||||||
@ -226,7 +229,7 @@ SCORING = {
|
|||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
Players = {},
|
Players = {},
|
||||||
AutoSave = true,
|
AutoSave = true,
|
||||||
version = "1.17.1"
|
version = "1.18.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
local _SCORINGCoalition = {
|
local _SCORINGCoalition = {
|
||||||
@ -428,6 +431,31 @@ function SCORING:AddScoreGroup( ScoreGroup, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Specify a special additional score for a @{Core.Set#SET_GROUP}.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Core.Set#SET_GROUP Set The @{Core.Set#SET_GROUP} for which each @{Wrapper.Unit} in each Group a Score is given.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddScoreSetGroup(Set, Score)
|
||||||
|
local set = Set:GetSetObjects()
|
||||||
|
|
||||||
|
for _,_group in pairs (set) do
|
||||||
|
if _group and _group:IsAlive() then
|
||||||
|
self:AddScoreGroup(_group,Score)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function AddScore(group)
|
||||||
|
self:AddScoreGroup(group,Score)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Set:OnAfterAdded(From,Event,To,ObjectName,Object)
|
||||||
|
AddScore(Object)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
|
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
|
||||||
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
|
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
|
||||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||||
@ -1030,7 +1058,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||||
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
||||||
-- After an instant kill we can't compute the thread level anymore. To fix this we compute at OnEventBirth
|
-- After an instant kill we can't compute the threat level anymore. To fix this we compute at OnEventBirth
|
||||||
if PlayerHit.UNIT.ThreatType == nil then
|
if PlayerHit.UNIT.ThreatType == nil then
|
||||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||||
-- if this fails for some reason, set a good default value
|
-- if this fails for some reason, set a good default value
|
||||||
@ -1141,7 +1169,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||||
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
||||||
-- After an instant kill we can't compute the thread level anymore. To fix this we compute at OnEventBirth
|
-- After an instant kill we can't compute the threat level anymore. To fix this we compute at OnEventBirth
|
||||||
if PlayerHit.UNIT.ThreatType == nil then
|
if PlayerHit.UNIT.ThreatType == nil then
|
||||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||||
-- if this fails for some reason, set a good default value
|
-- if this fails for some reason, set a good default value
|
||||||
@ -1288,17 +1316,17 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
||||||
|
|
||||||
|
|
||||||
self:OnKillPvP(Player, TargetPlayerName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
--self:OnKillPvP(PlayerName, TargetPlayerName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
||||||
|
|
||||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||||
self:OnKillPvP(Player, TargetPlayerName, true)
|
self:OnKillPvP(PlayerName, TargetPlayerName, true)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
self:OnKillPvE(Player, TargetUnitName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
self:OnKillPvE(PlayerName, TargetUnitName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
@ -1326,14 +1354,14 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
else
|
else
|
||||||
Player.PlayerKills = 1
|
Player.PlayerKills = 1
|
||||||
end
|
end
|
||||||
self:OnKillPvP(Player, TargetPlayerName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
self:OnKillPvP(PlayerName, TargetPlayerName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
self:OnKillPvE(Player, TargetUnitName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
self:OnKillPvE(PlayerName, TargetUnitName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
@ -1935,23 +1963,23 @@ end
|
|||||||
|
|
||||||
--- Handles the event when one player kill another player
|
--- Handles the event when one player kill another player
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #PLAYER Player the ataching player
|
-- @param #string PlayerName The attacking player
|
||||||
-- @param #string TargetPlayerName the name of the killed player
|
-- @param #string TargetPlayerName The name of the killed player
|
||||||
-- @param #bool IsTeamKill true if this kill was a team kill
|
-- @param #boolean IsTeamKill true if this kill was a team kill
|
||||||
-- @param #number TargetThreatLevel Thread level of the target
|
-- @param #number TargetThreatLevel Threat level of the target
|
||||||
-- @param #number PlayerThreatLevelThread level of the player
|
-- @param #number PlayerThreatLevel Threat level of the player
|
||||||
-- @param #number Score The score based on both threat levels
|
-- @param #number Score The score based on both threat levels
|
||||||
function SCORING:OnKillPvP(Player, TargetPlayerName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
function SCORING:OnKillPvP(PlayerName, TargetPlayerName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
||||||
|
|
||||||
end
|
end
|
||||||
--- Handles the event when one player kill another player
|
--- Handles the event when one player kill another player
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #PLAYER Player the ataching player
|
-- @param #string PlayerName The attacking player
|
||||||
-- @param #string TargetUnitName the name of the killed unit
|
-- @param #string TargetUnitName the name of the killed unit
|
||||||
-- @param #bool IsTeamKill true if this kill was a team kill
|
-- @param #boolean IsTeamKill true if this kill was a team kill
|
||||||
-- @param #number TargetThreatLevel Thread level of the target
|
-- @param #number TargetThreatLevel Threat level of the target
|
||||||
-- @param #number PlayerThreatLevelThread level of the player
|
-- @param #number PlayerThreatLevel Threat level of the player
|
||||||
-- @param #number Score The score based on both threat levels
|
-- @param #number Score The score based on both threat levels
|
||||||
function SCORING:OnKillPvE(Player, TargetUnitName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
function SCORING:OnKillPvE(PlayerName, TargetUnitName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -320,9 +320,6 @@ function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADG
|
|||||||
end
|
end
|
||||||
|
|
||||||
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
|
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
|
||||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
|
||||||
--if tgtcoord and tgtcoord.ClassName == "COORDINATE" then
|
|
||||||
--local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
|
||||||
local tgtgrp = seadset:GetRandom()
|
local tgtgrp = seadset:GetRandom()
|
||||||
local _targetgroup = nil
|
local _targetgroup = nil
|
||||||
local _targetgroupname = "none"
|
local _targetgroupname = "none"
|
||||||
|
|||||||
@ -41,6 +41,7 @@
|
|||||||
-- @field #boolean usebudget
|
-- @field #boolean usebudget
|
||||||
-- @field #number CaptureUnits
|
-- @field #number CaptureUnits
|
||||||
-- @field #number CaptureThreatlevel
|
-- @field #number CaptureThreatlevel
|
||||||
|
-- @field #boolean ExcludeShips
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ STRATEGO = {
|
|||||||
debug = false,
|
debug = false,
|
||||||
drawzone = false,
|
drawzone = false,
|
||||||
markzone = false,
|
markzone = false,
|
||||||
version = "0.2.4",
|
version = "0.2.5",
|
||||||
portweight = 3,
|
portweight = 3,
|
||||||
POIweight = 1,
|
POIweight = 1,
|
||||||
maxrunways = 3,
|
maxrunways = 3,
|
||||||
@ -195,6 +196,7 @@ STRATEGO = {
|
|||||||
usebudget = false,
|
usebudget = false,
|
||||||
CaptureUnits = 3,
|
CaptureUnits = 3,
|
||||||
CaptureThreatlevel = 1,
|
CaptureThreatlevel = 1,
|
||||||
|
ExcludeShips = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -256,6 +258,7 @@ function STRATEGO:New(Name,Coalition,MaxDist)
|
|||||||
self.maxdist = MaxDist or 150 -- km
|
self.maxdist = MaxDist or 150 -- km
|
||||||
self.disttable = {}
|
self.disttable = {}
|
||||||
self.routexists = {}
|
self.routexists = {}
|
||||||
|
self.ExcludeShips = true
|
||||||
|
|
||||||
self.lid = string.format("STRATEGO %s %s | ",self.name,self.version)
|
self.lid = string.format("STRATEGO %s %s | ",self.name,self.version)
|
||||||
|
|
||||||
@ -427,6 +430,7 @@ function STRATEGO:AnalyseBases()
|
|||||||
self.bases:ForEach(
|
self.bases:ForEach(
|
||||||
function(afb)
|
function(afb)
|
||||||
local ab = afb -- Wrapper.Airbase#AIRBASE
|
local ab = afb -- Wrapper.Airbase#AIRBASE
|
||||||
|
if self.ExcludeShips and ab:IsShip() then return end
|
||||||
local abname = ab:GetName()
|
local abname = ab:GetName()
|
||||||
local runways = ab:GetRunways()
|
local runways = ab:GetRunways()
|
||||||
local numrwys = #runways
|
local numrwys = #runways
|
||||||
@ -438,14 +442,14 @@ function STRATEGO:AnalyseBases()
|
|||||||
local coa = ab:GetCoalition()
|
local coa = ab:GetCoalition()
|
||||||
if coa == nil then return end -- Spawned FARPS issue - these have no tangible data
|
if coa == nil then return end -- Spawned FARPS issue - these have no tangible data
|
||||||
coa = coa+1
|
coa = coa+1
|
||||||
local abtype = "AIRBASE"
|
local abtype = STRATEGO.Type.AIRBASE
|
||||||
if ab:IsShip() then
|
if ab:IsShip() then
|
||||||
numrwys = 1
|
numrwys = 1
|
||||||
abtype = "SHIP"
|
abtype = STRATEGO.Type.SHIP
|
||||||
end
|
end
|
||||||
if ab:IsHelipad() then
|
if ab:IsHelipad() then
|
||||||
numrwys = 1
|
numrwys = 1
|
||||||
abtype = "FARP"
|
abtype = STRATEGO.Type.FARP
|
||||||
end
|
end
|
||||||
local coord = ab:GetCoordinate()
|
local coord = ab:GetCoordinate()
|
||||||
if debug then
|
if debug then
|
||||||
@ -481,10 +485,10 @@ function STRATEGO:UpdateNodeCoalitions()
|
|||||||
local newtable = {}
|
local newtable = {}
|
||||||
for _id,_data in pairs(self.airbasetable) do
|
for _id,_data in pairs(self.airbasetable) do
|
||||||
local data = _data -- #STRATEGO.Data
|
local data = _data -- #STRATEGO.Data
|
||||||
if data.type == "AIRBASE" or data.type == "FARP" then
|
if data.type == STRATEGO.Type.AIRBASE or data.type == STRATEGO.Type.FARP or data.type == STRATEGO.Type.SHIP then
|
||||||
data.coalition = AIRBASE:FindByName(data.name):GetCoalition()
|
data.coalition = AIRBASE:FindByName(data.name):GetCoalition() or 0
|
||||||
else
|
else
|
||||||
data.coalition = data.opszone:GetOwner()
|
data.coalition = data.opszone:GetOwner() or 0
|
||||||
end
|
end
|
||||||
newtable[_id] = _data
|
newtable[_id] = _data
|
||||||
end
|
end
|
||||||
@ -937,11 +941,13 @@ function STRATEGO:FindClosestConsolidationTarget(Startpoint,BaseWeight)
|
|||||||
local cname = self.easynames[tname]
|
local cname = self.easynames[tname]
|
||||||
local targetweight = self.airbasetable[cname].baseweight
|
local targetweight = self.airbasetable[cname].baseweight
|
||||||
coa = self.airbasetable[cname].coalition
|
coa = self.airbasetable[cname].coalition
|
||||||
|
--self:T("Start -> End: "..startpoint.." -> "..cname)
|
||||||
if (dist < shortest) and (coa ~= self.coalition) and (BaseWeight >= targetweight) then
|
if (dist < shortest) and (coa ~= self.coalition) and (BaseWeight >= targetweight) then
|
||||||
|
self:T("Found Consolidation Target: "..cname)
|
||||||
shortest = dist
|
shortest = dist
|
||||||
target = cname
|
target = cname
|
||||||
weight = self.airbasetable[cname].weight
|
weight = self.airbasetable[cname].weight
|
||||||
coa = self.airbasetable[cname].coalition
|
coa = coa
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -974,8 +980,9 @@ function STRATEGO:FindClosestStrategicTarget(Startpoint,Weight)
|
|||||||
local coa = self.airbasetable[cname].coalition
|
local coa = self.airbasetable[cname].coalition
|
||||||
local tweight = self.airbasetable[cname].baseweight
|
local tweight = self.airbasetable[cname].baseweight
|
||||||
local ttweight = self.airbasetable[cname].weight
|
local ttweight = self.airbasetable[cname].weight
|
||||||
self:T("Start -> End: "..startpoint.." -> "..cname)
|
--self:T("Start -> End: "..startpoint.." -> "..cname)
|
||||||
if (dist < shortest) and (coa ~= self.coalition) and (tweight >= Weight) then
|
if (dist < shortest) and (coa ~= self.coalition) and (tweight >= Weight) then
|
||||||
|
self:T("Found Strategic Target: "..cname)
|
||||||
shortest = dist
|
shortest = dist
|
||||||
target = cname
|
target = cname
|
||||||
weight = self.airbasetable[cname].weight
|
weight = self.airbasetable[cname].weight
|
||||||
@ -996,38 +1003,31 @@ function STRATEGO:FindStrategicTargets()
|
|||||||
local data = _data -- #STRATEGO.Data
|
local data = _data -- #STRATEGO.Data
|
||||||
if data.coalition == self.coalition then
|
if data.coalition == self.coalition then
|
||||||
local dist, name, points, coa = self:FindClosestStrategicTarget(data.name,data.weight)
|
local dist, name, points, coa = self:FindClosestStrategicTarget(data.name,data.weight)
|
||||||
if coa == coalition.side.NEUTRAL and points ~= 0 then
|
if points > 0 then
|
||||||
local fpoints = points + self.NeutralBenefit
|
self:T({dist=dist, name=name, points=points, coa=coa})
|
||||||
local tries = 1
|
|
||||||
while targets[fpoints] or tries < 100 do
|
|
||||||
fpoints = points + (self.NeutralBenefit+math.random(1,100))
|
|
||||||
tries = tries + 1
|
|
||||||
end
|
|
||||||
targets[fpoints] = {
|
|
||||||
name = name,
|
|
||||||
dist = dist,
|
|
||||||
points = fpoints,
|
|
||||||
coalition = coa,
|
|
||||||
coalitionname = UTILS.GetCoalitionName(coa),
|
|
||||||
coordinate = self.airbasetable[name].coord,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
local enemycoa = self.coalition == coalition.side.BLUE and coalition.side.RED or coalition.side.BLUE
|
if points ~= 0 then
|
||||||
if coa == enemycoa and points ~= 0 then
|
local enemycoa = self.coalition == coalition.side.BLUE and coalition.side.RED or coalition.side.BLUE
|
||||||
local fpoints = points
|
self:T("Enemycoa = "..enemycoa)
|
||||||
local tries = 1
|
if coa == coalition.side.NEUTRAL then
|
||||||
while targets[fpoints] or tries < 100 do
|
local tdata = {}
|
||||||
fpoints = points + (math.random(1,100))
|
tdata.name = name
|
||||||
tries = tries + 1
|
tdata.dist = dist
|
||||||
|
tdata.points = points + self.NeutralBenefit
|
||||||
|
tdata.coalition = coa
|
||||||
|
tdata.coalitionname = UTILS.GetCoalitionName(coa)
|
||||||
|
tdata.coordinate = self.airbasetable[name].coord
|
||||||
|
table.insert(targets,tdata)
|
||||||
|
else
|
||||||
|
local tdata = {}
|
||||||
|
tdata.name = name
|
||||||
|
tdata.dist = dist
|
||||||
|
tdata.points = points
|
||||||
|
tdata.coalition = coa
|
||||||
|
tdata.coalitionname = UTILS.GetCoalitionName(coa)
|
||||||
|
tdata.coordinate = self.airbasetable[name].coord
|
||||||
|
table.insert(targets,tdata)
|
||||||
end
|
end
|
||||||
targets[fpoints] = {
|
|
||||||
name = name,
|
|
||||||
dist = dist,
|
|
||||||
points = fpoints,
|
|
||||||
coalition = coa,
|
|
||||||
coalitionname = UTILS.GetCoalitionName(coa),
|
|
||||||
coordinate = self.airbasetable[name].coord,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1044,38 +1044,31 @@ function STRATEGO:FindConsolidationTargets()
|
|||||||
local data = _data -- #STRATEGO.Data
|
local data = _data -- #STRATEGO.Data
|
||||||
if data.coalition == self.coalition then
|
if data.coalition == self.coalition then
|
||||||
local dist, name, points, coa = self:FindClosestConsolidationTarget(data.name,self.maxrunways-1)
|
local dist, name, points, coa = self:FindClosestConsolidationTarget(data.name,self.maxrunways-1)
|
||||||
if coa == coalition.side.NEUTRAL and points ~= 0 then
|
if points > 0 then
|
||||||
local fpoints = points + self.NeutralBenefit
|
self:T({dist=dist, name=name, points=points, coa=coa})
|
||||||
local tries = 1
|
|
||||||
while targets[fpoints] or tries < 100 do
|
|
||||||
fpoints = points - (self.NeutralBenefit+math.random(1,100))
|
|
||||||
tries = tries + 1
|
|
||||||
end
|
|
||||||
targets[fpoints] = {
|
|
||||||
name = name,
|
|
||||||
dist = dist,
|
|
||||||
points = fpoints,
|
|
||||||
coalition = coa,
|
|
||||||
coalitionname = UTILS.GetCoalitionName(coa),
|
|
||||||
coordinate = self.airbasetable[name].coord,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
local enemycoa = self.coalition == coalition.side.BLUE and coalition.side.RED or coalition.side.BLUE
|
if points ~= 0 then
|
||||||
if coa == enemycoa and points ~= 0 then
|
local enemycoa = self.coalition == coalition.side.BLUE and coalition.side.RED or coalition.side.BLUE
|
||||||
local fpoints = points
|
self:T("Enemycoa = "..enemycoa)
|
||||||
local tries = 1
|
if coa == coalition.side.NEUTRAL then
|
||||||
while targets[fpoints] or tries < 100 do
|
local tdata = {}
|
||||||
fpoints = points - (math.random(1,100))
|
tdata.name = name
|
||||||
tries = tries + 1
|
tdata.dist = dist
|
||||||
|
tdata.points = points + self.NeutralBenefit
|
||||||
|
tdata.coalition = coa
|
||||||
|
tdata.coalitionname = UTILS.GetCoalitionName(coa)
|
||||||
|
tdata.coordinate = self.airbasetable[name].coord
|
||||||
|
table.insert(targets,tdata)
|
||||||
|
else
|
||||||
|
local tdata = {}
|
||||||
|
tdata.name = name
|
||||||
|
tdata.dist = dist
|
||||||
|
tdata.points = points
|
||||||
|
tdata.coalition = coa
|
||||||
|
tdata.coalitionname = UTILS.GetCoalitionName(coa)
|
||||||
|
tdata.coordinate = self.airbasetable[name].coord
|
||||||
|
table.insert(targets,tdata)
|
||||||
end
|
end
|
||||||
targets[fpoints] = {
|
|
||||||
name = name,
|
|
||||||
dist = dist,
|
|
||||||
points = fpoints,
|
|
||||||
coalition = coa,
|
|
||||||
coalitionname = UTILS.GetCoalitionName(coa),
|
|
||||||
coordinate = self.airbasetable[name].coord,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1245,13 +1238,15 @@ end
|
|||||||
-- @return #table Target Table with #STRATEGO.Target data or nil if none found.
|
-- @return #table Target Table with #STRATEGO.Target data or nil if none found.
|
||||||
function STRATEGO:FindAffordableStrategicTarget()
|
function STRATEGO:FindAffordableStrategicTarget()
|
||||||
self:T(self.lid.."FindAffordableStrategicTarget")
|
self:T(self.lid.."FindAffordableStrategicTarget")
|
||||||
local targets = self:FindStrategicTargets() -- #table of #STRATEGO.Target
|
local Stargets = self:FindStrategicTargets() -- #table of #STRATEGO.Target
|
||||||
|
--UTILS.PrintTableToLog(Stargets,1)
|
||||||
local budget = self.Budget
|
local budget = self.Budget
|
||||||
--local leftover = self.Budget
|
--local leftover = self.Budget
|
||||||
local target = nil -- #STRATEGO.Target
|
local ftarget = nil -- #STRATEGO.Target
|
||||||
local Targets = {}
|
local Targets = {}
|
||||||
for _,_data in pairs(targets) do
|
for _,_data in pairs(Stargets) do
|
||||||
local data = _data -- #STRATEGO.Target
|
local data = _data -- #STRATEGO.Target
|
||||||
|
self:T("Considering Strategic Target "..data.name)
|
||||||
--if data.points <= budget and budget-data.points < leftover then
|
--if data.points <= budget and budget-data.points < leftover then
|
||||||
if data.points <= budget then
|
if data.points <= budget then
|
||||||
--leftover = budget-data.points
|
--leftover = budget-data.points
|
||||||
@ -1259,14 +1254,18 @@ function STRATEGO:FindAffordableStrategicTarget()
|
|||||||
self:T(self.lid.."Affordable strategic target: "..data.name)
|
self:T(self.lid.."Affordable strategic target: "..data.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not targets then
|
if #Targets == 0 then
|
||||||
self:T(self.lid.."No suitable target found!")
|
self:T(self.lid.."No suitable target found!")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
target = Targets[math.random(1,#Targets)]
|
if #Targets > 1 then
|
||||||
if target then
|
ftarget = Targets[math.random(1,#Targets)]
|
||||||
self:T(self.lid.."Final affordable strategic target: "..target.name)
|
else
|
||||||
return target
|
ftarget = Targets[1]
|
||||||
|
end
|
||||||
|
if ftarget then
|
||||||
|
self:T(self.lid.."Final affordable strategic target: "..ftarget.name)
|
||||||
|
return ftarget
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@ -1277,13 +1276,15 @@ end
|
|||||||
-- @return #table Target Table with #STRATEGO.Target data or nil if none found.
|
-- @return #table Target Table with #STRATEGO.Target data or nil if none found.
|
||||||
function STRATEGO:FindAffordableConsolidationTarget()
|
function STRATEGO:FindAffordableConsolidationTarget()
|
||||||
self:T(self.lid.."FindAffordableConsolidationTarget")
|
self:T(self.lid.."FindAffordableConsolidationTarget")
|
||||||
local targets = self:FindConsolidationTargets() -- #table of #STRATEGO.Target
|
local Ctargets = self:FindConsolidationTargets() -- #table of #STRATEGO.Target
|
||||||
|
--UTILS.PrintTableToLog(Ctargets,1)
|
||||||
local budget = self.Budget
|
local budget = self.Budget
|
||||||
--local leftover = self.Budget
|
--local leftover = self.Budget
|
||||||
local target = nil -- #STRATEGO.Target
|
local ftarget = nil -- #STRATEGO.Target
|
||||||
local Targets = {}
|
local Targets = {}
|
||||||
for _,_data in pairs(targets) do
|
for _,_data in pairs(Ctargets) do
|
||||||
local data = _data -- #STRATEGO.Target
|
local data = _data -- #STRATEGO.Target
|
||||||
|
self:T("Considering Consolidation Target "..data.name)
|
||||||
--if data.points <= budget and budget-data.points < leftover then
|
--if data.points <= budget and budget-data.points < leftover then
|
||||||
if data.points <= budget then
|
if data.points <= budget then
|
||||||
--leftover = budget-data.points
|
--leftover = budget-data.points
|
||||||
@ -1291,14 +1292,18 @@ function STRATEGO:FindAffordableConsolidationTarget()
|
|||||||
self:T(self.lid.."Affordable consolidation target: "..data.name)
|
self:T(self.lid.."Affordable consolidation target: "..data.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not targets then
|
if #Targets == 0 then
|
||||||
self:T(self.lid.."No suitable target found!")
|
self:T(self.lid.."No suitable target found!")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
target = Targets[math.random(1,#Targets)]
|
if #Targets > 1 then
|
||||||
if target then
|
ftarget = Targets[math.random(1,#Targets)]
|
||||||
self:T(self.lid.."Final affordable consolidation target: "..target.name)
|
else
|
||||||
return target
|
ftarget = Targets[1]
|
||||||
|
end
|
||||||
|
if ftarget then
|
||||||
|
self:T(self.lid.."Final affordable consolidation target: "..ftarget.name)
|
||||||
|
return ftarget
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|||||||
@ -9755,7 +9755,7 @@ function AIRBOSS:_Groove( playerData )
|
|||||||
local glideslopeError = groovedata.GSE
|
local glideslopeError = groovedata.GSE
|
||||||
local AoA = groovedata.AoA
|
local AoA = groovedata.AoA
|
||||||
|
|
||||||
if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 4.0 or playerData.unit:IsInZone( self:_GetZoneLineup() )) then
|
if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 4.0 and playerData.unit:IsInZone( self:_GetZoneLineup() )) then
|
||||||
|
|
||||||
-- Start time in groove
|
-- Start time in groove
|
||||||
playerData.TIG0 = timer.getTime()
|
playerData.TIG0 = timer.getTime()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -508,7 +508,7 @@ do
|
|||||||
-- @field #AWACS
|
-- @field #AWACS
|
||||||
AWACS = {
|
AWACS = {
|
||||||
ClassName = "AWACS", -- #string
|
ClassName = "AWACS", -- #string
|
||||||
version = "0.2.61", -- #string
|
version = "0.2.63", -- #string
|
||||||
lid = "", -- #string
|
lid = "", -- #string
|
||||||
coalition = coalition.side.BLUE, -- #number
|
coalition = coalition.side.BLUE, -- #number
|
||||||
coalitiontxt = "blue", -- #string
|
coalitiontxt = "blue", -- #string
|
||||||
@ -1384,7 +1384,7 @@ end
|
|||||||
-- Functions
|
-- Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- [User] Set the tactical information option, create 10 radio channels groups can subscribe and get Bogey Dope on a specific frequency automatically.
|
--- [User] Set the tactical information option, create 10 radio channels groups can subscribe and get Bogey Dope on a specific frequency automatically. You **need** to set up SRS first before using this!
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #number BaseFreq Base Frequency to use, defaults to 130.
|
-- @param #number BaseFreq Base Frequency to use, defaults to 130.
|
||||||
-- @param #number Increase Increase to use, defaults to 0.5, thus channels created are 130, 130.5, 131 .. etc.
|
-- @param #number Increase Increase to use, defaults to 0.5, thus channels created are 130, 130.5, 131 .. etc.
|
||||||
@ -1394,6 +1394,10 @@ end
|
|||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number)
|
function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number)
|
||||||
self:T(self.lid.."SetTacticalRadios")
|
self:T(self.lid.."SetTacticalRadios")
|
||||||
|
if not self.AwacsSRS then
|
||||||
|
MESSAGE:New("AWACS: Setup SRS in your code BEFORE trying to add tac radios please!",30,"ERROR",true):ToLog():ToAll()
|
||||||
|
return self
|
||||||
|
end
|
||||||
self.TacticalMenu = true
|
self.TacticalMenu = true
|
||||||
self.TacticalBaseFreq = BaseFreq or 130
|
self.TacticalBaseFreq = BaseFreq or 130
|
||||||
self.TacticalIncrFreq = Increase or 0.5
|
self.TacticalIncrFreq = Increase or 0.5
|
||||||
@ -1407,7 +1411,7 @@ function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number)
|
|||||||
self.TacticalFrequencies[freq] = freq
|
self.TacticalFrequencies[freq] = freq
|
||||||
end
|
end
|
||||||
if self.AwacsSRS then
|
if self.AwacsSRS then
|
||||||
self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation)
|
self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation,self.Backend)
|
||||||
self.TacticalSRS:SetCoalition(self.coalition)
|
self.TacticalSRS:SetCoalition(self.coalition)
|
||||||
self.TacticalSRS:SetGender(self.Gender)
|
self.TacticalSRS:SetGender(self.Gender)
|
||||||
self.TacticalSRS:SetCulture(self.Culture)
|
self.TacticalSRS:SetCulture(self.Culture)
|
||||||
@ -2085,8 +2089,9 @@ end
|
|||||||
-- @param #number Volume Volume - between 0.0 (silent) and 1.0 (loudest)
|
-- @param #number Volume Volume - between 0.0 (silent) and 1.0 (loudest)
|
||||||
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS; if you use a config file for MSRS, hand in nil here.
|
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS; if you use a config file for MSRS, hand in nil here.
|
||||||
-- @param #string AccessKey (Optional) Your Google API access key. This is necessary if DCS-gRPC is used as backend; if you use a config file for MSRS, hand in nil here.
|
-- @param #string AccessKey (Optional) Your Google API access key. This is necessary if DCS-gRPC is used as backend; if you use a config file for MSRS, hand in nil here.
|
||||||
|
-- @param #string Backend (Optional) Your MSRS Backend if different from your config file settings, e.g. MSRS.Backend.SRSEXE or MSRS.Backend.GRPC
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey)
|
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend)
|
||||||
self:T(self.lid.."SetSRS")
|
self:T(self.lid.."SetSRS")
|
||||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||||
self.Gender = Gender or MSRS.gender or "male"
|
self.Gender = Gender or MSRS.gender or "male"
|
||||||
@ -2096,8 +2101,9 @@ function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey
|
|||||||
self.PathToGoogleKey = PathToGoogleKey
|
self.PathToGoogleKey = PathToGoogleKey
|
||||||
self.AccessKey = AccessKey
|
self.AccessKey = AccessKey
|
||||||
self.Volume = Volume or 1.0
|
self.Volume = Volume or 1.0
|
||||||
|
self.Backend = Backend or MSRS.backend
|
||||||
self.AwacsSRS = MSRS:New(self.PathToSRS,self.MultiFrequency,self.MultiModulation)
|
BASE:I({backend = self.Backend})
|
||||||
|
self.AwacsSRS = MSRS:New(self.PathToSRS,self.MultiFrequency,self.MultiModulation,self.Backend)
|
||||||
self.AwacsSRS:SetCoalition(self.coalition)
|
self.AwacsSRS:SetCoalition(self.coalition)
|
||||||
self.AwacsSRS:SetGender(self.Gender)
|
self.AwacsSRS:SetGender(self.Gender)
|
||||||
self.AwacsSRS:SetCulture(self.Culture)
|
self.AwacsSRS:SetCulture(self.Culture)
|
||||||
@ -2499,13 +2505,22 @@ function AWACS:_CheckMerges()
|
|||||||
local cpos = contact.Cluster.coordinate or contact.Contact.position or contact.Contact.group:GetCoordinate()
|
local cpos = contact.Cluster.coordinate or contact.Contact.position or contact.Contact.group:GetCoordinate()
|
||||||
local dist = ppos:Get2DDistance(cpos)
|
local dist = ppos:Get2DDistance(cpos)
|
||||||
local distnm = UTILS.Round(UTILS.MetersToNM(dist),0)
|
local distnm = UTILS.Round(UTILS.MetersToNM(dist),0)
|
||||||
if (pilot.IsPlayer or self.debug) and distnm <= 5 and not contact.MergeCallDone then
|
if (pilot.IsPlayer or self.debug) and distnm <= 5 then --and ((not contact.MergeCallDone) or (timer.getTime() - contact.MergeCallDone > 30)) then
|
||||||
local label = contact.EngagementTag or ""
|
--local label = contact.EngagementTag or ""
|
||||||
if not contact.MergeCallDone or not string.find(label,pcallsign) then
|
--if not contact.MergeCallDone or not string.find(label,pcallsign) then
|
||||||
self:T(self.lid.."Merged")
|
self:T(self.lid.."Merged")
|
||||||
self:_MergedCall(_id)
|
self:_MergedCall(_id)
|
||||||
contact.MergeCallDone = true
|
--contact.MergeCallDone = true
|
||||||
end
|
--end
|
||||||
|
end
|
||||||
|
if (pilot.IsPlayer or self.debug) and distnm >5 and distnm <= self.ThreatDistance then
|
||||||
|
self:_ThreatRangeCall(_id,Contact)
|
||||||
|
end
|
||||||
|
if (pilot.IsPlayer or self.debug) and distnm > self.ThreatDistance and distnm <= self.MeldDistance then
|
||||||
|
self:_MeldRangeCall(_id,Contact)
|
||||||
|
end
|
||||||
|
if (pilot.IsPlayer or self.debug) and distnm > self.MeldDistance and distnm <= self.TacDistance then
|
||||||
|
self:_TACRangeCall(_id,Contact)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
@ -3099,7 +3114,7 @@ function AWACS:_BogeyDope(Group,Tactical)
|
|||||||
local clean = self.gettext:GetEntry("CLEAN",self.locale)
|
local clean = self.gettext:GetEntry("CLEAN",self.locale)
|
||||||
text = string.format(clean,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt)
|
text = string.format(clean,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt)
|
||||||
|
|
||||||
self:_NewRadioEntry(text,textScreen,GID,Outcome,Outcome,true,false,true,Tactical)
|
self:_NewRadioEntry(text,text,GID,Outcome,Outcome,true,false,true,Tactical)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@ -3141,9 +3156,13 @@ end
|
|||||||
function AWACS:_ShowAwacsInfo(Group)
|
function AWACS:_ShowAwacsInfo(Group)
|
||||||
self:T(self.lid.."_ShowAwacsInfo")
|
self:T(self.lid.."_ShowAwacsInfo")
|
||||||
local report = REPORT:New("Info")
|
local report = REPORT:New("Info")
|
||||||
|
local STN = self.STN
|
||||||
report:Add("====================")
|
report:Add("====================")
|
||||||
report:Add(string.format("AWACS %s",self.callsigntxt))
|
report:Add(string.format("AWACS %s",self.callsigntxt))
|
||||||
report:Add(string.format("Radio: %.3f %s",self.Frequency,UTILS.GetModulationName(self.Modulation)))
|
report:Add(string.format("Radio: %.3f %s",self.Frequency,UTILS.GetModulationName(self.Modulation)))
|
||||||
|
if STN then
|
||||||
|
report:Add(string.format("Link-16 STN: %s",STN))
|
||||||
|
end
|
||||||
report:Add(string.format("Bulls Alias: %s",self.AOName))
|
report:Add(string.format("Bulls Alias: %s",self.AOName))
|
||||||
report:Add(string.format("Coordinate: %s",self.AOCoordinate:ToStringLLDDM()))
|
report:Add(string.format("Coordinate: %s",self.AOCoordinate:ToStringLLDDM()))
|
||||||
report:Add("====================")
|
report:Add("====================")
|
||||||
@ -5467,7 +5486,7 @@ function AWACS:_TACRangeCall(GID,Contact)
|
|||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
||||||
local contacttag = Contact.TargetGroupNaming
|
local contacttag = Contact.TargetGroupNaming
|
||||||
if contact and not Contact.TACCallDone then
|
if contact then --and not Contact.TACCallDone then
|
||||||
local position = contact.position -- Core.Point#COORDINATE
|
local position = contact.position -- Core.Point#COORDINATE
|
||||||
if position then
|
if position then
|
||||||
local distance = position:Get2DDistance(managedgroup.Group:GetCoordinate())
|
local distance = position:Get2DDistance(managedgroup.Group:GetCoordinate())
|
||||||
@ -5477,6 +5496,15 @@ function AWACS:_TACRangeCall(GID,Contact)
|
|||||||
local text = string.format("%s. %s. %s %s, %d %s.",self.callsigntxt,pilotcallsign,contacttag,grptxt,distance,miles)
|
local text = string.format("%s. %s. %s %s, %d %s.",self.callsigntxt,pilotcallsign,contacttag,grptxt,distance,miles)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,false,AWACS.TaskStatus.EXECUTING)
|
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,false,AWACS.TaskStatus.EXECUTING)
|
||||||
|
if GID and GID ~= 0 then
|
||||||
|
--local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
|
local name = managedgroup.GroupName
|
||||||
|
if self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@ -5495,8 +5523,8 @@ function AWACS:_MeldRangeCall(GID,Contact)
|
|||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
local flightpos = managedgroup.Group:GetCoordinate()
|
local flightpos = managedgroup.Group:GetCoordinate()
|
||||||
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
||||||
local contacttag = Contact.TargetGroupNaming
|
local contacttag = Contact.TargetGroupNaming or "Bogey"
|
||||||
if contact and not Contact.MeldCallDone then
|
if contact then --and not Contact.MeldCallDone then
|
||||||
local position = contact.position -- Core.Point#COORDINATE
|
local position = contact.position -- Core.Point#COORDINATE
|
||||||
if position then
|
if position then
|
||||||
local BRATExt = ""
|
local BRATExt = ""
|
||||||
@ -5509,6 +5537,15 @@ function AWACS:_MeldRangeCall(GID,Contact)
|
|||||||
local text = string.format("%s. %s. %s %s, %s",self.callsigntxt,pilotcallsign,contacttag,grptxt,BRATExt)
|
local text = string.format("%s. %s. %s %s, %s",self.callsigntxt,pilotcallsign,contacttag,grptxt,BRATExt)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,true,AWACS.TaskStatus.EXECUTING)
|
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,true,AWACS.TaskStatus.EXECUTING)
|
||||||
|
if GID and GID ~= 0 then
|
||||||
|
--local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
|
local name = managedgroup.GroupName
|
||||||
|
if self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@ -5525,7 +5562,7 @@ function AWACS:_ThreatRangeCall(GID,Contact)
|
|||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
local flightpos = managedgroup.Group:GetCoordinate() or managedgroup.LastKnownPosition
|
local flightpos = managedgroup.Group:GetCoordinate() or managedgroup.LastKnownPosition
|
||||||
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
||||||
local contacttag = Contact.TargetGroupNaming
|
local contacttag = Contact.TargetGroupNaming or "Bogey"
|
||||||
if contact then
|
if contact then
|
||||||
local position = contact.position or contact.group:GetCoordinate() -- Core.Point#COORDINATE
|
local position = contact.position or contact.group:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
if position then
|
if position then
|
||||||
@ -5539,6 +5576,15 @@ function AWACS:_ThreatRangeCall(GID,Contact)
|
|||||||
local thrt = self.gettext:GetEntry("THREAT",self.locale)
|
local thrt = self.gettext:GetEntry("THREAT",self.locale)
|
||||||
local text = string.format("%s. %s. %s %s, %s. %s",self.callsigntxt,pilotcallsign,contacttag,grptxt, thrt, BRATExt)
|
local text = string.format("%s. %s. %s %s, %s. %s",self.callsigntxt,pilotcallsign,contacttag,grptxt, thrt, BRATExt)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
|
if GID and GID ~= 0 then
|
||||||
|
--local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
|
local name = managedgroup.GroupName
|
||||||
|
if self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@ -5953,6 +5999,10 @@ function AWACS:_CheckAwacsStatus()
|
|||||||
local awacs = nil -- Wrapper.Group#GROUP
|
local awacs = nil -- Wrapper.Group#GROUP
|
||||||
if self.AwacsFG then
|
if self.AwacsFG then
|
||||||
awacs = self.AwacsFG:GetGroup() -- Wrapper.Group#GROUP
|
awacs = self.AwacsFG:GetGroup() -- Wrapper.Group#GROUP
|
||||||
|
local unit = awacs:GetUnit(1)
|
||||||
|
if unit then
|
||||||
|
self.STN = tostring(unit:GetSTN())
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local monitoringdata = self.MonitoringData -- #AWACS.MonitoringData
|
local monitoringdata = self.MonitoringData -- #AWACS.MonitoringData
|
||||||
@ -6632,7 +6682,7 @@ function AWACS:onafterCheckTacticalQueue(From,Event,To)
|
|||||||
|
|
||||||
end -- end while
|
end -- end while
|
||||||
|
|
||||||
if self:Is("Running") then
|
if not self:Is("Stopped") then
|
||||||
self:__CheckTacticalQueue(-self.TacticalInterval)
|
self:__CheckTacticalQueue(-self.TacticalInterval)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
|
|||||||
@ -313,8 +313,8 @@ end
|
|||||||
--
|
--
|
||||||
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
||||||
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
||||||
-- local BlueSaveOps = SET_GROUP:New():FilterCoalitions("blue"):FilterPrefixes("AID"):FilterCategoryGround():FilterOnce()
|
-- local BlueSaveOps = SET_OPSGROUP:New():FilterCoalitions("blue"):FilterCategoryGround():FilterOnce()
|
||||||
-- UTILS.SaveSetOfGroups(BlueSaveOps,Path,BlueOpsFilename)
|
-- UTILS.SaveSetOfOpsGroups(BlueSaveOps,Path,BlueOpsFilename)
|
||||||
--
|
--
|
||||||
-- where Path and Filename are strings, as chosen by you.
|
-- where Path and Filename are strings, as chosen by you.
|
||||||
-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the
|
-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the
|
||||||
@ -324,7 +324,7 @@ end
|
|||||||
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
||||||
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
||||||
-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then
|
-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then
|
||||||
-- local loadback = UTILS.LoadSetOfGroups(Path,BlueOpsFilename,false)
|
-- local loadback = UTILS.LoadSetOfOpsGroups(Path,BlueOpsFilename,false)
|
||||||
-- for _,_platoondata in pairs (loadback) do
|
-- for _,_platoondata in pairs (loadback) do
|
||||||
-- local groupname = _platoondata.groupname -- #string
|
-- local groupname = _platoondata.groupname -- #string
|
||||||
-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE
|
-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE
|
||||||
|
|||||||
@ -290,10 +290,11 @@ CSAR.AircraftType["Bell-47"] = 2
|
|||||||
CSAR.AircraftType["UH-60L"] = 10
|
CSAR.AircraftType["UH-60L"] = 10
|
||||||
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
||||||
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
||||||
|
CSAR.AircraftType["MH-60R"] = 10
|
||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.19"
|
CSAR.version="1.0.20"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
-- @module Ops.CTLD
|
-- @module Ops.CTLD
|
||||||
-- @image OPS_CTLD.jpg
|
-- @image OPS_CTLD.jpg
|
||||||
|
|
||||||
-- Last Update December 2023
|
-- Last Update February 2024
|
||||||
|
|
||||||
do
|
do
|
||||||
|
|
||||||
@ -44,6 +44,7 @@ do
|
|||||||
-- @field #number PerCrateMass Mass in kg.
|
-- @field #number PerCrateMass Mass in kg.
|
||||||
-- @field #number Stock Number of builds available, -1 for unlimited.
|
-- @field #number Stock Number of builds available, -1 for unlimited.
|
||||||
-- @field #string Subcategory Sub-category name.
|
-- @field #string Subcategory Sub-category name.
|
||||||
|
-- @field #boolean DontShowInMenu Show this item in menu or not.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -62,6 +63,7 @@ CTLD_CARGO = {
|
|||||||
PerCrateMass = 0,
|
PerCrateMass = 0,
|
||||||
Stock = nil,
|
Stock = nil,
|
||||||
Mark = nil,
|
Mark = nil,
|
||||||
|
DontShowInMenu = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Define cargo types.
|
--- Define cargo types.
|
||||||
@ -97,8 +99,9 @@ CTLD_CARGO = {
|
|||||||
-- @param #number PerCrateMass Mass in kg
|
-- @param #number PerCrateMass Mass in kg
|
||||||
-- @param #number Stock Number of builds available, nil for unlimited
|
-- @param #number Stock Number of builds available, nil for unlimited
|
||||||
-- @param #string Subcategory Name of subcategory, handy if using > 10 types to load.
|
-- @param #string Subcategory Name of subcategory, handy if using > 10 types to load.
|
||||||
|
-- @param #boolean DontShowInMenu Show this item in menu or not (default: false == show it).
|
||||||
-- @return #CTLD_CARGO self
|
-- @return #CTLD_CARGO self
|
||||||
function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory)
|
function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory,DontShowInMenu)
|
||||||
-- Inherit everything from BASE class.
|
-- Inherit everything from BASE class.
|
||||||
local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO
|
local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO
|
||||||
self:T({ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped})
|
self:T({ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped})
|
||||||
@ -115,6 +118,7 @@ CTLD_CARGO = {
|
|||||||
self.Stock = Stock or nil --#number
|
self.Stock = Stock or nil --#number
|
||||||
self.Mark = nil
|
self.Mark = nil
|
||||||
self.Subcategory = Subcategory or "Other"
|
self.Subcategory = Subcategory or "Other"
|
||||||
|
self.DontShowInMenu = DontShowInMenu or false
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1222,13 +1226,14 @@ CTLD.UnitTypeCapabilities = {
|
|||||||
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
|
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
|
||||||
--Actually it's longer, but the center coord is off-center of the model.
|
--Actually it's longer, but the center coord is off-center of the model.
|
||||||
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
|
["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
||||||
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- CTLD class version.
|
--- CTLD class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CTLD.version="1.0.45"
|
CTLD.version="1.0.48"
|
||||||
|
|
||||||
--- Instantiate a new CTLD.
|
--- Instantiate a new CTLD.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
@ -1433,7 +1438,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
--- Pseudo Functions ---
|
--- Pseudo Functions ---
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
--- Triggers the FSM event "Start". Starts the CTLD. Initializes parameters and starts event handlers.
|
--- Triggers the FSM event "Start". Starts the CTLD. Initializes parameters and starts event handlers.
|
||||||
-- @function [parent=#CTLD] Start
|
-- @function [parent=#CTLD] Start
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
|
|
||||||
@ -3024,9 +3029,10 @@ end
|
|||||||
function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
||||||
local Positions = {}
|
local Positions = {}
|
||||||
local template = _DATABASE:GetGroupTemplate(Template)
|
local template = _DATABASE:GetGroupTemplate(Template)
|
||||||
UTILS.PrintTableToLog(template)
|
--UTILS.PrintTableToLog(template)
|
||||||
local numbertroops = #template.units
|
local numbertroops = #template.units
|
||||||
local newcenter = Coordinate:Translate(Radius,((Heading+270)%360))
|
local slightshift = math.abs(math.random(0,200)/100)
|
||||||
|
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270)%360))
|
||||||
for i=1,360,math.floor(360/numbertroops) do
|
for i=1,360,math.floor(360/numbertroops) do
|
||||||
local phead = ((Heading+270+i)%360)
|
local phead = ((Heading+270+i)%360)
|
||||||
local post = newcenter:Translate(Radius,phead)
|
local post = newcenter:Translate(Radius,phead)
|
||||||
@ -3038,7 +3044,7 @@ function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
|||||||
}
|
}
|
||||||
table.insert(Positions,p1t)
|
table.insert(Positions,p1t)
|
||||||
end
|
end
|
||||||
UTILS.PrintTableToLog(Positions)
|
--UTILS.PrintTableToLog(Positions)
|
||||||
return Positions
|
return Positions
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -3700,14 +3706,20 @@ function CTLD:_RefreshF10Menus()
|
|||||||
for _,_entry in pairs(self.Cargo_Troops) do
|
for _,_entry in pairs(self.Cargo_Troops) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
local subcat = entry.Subcategory
|
local subcat = entry.Subcategory
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,subcatmenus[subcat],self._LoadTroops, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,subcatmenus[subcat],self._LoadTroops, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,_entry in pairs(self.Cargo_Troops) do
|
for _,_entry in pairs(self.Cargo_Troops) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,troopsmenu,self._LoadTroops, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,troopsmenu,self._LoadTroops, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local unloadmenu1 = MENU_GROUP_COMMAND:New(_group,"Drop troops",toptroops, self._UnloadTroops, self, _group, _unit):Refresh()
|
local unloadmenu1 = MENU_GROUP_COMMAND:New(_group,"Drop troops",toptroops, self._UnloadTroops, self, _group, _unit):Refresh()
|
||||||
@ -3728,33 +3740,45 @@ function CTLD:_RefreshF10Menus()
|
|||||||
for _,_entry in pairs(self.Cargo_Crates) do
|
for _,_entry in pairs(self.Cargo_Crates) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
local subcat = entry.Subcategory
|
local subcat = entry.Subcategory
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
if not noshow then
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
for _,_entry in pairs(self.Cargo_Statics) do
|
for _,_entry in pairs(self.Cargo_Statics) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
local subcat = entry.Subcategory
|
local subcat = entry.Subcategory
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
if not noshow then
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,_entry in pairs(self.Cargo_Crates) do
|
for _,_entry in pairs(self.Cargo_Crates) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
if not noshow then
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
for _,_entry in pairs(self.Cargo_Statics) do
|
for _,_entry in pairs(self.Cargo_Statics) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
if not noshow then
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit)
|
listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit)
|
||||||
removecrates = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
|
local removecrates = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
|
||||||
local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit)
|
local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit)
|
||||||
if not self.nobuildmenu then
|
if not self.nobuildmenu then
|
||||||
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
||||||
|
|||||||
@ -140,7 +140,7 @@ COMMANDER = {
|
|||||||
|
|
||||||
--- COMMANDER class version.
|
--- COMMANDER class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
COMMANDER.version="0.1.3"
|
COMMANDER.version="0.1.4"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@ -675,7 +675,8 @@ function COMMANDER:AddCapZone(Zone, Altitude, Speed, Heading, Leg)
|
|||||||
patrolzone.zone=Zone
|
patrolzone.zone=Zone
|
||||||
patrolzone.altitude=Altitude or 12000
|
patrolzone.altitude=Altitude or 12000
|
||||||
patrolzone.heading=Heading or 270
|
patrolzone.heading=Heading or 270
|
||||||
patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
--patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
||||||
|
patrolzone.speed=Speed or 350
|
||||||
patrolzone.leg=Leg or 30
|
patrolzone.leg=Leg or 30
|
||||||
patrolzone.mission=nil
|
patrolzone.mission=nil
|
||||||
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "CAP Zone"):ToCoalition(self:GetCoalition())
|
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "CAP Zone"):ToCoalition(self:GetCoalition())
|
||||||
@ -700,7 +701,8 @@ function COMMANDER:AddGciCapZone(Zone, Altitude, Speed, Heading, Leg)
|
|||||||
patrolzone.zone=Zone
|
patrolzone.zone=Zone
|
||||||
patrolzone.altitude=Altitude or 12000
|
patrolzone.altitude=Altitude or 12000
|
||||||
patrolzone.heading=Heading or 270
|
patrolzone.heading=Heading or 270
|
||||||
patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
--patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
||||||
|
patrolzone.speed=Speed or 350
|
||||||
patrolzone.leg=Leg or 30
|
patrolzone.leg=Leg or 30
|
||||||
patrolzone.mission=nil
|
patrolzone.mission=nil
|
||||||
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "GCICAP Zone"):ToCoalition(self:GetCoalition())
|
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "GCICAP Zone"):ToCoalition(self:GetCoalition())
|
||||||
@ -745,7 +747,9 @@ function COMMANDER:AddAwacsZone(Zone, Altitude, Speed, Heading, Leg)
|
|||||||
awacszone.zone=Zone
|
awacszone.zone=Zone
|
||||||
awacszone.altitude=Altitude or 12000
|
awacszone.altitude=Altitude or 12000
|
||||||
awacszone.heading=Heading or 270
|
awacszone.heading=Heading or 270
|
||||||
awacszone.speed=UTILS.KnotsToAltKIAS(Speed or 350, awacszone.altitude)
|
--awacszone.speed=UTILS.KnotsToAltKIAS(Speed or 350, awacszone.altitude)
|
||||||
|
awacszone.speed=Speed or 350
|
||||||
|
awacszone.speed=Speed or 350
|
||||||
awacszone.leg=Leg or 30
|
awacszone.leg=Leg or 30
|
||||||
awacszone.mission=nil
|
awacszone.mission=nil
|
||||||
--awacszone.marker=MARKER:New(awacszone.zone:GetCoordinate(), "AWACS Zone"):ToCoalition(self:GetCoalition())
|
--awacszone.marker=MARKER:New(awacszone.zone:GetCoordinate(), "AWACS Zone"):ToCoalition(self:GetCoalition())
|
||||||
@ -791,7 +795,8 @@ function COMMANDER:AddTankerZone(Zone, Altitude, Speed, Heading, Leg, RefuelSyst
|
|||||||
tankerzone.zone=Zone
|
tankerzone.zone=Zone
|
||||||
tankerzone.altitude=Altitude or 12000
|
tankerzone.altitude=Altitude or 12000
|
||||||
tankerzone.heading=Heading or 270
|
tankerzone.heading=Heading or 270
|
||||||
tankerzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, tankerzone.altitude)
|
--tankerzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, tankerzone.altitude) -- speed translation to alt will be done by AUFTRAG anyhow
|
||||||
|
tankerzone.speed = Speed or 350
|
||||||
tankerzone.leg=Leg or 30
|
tankerzone.leg=Leg or 30
|
||||||
tankerzone.refuelsystem=RefuelSystem
|
tankerzone.refuelsystem=RefuelSystem
|
||||||
tankerzone.mission=nil
|
tankerzone.mission=nil
|
||||||
|
|||||||
@ -3799,10 +3799,11 @@ function FLIGHTGROUP:_InitGroup(Template)
|
|||||||
self.speedMax=group:GetSpeedMax()
|
self.speedMax=group:GetSpeedMax()
|
||||||
|
|
||||||
-- Is group mobile?
|
-- Is group mobile?
|
||||||
if self.speedMax>3.6 then
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
self.isMobile=true
|
self.isMobile=true
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cruise speed limit 380 kts for fixed and 110 knots for rotary wings.
|
-- Cruise speed limit 380 kts for fixed and 110 knots for rotary wings.
|
||||||
|
|||||||
@ -3190,14 +3190,14 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
|
|||||||
elseif (currmission.type==AUFTRAG.Type.ONGUARD or currmission.type==AUFTRAG.Type.PATROLZONE) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
|
elseif (currmission.type==AUFTRAG.Type.ONGUARD or currmission.type==AUFTRAG.Type.PATROLZONE) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
|
||||||
score=score+25
|
score=score+25
|
||||||
elseif currmission.type==AUFTRAG.Type.NOTHING then
|
elseif currmission.type==AUFTRAG.Type.NOTHING then
|
||||||
score=score+25
|
score=score+30
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then
|
if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then
|
||||||
-- TODO: need to check for missions that do not require ammo like transport, recon, awacs, tanker etc.
|
-- TODO: need to check for missions that do not require ammo like transport, recon, awacs, tanker etc.
|
||||||
-- We better take a fresh asset. Sometimes spawned assets to something else, which is difficult to check.
|
-- We better take a fresh asset. Sometimes spawned assets do something else, which is difficult to check.
|
||||||
score=score-10
|
score=score-10
|
||||||
else
|
else
|
||||||
-- Combat mission.
|
-- Combat mission.
|
||||||
|
|||||||
@ -1800,10 +1800,11 @@ function NAVYGROUP:_InitGroup(Template)
|
|||||||
self.speedMax=self.group:GetSpeedMax()
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
-- Is group mobile?
|
-- Is group mobile?
|
||||||
if self.speedMax>3.6 then
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
self.isMobile=true
|
self.isMobile=true
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cruise speed: 70% of max speed.
|
-- Cruise speed: 70% of max speed.
|
||||||
|
|||||||
@ -508,7 +508,7 @@ OPSGROUP.CargoStatus={
|
|||||||
|
|
||||||
--- OpsGroup version.
|
--- OpsGroup version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
OPSGROUP.version="1.0.0"
|
OPSGROUP.version="1.0.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@ -535,7 +535,7 @@ OPSGROUP.version="1.0.0"
|
|||||||
-- @param Wrapper.Group#GROUP group The GROUP object. Can also be given by its group name as `#string`.
|
-- @param Wrapper.Group#GROUP group The GROUP object. Can also be given by its group name as `#string`.
|
||||||
-- @return #OPSGROUP self
|
-- @return #OPSGROUP self
|
||||||
function OPSGROUP:New(group)
|
function OPSGROUP:New(group)
|
||||||
|
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self=BASE:Inherit(self, FSM:New()) -- #OPSGROUP
|
local self=BASE:Inherit(self, FSM:New()) -- #OPSGROUP
|
||||||
|
|
||||||
@ -554,10 +554,15 @@ function OPSGROUP:New(group)
|
|||||||
-- Check if group exists.
|
-- Check if group exists.
|
||||||
if self.group then
|
if self.group then
|
||||||
if not self:IsExist() then
|
if not self:IsExist() then
|
||||||
self:T(self.lid.."ERROR: GROUP does not exist! Returning nil")
|
self:E(self.lid.."ERROR: GROUP does not exist! Returning nil")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if UTILS.IsInstanceOf(group,"OPSGROUP") then
|
||||||
|
self:E(self.lid.."ERROR: GROUP is already an OPSGROUP: "..tostring(self.groupname).."!")
|
||||||
|
return group
|
||||||
|
end
|
||||||
|
|
||||||
-- Set the template.
|
-- Set the template.
|
||||||
self:_SetTemplate()
|
self:_SetTemplate()
|
||||||
@ -591,33 +596,34 @@ function OPSGROUP:New(group)
|
|||||||
|
|
||||||
if units then
|
if units then
|
||||||
local masterunit=units[1] --Wrapper.Unit#UNIT
|
local masterunit=units[1] --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
-- Get Descriptors.
|
if unit then
|
||||||
self.descriptors=masterunit:GetDesc()
|
-- Get Descriptors.
|
||||||
|
self.descriptors=masterunit:GetDesc()
|
||||||
-- Set type name.
|
|
||||||
self.actype=masterunit:GetTypeName()
|
-- Set type name.
|
||||||
|
self.actype=masterunit:GetTypeName()
|
||||||
-- Is this a submarine.
|
|
||||||
self.isSubmarine=masterunit:HasAttribute("Submarines")
|
-- Is this a submarine.
|
||||||
|
self.isSubmarine=masterunit:HasAttribute("Submarines")
|
||||||
-- Has this a datalink?
|
|
||||||
self.isEPLRS=masterunit:HasAttribute("Datalink")
|
-- Has this a datalink?
|
||||||
|
self.isEPLRS=masterunit:HasAttribute("Datalink")
|
||||||
if self:IsFlightgroup() then
|
|
||||||
|
if self:IsFlightgroup() then
|
||||||
self.rangemax=self.descriptors.range and self.descriptors.range*1000 or 500*1000
|
|
||||||
|
self.rangemax=self.descriptors.range and self.descriptors.range*1000 or 500*1000
|
||||||
self.ceiling=self.descriptors.Hmax
|
|
||||||
|
self.ceiling=self.descriptors.Hmax
|
||||||
self.tankertype=select(2, masterunit:IsTanker())
|
|
||||||
self.refueltype=select(2, masterunit:IsRefuelable())
|
self.tankertype=select(2, masterunit:IsTanker())
|
||||||
|
self.refueltype=select(2, masterunit:IsRefuelable())
|
||||||
--env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
|
|
||||||
--env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
|
--env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
|
||||||
|
--env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Init set of detected units.
|
-- Init set of detected units.
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
-- @module Ops.PlayerTask
|
-- @module Ops.PlayerTask
|
||||||
-- @image OPS_PlayerTask.jpg
|
-- @image OPS_PlayerTask.jpg
|
||||||
-- @date Last Update Jan 2024
|
-- @date Last Update Feb 2024
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -411,6 +411,15 @@ function PLAYERTASK:IsDone()
|
|||||||
return IsDone
|
return IsDone
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Check if PLAYERTASK has clients assigned to it.
|
||||||
|
-- @param #PLAYERTASK self
|
||||||
|
-- @return #boolean hasclients
|
||||||
|
function PLAYERTASK:HasClients()
|
||||||
|
self:T(self.lid.."HasClients?")
|
||||||
|
local hasclients = self:CountClients() > 0 and true or false
|
||||||
|
return hasclients
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Get client names assigned as table of #strings
|
--- [User] Get client names assigned as table of #strings
|
||||||
-- @param #PLAYERTASK self
|
-- @param #PLAYERTASK self
|
||||||
-- @return #table clients
|
-- @return #table clients
|
||||||
@ -1552,7 +1561,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASKCONTROLLER.version="0.1.64"
|
PLAYERTASKCONTROLLER.version="0.1.65"
|
||||||
|
|
||||||
--- Create and run a new TASKCONTROLLER instance.
|
--- Create and run a new TASKCONTROLLER instance.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
@ -3173,7 +3182,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
local ttsname = self.gettext:GetEntry("TASKNAMETTS",self.locale)
|
local ttsname = self.gettext:GetEntry("TASKNAMETTS",self.locale)
|
||||||
local taskname = string.format(tname,task.Type,task.PlayerTaskNr)
|
local taskname = string.format(tname,task.Type,task.PlayerTaskNr)
|
||||||
local ttstaskname = string.format(ttsname,task.TTSType,task.PlayerTaskNr)
|
local ttstaskname = string.format(ttsname,task.TTSType,task.PlayerTaskNr)
|
||||||
local Coordinate = task.Target:GetCoordinate()
|
local Coordinate = task.Target:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||||
local CoordText = ""
|
local CoordText = ""
|
||||||
local CoordTextLLDM = nil
|
local CoordTextLLDM = nil
|
||||||
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
||||||
|
|||||||
@ -30,6 +30,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Sound/Radio)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
||||||
--
|
--
|
||||||
-- @module Sound.Radio
|
-- @module Sound.Radio
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Example Missions: [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Sound/MSRS).
|
-- ## Example Missions: [GitHub](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Sound/MSRS).
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@ -444,10 +444,11 @@ end
|
|||||||
--- Print a table to log in a nice format
|
--- Print a table to log in a nice format
|
||||||
-- @param #table table The table to print
|
-- @param #table table The table to print
|
||||||
-- @param #number indent Number of indents
|
-- @param #number indent Number of indents
|
||||||
|
-- @param #boolean noprint Don't log but return text
|
||||||
-- @return #string text Text created on the fly of the log output
|
-- @return #string text Text created on the fly of the log output
|
||||||
function UTILS.PrintTableToLog(table, indent)
|
function UTILS.PrintTableToLog(table, indent, noprint)
|
||||||
local text = "\n"
|
local text = "\n"
|
||||||
if not table then
|
if not table or type(table) ~= "table" then
|
||||||
env.warning("No table passed!")
|
env.warning("No table passed!")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@ -455,11 +456,16 @@ function UTILS.PrintTableToLog(table, indent)
|
|||||||
for k, v in pairs(table) do
|
for k, v in pairs(table) do
|
||||||
if string.find(k," ") then k='"'..k..'"'end
|
if string.find(k," ") then k='"'..k..'"'end
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
env.info(string.rep(" ", indent) .. tostring(k) .. " = {")
|
if not noprint then
|
||||||
|
env.info(string.rep(" ", indent) .. tostring(k) .. " = {")
|
||||||
|
end
|
||||||
text = text ..string.rep(" ", indent) .. tostring(k) .. " = {\n"
|
text = text ..string.rep(" ", indent) .. tostring(k) .. " = {\n"
|
||||||
text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1)).."\n"
|
text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1)).."\n"
|
||||||
env.info(string.rep(" ", indent) .. "},")
|
if not noprint then
|
||||||
|
env.info(string.rep(" ", indent) .. "},")
|
||||||
|
end
|
||||||
text = text .. string.rep(" ", indent) .. "},\n"
|
text = text .. string.rep(" ", indent) .. "},\n"
|
||||||
|
elseif type(v) == "function" then
|
||||||
else
|
else
|
||||||
local value
|
local value
|
||||||
if tostring(v) == "true" or tostring(v) == "false" or tonumber(v) ~= nil then
|
if tostring(v) == "true" or tostring(v) == "false" or tonumber(v) ~= nil then
|
||||||
@ -467,7 +473,9 @@ function UTILS.PrintTableToLog(table, indent)
|
|||||||
else
|
else
|
||||||
value = '"'..tostring(v)..'"'
|
value = '"'..tostring(v)..'"'
|
||||||
end
|
end
|
||||||
env.info(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n")
|
if not noprint then
|
||||||
|
env.info(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n")
|
||||||
|
end
|
||||||
text = text .. string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n"
|
text = text .. string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -2229,6 +2237,11 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
return true -- no doors on this one ;)
|
return true -- no doors on this one ;)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if type_name == "MH-60R" and (unit:getDrawArgumentValue(403) > 0 or unit:getDrawArgumentValue(403) == -1) then
|
||||||
|
BASE:T(unit_name .. " cargo door is open")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
end -- nil
|
end -- nil
|
||||||
@ -3717,3 +3730,116 @@ end
|
|||||||
function UTILS.OctalToDecimal(Number)
|
function UTILS.OctalToDecimal(Number)
|
||||||
return tonumber(Number,8)
|
return tonumber(Number,8)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to save the position of a set of #OPSGROUP (ARMYGROUP) objects.
|
||||||
|
-- @param Core.Set#SET_OPSGROUP Set of ops objects to save
|
||||||
|
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||||
|
-- @param #string Filename The name of the file.
|
||||||
|
-- @param #boolean Structured Append the data with a list of typenames in the group plus their count.
|
||||||
|
-- @return #boolean outcome True if saving is successful, else false.
|
||||||
|
function UTILS.SaveSetOfOpsGroups(Set,Path,Filename,Structured)
|
||||||
|
local filename = Filename or "SetOfGroups"
|
||||||
|
local data = "--Save SET of groups: (name,legion,template,alttemplate,units,position.x,position.y,position.z,strucdata) "..Filename .."\n"
|
||||||
|
local List = Set:GetSetObjects()
|
||||||
|
for _,_group in pairs (List) do
|
||||||
|
local group = _group:GetGroup() -- Wrapper.Group#GROUP
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
local name = group:GetName()
|
||||||
|
local template = string.gsub(name,"(.AID.%d+$","")
|
||||||
|
if string.find(template,"#") then
|
||||||
|
template = string.gsub(name,"#(%d+)$","")
|
||||||
|
end
|
||||||
|
local alttemplate = _group.templatename or "none"
|
||||||
|
local legiono = _group.legion -- Ops.Legion#LEGION
|
||||||
|
local legion = "none"
|
||||||
|
if legiono and type(legiono) == "table" and legiono.ClassName then
|
||||||
|
legion = legiono:GetName()
|
||||||
|
local asset = legiono:GetAssetByName(name) -- Functional.Warehouse#WAREHOUSE.Assetitem
|
||||||
|
alttemplate=asset.templatename
|
||||||
|
end
|
||||||
|
local units = group:CountAliveUnits()
|
||||||
|
local position = group:GetVec3()
|
||||||
|
if Structured then
|
||||||
|
local structure = UTILS.GetCountPerTypeName(group)
|
||||||
|
local strucdata = ""
|
||||||
|
for typen,anzahl in pairs (structure) do
|
||||||
|
strucdata = strucdata .. typen .. "=="..anzahl..";"
|
||||||
|
end
|
||||||
|
data = string.format("%s%s,%s,%s,%s,%d,%d,%d,%d,%s\n",data,name,legion,template,alttemplate,units,position.x,position.y,position.z,strucdata)
|
||||||
|
else
|
||||||
|
data = string.format("%s%s,%s,%s,%s,%d,%d,%d,%d\n",data,name,legion,template,alttemplate,units,position.x,position.y,position.z)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- save the data
|
||||||
|
local outcome = UTILS.SaveToFile(Path,Filename,data)
|
||||||
|
return outcome
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Load back a #OPSGROUP (ARMYGROUP) data from file for use with @{Ops.Brigade#BRIGADE.LoadBackAssetInPosition}()
|
||||||
|
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||||
|
-- @param #string Filename The name of the file.
|
||||||
|
-- @return #table Returns a table of data entries: `{ groupname=groupname, size=size, coordinate=coordinate, template=template, structure=structure, legion=legion, alttemplate=alttemplate }`
|
||||||
|
-- Returns nil when the file cannot be read.
|
||||||
|
function UTILS.LoadSetOfOpsGroups(Path,Filename)
|
||||||
|
|
||||||
|
local filename = Filename or "SetOfGroups"
|
||||||
|
local datatable = {}
|
||||||
|
|
||||||
|
if UTILS.CheckFileExists(Path,filename) then
|
||||||
|
local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename)
|
||||||
|
-- remove header
|
||||||
|
table.remove(loadeddata, 1)
|
||||||
|
for _id,_entry in pairs (loadeddata) do
|
||||||
|
local dataset = UTILS.Split(_entry,",")
|
||||||
|
-- 1name,2legion,3template,4alttemplate,5units,6position.x,7position.y,8position.z,9strucdata
|
||||||
|
local groupname = dataset[1]
|
||||||
|
local legion = dataset[2]
|
||||||
|
local template = dataset[3]
|
||||||
|
local alttemplate = dataset[4]
|
||||||
|
local size = tonumber(dataset[5])
|
||||||
|
local posx = tonumber(dataset[6])
|
||||||
|
local posy = tonumber(dataset[7])
|
||||||
|
local posz = tonumber(dataset[8])
|
||||||
|
local structure = dataset[9]
|
||||||
|
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz})
|
||||||
|
if size > 0 then
|
||||||
|
local data = { groupname=groupname, size=size, coordinate=coordinate, template=template, structure=structure, legion=legion, alttemplate=alttemplate }
|
||||||
|
table.insert(datatable,data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return datatable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the clock position from a relative heading
|
||||||
|
-- @param #number refHdg The heading of the reference object (such as a Wrapper.UNIT) in 0-360
|
||||||
|
-- @param #number tgtHdg The absolute heading from the reference object to the target object/point in 0-360
|
||||||
|
-- @return #string text Text in clock heading such as "4 O'CLOCK"
|
||||||
|
-- @usage Display the range and clock distance of a BTR in relation to REAPER 1-1's heading:
|
||||||
|
--
|
||||||
|
-- myUnit = UNIT:FindByName( "REAPER 1-1" )
|
||||||
|
-- myTarget = GROUP:FindByName( "BTR-1" )
|
||||||
|
--
|
||||||
|
-- coordUnit = myUnit:GetCoordinate()
|
||||||
|
-- coordTarget = myTarget:GetCoordinate()
|
||||||
|
--
|
||||||
|
-- hdgUnit = myUnit:GetHeading()
|
||||||
|
-- hdgTarget = coordUnit:HeadingTo( coordTarget )
|
||||||
|
-- distTarget = coordUnit:Get3DDistance( coordTarget )
|
||||||
|
--
|
||||||
|
-- clockString = UTILS.ClockHeadingString( hdgUnit, hdgTarget )
|
||||||
|
--
|
||||||
|
-- -- Will show this message to REAPER 1-1 in-game: Contact BTR at 3 o'clock for 1134m!
|
||||||
|
-- MESSAGE:New("Contact BTR at " .. clockString .. " for " .. distTarget .. "m!):ToUnit( myUnit )
|
||||||
|
function UTILS.ClockHeadingString(refHdg,tgtHdg)
|
||||||
|
local relativeAngle = tgtHdg - refHdg
|
||||||
|
if relativeAngle < 0 then
|
||||||
|
relativeAngle = relativeAngle + 360
|
||||||
|
end
|
||||||
|
local clockPos = math.ceil((relativeAngle % 360) / 30)
|
||||||
|
return clockPos.." o'clock"
|
||||||
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,8 @@
|
|||||||
-- @image Wrapper_Static.JPG
|
-- @image Wrapper_Static.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type STATIC
|
---
|
||||||
|
-- @type STATIC
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
--- Wrapper class to handle Static objects.
|
--- Wrapper class to handle Static objects.
|
||||||
@ -236,7 +237,7 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
--- Respawn the @{Wrapper.Static} at the same location with the same properties.
|
||||||
-- This is useful to respawn a cargo after it has been destroyed.
|
-- This is useful to respawn a cargo after it has been destroyed.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
|
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
|
||||||
@ -248,7 +249,7 @@ function STATIC:ReSpawn(CountryID, Delay)
|
|||||||
else
|
else
|
||||||
|
|
||||||
CountryID=CountryID or self:GetCountry()
|
CountryID=CountryID or self:GetCountry()
|
||||||
|
|
||||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||||
|
|
||||||
SpawnStatic:Spawn(nil, self.StaticName)
|
SpawnStatic:Spawn(nil, self.StaticName)
|
||||||
@ -270,8 +271,8 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
|||||||
|
|
||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
||||||
else
|
else
|
||||||
|
|
||||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||||
|
|
||||||
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||||
@ -280,3 +281,52 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find the first(!) STATIC matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
|
||||||
|
-- @param #STATIC self
|
||||||
|
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
|
||||||
|
-- @return #STATIC The STATIC.
|
||||||
|
-- @usage
|
||||||
|
-- -- Find a static with a partial static name
|
||||||
|
-- local grp = STATIC:FindByMatching( "Apple" )
|
||||||
|
-- -- will return e.g. a static named "Apple-1-1"
|
||||||
|
--
|
||||||
|
-- -- using a pattern
|
||||||
|
-- local grp = STATIC:FindByMatching( ".%d.%d$" )
|
||||||
|
-- -- will return the first static found ending in "-1-1" to "-9-9", but not e.g. "-10-1"
|
||||||
|
function STATIC:FindByMatching( Pattern )
|
||||||
|
local GroupFound = nil
|
||||||
|
|
||||||
|
for name,static in pairs(_DATABASE.STATICS) do
|
||||||
|
if string.match(name, Pattern ) then
|
||||||
|
GroupFound = static
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return GroupFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find all STATIC objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
|
||||||
|
-- @param #STATIC self
|
||||||
|
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
|
||||||
|
-- @return #table Groups Table of matching #STATIC objects found
|
||||||
|
-- @usage
|
||||||
|
-- -- Find all static with a partial static name
|
||||||
|
-- local grptable = STATIC:FindAllByMatching( "Apple" )
|
||||||
|
-- -- will return all statics with "Apple" in the name
|
||||||
|
--
|
||||||
|
-- -- using a pattern
|
||||||
|
-- local grp = STATIC:FindAllByMatching( ".%d.%d$" )
|
||||||
|
-- -- will return the all statics found ending in "-1-1" to "-9-9", but not e.g. "-10-1" or "-1-10"
|
||||||
|
function STATIC:FindAllByMatching( Pattern )
|
||||||
|
local GroupsFound = {}
|
||||||
|
|
||||||
|
for name,static in pairs(_DATABASE.STATICS) do
|
||||||
|
if string.match(name, Pattern ) then
|
||||||
|
GroupsFound[#GroupsFound+1] = static
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return GroupsFound
|
||||||
|
end
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Example Missions:
|
-- ## Example Missions:
|
||||||
--
|
--
|
||||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Wrapper/Storage).
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Storage).
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -33,93 +33,93 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # The STORAGE Concept
|
-- # The STORAGE Concept
|
||||||
--
|
--
|
||||||
-- The STORAGE class offers an easy-to-use wrapper interface to all DCS API functions of DCS warehouses.
|
-- The STORAGE class offers an easy-to-use wrapper interface to all DCS API functions of DCS warehouses.
|
||||||
-- We named the class STORAGE, because the name WAREHOUSE is already taken by another MOOSE class.
|
-- We named the class STORAGE, because the name WAREHOUSE is already taken by another MOOSE class.
|
||||||
--
|
--
|
||||||
-- This class allows you to add and remove items to a DCS warehouse, such as aircraft, liquids, weapons and other equipment.
|
-- This class allows you to add and remove items to a DCS warehouse, such as aircraft, liquids, weapons and other equipment.
|
||||||
--
|
--
|
||||||
-- # Constructor
|
-- # Constructor
|
||||||
--
|
--
|
||||||
-- A DCS warehouse is associated with an airbase. Therefore, a `STORAGE` instance is automatically created, once an airbase is registered and added to the MOOSE database.
|
-- A DCS warehouse is associated with an airbase. Therefore, a `STORAGE` instance is automatically created, once an airbase is registered and added to the MOOSE database.
|
||||||
--
|
--
|
||||||
-- You can get the `STORAGE` object from the
|
-- You can get the `STORAGE` object from the
|
||||||
--
|
--
|
||||||
-- -- Create a STORAGE instance of the Batumi warehouse
|
-- -- Create a STORAGE instance of the Batumi warehouse
|
||||||
-- local storage=STORAGE:FindByName("Batumi")
|
-- local storage=STORAGE:FindByName("Batumi")
|
||||||
--
|
--
|
||||||
-- An other way to get the `STORAGE` object is to retrieve it from the AIRBASE function `AIRBASE:GetStorage()`
|
-- An other way to get the `STORAGE` object is to retrieve it from the AIRBASE function `AIRBASE:GetStorage()`
|
||||||
--
|
--
|
||||||
-- -- Get storage instance of Batumi airbase
|
-- -- Get storage instance of Batumi airbase
|
||||||
-- local Batumi=AIRBASE:FindByName("Batumi")
|
-- local Batumi=AIRBASE:FindByName("Batumi")
|
||||||
-- local storage=Batumi:GetStorage()
|
-- local storage=Batumi:GetStorage()
|
||||||
--
|
--
|
||||||
-- # Aircraft, Weapons and Equipment
|
-- # Aircraft, Weapons and Equipment
|
||||||
--
|
--
|
||||||
-- ## Adding Items
|
-- ## Adding Items
|
||||||
--
|
--
|
||||||
-- To add aircraft, weapons and/or othe equipment, you can use the @{#STORAGE.AddItem}() function
|
-- To add aircraft, weapons and/or othe equipment, you can use the @{#STORAGE.AddItem}() function
|
||||||
--
|
--
|
||||||
-- storage:AddItem("A-10C", 3)
|
-- storage:AddItem("A-10C", 3)
|
||||||
-- storage:AddItem("weapons.missiles.AIM_120C", 10)
|
-- storage:AddItem("weapons.missiles.AIM_120C", 10)
|
||||||
--
|
--
|
||||||
-- This will add three A-10Cs and ten AIM-120C missiles to the warehouse inventory.
|
-- This will add three A-10Cs and ten AIM-120C missiles to the warehouse inventory.
|
||||||
--
|
--
|
||||||
-- ## Setting Items
|
-- ## Setting Items
|
||||||
--
|
--
|
||||||
-- You can also explicitly set, how many items are in the inventory with the @{#STORAGE.SetItem}() function.
|
-- You can also explicitly set, how many items are in the inventory with the @{#STORAGE.SetItem}() function.
|
||||||
--
|
--
|
||||||
-- ## Removing Items
|
-- ## Removing Items
|
||||||
--
|
--
|
||||||
-- Items can be removed from the inventory with the @{#STORAGE.RemoveItem}() function.
|
-- Items can be removed from the inventory with the @{#STORAGE.RemoveItem}() function.
|
||||||
--
|
--
|
||||||
-- ## Getting Amount
|
-- ## Getting Amount
|
||||||
--
|
--
|
||||||
-- The number of items currently in the inventory can be obtained with the @{#STORAGE.GetItemAmount}() function
|
-- The number of items currently in the inventory can be obtained with the @{#STORAGE.GetItemAmount}() function
|
||||||
--
|
--
|
||||||
-- local N=storage:GetItemAmount("A-10C")
|
-- local N=storage:GetItemAmount("A-10C")
|
||||||
-- env.info(string.format("We currently have %d A-10Cs available", N))
|
-- env.info(string.format("We currently have %d A-10Cs available", N))
|
||||||
--
|
--
|
||||||
-- # Liquids
|
-- # Liquids
|
||||||
--
|
--
|
||||||
-- Liquids can be added and removed by slightly different functions as described below. Currently there are four types of liquids
|
-- Liquids can be added and removed by slightly different functions as described below. Currently there are four types of liquids
|
||||||
--
|
--
|
||||||
-- * Jet fuel `STORAGE.Liquid.JETFUEL`
|
-- * Jet fuel `STORAGE.Liquid.JETFUEL`
|
||||||
-- * Aircraft gasoline `STORAGE.Liquid.GASOLINE`
|
-- * Aircraft gasoline `STORAGE.Liquid.GASOLINE`
|
||||||
-- * MW 50 `STORAGE.Liquid.MW50`
|
-- * MW 50 `STORAGE.Liquid.MW50`
|
||||||
-- * Diesel `STORAGE.Liquid.DIESEL`
|
-- * Diesel `STORAGE.Liquid.DIESEL`
|
||||||
--
|
--
|
||||||
-- ## Adding Liquids
|
-- ## Adding Liquids
|
||||||
--
|
--
|
||||||
-- To add a certain type of liquid, you can use the @{#STORAGE.AddItem}(Type, Amount) function
|
-- To add a certain type of liquid, you can use the @{#STORAGE.AddItem}(Type, Amount) function
|
||||||
--
|
--
|
||||||
-- storage:AddLiquid(STORAGE.Liquid.JETFUEL, 10000)
|
-- storage:AddLiquid(STORAGE.Liquid.JETFUEL, 10000)
|
||||||
-- storage:AddLiquid(STORAGE.Liquid.DIESEL, 20000)
|
-- storage:AddLiquid(STORAGE.Liquid.DIESEL, 20000)
|
||||||
--
|
--
|
||||||
-- This will add 10,000 kg of jet fuel and 20,000 kg of diesel to the inventory.
|
-- This will add 10,000 kg of jet fuel and 20,000 kg of diesel to the inventory.
|
||||||
--
|
--
|
||||||
-- ## Setting Liquids
|
-- ## Setting Liquids
|
||||||
--
|
--
|
||||||
-- You can also explicitly set the amount of liquid with the @{#STORAGE.SetLiquid}(Type, Amount) function.
|
-- You can also explicitly set the amount of liquid with the @{#STORAGE.SetLiquid}(Type, Amount) function.
|
||||||
--
|
--
|
||||||
-- ## Removing Liquids
|
-- ## Removing Liquids
|
||||||
--
|
--
|
||||||
-- Liquids can be removed with @{#STORAGE.RemoveLiquid}(Type, Amount) function.
|
-- Liquids can be removed with @{#STORAGE.RemoveLiquid}(Type, Amount) function.
|
||||||
--
|
--
|
||||||
-- ## Getting Amount
|
-- ## Getting Amount
|
||||||
--
|
--
|
||||||
-- The current amount of a certain liquid can be obtained with the @{#STORAGE.GetLiquidAmount}(Type) function
|
-- The current amount of a certain liquid can be obtained with the @{#STORAGE.GetLiquidAmount}(Type) function
|
||||||
--
|
--
|
||||||
-- local N=storage:GetLiquidAmount(STORAGE.Liquid.DIESEL)
|
-- local N=storage:GetLiquidAmount(STORAGE.Liquid.DIESEL)
|
||||||
-- env.info(string.format("We currently have %d kg of Diesel available", N))
|
-- env.info(string.format("We currently have %d kg of Diesel available", N))
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- # Inventory
|
-- # Inventory
|
||||||
--
|
--
|
||||||
-- The current inventory of the warehouse can be obtained with the @{#STORAGE.GetInventory}() function. This returns three tables with the aircraft, liquids and weapons:
|
-- The current inventory of the warehouse can be obtained with the @{#STORAGE.GetInventory}() function. This returns three tables with the aircraft, liquids and weapons:
|
||||||
--
|
--
|
||||||
-- local aircraft, liquids, weapons=storage:GetInventory()
|
-- local aircraft, liquids, weapons=storage:GetInventory()
|
||||||
--
|
--
|
||||||
-- UTILS.PrintTableToLog(aircraft)
|
-- UTILS.PrintTableToLog(aircraft)
|
||||||
-- UTILS.PrintTableToLog(liquids)
|
-- UTILS.PrintTableToLog(liquids)
|
||||||
-- UTILS.PrintTableToLog(weapons)
|
-- UTILS.PrintTableToLog(weapons)
|
||||||
@ -168,7 +168,7 @@ function STORAGE:New(AirbaseName)
|
|||||||
local self=BASE:Inherit(self, BASE:New()) -- #STORAGE
|
local self=BASE:Inherit(self, BASE:New()) -- #STORAGE
|
||||||
|
|
||||||
self.airbase=Airbase.getByName(AirbaseName)
|
self.airbase=Airbase.getByName(AirbaseName)
|
||||||
|
|
||||||
if Airbase.getWarehouse then
|
if Airbase.getWarehouse then
|
||||||
self.warehouse=self.airbase:getWarehouse()
|
self.warehouse=self.airbase:getWarehouse()
|
||||||
end
|
end
|
||||||
@ -322,7 +322,7 @@ end
|
|||||||
function STORAGE:GetLiquidName(Type)
|
function STORAGE:GetLiquidName(Type)
|
||||||
|
|
||||||
local name="Unknown"
|
local name="Unknown"
|
||||||
|
|
||||||
if Type==STORAGE.Liquid.JETFUEL then
|
if Type==STORAGE.Liquid.JETFUEL then
|
||||||
name = "Jet fuel"
|
name = "Jet fuel"
|
||||||
elseif Type==STORAGE.Liquid.GASOLINE then
|
elseif Type==STORAGE.Liquid.GASOLINE then
|
||||||
@ -411,25 +411,25 @@ function STORAGE:IsUnlimited(Type)
|
|||||||
|
|
||||||
-- Get current amount of type.
|
-- Get current amount of type.
|
||||||
local N=self:GetAmount(Type)
|
local N=self:GetAmount(Type)
|
||||||
|
|
||||||
local unlimited=false
|
local unlimited=false
|
||||||
|
|
||||||
if N>0 then
|
if N>0 then
|
||||||
|
|
||||||
-- Remove one item.
|
-- Remove one item.
|
||||||
self:RemoveAmount(Type, 1)
|
self:RemoveAmount(Type, 1)
|
||||||
|
|
||||||
-- Get amount.
|
-- Get amount.
|
||||||
local n=self:GetAmount(Type)
|
local n=self:GetAmount(Type)
|
||||||
|
|
||||||
-- If amount did not change, it is unlimited.
|
-- If amount did not change, it is unlimited.
|
||||||
unlimited=n==N
|
unlimited=n==N
|
||||||
|
|
||||||
-- Add item back.
|
-- Add item back.
|
||||||
if not unlimited then
|
if not unlimited then
|
||||||
self:AddAmount(Type, 1)
|
self:AddAmount(Type, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(self.lid..string.format("Type=%s: unlimited=%s (N=%d n=%d)", tostring(Type), tostring(unlimited), N, n))
|
self:I(self.lid..string.format("Type=%s: unlimited=%s (N=%d n=%d)", tostring(Type), tostring(unlimited), N, n))
|
||||||
end
|
end
|
||||||
@ -523,7 +523,7 @@ end
|
|||||||
function STORAGE:GetInventory(Item)
|
function STORAGE:GetInventory(Item)
|
||||||
|
|
||||||
local inventory=self.warehouse:getInventory(Item)
|
local inventory=self.warehouse:getInventory(Item)
|
||||||
|
|
||||||
return inventory.aircraft, inventory.liquids, inventory.weapon
|
return inventory.aircraft, inventory.liquids, inventory.weapon
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1244,7 +1244,9 @@ function UNIT:GetThreatLevel()
|
|||||||
|
|
||||||
if Attributes["Fighters"] then ThreatLevel = 10
|
if Attributes["Fighters"] then ThreatLevel = 10
|
||||||
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
||||||
|
elseif Attributes["Interceptors"] then ThreatLevel = 9
|
||||||
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
||||||
|
elseif Attributes["Battle airplanes"] then ThreatLevel = 8
|
||||||
elseif Attributes["Attack helicopters"] then ThreatLevel = 7
|
elseif Attributes["Attack helicopters"] then ThreatLevel = 7
|
||||||
elseif Attributes["Strategic bombers"] then ThreatLevel = 6
|
elseif Attributes["Strategic bombers"] then ThreatLevel = 6
|
||||||
elseif Attributes["Bombers"] then ThreatLevel = 5
|
elseif Attributes["Bombers"] then ThreatLevel = 5
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Additional Material:
|
-- ## Additional Material:
|
||||||
--
|
--
|
||||||
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Wrapper/Weapon)
|
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Weapon)
|
||||||
-- * **YouTube videos:** None
|
-- * **YouTube videos:** None
|
||||||
-- * **Guides:** None
|
-- * **Guides:** None
|
||||||
--
|
--
|
||||||
@ -69,77 +69,77 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # The WEAPON Concept
|
-- # The WEAPON Concept
|
||||||
--
|
--
|
||||||
-- The WEAPON class offers an easy-to-use wrapper interface to all DCS API functions.
|
-- The WEAPON class offers an easy-to-use wrapper interface to all DCS API functions.
|
||||||
--
|
--
|
||||||
-- Probably, the most striking highlight is that the position of the weapon can be tracked and its impact position can be determined, which is not
|
-- Probably, the most striking highlight is that the position of the weapon can be tracked and its impact position can be determined, which is not
|
||||||
-- possible with the native DCS scripting engine functions.
|
-- possible with the native DCS scripting engine functions.
|
||||||
--
|
--
|
||||||
-- **Note** that this wrapper class is different from most others as weapon objects cannot be found with a DCS API function like `getByName()`.
|
-- **Note** that this wrapper class is different from most others as weapon objects cannot be found with a DCS API function like `getByName()`.
|
||||||
-- They can only be found in DCS events like the "Shot" event, where the weapon object is contained in the event data.
|
-- They can only be found in DCS events like the "Shot" event, where the weapon object is contained in the event data.
|
||||||
--
|
--
|
||||||
-- # Tracking
|
-- # Tracking
|
||||||
--
|
--
|
||||||
-- The status of the weapon can be tracked with the @{#WEAPON.StartTrack} function. This function will try to determin the position of the weapon in (normally) relatively
|
-- The status of the weapon can be tracked with the @{#WEAPON.StartTrack} function. This function will try to determin the position of the weapon in (normally) relatively
|
||||||
-- small time steps. The time step can be set via the @{#WEAPON.SetTimeStepTrack} function and is by default set to 0.01 seconds.
|
-- small time steps. The time step can be set via the @{#WEAPON.SetTimeStepTrack} function and is by default set to 0.01 seconds.
|
||||||
--
|
--
|
||||||
-- Once the position cannot be retrieved any more, the weapon has impacted (or was destroyed otherwise) and the last known position is safed as the impact point.
|
-- Once the position cannot be retrieved any more, the weapon has impacted (or was destroyed otherwise) and the last known position is safed as the impact point.
|
||||||
-- The impact point can be accessed with the @{#WEAPON.GetImpactVec3} or @{#WEAPON.GetImpactCoordinate} functions.
|
-- The impact point can be accessed with the @{#WEAPON.GetImpactVec3} or @{#WEAPON.GetImpactCoordinate} functions.
|
||||||
--
|
--
|
||||||
-- ## Impact Point Marking
|
-- ## Impact Point Marking
|
||||||
--
|
--
|
||||||
-- You can mark the impact point on the F10 map with @{#WEAPON.SetMarkImpact}.
|
-- You can mark the impact point on the F10 map with @{#WEAPON.SetMarkImpact}.
|
||||||
--
|
--
|
||||||
-- You can also trigger coloured smoke at the impact point via @{#WEAPON.SetSmokeImpact}.
|
-- You can also trigger coloured smoke at the impact point via @{#WEAPON.SetSmokeImpact}.
|
||||||
--
|
--
|
||||||
-- ## Callback functions
|
-- ## Callback functions
|
||||||
--
|
--
|
||||||
-- It is possible to define functions that are called during the tracking of the weapon and upon impact, which help you to customize further actions.
|
-- It is possible to define functions that are called during the tracking of the weapon and upon impact, which help you to customize further actions.
|
||||||
--
|
--
|
||||||
-- ### Callback on Impact
|
-- ### Callback on Impact
|
||||||
--
|
--
|
||||||
-- The function called on impact can be set with @{#WEAPON.SetFuncImpact}
|
-- The function called on impact can be set with @{#WEAPON.SetFuncImpact}
|
||||||
--
|
--
|
||||||
-- ### Callback when Tracking
|
-- ### Callback when Tracking
|
||||||
--
|
--
|
||||||
-- The function called each time the weapon status is tracked can be set with @{#WEAPON.SetFuncTrack}
|
-- The function called each time the weapon status is tracked can be set with @{#WEAPON.SetFuncTrack}
|
||||||
--
|
--
|
||||||
-- # Target
|
-- # Target
|
||||||
--
|
--
|
||||||
-- If the weapon has a specific target, you can get it with the @{#WEAPON.GetTarget} function. Note that the object, which is returned can vary. Normally, it is a UNIT
|
-- If the weapon has a specific target, you can get it with the @{#WEAPON.GetTarget} function. Note that the object, which is returned can vary. Normally, it is a UNIT
|
||||||
-- but it could also be a STATIC object.
|
-- but it could also be a STATIC object.
|
||||||
--
|
--
|
||||||
-- Also note that the weapon does not always have a target, it can loose a target and re-aquire it and the target might change to another unit.
|
-- Also note that the weapon does not always have a target, it can loose a target and re-aquire it and the target might change to another unit.
|
||||||
--
|
--
|
||||||
-- You can get the target name with the @{#WEAPON.GetTargetName} function.
|
-- You can get the target name with the @{#WEAPON.GetTargetName} function.
|
||||||
--
|
--
|
||||||
-- The distance to the target is returned by the @{#WEAPON.GetTargetDistance} function.
|
-- The distance to the target is returned by the @{#WEAPON.GetTargetDistance} function.
|
||||||
--
|
--
|
||||||
-- # Category
|
-- # Category
|
||||||
--
|
--
|
||||||
-- The category (bomb, rocket, missile, shell, torpedo) of the weapon can be retrieved with the @{#WEAPON.GetCategory} function.
|
-- The category (bomb, rocket, missile, shell, torpedo) of the weapon can be retrieved with the @{#WEAPON.GetCategory} function.
|
||||||
--
|
--
|
||||||
-- You can check if the weapon is a
|
-- You can check if the weapon is a
|
||||||
--
|
--
|
||||||
-- * bomb with @{#WEAPON.IsBomb}
|
-- * bomb with @{#WEAPON.IsBomb}
|
||||||
-- * rocket with @{#WEAPON.IsRocket}
|
-- * rocket with @{#WEAPON.IsRocket}
|
||||||
-- * missile with @{#WEAPON.IsMissile}
|
-- * missile with @{#WEAPON.IsMissile}
|
||||||
-- * shell with @{#WEAPON.IsShell}
|
-- * shell with @{#WEAPON.IsShell}
|
||||||
-- * torpedo with @{#WEAPON.IsTorpedo}
|
-- * torpedo with @{#WEAPON.IsTorpedo}
|
||||||
--
|
--
|
||||||
-- # Parameters
|
-- # Parameters
|
||||||
--
|
--
|
||||||
-- You can get various parameters of the weapon, *e.g.*
|
-- You can get various parameters of the weapon, *e.g.*
|
||||||
--
|
--
|
||||||
-- * position: @{#WEAPON.GetVec3}, @{#WEAPON.GetVec2 }, @{#WEAPON.GetCoordinate}
|
-- * position: @{#WEAPON.GetVec3}, @{#WEAPON.GetVec2 }, @{#WEAPON.GetCoordinate}
|
||||||
-- * speed: @{#WEAPON.GetSpeed}
|
-- * speed: @{#WEAPON.GetSpeed}
|
||||||
-- * coalition: @{#WEAPON.GetCoalition}
|
-- * coalition: @{#WEAPON.GetCoalition}
|
||||||
-- * country: @{#WEAPON.GetCountry}
|
-- * country: @{#WEAPON.GetCountry}
|
||||||
--
|
--
|
||||||
-- # Dependencies
|
-- # Dependencies
|
||||||
--
|
--
|
||||||
-- This class is used (at least) in the MOOSE classes:
|
-- This class is used (at least) in the MOOSE classes:
|
||||||
--
|
--
|
||||||
-- * RANGE (to determine the impact points of bombs and missiles)
|
-- * RANGE (to determine the impact points of bombs and missiles)
|
||||||
-- * ARTY (to destroy and replace shells with smoke or illumination)
|
-- * ARTY (to destroy and replace shells with smoke or illumination)
|
||||||
-- * FOX (to destroy the missile before it hits the target)
|
-- * FOX (to destroy the missile before it hits the target)
|
||||||
@ -181,48 +181,48 @@ function WEAPON:New(WeaponObject)
|
|||||||
|
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self=BASE:Inherit(self, POSITIONABLE:New("Weapon")) -- #WEAPON
|
local self=BASE:Inherit(self, POSITIONABLE:New("Weapon")) -- #WEAPON
|
||||||
|
|
||||||
-- Set DCS weapon object.
|
-- Set DCS weapon object.
|
||||||
self.weapon=WeaponObject
|
self.weapon=WeaponObject
|
||||||
|
|
||||||
-- Descriptors containing a lot of info.
|
-- Descriptors containing a lot of info.
|
||||||
self.desc=WeaponObject:getDesc()
|
self.desc=WeaponObject:getDesc()
|
||||||
|
|
||||||
-- This gives the object category which is always Object.Category.WEAPON!
|
-- This gives the object category which is always Object.Category.WEAPON!
|
||||||
--self.category=WeaponObject:getCategory()
|
--self.category=WeaponObject:getCategory()
|
||||||
|
|
||||||
-- Weapon category: 0=SHELL, 1=MISSILE, 2=ROCKET, 3=BOMB (Weapon.Category.X)
|
-- Weapon category: 0=SHELL, 1=MISSILE, 2=ROCKET, 3=BOMB (Weapon.Category.X)
|
||||||
self.category = self.desc.category
|
self.category = self.desc.category
|
||||||
|
|
||||||
if self:IsMissile() and self.desc.missileCategory then
|
if self:IsMissile() and self.desc.missileCategory then
|
||||||
self.categoryMissile=self.desc.missileCategory
|
self.categoryMissile=self.desc.missileCategory
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get type name.
|
-- Get type name.
|
||||||
self.typeName=WeaponObject:getTypeName() or "Unknown Type"
|
self.typeName=WeaponObject:getTypeName() or "Unknown Type"
|
||||||
|
|
||||||
-- Get name of object. Usually a number like "1234567".
|
-- Get name of object. Usually a number like "1234567".
|
||||||
self.name=WeaponObject:getName()
|
self.name=WeaponObject:getName()
|
||||||
|
|
||||||
-- Get coaliton of weapon.
|
-- Get coaliton of weapon.
|
||||||
self.coalition=WeaponObject:getCoalition()
|
self.coalition=WeaponObject:getCoalition()
|
||||||
|
|
||||||
-- Get country of weapon.
|
-- Get country of weapon.
|
||||||
self.country=WeaponObject:getCountry()
|
self.country=WeaponObject:getCountry()
|
||||||
|
|
||||||
-- Get DCS unit of the launcher.
|
-- Get DCS unit of the launcher.
|
||||||
self.launcher=WeaponObject:getLauncher()
|
self.launcher=WeaponObject:getLauncher()
|
||||||
|
|
||||||
-- Get launcher of weapon.
|
-- Get launcher of weapon.
|
||||||
self.launcherName="Unknown Launcher"
|
self.launcherName="Unknown Launcher"
|
||||||
if self.launcher then
|
if self.launcher then
|
||||||
self.launcherName=self.launcher:getName()
|
self.launcherName=self.launcher:getName()
|
||||||
self.launcherUnit=UNIT:Find(self.launcher)
|
self.launcherUnit=UNIT:Find(self.launcher)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Init the coordinate of the weapon from that of the launcher.
|
-- Init the coordinate of the weapon from that of the launcher.
|
||||||
self.coordinate=COORDINATE:NewFromVec3(self.launcher:getPoint())
|
self.coordinate=COORDINATE:NewFromVec3(self.launcher:getPoint())
|
||||||
|
|
||||||
-- Set log ID.
|
-- Set log ID.
|
||||||
self.lid=string.format("[%s] %s | ", self.typeName, self.name)
|
self.lid=string.format("[%s] %s | ", self.typeName, self.name)
|
||||||
|
|
||||||
@ -237,12 +237,12 @@ function WEAPON:New(WeaponObject)
|
|||||||
-- Set default parameters
|
-- Set default parameters
|
||||||
self:SetTimeStepTrack()
|
self:SetTimeStepTrack()
|
||||||
self:SetDistanceInterceptPoint()
|
self:SetDistanceInterceptPoint()
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
local text=string.format("Weapon v%s\nName=%s, TypeName=%s, Category=%s, Coalition=%d, Country=%d, Launcher=%s",
|
local text=string.format("Weapon v%s\nName=%s, TypeName=%s, Category=%s, Coalition=%d, Country=%d, Launcher=%s",
|
||||||
self.version, self.name, self.typeName, self.category, self.coalition, self.country, self.launcherName)
|
self.version, self.name, self.typeName, self.category, self.coalition, self.country, self.launcherName)
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
|
|
||||||
-- Descriptors.
|
-- Descriptors.
|
||||||
self:T2(self.desc)
|
self:T2(self.desc)
|
||||||
|
|
||||||
@ -312,13 +312,13 @@ function WEAPON:SetSmokeImpact(Switch, SmokeColor)
|
|||||||
else
|
else
|
||||||
self.impactSmoke=true
|
self.impactSmoke=true
|
||||||
end
|
end
|
||||||
|
|
||||||
self.impactSmokeColor=SmokeColor or SMOKECOLOR.Red
|
self.impactSmokeColor=SmokeColor or SMOKECOLOR.Red
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set callback function when weapon is tracked and still alive. The first argument will be the WEAPON object.
|
--- Set callback function when weapon is tracked and still alive. The first argument will be the WEAPON object.
|
||||||
-- Note that this can be called many times per second. So be careful for performance reasons.
|
-- Note that this can be called many times per second. So be careful for performance reasons.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @param #function FuncTrack Function called during tracking.
|
-- @param #function FuncTrack Function called during tracking.
|
||||||
@ -335,19 +335,19 @@ end
|
|||||||
-- @param #function FuncImpact Function called once the weapon impacted.
|
-- @param #function FuncImpact Function called once the weapon impacted.
|
||||||
-- @param ... Optional function arguments.
|
-- @param ... Optional function arguments.
|
||||||
-- @return #WEAPON self
|
-- @return #WEAPON self
|
||||||
--
|
--
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Function called on impact.
|
-- -- Function called on impact.
|
||||||
-- local function OnImpact(Weapon)
|
-- local function OnImpact(Weapon)
|
||||||
-- Weapon:GetImpactCoordinate():MarkToAll("Impact Coordinate of weapon")
|
-- Weapon:GetImpactCoordinate():MarkToAll("Impact Coordinate of weapon")
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
-- -- Set which function to call.
|
-- -- Set which function to call.
|
||||||
-- myweapon:SetFuncImpact(OnImpact)
|
-- myweapon:SetFuncImpact(OnImpact)
|
||||||
--
|
--
|
||||||
-- -- Start tracking.
|
-- -- Start tracking.
|
||||||
-- myweapon:Track()
|
-- myweapon:Track()
|
||||||
--
|
--
|
||||||
function WEAPON:SetFuncImpact(FuncImpact, ...)
|
function WEAPON:SetFuncImpact(FuncImpact, ...)
|
||||||
self.impactFunc=FuncImpact
|
self.impactFunc=FuncImpact
|
||||||
self.impactArg=arg or {}
|
self.impactArg=arg or {}
|
||||||
@ -368,37 +368,37 @@ end
|
|||||||
function WEAPON:GetTarget()
|
function WEAPON:GetTarget()
|
||||||
|
|
||||||
local target=nil --Wrapper.Object#OBJECT
|
local target=nil --Wrapper.Object#OBJECT
|
||||||
|
|
||||||
if self.weapon then
|
if self.weapon then
|
||||||
|
|
||||||
-- Get the DCS target object, which can be a Unit, Weapon, Static, Scenery, Airbase.
|
-- Get the DCS target object, which can be a Unit, Weapon, Static, Scenery, Airbase.
|
||||||
local object=self.weapon:getTarget()
|
local object=self.weapon:getTarget()
|
||||||
|
|
||||||
if object then
|
if object then
|
||||||
|
|
||||||
-- Get object category.
|
-- Get object category.
|
||||||
local category=Object.getCategory(object)
|
local category=Object.getCategory(object)
|
||||||
|
|
||||||
--Target name
|
--Target name
|
||||||
local name=object:getName()
|
local name=object:getName()
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Got Target Object %s, category=%d", object:getName(), category))
|
self:T(self.lid..string.format("Got Target Object %s, category=%d", object:getName(), category))
|
||||||
|
|
||||||
if category==Object.Category.UNIT then
|
if category==Object.Category.UNIT then
|
||||||
|
|
||||||
target=UNIT:FindByName(name)
|
target=UNIT:FindByName(name)
|
||||||
|
|
||||||
elseif category==Object.Category.STATIC then
|
elseif category==Object.Category.STATIC then
|
||||||
|
|
||||||
target=STATIC:FindByName(name, false)
|
target=STATIC:FindByName(name, false)
|
||||||
|
|
||||||
elseif category==Object.Category.SCENERY then
|
elseif category==Object.Category.SCENERY then
|
||||||
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
|
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
|
||||||
else
|
else
|
||||||
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
|
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -413,25 +413,25 @@ function WEAPON:GetTargetDistance(ConversionFunction)
|
|||||||
|
|
||||||
-- Get the target of the weapon.
|
-- Get the target of the weapon.
|
||||||
local target=self:GetTarget() --Wrapper.Unit#UNIT
|
local target=self:GetTarget() --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
local distance=nil
|
local distance=nil
|
||||||
if target then
|
if target then
|
||||||
|
|
||||||
-- Current position of target.
|
-- Current position of target.
|
||||||
local tv3=target:GetVec3()
|
local tv3=target:GetVec3()
|
||||||
|
|
||||||
-- Current position of weapon.
|
-- Current position of weapon.
|
||||||
local wv3=self:GetVec3()
|
local wv3=self:GetVec3()
|
||||||
|
|
||||||
if tv3 and wv3 then
|
if tv3 and wv3 then
|
||||||
distance=UTILS.VecDist3D(tv3, wv3)
|
distance=UTILS.VecDist3D(tv3, wv3)
|
||||||
|
|
||||||
if ConversionFunction then
|
if ConversionFunction then
|
||||||
distance=ConversionFunction(distance)
|
distance=ConversionFunction(distance)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return distance
|
return distance
|
||||||
@ -445,10 +445,10 @@ function WEAPON:GetTargetName()
|
|||||||
|
|
||||||
-- Get the target of the weapon.
|
-- Get the target of the weapon.
|
||||||
local target=self:GetTarget() --Wrapper.Unit#UNIT
|
local target=self:GetTarget() --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
local name="None"
|
local name="None"
|
||||||
if target then
|
if target then
|
||||||
name=target:GetName()
|
name=target:GetName()
|
||||||
end
|
end
|
||||||
|
|
||||||
return name
|
return name
|
||||||
@ -476,13 +476,13 @@ function WEAPON:GetSpeed(ConversionFunction)
|
|||||||
if self.weapon then
|
if self.weapon then
|
||||||
|
|
||||||
local v=self:GetVelocityVec3()
|
local v=self:GetVelocityVec3()
|
||||||
|
|
||||||
speed=UTILS.VecNorm(v)
|
speed=UTILS.VecNorm(v)
|
||||||
|
|
||||||
if ConversionFunction then
|
if ConversionFunction then
|
||||||
speed=ConversionFunction(speed)
|
speed=ConversionFunction(speed)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return speed
|
return speed
|
||||||
@ -508,11 +508,11 @@ end
|
|||||||
function WEAPON:GetVec2()
|
function WEAPON:GetVec2()
|
||||||
|
|
||||||
local vec3=self:GetVec3()
|
local vec3=self:GetVec3()
|
||||||
|
|
||||||
if vec3 then
|
if vec3 then
|
||||||
|
|
||||||
local vec2={x=vec3.x, y=vec3.z}
|
local vec2={x=vec3.x, y=vec3.z}
|
||||||
|
|
||||||
return vec2
|
return vec2
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -521,28 +521,28 @@ end
|
|||||||
|
|
||||||
--- Get type name.
|
--- Get type name.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @return #string The type name.
|
-- @return #string The type name.
|
||||||
function WEAPON:GetTypeName()
|
function WEAPON:GetTypeName()
|
||||||
return self.typeName
|
return self.typeName
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get coalition.
|
--- Get coalition.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @return #number Coalition ID.
|
-- @return #number Coalition ID.
|
||||||
function WEAPON:GetCoalition()
|
function WEAPON:GetCoalition()
|
||||||
return self.coalition
|
return self.coalition
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get country.
|
--- Get country.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @return #number Country ID.
|
-- @return #number Country ID.
|
||||||
function WEAPON:GetCountry()
|
function WEAPON:GetCountry()
|
||||||
return self.country
|
return self.country
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get DCS object.
|
--- Get DCS object.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @return DCS#Weapon The weapon object.
|
-- @return DCS#Weapon The weapon object.
|
||||||
function WEAPON:GetDCSObject()
|
function WEAPON:GetDCSObject()
|
||||||
-- This polymorphic function is used in Wrapper.Identifiable#IDENTIFIABLE
|
-- This polymorphic function is used in Wrapper.Identifiable#IDENTIFIABLE
|
||||||
return self.weapon
|
return self.weapon
|
||||||
@ -675,23 +675,23 @@ end
|
|||||||
function WEAPON:Destroy(Delay)
|
function WEAPON:Destroy(Delay)
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
self:ScheduleOnce(Delay, WEAPON.Destroy, self, 0)
|
self:ScheduleOnce(Delay, WEAPON.Destroy, self, 0)
|
||||||
else
|
else
|
||||||
if self.weapon then
|
if self.weapon then
|
||||||
self:T(self.lid.."Destroying Weapon NOW!")
|
self:T(self.lid.."Destroying Weapon NOW!")
|
||||||
self:StopTrack()
|
self:StopTrack()
|
||||||
self.weapon:destroy()
|
self.weapon:destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Start tracking the weapon until it impacts or is destroyed otherwise.
|
--- Start tracking the weapon until it impacts or is destroyed otherwise.
|
||||||
-- The position of the weapon is monitored in small time steps. Once the position cannot be determined anymore, the monitoring is stopped and the last known position is
|
-- The position of the weapon is monitored in small time steps. Once the position cannot be determined anymore, the monitoring is stopped and the last known position is
|
||||||
-- the (approximate) impact point. Of course, the smaller the time step, the better the position can be determined. However, this can hit the performance as many
|
-- the (approximate) impact point. Of course, the smaller the time step, the better the position can be determined. However, this can hit the performance as many
|
||||||
-- calculations per second need to be carried out.
|
-- calculations per second need to be carried out.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @param #number Delay Delay in seconds before the tracking starts. Default 0.001 sec.
|
-- @param #number Delay Delay in seconds before the tracking starts. Default 0.001 sec.
|
||||||
-- @return #WEAPON self
|
-- @return #WEAPON self
|
||||||
function WEAPON:StartTrack(Delay)
|
function WEAPON:StartTrack(Delay)
|
||||||
@ -700,8 +700,8 @@ function WEAPON:StartTrack(Delay)
|
|||||||
Delay=math.max(Delay or 0.001, 0.001)
|
Delay=math.max(Delay or 0.001, 0.001)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Start tracking weapon in %.4f sec", Delay))
|
self:T(self.lid..string.format("Start tracking weapon in %.4f sec", Delay))
|
||||||
|
|
||||||
-- Weapon is not yet "alife" just yet. Start timer in 0.001 seconds.
|
-- Weapon is not yet "alife" just yet. Start timer in 0.001 seconds.
|
||||||
self.trackScheduleID=timer.scheduleFunction(WEAPON._TrackWeapon, self, timer.getTime() + Delay)
|
self.trackScheduleID=timer.scheduleFunction(WEAPON._TrackWeapon, self, timer.getTime() + Delay)
|
||||||
|
|
||||||
@ -710,7 +710,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
--- Stop tracking the weapon by removing the scheduler function.
|
--- Stop tracking the weapon by removing the scheduler function.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
-- @param #number Delay (Optional) Delay in seconds before the tracking is stopped.
|
-- @param #number Delay (Optional) Delay in seconds before the tracking is stopped.
|
||||||
-- @return #WEAPON self
|
-- @return #WEAPON self
|
||||||
function WEAPON:StopTrack(Delay)
|
function WEAPON:StopTrack(Delay)
|
||||||
@ -719,13 +719,13 @@ function WEAPON:StopTrack(Delay)
|
|||||||
-- Delayed call.
|
-- Delayed call.
|
||||||
self:ScheduleOnce(Delay, WEAPON.StopTrack, self, 0)
|
self:ScheduleOnce(Delay, WEAPON.StopTrack, self, 0)
|
||||||
else
|
else
|
||||||
|
|
||||||
if self.trackScheduleID then
|
if self.trackScheduleID then
|
||||||
|
|
||||||
timer.removeFunction(self.trackScheduleID)
|
timer.removeFunction(self.trackScheduleID)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -762,10 +762,10 @@ function WEAPON:_TrackWeapon(time)
|
|||||||
|
|
||||||
-- Update last known position.
|
-- Update last known position.
|
||||||
self.pos3 = pos3
|
self.pos3 = pos3
|
||||||
|
|
||||||
-- Update last known vec3.
|
-- Update last known vec3.
|
||||||
self.vec3 = UTILS.DeepCopy(self.pos3.p)
|
self.vec3 = UTILS.DeepCopy(self.pos3.p)
|
||||||
|
|
||||||
-- Update coordinate.
|
-- Update coordinate.
|
||||||
self.coordinate:UpdateFromVec3(self.vec3)
|
self.coordinate:UpdateFromVec3(self.vec3)
|
||||||
|
|
||||||
@ -774,70 +774,70 @@ function WEAPON:_TrackWeapon(time)
|
|||||||
|
|
||||||
-- Keep on tracking by returning the next time below.
|
-- Keep on tracking by returning the next time below.
|
||||||
self.tracking=true
|
self.tracking=true
|
||||||
|
|
||||||
-- Callback function.
|
-- Callback function.
|
||||||
if self.trackFunc then
|
if self.trackFunc then
|
||||||
self.trackFunc(self, unpack(self.trackArg))
|
self.trackFunc(self, unpack(self.trackArg))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Verbose output.
|
-- Verbose output.
|
||||||
if self.verbose>=5 then
|
if self.verbose>=5 then
|
||||||
|
|
||||||
-- Get vec2 of current position.
|
-- Get vec2 of current position.
|
||||||
local vec2={x=self.vec3.x, y=self.vec3.z}
|
local vec2={x=self.vec3.x, y=self.vec3.z}
|
||||||
|
|
||||||
-- Land hight.
|
-- Land hight.
|
||||||
local height=land.getHeight(vec2)
|
local height=land.getHeight(vec2)
|
||||||
|
|
||||||
-- Current height above ground level.
|
-- Current height above ground level.
|
||||||
local agl=self.vec3.y-height
|
local agl=self.vec3.y-height
|
||||||
|
|
||||||
-- Estimated IP (if any)
|
-- Estimated IP (if any)
|
||||||
local ip=self:_GetIP(self.distIP)
|
local ip=self:_GetIP(self.distIP)
|
||||||
|
|
||||||
-- Distance between positon and estimated impact.
|
-- Distance between positon and estimated impact.
|
||||||
local d=0
|
local d=0
|
||||||
if ip then
|
if ip then
|
||||||
d=UTILS.VecDist3D(self.vec3, ip)
|
d=UTILS.VecDist3D(self.vec3, ip)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Output.
|
-- Output.
|
||||||
self:I(self.lid..string.format("T=%.3f: Height=%.3f m AGL=%.3f m, dIP=%.3f", time, height, agl, d))
|
self:I(self.lid..string.format("T=%.3f: Height=%.3f m AGL=%.3f m, dIP=%.3f", time, height, agl, d))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
---------------------------
|
---------------------------
|
||||||
-- Weapon does NOT exist --
|
-- Weapon does NOT exist --
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
-- Get intercept point from position (p) and direction (x) in 50 meters.
|
-- Get intercept point from position (p) and direction (x) in 50 meters.
|
||||||
local ip = self:_GetIP(self.distIP)
|
local ip = self:_GetIP(self.distIP)
|
||||||
|
|
||||||
if self.verbose>=10 and ip then
|
if self.verbose>=10 and ip then
|
||||||
|
|
||||||
-- Output.
|
-- Output.
|
||||||
self:I(self.lid.."Got intercept point!")
|
self:I(self.lid.."Got intercept point!")
|
||||||
|
|
||||||
-- Coordinate of the impact point.
|
-- Coordinate of the impact point.
|
||||||
local coord=COORDINATE:NewFromVec3(ip)
|
local coord=COORDINATE:NewFromVec3(ip)
|
||||||
|
|
||||||
-- Mark coordinate.
|
-- Mark coordinate.
|
||||||
coord:MarkToAll("Intercept point")
|
coord:MarkToAll("Intercept point")
|
||||||
coord:SmokeBlue()
|
coord:SmokeBlue()
|
||||||
|
|
||||||
-- Distance to last known pos.
|
-- Distance to last known pos.
|
||||||
local d=UTILS.VecDist3D(ip, self.vec3)
|
local d=UTILS.VecDist3D(ip, self.vec3)
|
||||||
|
|
||||||
-- Output.
|
-- Output.
|
||||||
self:I(self.lid..string.format("FF d(ip, vec3)=%.3f meters", d))
|
self:I(self.lid..string.format("FF d(ip, vec3)=%.3f meters", d))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Safe impact vec3.
|
-- Safe impact vec3.
|
||||||
self.impactVec3=ip or self.vec3
|
self.impactVec3=ip or self.vec3
|
||||||
|
|
||||||
-- Safe impact coordinate.
|
-- Safe impact coordinate.
|
||||||
self.impactCoord=COORDINATE:NewFromVec3(self.vec3)
|
self.impactCoord=COORDINATE:NewFromVec3(self.vec3)
|
||||||
|
|
||||||
@ -848,22 +848,22 @@ function WEAPON:_TrackWeapon(time)
|
|||||||
if self.impactMark then
|
if self.impactMark then
|
||||||
self.impactCoord:MarkToAll(string.format("Impact point of weapon %s\ntype=%s\nlauncher=%s", self.name, self.typeName, self.launcherName))
|
self.impactCoord:MarkToAll(string.format("Impact point of weapon %s\ntype=%s\nlauncher=%s", self.name, self.typeName, self.launcherName))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Smoke on impact point.
|
-- Smoke on impact point.
|
||||||
if self.impactSmoke then
|
if self.impactSmoke then
|
||||||
self.impactCoord:Smoke(self.impactSmokeColor)
|
self.impactCoord:Smoke(self.impactSmokeColor)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Call callback function.
|
-- Call callback function.
|
||||||
if self.impactFunc then
|
if self.impactFunc then
|
||||||
self.impactFunc(self, unpack(self.impactArg or {}))
|
self.impactFunc(self, unpack(self.impactArg or {}))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Stop tracking by returning nil below.
|
-- Stop tracking by returning nil below.
|
||||||
self.tracking=false
|
self.tracking=false
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Return next time the function is called or nil to stop the scheduler.
|
-- Return next time the function is called or nil to stop the scheduler.
|
||||||
if self.tracking then
|
if self.tracking then
|
||||||
if self.dtTrack and self.dtTrack>=0.00001 then
|
if self.dtTrack and self.dtTrack>=0.00001 then
|
||||||
@ -885,12 +885,12 @@ function WEAPON:_GetIP(Distance)
|
|||||||
Distance=Distance or 50
|
Distance=Distance or 50
|
||||||
|
|
||||||
local ip=nil --DCS#Vec3
|
local ip=nil --DCS#Vec3
|
||||||
|
|
||||||
if Distance>0 and self.pos3 then
|
if Distance>0 and self.pos3 then
|
||||||
|
|
||||||
-- Get intercept point from position (p) and direction (x) in 20 meters.
|
-- Get intercept point from position (p) and direction (x) in 20 meters.
|
||||||
ip = land.getIP(self.pos3.p, self.pos3.x, Distance or 20) --DCS#Vec3
|
ip = land.getIP(self.pos3.p, self.pos3.x, Distance or 20) --DCS#Vec3
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return ip
|
return ip
|
||||||
|
|||||||
263
docs/advanced/concepts.md
Normal file
263
docs/advanced/concepts.md
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
---
|
||||||
|
title: Concepts
|
||||||
|
parent: Advanced
|
||||||
|
nav_order: 01
|
||||||
|
---
|
||||||
|
|
||||||
|
# Concepts
|
||||||
|
{: .no_toc }
|
||||||
|
|
||||||
|
1. Table of contents
|
||||||
|
{:toc}
|
||||||
|
|
||||||
|
If you want to get deeper into Moose, you will encounter a few terms and
|
||||||
|
concepts that we will explain here. You will need them for the later pages.
|
||||||
|
|
||||||
|
# Git and GitHub
|
||||||
|
|
||||||
|
Moose has about 260.000 lines of code and the amount is increasing each week.
|
||||||
|
To maintain such a big code base a vcs (version control system) is needed.
|
||||||
|
Moose uses [GitHub] as developer platform to create, store, and manage the code.
|
||||||
|
[GitHub] uses [Git] as version control system and provides additional
|
||||||
|
functionality like access control, bug tracking, feature requests and much more.
|
||||||
|
|
||||||
|
As a Moose user you don't need to learn how to use [Git]. You can download the
|
||||||
|
files on [GitHub] with a browser. But using [Git] will ease up the steps to keep
|
||||||
|
the Moose version on your hard disk up to date.
|
||||||
|
|
||||||
|
You will need to interact with [GitHub]. At least to download the Moose files.
|
||||||
|
For non-developers the page can be confusing. Take your time and read this
|
||||||
|
documentation. We are not able to explain every single detail on using [GitHub]
|
||||||
|
and [Git]. Especially because it is changing really quick and this documentation
|
||||||
|
will not. So try to use the help system of [GitHub] or find some videos on
|
||||||
|
[YouTube]. If you get stuck ask for help in the [Moose Discord].
|
||||||
|
|
||||||
|
Moose uses more than one repository on [GitHub] which doesn't exactly make it
|
||||||
|
any clearer. A list can be found on the [reposities] page.
|
||||||
|
|
||||||
|
# Branches: master & develop
|
||||||
|
|
||||||
|
As already explained in the [overview] two branches are used:
|
||||||
|
|
||||||
|
- Branch [master]: Stable release branch.
|
||||||
|
- Branch [develop]: Newest development with more OPS classes.
|
||||||
|
|
||||||
|
As a starter it is okay to begin your journey with the `master` branch.
|
||||||
|
If you are interested in some newer classes you need to use the `develop`
|
||||||
|
branch. The later one is also very stable, but it's missing more detailed
|
||||||
|
documentation and example missions for some of the new OPS classes.
|
||||||
|
|
||||||
|
You can switch between these branches with a drop down in the upper left corner
|
||||||
|
of the [GitHub] repository page. The list of branches is long. So it is a best
|
||||||
|
practice to save a bookmark in your browser with the links above.
|
||||||
|
Both branches are available on most of the different repositories. But because
|
||||||
|
of a limitation of [GitHub pages], we had to split the documentation in two
|
||||||
|
different repositories:
|
||||||
|
|
||||||
|
- Documentation of `master` branch: [MOOSE_DOCS]
|
||||||
|
- Documentation of `develop` branch: [MOOSE_DOCS_DEVELOP]
|
||||||
|
|
||||||
|
# Build result vs. source files
|
||||||
|
|
||||||
|
Moose consists of more than 140 individual files with the file extension `.lua`.
|
||||||
|
They are places in a [directory tree], which makes it more organized and its
|
||||||
|
semantic is pre-defined for [IntelliSense] to work.
|
||||||
|
|
||||||
|
On every change which is pushed to [GitHub] a build job will combine all of
|
||||||
|
these files to a single file called `Moose.lua`. In a second step all
|
||||||
|
comments will be removed to decrease the file size and the result will be saved
|
||||||
|
as `Moose_.lua`. These both files are created for users of Moose to include in
|
||||||
|
your missions.
|
||||||
|
|
||||||
|
The individual `.lua` files are used by the Moose developers and power users.
|
||||||
|
It is complicated to use them, but in combination with an IDE and a debugger it
|
||||||
|
is very useful to analyze even complex problems or write new additions to the
|
||||||
|
Moose framework.
|
||||||
|
|
||||||
|
# Static loading
|
||||||
|
|
||||||
|
If you add a script file with a `DO SCRIPT FILE` trigger, like we described in
|
||||||
|
[Create your own Hello world], the script file will be copied into the mission
|
||||||
|
file. This mission file (file extension .MIZ) is only a compressed ZIP archive
|
||||||
|
with another file ending.
|
||||||
|
|
||||||
|
If you change the script file after adding it to the mission, the changes are
|
||||||
|
not available on mission start. You have to re-add the script after each change.
|
||||||
|
This can be very annoying and often leads to forgetting to add the change again.
|
||||||
|
Then you wonder why the mission does not deliver the desired result.
|
||||||
|
|
||||||
|
But when the mission is finished you can upload it to your dedicated DCS server
|
||||||
|
or give it to a friend and it should run without problems. This way of embedding
|
||||||
|
the scripts do we call `static loading` and the resulting mission is very
|
||||||
|
portable.
|
||||||
|
|
||||||
|
# Dynamic loading of mission scripts
|
||||||
|
|
||||||
|
The other way of loading scripts is by using `DO SCRIPT`. This time the mission
|
||||||
|
editor don't show a file browse button. Instead you see a (very small) text
|
||||||
|
field to enter the code directly into it. It is only useful for very small
|
||||||
|
script snippets. But we can use it to load a file from your hard drive like
|
||||||
|
this:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
dofile('C:/MyScripts/hello-world.lua')
|
||||||
|
dofile('C:\\MyScripts\\hello-world.lua')
|
||||||
|
dofile([[C:\MyScripts\hello-world.lua]])
|
||||||
|
```
|
||||||
|
|
||||||
|
So all lines above do the same. In [Lua] you need to specify the path with
|
||||||
|
slashes, escape backslashes or use double square brackets around the string.
|
||||||
|
Double square brackets are usefull, because you can copy paste the path
|
||||||
|
without any modification.
|
||||||
|
|
||||||
|
If you upload a mission with this code, you need to create the folder
|
||||||
|
`C:\MyScripts\` on the server file system and upload the newest version of
|
||||||
|
`hello-world.lua`, too. The same applies, if you give the mission to a friend.
|
||||||
|
This makes the mission less portable, but on the other hand the mission uses the
|
||||||
|
file on the hard disk, without the need to add it to the mission again.
|
||||||
|
All you need to do is save the file and restart the mission.
|
||||||
|
|
||||||
|
The following can be used to increase portability:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
dofile(lfs.writedir() .. '/Missions/hello-world.lua')
|
||||||
|
```
|
||||||
|
|
||||||
|
The function `lfs.writedir()` will return your [Saved Games folder].
|
||||||
|
So you place the scripts in the subfolder Missions. This way the folder
|
||||||
|
structure is already available on all target systems. But you need to ensure
|
||||||
|
mission and script are both in sync to avoid problems. If you changed both and
|
||||||
|
upload only one of them to your server, you may get trouble.
|
||||||
|
|
||||||
|
There is another method you may find useful to dynamically load scripts:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
assert(loadfile('C:/MyScripts/hello-world.lua'))()
|
||||||
|
assert(loadfile('C:\\MyScripts\\hello-world.lua'))()
|
||||||
|
assert(loadfile([[C:\MyScripts\hello-world.lua]]))()
|
||||||
|
```
|
||||||
|
|
||||||
|
It is a little bit harder to read and write because of all these different
|
||||||
|
brackets. Especially the one on line 3. But it is a little safer than `dofile`.
|
||||||
|
Because of readability I prefer to use `dofile`.
|
||||||
|
|
||||||
|
# Dynamic loading of Moose
|
||||||
|
|
||||||
|
Of course you can use the same method to load Moose. This way you can place one
|
||||||
|
Moose file in your [Saved Games folder], which is used by multiple missions.
|
||||||
|
If you want to update Moose you just need to replace the file and all missions
|
||||||
|
will use the new version. But I prefer to add Moose by a `DO SCRIPT FILE`
|
||||||
|
trigger so I can add and test the new version for each mission step by step.
|
||||||
|
|
||||||
|
But we added two different ways to load the Moose source files automatically.
|
||||||
|
This is useful for Moose developers and it is a requirement to use a debugger.
|
||||||
|
This will be explained later in the [Debugger Guide].
|
||||||
|
|
||||||
|
# Automatic dynamic loading
|
||||||
|
|
||||||
|
With the code below you can have the advantages of both approaches.
|
||||||
|
- Copy the code into your mission script at the beginning.
|
||||||
|
- Save the mission script into the folder Missions in your [Saved Games folder].
|
||||||
|
- Change script filename in line 2 to match to your script.
|
||||||
|
- [De-Sanitize] your `MissionScripting.lua`.
|
||||||
|
|
||||||
|
Now the mission will use the script on your hard drive instead of the script
|
||||||
|
embedded in th MIZ file, as long as it is available. So you can chnge the
|
||||||
|
script, save it and restart the mission, without the need to readd it after each
|
||||||
|
change.
|
||||||
|
|
||||||
|
If you reach a stable state in your script development and want to upload the
|
||||||
|
mission to your server or give it to a friend, then just add the script again
|
||||||
|
like in the static method and save the mission.
|
||||||
|
|
||||||
|
{: .important }
|
||||||
|
> Do not forget to readd the script, prior uploading or sharing the mission,
|
||||||
|
> or it will run with an outdated version of your script and may fail if the
|
||||||
|
> objects in the mission don't match to this old version.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Use script file from hard disk instead of the one included in the .miz file
|
||||||
|
if lfs and io then
|
||||||
|
MissionScript = lfs.writedir() .. '/Missions/hello-world-autodyn.lua'
|
||||||
|
-- Check if the running skript is from temp directory to avoid an endless loop
|
||||||
|
if string.find( debug.getinfo(1).source, lfs.tempdir() ) then
|
||||||
|
local f=io.open(MissionScript,"r")
|
||||||
|
if f~=nil then
|
||||||
|
io.close(f)
|
||||||
|
|
||||||
|
env.info( '*** LOAD MISSION SCRIPT FROM HARD DISK *** ' )
|
||||||
|
dofile(MissionScript)
|
||||||
|
do return end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
env.error( '*** LOAD MISSION SCRIPT FROM HARD DISK FAILED (Desanitize lfs and io)*** ' )
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Simple example mission to show the very basics of MOOSE
|
||||||
|
--
|
||||||
|
MESSAGE:New( "Hello World! This messages is printed by MOOSE!", 35, "INFO" ):ToAll():ToLog()
|
||||||
|
```
|
||||||
|
|
||||||
|
# IDE vs. Notepad++
|
||||||
|
|
||||||
|
As a beginner you should start with a good text editor, which supports syntax
|
||||||
|
highlighting of [Lua] code. This must not be [Notepad++]. It can be any other
|
||||||
|
powerful editor of your choice. Do yourself a favor and don't use the Windows
|
||||||
|
editor.
|
||||||
|
|
||||||
|
If you are a developer of [Lua] or another programming language, then your are
|
||||||
|
most likely familiar with an IDE (Integrated Develop Environment).
|
||||||
|
|
||||||
|
Otherwise you should know, that an IDE may help you with code completion,
|
||||||
|
Refactoring, Autocorrection, Formatting Source Code, showing documentation
|
||||||
|
as popup on mouse hover over keywords and Debugging.
|
||||||
|
|
||||||
|
There are different IDEs available. And not all IDEs support all features.
|
||||||
|
The three most important for Moose are:
|
||||||
|
|
||||||
|
- [Eclipse LDT]
|
||||||
|
- [Visual Studio Code]
|
||||||
|
- [PyCharm] (or [IntelliJ IDEA])
|
||||||
|
|
||||||
|
Eclipse has the best support for hover documentation and [IntelliSense] with
|
||||||
|
Moose. The Inventor of Moose (FlightControl) did an amazing job by adding an
|
||||||
|
integration to Eclipse LDT (a special version for Lua).
|
||||||
|
Unfortunately Eclipse LDT is not maintained any longer (last release 2018).
|
||||||
|
And the debugger doesn't work anymore, since an update of DCS.
|
||||||
|
|
||||||
|
In Visual Studio Code the support of Lua can be added by an addon.
|
||||||
|
The debugger works with Moose and DCS, but showing the LuaDoc and [IntelliSense]
|
||||||
|
is very limited.
|
||||||
|
|
||||||
|
PyCharm supports Lua also with an addon. The debugger works with Moose and DCS,
|
||||||
|
but showing the LuaDoc and [IntelliSense] is very limited.
|
||||||
|
|
||||||
|
It is up to you to choose the IDE according to your taste. Guides on how to
|
||||||
|
setup Moose with different IDEs and Debuggers are provided later in this
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
[Git]: https://en.wikipedia.org/wiki/Git
|
||||||
|
[GitHub]: https://github.com/
|
||||||
|
[YouTube]: https://www.youtube.com/
|
||||||
|
[Moose Discord]: https://discord.gg/gj68fm969S
|
||||||
|
[overview]: ../index.md
|
||||||
|
[reposities]: ../repositories.md
|
||||||
|
[master]: https://github.com/FlightControl-Master/MOOSE/tree/master
|
||||||
|
[develop]: https://github.com/FlightControl-Master/MOOSE/tree/develop
|
||||||
|
[GitHub pages]: https://pages.github.com/
|
||||||
|
[MOOSE_DOCS]: https://flightcontrol-master.github.io/MOOSE_DOCS/
|
||||||
|
[MOOSE_DOCS_DEVELOP]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/
|
||||||
|
[directory tree]: https://github.com/FlightControl-Master/MOOSE/tree/master/Moose%20Development/Moose
|
||||||
|
[Saved Games folder]: ../beginner/tipps-and-tricks.md#find-the-saved-games-folder
|
||||||
|
[Lua]: https://www.lua.org/
|
||||||
|
[Create your own Hello world]: ../beginner/hello-world-build.md
|
||||||
|
[Debugger Guide]: debugger.md
|
||||||
|
[IntelliSense]: https://en.wikipedia.org/wiki/IntelliSense
|
||||||
|
[De-Sanitize]: desanitize-dcs.md
|
||||||
|
[Notepad++]: https://notepad-plus-plus.org/downloads/
|
||||||
|
[Eclipse LDT]: https://projects.eclipse.org/projects/tools.ldt
|
||||||
|
[Visual Studio Code]: https://code.visualstudio.com/
|
||||||
|
[PyCharm]: https://www.jetbrains.com/pycharm/
|
||||||
|
[IntelliJ IDEA]: https://www.jetbrains.com/idea/
|
||||||
8
docs/advanced/debugger.md
Normal file
8
docs/advanced/debugger.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
title: Debugger
|
||||||
|
parent: Advanced
|
||||||
|
nav_order: 100
|
||||||
|
---
|
||||||
|
|
||||||
|
{: .warning }
|
||||||
|
> THIS DOCUMENT IS STILL WORK IN PROGRESS!
|
||||||
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: De-Sanitize DCS
|
title: De-Sanitize DCS
|
||||||
parent: Advanced
|
parent: Advanced
|
||||||
nav_order: 2
|
nav_order: 98
|
||||||
---
|
---
|
||||||
# De-Sanitize the DCS scripting environment
|
# De-Sanitize the DCS scripting environment
|
||||||
{: .no_toc }
|
{: .no_toc }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
parent: Advanced
|
parent: Advanced
|
||||||
nav_order: 1
|
nav_order: 97
|
||||||
---
|
---
|
||||||
# Eclipse Installation
|
# Eclipse Installation
|
||||||
{: .no_toc }
|
{: .no_toc }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
parent: Advanced
|
parent: Advanced
|
||||||
nav_order: 2
|
nav_order: 99
|
||||||
---
|
---
|
||||||
# Text to Speech
|
# Text to Speech
|
||||||
{: .no_toc }
|
{: .no_toc }
|
||||||
|
|||||||
@ -35,16 +35,24 @@ Please remember when posting a question:
|
|||||||
- Before posting anything follow the [troubleshooting steps].
|
- Before posting anything follow the [troubleshooting steps].
|
||||||
- **Read your logs**.
|
- **Read your logs**.
|
||||||
|
|
||||||
|
### Formulate a good description
|
||||||
|
|
||||||
A post should contain the following:
|
A post should contain the following:
|
||||||
|
|
||||||
1. A describtion what you expected to happen and what actually happened.
|
- A description what you expected to happen and what actually happened.
|
||||||
- Do not use vague words this stuff is hard to help with! Be specific.
|
- Do not use vague words this stuff is hard to help with! Be specific.
|
||||||
|
|
||||||
2. Describe what happens instead.
|
- Describe what happens instead.
|
||||||
- The less detail you offer, the less chance you can be helped.
|
- The less detail you offer, the less chance you can be helped.
|
||||||
- Don’t say it doesn’t work. Or is it broken. Say what it actually does.
|
- Don't say it doesn't work. Or is it broken. Say what it actually does.
|
||||||
|
|
||||||
3. Post your code in Discord as formatted code:
|
### Format your code
|
||||||
|
|
||||||
|
The easier your code is to read, the more likely you are to get a helpful answer. If your code is hard to read, some
|
||||||
|
people who could help you may not even bother to read your code. Syntax Highlighting makes the code much clearer and
|
||||||
|
easier to understand. Therefore:
|
||||||
|
|
||||||
|
- Post your code in Discord as formatted code:
|
||||||
|
|
||||||
- Wrap a single line of code in backticks \` like this:
|
- Wrap a single line of code in backticks \` like this:
|
||||||
|
|
||||||
@ -54,14 +62,31 @@ A post should contain the following:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Post your log lines with the error or warning messages. Format them like this:
|
### Do not post a screenshot of your code
|
||||||
|
|
||||||

|
Your code is easy to read on a screenshot if you are using a good text editor or IDE, but if someone discovers an error
|
||||||
|
in your code and wants to post a corrected version, they will have to type out the entire code. This could lead to them
|
||||||
|
not helping you because it's too much work for them.
|
||||||
|
|
||||||
|
### Post your log
|
||||||
|
|
||||||
|
If the error message in the `dcs.log` does not tell you anything, then post it in the Discord.
|
||||||
|
|
||||||
|
- Post the important log lines with the error or warning messages. Format them like this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Send your mission when requested
|
||||||
|
|
||||||
|
Please don't just send your mission file. You have to manually extract the script from the file.
|
||||||
|
It is better to send your script code and log lines beforehand.
|
||||||
|
If this does not help, you may be asked to send your mission.
|
||||||
|
|
||||||
- Some complex problems need the mission (.miz file) also.
|
- Some complex problems need the mission (.miz file) also.
|
||||||
|
|
||||||
- But post your mission only when requested.
|
- But post your mission only when requested.
|
||||||
- Try to simplify your mission if it is complex!
|
- Try to simplify your mission if it is complex!
|
||||||
|
- Try to avoid or delete MODs, because could prevent people from helping you.
|
||||||
|
|
||||||
There are people in the Discord and in the forum, who spend their free time to
|
There are people in the Discord and in the forum, who spend their free time to
|
||||||
help you. <br />
|
help you. <br />
|
||||||
|
|||||||
@ -11,10 +11,14 @@ nav_order: 05
|
|||||||
|
|
||||||
## Something went wrong
|
## Something went wrong
|
||||||
|
|
||||||
If the mission shows not the expected behaviour do the following steps:
|
If the mission shows not the expected behavior do the following steps:
|
||||||
|
|
||||||
1. Double check if you added the changed mission script to the mission again!
|
1. Double check if you added the changed mission script to the mission again!
|
||||||
1. Check if the triggers are configured as requested in the last sections.
|
1. Check if the triggers are configured as requested in the last sections:
|
||||||
|
- To load MOOSE: `4 MISSION START`, nothing on `CONDITIONS`, `DO SCRIPT FILE` to load `Moose_.lua`.
|
||||||
|
- To load mission script(s): `1 ONCE`, in `CONDITIONS` add `TIME MORE` = 1, `DO SCRIPT FILE` to load `yourscript.lua`.
|
||||||
|
1. Double check if you have the right version of MOOSE (some classes need the develop branch).
|
||||||
|
1. Try the newest version of MOOSE.
|
||||||
|
|
||||||
## Read the logs
|
## Read the logs
|
||||||
|
|
||||||
@ -22,8 +26,7 @@ The DCS log is a super important and useful log for the entire of DCS World.
|
|||||||
All scripting and other errors are recorded here. It is the one stop shop for
|
All scripting and other errors are recorded here. It is the one stop shop for
|
||||||
things that occurred in your mission. It will tell you if there was a mistake.
|
things that occurred in your mission. It will tell you if there was a mistake.
|
||||||
|
|
||||||
1. Open the file `dcs.log` in the `Logs` subfolder in your DCS
|
1. Open the file `dcs.log` in the `Logs` subfolder in your DCS [Saved Games folder].
|
||||||
[Saved Games folder].
|
|
||||||
|
|
||||||
1. Search for the following line: `*** MOOSE INCLUDE END ***`
|
1. Search for the following line: `*** MOOSE INCLUDE END ***`
|
||||||
- If it is included in the log, Moose was loaded.
|
- If it is included in the log, Moose was loaded.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Loading…
x
Reference in New Issue
Block a user