mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-10 17:59:24 +00:00
Compare commits
177 Commits
2.9.13
...
FF/MasterDev
| Author | SHA1 | Date | |
|---|---|---|---|
| a0c5466f7f | |||
| 2f002703ee | |||
| b0c6ed1d59 | |||
| 950e97b6d7 | |||
| 6d54e5a47f | |||
| 35c8803f8b | |||
| d9c8542993 | |||
| f3c38a4288 | |||
| 626b03c93a | |||
| cf5c55209a | |||
| 19921414cf | |||
| c4de2b6990 | |||
| 7907e4b830 | |||
| 5955c2d61f | |||
| 26fbae8672 | |||
| 5089e7df25 | |||
| 0c0d1cc794 | |||
| 21b968a9c6 | |||
| 704bb8668f | |||
| 763bfb4bb1 | |||
| 046bd37fd5 | |||
| fbf83b3aed | |||
| 22097987dc | |||
| 98d02d7532 | |||
| 7b44e7a3f6 | |||
| aa4cf37aed | |||
| caf2b4e736 | |||
| da516a0167 | |||
| 17d1cf673d | |||
| 1fcd70b0d0 | |||
| 832941494b | |||
| 0e82cb977e | |||
| e9237146a3 | |||
| b72899b500 | |||
| 2f39e38264 | |||
| db54672fbd | |||
| 30d9a7d703 | |||
| 5a088a740e | |||
| be220b6c1d | |||
| 645c4a4dbc | |||
| c2a630dabd | |||
| 07a14bc176 | |||
| 2047e818ef | |||
| 801b4f01b6 | |||
| 6058160160 | |||
| 479dfc28b9 | |||
| 8392788cdb | |||
| 4a1b23c52a | |||
| 55242edbde | |||
| 2c5d9f043e | |||
| 2b2acbe244 | |||
| 7d4e103660 | |||
| 86798ae9ea | |||
| 2830e6d199 | |||
| 8c07573f8f | |||
| f3af0262df | |||
| 0f270a6a35 | |||
| 8432f46e48 | |||
| faccee88e7 | |||
| e8246b3b90 | |||
| eb4e7b9281 | |||
| 1e2190a6cc | |||
| 1644c1dc5b | |||
| 5fc3798c42 | |||
| fae81cdb1b | |||
| dbae37f151 | |||
| f7d58a0b76 | |||
| 2e0d1fd90f | |||
| 69e6497655 | |||
| ef8c7c9084 | |||
| e4eaf72769 | |||
| 5138ced630 | |||
| 534f445f8c | |||
| b2cc3e5329 | |||
| efde321616 | |||
| 3a61581608 | |||
| 3a10f0b946 | |||
| 6dc6972bdb | |||
| 405235a59d | |||
| 9c148625e4 | |||
| a08d82a3d9 | |||
| 48b51f21de | |||
| 3260279cb7 | |||
| 1e60a0a32a | |||
| 146f869aaa | |||
| 0bd35727f4 | |||
| 5183fcc316 | |||
| bf7596521c | |||
| a85b6c960c | |||
| a1aebf0575 | |||
| 0f42218681 | |||
| 5404f9ef19 | |||
| 8a84be19df | |||
| fd4ea81e46 | |||
| 3df79aedb1 | |||
| 4141aa35ba | |||
| 6e45ee558e | |||
| db138be5f3 | |||
| 5ae6495e69 | |||
| 58f1bc5531 | |||
| 935b52c489 | |||
| aace98545a | |||
| f39236c8fd | |||
| 43b4a6834b | |||
| aa3978b04d | |||
| b51e758516 | |||
| 5be1832c09 | |||
| 362652ac6c | |||
| aec69884dc | |||
| 8fb4d4c7c6 | |||
| b5524b9a69 | |||
| ec0ff7afcd | |||
| d0cf68c2e2 | |||
| 3beb98a5e9 | |||
| dd83ebe0e2 | |||
| 6fdf3957bd | |||
| f3d586d455 | |||
| c2f0ce0fa2 | |||
| 354490d149 | |||
| c5b0be5d21 | |||
| 5e8676cf8a | |||
| f4264cd149 | |||
| 65d1c4187e | |||
| cda1432d04 | |||
| 09e5fca1a5 | |||
| e38d73df8b | |||
| 7df90b2d30 | |||
| a917ee8f1e | |||
| 44f3c776eb | |||
| 873879ff79 | |||
| 6c1907f7e0 | |||
| 42ecdd3b14 | |||
| 297164a0ee | |||
| 323f09b06c | |||
| e003b91bbe | |||
| f1636fc5a9 | |||
| db053398d2 | |||
| 417caf1b62 | |||
| cc76851614 | |||
| 27fe314c1e | |||
| 2c12cfe4fd | |||
| 9adf342dd8 | |||
| facac82130 | |||
| 3e095711f4 | |||
| ca1ddb4013 | |||
| 8169235d2f | |||
| 4553785918 | |||
| 78b3efcf00 | |||
| 67cb844550 | |||
| b9cf1e46af | |||
| 4a04d7cce7 | |||
| 35f15435a3 | |||
| 4c97d966a2 | |||
| 674c6eec81 | |||
| c75c3d8777 | |||
| 4fa63986dc | |||
| 029f7a3f5c | |||
| e9194c59f4 | |||
| c8d693c8e7 | |||
| 2341014882 | |||
| eb15fadcfe | |||
| 13fa8f373e | |||
| b318e8ae13 | |||
| 7e963bef41 | |||
| 933000ffc7 | |||
| 9b217e1c97 | |||
| 324f4944b4 | |||
| f735f1eb53 | |||
| 7149226283 | |||
| 4164a5288a | |||
| 1992276b07 | |||
| 21a7023b7b | |||
| f094716b73 | |||
| 4b1888a34d | |||
| b9be3aa7f8 | |||
| fd2dacaefb | |||
| cc60e85901 |
@@ -577,13 +577,19 @@ do -- Zones and Pathlines
|
|||||||
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
||||||
local w=objectData.width
|
local w=objectData.width
|
||||||
local h=objectData.height
|
local h=objectData.height
|
||||||
|
local rotation = UTILS.ToRadian(objectData.angle or 0)
|
||||||
|
|
||||||
-- Create points from center using with and height (width for y and height for x is a bit confusing, but this is how ED implemented it).
|
local sinRot = math.sin(rotation)
|
||||||
local points={}
|
local cosRot = math.cos(rotation)
|
||||||
points[1]={x=vec2.x-h/2, y=vec2.y+w/2} --Upper left
|
local dx = h / 2
|
||||||
points[2]={x=vec2.x+h/2, y=vec2.y+w/2} --Upper right
|
local dy = w / 2
|
||||||
points[3]={x=vec2.x+h/2, y=vec2.y-w/2} --Lower right
|
|
||||||
points[4]={x=vec2.x-h/2, y=vec2.y-w/2} --Lower left
|
local points = {
|
||||||
|
{ x = -dx * cosRot - (-dy * sinRot) + vec2.x, y = -dx * sinRot + (-dy * cosRot) + vec2.y },
|
||||||
|
{ x = dx * cosRot - (-dy * sinRot) + vec2.x, y = dx * sinRot + (-dy * cosRot) + vec2.y },
|
||||||
|
{ x = dx * cosRot - (dy * sinRot) + vec2.x, y = dx * sinRot + (dy * cosRot) + vec2.y },
|
||||||
|
{ x = -dx * cosRot - (dy * sinRot) + vec2.x, y = -dx * sinRot + (dy * cosRot) + vec2.y },
|
||||||
|
}
|
||||||
|
|
||||||
--local coord=COORDINATE:NewFromVec2(vec2):MarkToAll("MapX, MapY")
|
--local coord=COORDINATE:NewFromVec2(vec2):MarkToAll("MapX, MapY")
|
||||||
|
|
||||||
|
|||||||
@@ -1475,7 +1475,7 @@ function EVENT:onEvent( Event )
|
|||||||
-- SCENERY
|
-- SCENERY
|
||||||
---
|
---
|
||||||
Event.TgtDCSUnit = Event.target
|
Event.TgtDCSUnit = Event.target
|
||||||
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
|
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit:getName() or nil
|
||||||
if Event.TgtDCSUnitName~=nil then
|
if Event.TgtDCSUnitName~=nil then
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||||
@@ -1508,10 +1508,12 @@ function EVENT:onEvent( Event )
|
|||||||
else
|
else
|
||||||
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
||||||
Event.Place=AIRBASE:Find(Event.place)
|
Event.Place=AIRBASE:Find(Event.place)
|
||||||
|
if Event.Place then
|
||||||
Event.PlaceName=Event.Place:GetName()
|
Event.PlaceName=Event.Place:GetName()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Mark points.
|
-- Mark points.
|
||||||
if Event.idx then
|
if Event.idx then
|
||||||
|
|||||||
@@ -777,7 +777,9 @@ do -- COORDINATE
|
|||||||
-- @return DCS#Vec2 Vec2
|
-- @return DCS#Vec2 Vec2
|
||||||
function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius )
|
function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius )
|
||||||
self:F2( { OuterRadius, InnerRadius } )
|
self:F2( { OuterRadius, InnerRadius } )
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
local Theta = 2 * math.pi * math.random()
|
local Theta = 2 * math.pi * math.random()
|
||||||
local Radials = math.random() + math.random()
|
local Radials = math.random() + math.random()
|
||||||
if Radials > 1 then
|
if Radials > 1 then
|
||||||
@@ -1635,6 +1637,7 @@ do -- COORDINATE
|
|||||||
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
||||||
RoutePoint.linkUnit = AirbaseID
|
RoutePoint.linkUnit = AirbaseID
|
||||||
RoutePoint.helipadId = AirbaseID
|
RoutePoint.helipadId = AirbaseID
|
||||||
|
RoutePoint.airdromeId = airbase:IsAirdrome() and AirbaseID or nil
|
||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||||
RoutePoint.airdromeId = AirbaseID
|
RoutePoint.airdromeId = AirbaseID
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -89,11 +89,23 @@ do -- SET_BASE
|
|||||||
Index = {},
|
Index = {},
|
||||||
Database = nil,
|
Database = nil,
|
||||||
CallScheduler = nil,
|
CallScheduler = nil,
|
||||||
|
Filter = {},
|
||||||
|
FilterCoalitionNumbers = {
|
||||||
|
[coalition.side.RED+1] = "red",
|
||||||
|
[coalition.side.BLUE+1] = "blue",
|
||||||
|
[coalition.side.NEUTRAL+1] = "neutral",
|
||||||
|
},
|
||||||
|
FilterMeta = {
|
||||||
|
Coalitions = {
|
||||||
|
["red"] = coalition.side.RED,
|
||||||
|
["blue"] = coalition.side.BLUE,
|
||||||
|
["neutral"] = coalition.side.NEUTRAL,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Filters
|
--- Filters
|
||||||
-- @type SET_BASE.Filters
|
-- @type SET_BASE.Filter
|
||||||
-- @field #table Coalition Coalitions
|
-- @field #table Coalition Coalitions
|
||||||
-- @field #table Prefix Prefixes.
|
-- @field #table Prefix Prefixes.
|
||||||
|
|
||||||
@@ -198,6 +210,32 @@ do -- SET_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Builds a set of objects of same coalitions.
|
||||||
|
-- Possible current coalitions are red, blue and neutral.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" and coalition.side.RED, coalition.side.BLUE,coalition.side.NEUTRAL
|
||||||
|
-- @param #boolean Clear If `true`, clear any previously defined filters.
|
||||||
|
-- @return #SET_BASE self
|
||||||
|
function SET_BASE:FilterCoalitions(Coalitions, Clear)
|
||||||
|
|
||||||
|
if Clear or (not self.Filter.Coalitions) then
|
||||||
|
self.Filter.Coalitions = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if type(Coalitions) ~= "table" then Coalitions = {Coalitions} end
|
||||||
|
for CoalitionID, Coalition in pairs(Coalitions) do
|
||||||
|
local coalition = Coalition
|
||||||
|
if type(Coalition) == "number" then
|
||||||
|
coalition = self.FilterCoalitionNumbers[Coalition+1] or "unknown"
|
||||||
|
--self:I("Filter Coaltion for "..coalition)
|
||||||
|
end
|
||||||
|
self.Filter.Coalitions[coalition] = coalition
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Finds an @{Core.Base#BASE} object based on the object Name.
|
--- Finds an @{Core.Base#BASE} object based on the object Name.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param #string ObjectName
|
-- @param #string ObjectName
|
||||||
@@ -907,7 +945,8 @@ do -- SET_BASE
|
|||||||
function SET_BASE:IsInSet(Object)
|
function SET_BASE:IsInSet(Object)
|
||||||
--self:F3(Object)
|
--self:F3(Object)
|
||||||
local outcome = false
|
local outcome = false
|
||||||
local name = Object:GetName()
|
if Object == nil then return false end
|
||||||
|
local name = (Object ~= nil and Object.GetName) and Object:GetName() or "none"
|
||||||
--self:I("SET_BASE: Objectname = "..name)
|
--self:I("SET_BASE: Objectname = "..name)
|
||||||
self:ForEach(
|
self:ForEach(
|
||||||
function(object)
|
function(object)
|
||||||
@@ -1343,21 +1382,6 @@ do
|
|||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @param #boolean Clear If `true`, clear any previously defined filters.
|
-- @param #boolean Clear If `true`, clear any previously defined filters.
|
||||||
-- @return #SET_GROUP self
|
-- @return #SET_GROUP self
|
||||||
function SET_GROUP:FilterCoalitions( Coalitions, Clear )
|
|
||||||
|
|
||||||
if Clear or (not self.Filter.Coalitions) then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Ensure table.
|
|
||||||
Coalitions = UTILS.EnsureTable(Coalitions, false)
|
|
||||||
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Builds a set of groups out of categories.
|
--- Builds a set of groups out of categories.
|
||||||
-- Possible current categories are plane, helicopter, ground, ship.
|
-- Possible current categories are plane, helicopter, ground, ship.
|
||||||
@@ -2387,19 +2411,7 @@ do -- SET_UNIT
|
|||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_UNIT self
|
-- @return #SET_UNIT self
|
||||||
function SET_UNIT:FilterCoalitions( Coalitions )
|
|
||||||
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Builds a set of units out of categories.
|
--- Builds a set of units out of categories.
|
||||||
-- Possible current categories are plane, helicopter, ground, ship.
|
-- Possible current categories are plane, helicopter, ground, ship.
|
||||||
@@ -3603,18 +3615,6 @@ do -- SET_STATIC
|
|||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_STATIC self
|
-- @return #SET_STATIC self
|
||||||
function SET_STATIC:FilterCoalitions( Coalitions )
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of statics in zones.
|
--- Builds a set of statics in zones.
|
||||||
@@ -4396,18 +4396,6 @@ do -- SET_CLIENT
|
|||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_CLIENT self
|
-- @return #SET_CLIENT self
|
||||||
function SET_CLIENT:FilterCoalitions( Coalitions )
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Builds a set of clients out of categories.
|
--- Builds a set of clients out of categories.
|
||||||
-- Possible current categories are plane, helicopter, ground, ship.
|
-- Possible current categories are plane, helicopter, ground, ship.
|
||||||
@@ -4691,8 +4679,8 @@ do -- SET_CLIENT
|
|||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @return #SET_CLIENT self
|
-- @return #SET_CLIENT self
|
||||||
function SET_CLIENT:HandleCASlots()
|
function SET_CLIENT:HandleCASlots()
|
||||||
self:HandleEvent(EVENTS.PlayerEnterUnit,SET_CLIENT._EventPlayerEnterUnit)
|
self:HandleEvent(EVENTS.PlayerEnterUnit,self._EventPlayerEnterUnit)
|
||||||
self:HandleEvent(EVENTS.PlayerLeaveUnit,SET_CLIENT._EventPlayerLeaveUnit)
|
--self:HandleEvent(EVENTS.PlayerLeaveUnit,self._EventPlayerLeaveUnit) -- Already set in :FilterStart()
|
||||||
self:FilterFunction(function(client) if client and client:IsAlive() and client:IsGround() then return true else return false end end)
|
self:FilterFunction(function(client) if client and client:IsAlive() and client:IsGround() then return true else return false end end)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -5112,18 +5100,6 @@ do -- SET_PLAYER
|
|||||||
-- @param #SET_PLAYER self
|
-- @param #SET_PLAYER self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_PLAYER self
|
-- @return #SET_PLAYER self
|
||||||
function SET_PLAYER:FilterCoalitions( Coalitions )
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Builds a set of players in zones.
|
--- Builds a set of players in zones.
|
||||||
-- @param #SET_PLAYER self
|
-- @param #SET_PLAYER self
|
||||||
@@ -5598,18 +5574,6 @@ do -- SET_AIRBASE
|
|||||||
-- @param #SET_AIRBASE self
|
-- @param #SET_AIRBASE self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_AIRBASE self
|
-- @return #SET_AIRBASE self
|
||||||
function SET_AIRBASE:FilterCoalitions( Coalitions )
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Builds a set of airbases out of categories.
|
--- Builds a set of airbases out of categories.
|
||||||
-- Possible current categories are plane, helicopter, ground, ship.
|
-- Possible current categories are plane, helicopter, ground, ship.
|
||||||
@@ -5896,7 +5860,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Add CARGO to SET_CARGO.
|
--- Add CARGO to SET_CARGO.
|
||||||
-- @param Core.Set#SET_CARGO self
|
-- @param Core.Set#SET_CARGO self
|
||||||
-- @param Cargo.Cargo#CARGO Cargo A single cargo.
|
-- @param Cargo.Cargo#CARGO Cargo A single cargo.
|
||||||
-- @return Core.Set#SET_CARGO self
|
-- @return Core.Set#SET_CARGO self
|
||||||
@@ -5907,7 +5871,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Add CARGOs to SET_CARGO.
|
--- Add CARGOs to SET_CARGO.
|
||||||
-- @param Core.Set#SET_CARGO self
|
-- @param Core.Set#SET_CARGO self
|
||||||
-- @param #string AddCargoNames A single name or an array of CARGO names.
|
-- @param #string AddCargoNames A single name or an array of CARGO names.
|
||||||
-- @return Core.Set#SET_CARGO self
|
-- @return Core.Set#SET_CARGO self
|
||||||
@@ -5922,7 +5886,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Remove CARGOs from SET_CARGO.
|
--- Remove CARGOs from SET_CARGO.
|
||||||
-- @param Core.Set#SET_CARGO self
|
-- @param Core.Set#SET_CARGO self
|
||||||
-- @param Cargo.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
|
-- @param Cargo.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
|
||||||
-- @return Core.Set#SET_CARGO self
|
-- @return Core.Set#SET_CARGO self
|
||||||
@@ -5937,7 +5901,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Finds a Cargo based on the Cargo Name.
|
--- Finds a Cargo based on the Cargo Name.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #string CargoName
|
-- @param #string CargoName
|
||||||
-- @return Cargo.Cargo#CARGO The found Cargo.
|
-- @return Cargo.Cargo#CARGO The found Cargo.
|
||||||
@@ -5947,25 +5911,13 @@ do -- SET_CARGO
|
|||||||
return CargoFound
|
return CargoFound
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Builds a set of cargos of coalitions.
|
--- Builds a set of cargos of coalitions.
|
||||||
-- Possible current coalitions are red, blue and neutral.
|
-- Possible current coalitions are red, blue and neutral.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_CARGO self
|
-- @return #SET_CARGO self
|
||||||
function SET_CARGO:FilterCoalitions( Coalitions ) -- R2.1
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (R2.1) Builds a set of cargos of defined cargo types.
|
--- Builds a set of cargos of defined cargo types.
|
||||||
-- Possible current types are those types known within DCS world.
|
-- Possible current types are those types known within DCS world.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #string Types Can take those type strings known within DCS world.
|
-- @param #string Types Can take those type strings known within DCS world.
|
||||||
@@ -5983,7 +5935,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Builds a set of cargos of defined countries.
|
--- Builds a set of cargos of defined countries.
|
||||||
-- Possible current countries are those known within DCS world.
|
-- Possible current countries are those known within DCS world.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #string Countries Can take those country strings known within DCS world.
|
-- @param #string Countries Can take those country strings known within DCS world.
|
||||||
@@ -6019,7 +5971,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Starts the filtering.
|
--- Starts the filtering.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @return #SET_CARGO self
|
-- @return #SET_CARGO self
|
||||||
function SET_CARGO:FilterStart() -- R2.1
|
function SET_CARGO:FilterStart() -- R2.1
|
||||||
@@ -6044,7 +5996,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Handles the Database to check on an event (birth) that the Object was added in the Database.
|
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||||
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
@@ -6056,7 +6008,7 @@ do -- SET_CARGO
|
|||||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Handles the Database to check on any event that Object exists in the Database.
|
--- Handles the Database to check on any event that Object exists in the Database.
|
||||||
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
|
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
@@ -6068,7 +6020,7 @@ do -- SET_CARGO
|
|||||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Iterate the SET_CARGO and call an iterator function for each CARGO, providing the CARGO and optional parameters.
|
--- Iterate the SET_CARGO and call an iterator function for each CARGO, providing the CARGO and optional parameters.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter.
|
-- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter.
|
||||||
-- @return #SET_CARGO self
|
-- @return #SET_CARGO self
|
||||||
@@ -6080,7 +6032,7 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#COORDINATE}.
|
--- Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#COORDINATE}.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Cargo.Cargo#CARGO}.
|
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Cargo.Cargo#CARGO}.
|
||||||
-- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
|
-- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
|
||||||
@@ -6155,7 +6107,7 @@ do -- SET_CARGO
|
|||||||
return FirstCargo
|
return FirstCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1)
|
---
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param AI.AI_Cargo#AI_CARGO MCargo
|
-- @param AI.AI_Cargo#AI_CARGO MCargo
|
||||||
-- @return #SET_CARGO self
|
-- @return #SET_CARGO self
|
||||||
@@ -6214,7 +6166,7 @@ do -- SET_CARGO
|
|||||||
return MCargoInclude
|
return MCargoInclude
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Handles the OnEventNewCargo event for the Set.
|
--- Handles the OnEventNewCargo event for the Set.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SET_CARGO:OnEventNewCargo(EventData) -- R2.1
|
function SET_CARGO:OnEventNewCargo(EventData) -- R2.1
|
||||||
@@ -6228,7 +6180,7 @@ do -- SET_CARGO
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Handles the OnDead or OnCrash event for alive units set.
|
--- Handles the OnDead or OnCrash event for alive units set.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SET_CARGO:OnEventDeleteCargo(EventData) -- R2.1
|
function SET_CARGO:OnEventDeleteCargo(EventData) -- R2.1
|
||||||
@@ -6691,6 +6643,8 @@ do -- SET_ZONE
|
|||||||
--
|
--
|
||||||
-- -- Stop watching after 1 hour
|
-- -- Stop watching after 1 hour
|
||||||
-- zoneset:__TriggerStop(3600)
|
-- zoneset:__TriggerStop(3600)
|
||||||
|
-- -- Call :SetPartlyInside() on any zone (or SET_ZONE) if you want GROUPs to count as inside when any of their units enters even if they are far apart.
|
||||||
|
-- -- Make sure to call :SetPartlyInside() before :Trigger()!.
|
||||||
function SET_ZONE:Trigger(Objects)
|
function SET_ZONE:Trigger(Objects)
|
||||||
--self:I("Added Set_Zone Trigger")
|
--self:I("Added Set_Zone Trigger")
|
||||||
self:AddTransition("*","TriggerStart","TriggerRunning")
|
self:AddTransition("*","TriggerStart","TriggerRunning")
|
||||||
@@ -6741,6 +6695,20 @@ do -- SET_ZONE
|
|||||||
-- @param Core.Zone#ZONE_BASE Zone The zone left.
|
-- @param Core.Zone#ZONE_BASE Zone The zone left.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Toggle “partly-inside” handling for every zone in the set when those zones are used with :Trigger().
|
||||||
|
-- * Call with no argument or **true** → enable for all.
|
||||||
|
-- * Call with **false** → disable again (handy if it was enabled before).
|
||||||
|
-- @param #SET_ZONE self
|
||||||
|
-- @return #SET_ZONE self
|
||||||
|
function SET_ZONE:SetPartlyInside(state)
|
||||||
|
for _,Zone in pairs(self.Set) do
|
||||||
|
if Zone.SetPartlyInside then
|
||||||
|
Zone:SetPartlyInside(state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Check the assigned objects for being in/out of the zone
|
--- (Internal) Check the assigned objects for being in/out of the zone
|
||||||
-- @param #SET_ZONE self
|
-- @param #SET_ZONE self
|
||||||
-- @param #boolean fromstart If true, do the init of the objects
|
-- @param #boolean fromstart If true, do the init of the objects
|
||||||
@@ -6776,8 +6744,13 @@ do -- SET_ZONE
|
|||||||
-- has not been tagged previously - wasn't in set!
|
-- has not been tagged previously - wasn't in set!
|
||||||
obj.TriggerInZone[_zone.ZoneName] = false
|
obj.TriggerInZone[_zone.ZoneName] = false
|
||||||
end
|
end
|
||||||
-- is obj in zone?
|
-- is obj in this zone?
|
||||||
local inzone = _zone:IsCoordinateInZone(obj:GetCoordinate())
|
local inzone
|
||||||
|
if _zone.PartlyInside and obj.ClassName == "GROUP" then
|
||||||
|
inzone = obj:IsAnyInZone(_zone) -- TRUE as soon as any unit is inside
|
||||||
|
else
|
||||||
|
inzone = _zone:IsCoordinateInZone(obj:GetCoordinate()) -- original centroid test
|
||||||
|
end
|
||||||
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
||||||
if inzone and not obj.TriggerInZone[_zone.ZoneName] then
|
if inzone and not obj.TriggerInZone[_zone.ZoneName] then
|
||||||
-- wasn't in zone before
|
-- wasn't in zone before
|
||||||
@@ -7299,23 +7272,6 @@ do -- SET_OPSZONE
|
|||||||
-- @param #SET_OPSZONE self
|
-- @param #SET_OPSZONE self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
||||||
-- @return #SET_OPSZONE self
|
-- @return #SET_OPSZONE self
|
||||||
function SET_OPSZONE:FilterCoalitions(Coalitions)
|
|
||||||
|
|
||||||
-- Create an empty set.
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions={}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Ensure we got a table.
|
|
||||||
Coalitions=UTILS.EnsureTable(Coalitions, false)
|
|
||||||
|
|
||||||
-- Set filter.
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Filters for the defined collection.
|
--- Filters for the defined collection.
|
||||||
-- @param #SET_OPSZONE self
|
-- @param #SET_OPSZONE self
|
||||||
@@ -7844,6 +7800,28 @@ do -- SET_OPSGROUP
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Iterate the SET_OPSGROUP and count how many GROUPs and UNITs are alive.
|
||||||
|
-- @param #SET_GROUP self
|
||||||
|
-- @return #number The number of GROUPs alive.
|
||||||
|
-- @return #number The number of UNITs alive.
|
||||||
|
function SET_OPSGROUP:CountAlive()
|
||||||
|
local CountG = 0
|
||||||
|
local CountU = 0
|
||||||
|
|
||||||
|
local Set = self:GetSet()
|
||||||
|
|
||||||
|
for GroupID, GroupData in pairs(Set) do -- For each GROUP in SET_GROUP
|
||||||
|
if GroupData and GroupData:IsAlive() then
|
||||||
|
CountG = CountG + 1
|
||||||
|
-- Count Units.
|
||||||
|
CountU = CountU + GroupData:GetGroup():CountAliveUnits()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return CountG, CountU
|
||||||
|
end
|
||||||
|
|
||||||
--- Finds an OPSGROUP based on the group name.
|
--- Finds an OPSGROUP based on the group name.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string GroupName Name of the group.
|
-- @param #string GroupName Name of the group.
|
||||||
@@ -7887,26 +7865,6 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
||||||
-- @param #boolean Clear If `true`, clear any previously defined filters.
|
-- @param #boolean Clear If `true`, clear any previously defined filters.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCoalitions(Coalitions, Clear)
|
|
||||||
|
|
||||||
-- Create an empty set.
|
|
||||||
if Clear or not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions={}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Ensure we got a table.
|
|
||||||
if type(Coalitions)~="table" then
|
|
||||||
Coalitions = {Coalitions}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set filter.
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of groups out of categories.
|
--- Builds a set of groups out of categories.
|
||||||
--
|
--
|
||||||
@@ -8884,18 +8842,6 @@ do -- SET_DYNAMICCARGO
|
|||||||
-- @param #SET_DYNAMICCARGO self
|
-- @param #SET_DYNAMICCARGO self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
|
||||||
-- @return #SET_DYNAMICCARGO self
|
-- @return #SET_DYNAMICCARGO self
|
||||||
function SET_DYNAMICCARGO:FilterCoalitions( Coalitions )
|
|
||||||
if not self.Filter.Coalitions then
|
|
||||||
self.Filter.Coalitions = {}
|
|
||||||
end
|
|
||||||
if type( Coalitions ) ~= "table" then
|
|
||||||
Coalitions = { Coalitions }
|
|
||||||
end
|
|
||||||
for CoalitionID, Coalition in pairs( Coalitions ) do
|
|
||||||
self.Filter.Coalitions[Coalition] = Coalition
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Builds a set of dynamic cargo of defined dynamic cargo type names.
|
--- Builds a set of dynamic cargo of defined dynamic cargo type names.
|
||||||
-- @param #SET_DYNAMICCARGO self
|
-- @param #SET_DYNAMICCARGO self
|
||||||
|
|||||||
@@ -1049,6 +1049,23 @@ function SPAWN:InitSetUnitAbsolutePositions(Positions)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area.
|
||||||
|
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #boolean OnOff Enable/disable the feature.
|
||||||
|
-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units.
|
||||||
|
-- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger.
|
||||||
|
-- @return #SPAWN
|
||||||
|
function SPAWN:InitValidateAndRepositionGroundUnits(OnOff, MaxRadius, Spacing)
|
||||||
|
self.SpawnValidateAndRepositionGroundUnits = OnOff
|
||||||
|
self.SpawnValidateAndRepositionGroundUnitsRadius = MaxRadius
|
||||||
|
self.SpawnValidateAndRepositionGroundUnitsSpacing = Spacing
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- This method is rather complicated to understand. But I'll try to explain.
|
--- This method is rather complicated to understand. But I'll try to explain.
|
||||||
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
|
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
|
||||||
-- but they will all follow the same Template route and have the same prefix name.
|
-- but they will all follow the same Template route and have the same prefix name.
|
||||||
@@ -1830,6 +1847,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
SpawnTemplate.hidden=self.SpawnHiddenOnMap
|
SpawnTemplate.hidden=self.SpawnHiddenOnMap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.SpawnValidateAndRepositionGroundUnits then
|
||||||
|
local units = SpawnTemplate.units
|
||||||
|
local gPos = { x = SpawnTemplate.x, y = SpawnTemplate.y }
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(units, gPos, self.SpawnValidateAndRepositionGroundUnitsRadius, self.SpawnValidateAndRepositionGroundUnitsSpacing)
|
||||||
|
end
|
||||||
|
|
||||||
-- Set country, coalition and category.
|
-- Set country, coalition and category.
|
||||||
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
||||||
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
||||||
|
|||||||
@@ -378,6 +378,20 @@ function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Uses Disposition and other fallback logic to find a better and valid ground spawn position.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to a find clear ground location avoiding trees, water, roads, runways, map scenery, other statics and other units in the area.
|
||||||
|
--- Uses the initial position if it's a valid location.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #boolean OnOff Enable/disable the feature.
|
||||||
|
-- @param #number MaxRadius (Optional) Max radius to search for a valid ground location in meters. Default is 10 times the max radius of the static.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitValidateAndRepositionStatic(OnOff, MaxRadius)
|
||||||
|
self.ValidateAndRepositionStatic = OnOff
|
||||||
|
self.ValidateAndRepositionStaticMaxRadius = MaxRadius
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Allows to place a CallFunction hook when a new static spawns.
|
--- Allows to place a CallFunction hook when a new static spawns.
|
||||||
-- The provided method will be called when a new group is spawned, including its given parameters.
|
-- The provided method will be called when a new group is spawned, including its given parameters.
|
||||||
-- The first parameter of the SpawnFunction is the @{Wrapper.Static#STATIC} that was spawned.
|
-- The first parameter of the SpawnFunction is the @{Wrapper.Static#STATIC} that was spawned.
|
||||||
@@ -544,6 +558,14 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
-- Add static to the game.
|
-- Add static to the game.
|
||||||
local Static=nil --DCS#StaticObject
|
local Static=nil --DCS#StaticObject
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionStatic then
|
||||||
|
local validPos = UTILS.ValidateAndRepositionStatic(CountryID, Template.category, Template.type, Template, Template.shape_name, self.ValidateAndRepositionStaticMaxRadius)
|
||||||
|
if validPos then
|
||||||
|
Template.x = validPos.x
|
||||||
|
Template.y = validPos.y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if self.InitFarp then
|
if self.InitFarp then
|
||||||
|
|
||||||
local TemplateGroup={}
|
local TemplateGroup={}
|
||||||
@@ -611,7 +633,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
|
|
||||||
if self.StaticCopyFrom ~= nil then
|
if self.StaticCopyFrom ~= nil then
|
||||||
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
||||||
if not _DATABASE.Templates.Statics[Template.name] then
|
end
|
||||||
|
|
||||||
local TemplateGroup={}
|
local TemplateGroup={}
|
||||||
TemplateGroup.units={}
|
TemplateGroup.units={}
|
||||||
TemplateGroup.units[1]=Template
|
TemplateGroup.units[1]=Template
|
||||||
@@ -619,8 +642,6 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
TemplateGroup.y=Template.y
|
TemplateGroup.y=Template.y
|
||||||
TemplateGroup.name=Template.name
|
TemplateGroup.name=Template.name
|
||||||
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return mystatic
|
return mystatic
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
-- @field #table Table of any trigger zone properties from the ME. The key is the Name of the property, and the value is the property's Value.
|
-- @field #table Table of any trigger zone properties from the ME. The key is the Name of the property, and the value is the property's Value.
|
||||||
-- @field #number Surface Type of surface. Only determined at the center of the zone!
|
-- @field #number Surface Type of surface. Only determined at the center of the zone!
|
||||||
-- @field #number Checktime Check every Checktime seconds, used for ZONE:Trigger()
|
-- @field #number Checktime Check every Checktime seconds, used for ZONE:Trigger()
|
||||||
|
-- @field #boolean PartlyInside When called, a GROUP is considered inside as soon as any of its units enters the zone even if they are far apart.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -612,6 +613,8 @@ end
|
|||||||
--
|
--
|
||||||
-- -- Stop watching the zone after 1 hour
|
-- -- Stop watching the zone after 1 hour
|
||||||
-- triggerzone:__TriggerStop(3600)
|
-- triggerzone:__TriggerStop(3600)
|
||||||
|
-- -- Call :SetPartlyInside() if you use SET_GROUP to count as inside when any of their units enters even when they are far apart.
|
||||||
|
-- -- Make sure to call :SetPartlyInside() before :Trigger()!
|
||||||
function ZONE_BASE:Trigger(Objects)
|
function ZONE_BASE:Trigger(Objects)
|
||||||
--self:I("Added Zone Trigger")
|
--self:I("Added Zone Trigger")
|
||||||
self:SetStartState("TriggerStopped")
|
self:SetStartState("TriggerStopped")
|
||||||
@@ -680,6 +683,16 @@ function ZONE_BASE:Trigger(Objects)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Toggle “partly-inside” handling for this zone. To be used before :Trigger().
|
||||||
|
-- * Default:* flag is **false** until you call the method.
|
||||||
|
-- * Call with no argument or with **true** → enable.
|
||||||
|
-- * Call with **false** → disable again (handy if it was enabled before).
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return #ZONE_BASE self
|
||||||
|
function ZONE_BASE:SetPartlyInside(state)
|
||||||
|
self.PartlyInside = state or not ( state == false )
|
||||||
|
return self
|
||||||
|
end
|
||||||
--- (Internal) Check the assigned objects for being in/out of the zone
|
--- (Internal) Check the assigned objects for being in/out of the zone
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param #boolean fromstart If true, do the init of the objects
|
-- @param #boolean fromstart If true, do the init of the objects
|
||||||
@@ -718,7 +731,12 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
|||||||
obj.TriggerInZone[self.ZoneName] = false
|
obj.TriggerInZone[self.ZoneName] = false
|
||||||
end
|
end
|
||||||
-- is obj in zone?
|
-- is obj in zone?
|
||||||
local inzone = self:IsCoordinateInZone(obj:GetCoordinate())
|
local inzone
|
||||||
|
if self.PartlyInside and obj.ClassName == "GROUP" then
|
||||||
|
inzone = obj:IsAnyInZone(self) -- TRUE if any unit is inside
|
||||||
|
else
|
||||||
|
inzone = self:IsCoordinateInZone(obj:GetCoordinate()) -- original barycentre test
|
||||||
|
end
|
||||||
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
||||||
if inzone and obj.TriggerInZone[self.ZoneName] then
|
if inzone and obj.TriggerInZone[self.ZoneName] then
|
||||||
-- just count
|
-- just count
|
||||||
@@ -1147,7 +1165,7 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
|||||||
self.ScanData.SceneryTable = {}
|
self.ScanData.SceneryTable = {}
|
||||||
self.ScanData.Units = {}
|
self.ScanData.Units = {}
|
||||||
|
|
||||||
local ZoneCoord = self:GetCoordinate()
|
local ZoneCoord = self:GetCoordinate():SetAlt()
|
||||||
local ZoneRadius = self:GetRadius()
|
local ZoneRadius = self:GetRadius()
|
||||||
|
|
||||||
--self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
|
--self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
|
||||||
@@ -1162,15 +1180,13 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
|||||||
|
|
||||||
local function EvaluateZone( ZoneObject )
|
local function EvaluateZone( ZoneObject )
|
||||||
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
|
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
|
||||||
if ZoneObject then
|
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||||
|
|
||||||
-- Get object category.
|
-- Get object category.
|
||||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
local ObjectCategory = Object.getCategory(ZoneObject)
|
||||||
|
|
||||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
||||||
|
|
||||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
|
||||||
|
|
||||||
local Include = false
|
local Include = false
|
||||||
if not UnitCategories then
|
if not UnitCategories then
|
||||||
-- Anything found is included.
|
-- Anything found is included.
|
||||||
@@ -1554,6 +1570,10 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
local _inner = inner or 0
|
local _inner = inner or 0
|
||||||
local _outer = outer or self:GetRadius()
|
local _outer = outer or self:GetRadius()
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
if surfacetypes and type(surfacetypes)~="table" then
|
if surfacetypes and type(surfacetypes)~="table" then
|
||||||
surfacetypes={surfacetypes}
|
surfacetypes={surfacetypes}
|
||||||
end
|
end
|
||||||
@@ -1914,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Updates the current location from a @{Wrapper.Group}.
|
||||||
|
-- @param #ZONE_UNIT self
|
||||||
|
-- @param Wrapper.Group#GROUP Group (optional) Update from this Unit, if nil, update from the UNIT this zone is based on.
|
||||||
|
-- @return self
|
||||||
|
function ZONE_UNIT:UpdateFromUnit(Unit)
|
||||||
|
if Unit and Unit:IsAlive() then
|
||||||
|
local vec2 = Unit:GetVec2()
|
||||||
|
self.LastVec2 = vec2
|
||||||
|
elseif self.ZoneUNIT and self.ZoneUNIT:IsAlive() then
|
||||||
|
local ZoneVec2 = self.ZoneUNIT:GetVec2()
|
||||||
|
self.LastVec2 = ZoneVec2
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the current location of the @{Wrapper.Unit#UNIT}.
|
--- Returns the current location of the @{Wrapper.Unit#UNIT}.
|
||||||
-- @param #ZONE_UNIT self
|
-- @param #ZONE_UNIT self
|
||||||
@@ -2051,6 +2086,22 @@ function ZONE_GROUP:GetVec2()
|
|||||||
return ZoneVec2
|
return ZoneVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Updates the current location from a @{Wrapper.Group}.
|
||||||
|
-- @param #ZONE_GROUP self
|
||||||
|
-- @param Wrapper.Group#GROUP Group (optional) Update from this Group, if nil, update from the GROUP this zone is based on.
|
||||||
|
-- @return self
|
||||||
|
function ZONE_GROUP:UpdateFromGroup(Group)
|
||||||
|
if Group and Group:IsAlive() then
|
||||||
|
local vec2 = Group:GetVec2()
|
||||||
|
self.Vec2 = vec2
|
||||||
|
elseif self._.ZoneGROUP and self._.ZoneGROUP:IsAlive() then
|
||||||
|
local ZoneVec2 = self._.ZoneGROUP:GetVec2()
|
||||||
|
self.Vec2 = ZoneVec2
|
||||||
|
self._.ZoneVec2Cache = ZoneVec2
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns a random location within the zone of the @{Wrapper.Group}.
|
--- Returns a random location within the zone of the @{Wrapper.Group}.
|
||||||
-- @param #ZONE_GROUP self
|
-- @param #ZONE_GROUP self
|
||||||
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
||||||
@@ -2918,6 +2969,11 @@ end
|
|||||||
function ZONE_POLYGON_BASE:GetRandomVec2()
|
function ZONE_POLYGON_BASE:GetRandomVec2()
|
||||||
-- make sure we assign weights to the triangles based on their surface area, otherwise
|
-- make sure we assign weights to the triangles based on their surface area, otherwise
|
||||||
-- we'll be more likely to generate random points in smaller triangles
|
-- we'll be more likely to generate random points in smaller triangles
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
local weights = {}
|
local weights = {}
|
||||||
for _, triangle in pairs(self._Triangles) do
|
for _, triangle in pairs(self._Triangles) do
|
||||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||||
@@ -3281,14 +3337,12 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
|||||||
|
|
||||||
local function EvaluateZone( ZoneObject )
|
local function EvaluateZone( ZoneObject )
|
||||||
|
|
||||||
if ZoneObject then
|
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||||
|
|
||||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
local ObjectCategory = Object.getCategory(ZoneObject)
|
||||||
|
|
||||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
||||||
|
|
||||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
|
||||||
|
|
||||||
local Include = false
|
local Include = false
|
||||||
if not UnitCategories then
|
if not UnitCategories then
|
||||||
-- Anything found is included.
|
-- Anything found is included.
|
||||||
@@ -3320,7 +3374,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- trying with box search
|
-- trying with box search
|
||||||
if ObjectCategory == Object.Category.SCENERY and self:IsVec3InZone(ZoneObject:getPoint()) then
|
if ObjectCategory == Object.Category.SCENERY then
|
||||||
local SceneryType = ZoneObject:getTypeName()
|
local SceneryType = ZoneObject:getTypeName()
|
||||||
local SceneryName = ZoneObject:getName()
|
local SceneryName = ZoneObject:getName()
|
||||||
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- @module Functional.Mantis
|
-- @module Functional.Mantis
|
||||||
-- @image Functional.Mantis.jpg
|
-- @image Functional.Mantis.jpg
|
||||||
--
|
--
|
||||||
-- Last Update: July 2025
|
-- Last Update: August 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends Core.Base#BASE
|
--- **MANTIS** class, extends Core.Base#BASE
|
||||||
@@ -108,10 +108,15 @@
|
|||||||
-- * Patriot
|
-- * Patriot
|
||||||
-- * Rapier
|
-- * Rapier
|
||||||
-- * Roland
|
-- * Roland
|
||||||
|
-- * IRIS-T SLM
|
||||||
|
-- * Pantsir S1
|
||||||
|
-- * TOR M2
|
||||||
|
-- * C-RAM
|
||||||
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
||||||
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
||||||
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
||||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2
|
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2
|
||||||
|
-- * Other Mods: Nike
|
||||||
--
|
--
|
||||||
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
||||||
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
|
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
|
||||||
@@ -275,7 +280,7 @@
|
|||||||
MANTIS = {
|
MANTIS = {
|
||||||
ClassName = "MANTIS",
|
ClassName = "MANTIS",
|
||||||
name = "mymantis",
|
name = "mymantis",
|
||||||
version = "0.9.32",
|
version = "0.9.34",
|
||||||
SAM_Templates_Prefix = "",
|
SAM_Templates_Prefix = "",
|
||||||
SAM_Group = nil,
|
SAM_Group = nil,
|
||||||
EWR_Templates_Prefix = "",
|
EWR_Templates_Prefix = "",
|
||||||
@@ -384,7 +389,7 @@ MANTIS.SamData = {
|
|||||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||||
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
||||||
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
||||||
["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" },
|
["C-RAM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" },
|
||||||
-- units from HDS Mod, multi launcher options is tricky
|
-- units from HDS Mod, multi launcher options is tricky
|
||||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
||||||
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
||||||
@@ -393,6 +398,12 @@ MANTIS.SamData = {
|
|||||||
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||||
["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" },
|
["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" },
|
||||||
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
||||||
|
["NIKE"] = { Range=155, Blindspot=6, Height=30, Type="Long", Radar="HIPAR" },
|
||||||
|
["Dog Ear"] = { Range=11, Blindspot=0, Height=9, Type="Point", Radar="Dog Ear", Point="true" },
|
||||||
|
-- CH Added to DCS core 2.9.19.x
|
||||||
|
["Pantsir S1"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1" , Point="true" },
|
||||||
|
["Tor M2"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" },
|
||||||
|
["IRIS-T SLM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
|
||||||
}
|
}
|
||||||
|
|
||||||
--- SAM data HDS
|
--- SAM data HDS
|
||||||
@@ -458,15 +469,15 @@ MANTIS.SamDataCH = {
|
|||||||
-- https://www.currenthill.com/
|
-- https://www.currenthill.com/
|
||||||
-- group name MUST contain CHM to ID launcher type correctly!
|
-- group name MUST contain CHM to ID launcher type correctly!
|
||||||
["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" },
|
["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" },
|
||||||
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1", Point="true" },
|
||||||
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
||||||
["PGL-625 CHM"] = { Range=10, Blindspot=1, Height=5, Type="Short", Radar="PGL_625" },
|
["PGL-625 CHM"] = { Range=10, Blindspot=1, Height=5, Type="Short", Radar="PGL_625" },
|
||||||
["HQ-17A CHM"] = { Range=15, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
["HQ-17A CHM"] = { Range=15, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
||||||
["M903PAC2 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
["M903PAC2 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
||||||
["M903PAC3 CHM"] = { Range=160, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
["M903PAC3 CHM"] = { Range=160, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
||||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" },
|
||||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2K", Point="true" },
|
||||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Point", Radar="TorM2M", Point="true" },
|
||||||
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
||||||
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
||||||
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_Centurion_C_RAM", Point="true" },
|
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_Centurion_C_RAM", Point="true" },
|
||||||
@@ -882,7 +893,11 @@ do
|
|||||||
self.AcceptZones = AcceptZones or {}
|
self.AcceptZones = AcceptZones or {}
|
||||||
self.RejectZones = RejectZones or {}
|
self.RejectZones = RejectZones or {}
|
||||||
self.ConflictZones = ConflictZones or {}
|
self.ConflictZones = ConflictZones or {}
|
||||||
if #self.AcceptZones > 0 or #self.RejectZones > 0 or #self.ConflictZones > 0 then
|
self.AcceptZonesNo = UTILS.TableLength(self.AcceptZones)
|
||||||
|
self.RejectZonesNo = UTILS.TableLength(self.RejectZones)
|
||||||
|
self.ConflictZonesNo = UTILS.TableLength(self.ConflictZones)
|
||||||
|
self:T(string.format("AcceptZonesNo = %d | RejectZonesNo = %d | ConflictZonesNo = %d",self.AcceptZonesNo,self.RejectZonesNo,self.ConflictZonesNo))
|
||||||
|
if self.AcceptZonesNo > 0 or self.RejectZonesNo > 0 or self.ConflictZonesNo > 0 then
|
||||||
self.usezones = true
|
self.usezones = true
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -1274,7 +1289,8 @@ do
|
|||||||
self:T(self.lid.."_CheckCoordinateInZones")
|
self:T(self.lid.."_CheckCoordinateInZones")
|
||||||
local inzone = false
|
local inzone = false
|
||||||
-- acceptzones
|
-- acceptzones
|
||||||
if #self.AcceptZones > 0 then
|
self:T(string.format("AcceptZonesNo = %d | RejectZonesNo = %d | ConflictZonesNo = %d",self.AcceptZonesNo,self.RejectZonesNo,self.ConflictZonesNo))
|
||||||
|
if self.AcceptZonesNo > 0 then
|
||||||
for _,_zone in pairs(self.AcceptZones) do
|
for _,_zone in pairs(self.AcceptZones) do
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
if zone:IsCoordinateInZone(coord) then
|
if zone:IsCoordinateInZone(coord) then
|
||||||
@@ -1285,7 +1301,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- rejectzones
|
-- rejectzones
|
||||||
if #self.RejectZones > 0 and inzone then -- maybe in accept zone, but check the overlaps
|
if self.RejectZonesNo > 0 then
|
||||||
for _,_zone in pairs(self.RejectZones) do
|
for _,_zone in pairs(self.RejectZones) do
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
if zone:IsCoordinateInZone(coord) then
|
if zone:IsCoordinateInZone(coord) then
|
||||||
@@ -1296,7 +1312,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- conflictzones
|
-- conflictzones
|
||||||
if #self.ConflictZones > 0 and not inzone then -- if not already accepted, might be in conflict zones
|
if self.ConflictZonesNo > 0 then
|
||||||
for _,_zone in pairs(self.ConflictZones) do
|
for _,_zone in pairs(self.ConflictZones) do
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
if zone:IsCoordinateInZone(coord) then
|
if zone:IsCoordinateInZone(coord) then
|
||||||
@@ -1362,6 +1378,7 @@ do
|
|||||||
end
|
end
|
||||||
-- check accept/reject zones
|
-- check accept/reject zones
|
||||||
local zonecheck = true
|
local zonecheck = true
|
||||||
|
self:T("self.usezones = "..tostring(self.usezones))
|
||||||
if self.usezones then
|
if self.usezones then
|
||||||
-- DONE
|
-- DONE
|
||||||
zonecheck = self:_CheckCoordinateInZones(coord)
|
zonecheck = self:_CheckCoordinateInZones(coord)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -90,7 +90,8 @@
|
|||||||
-- @image Scoring.JPG
|
-- @image Scoring.JPG
|
||||||
|
|
||||||
--- @type SCORING
|
--- @type SCORING
|
||||||
-- @field Players A collection of the current players that have joined the game.
|
-- @field #table Players A collection of the current players that have joined the game.
|
||||||
|
-- @field Core.Set#SET_SCENERY ScoringScenery
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- SCORING class
|
--- SCORING class
|
||||||
@@ -229,7 +230,8 @@ SCORING = {
|
|||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
Players = {},
|
Players = {},
|
||||||
AutoSave = true,
|
AutoSave = true,
|
||||||
version = "1.18.4"
|
version = "1.18.4",
|
||||||
|
ScoringScenery = nil, -- Core.Set#SET_SCENERY
|
||||||
}
|
}
|
||||||
|
|
||||||
local _SCORINGCoalition = {
|
local _SCORINGCoalition = {
|
||||||
@@ -320,8 +322,12 @@ function SCORING:New( GameName, SavePath, AutoSave )
|
|||||||
|
|
||||||
-- Create the CSV file.
|
-- Create the CSV file.
|
||||||
self.AutoSavePath = SavePath
|
self.AutoSavePath = SavePath
|
||||||
self.AutoSave = AutoSave or true
|
self.AutoSave = (AutoSave == nil or AutoSave == true) and true or false
|
||||||
|
if self.AutoSavePath and self.AutoSave == true then
|
||||||
self:OpenCSV( GameName )
|
self:OpenCSV( GameName )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:I("SCORING "..tostring(GameName).." started! v"..self.version)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -375,7 +381,7 @@ function SCORING:AddUnitScore( ScoreUnit, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a @{Wrapper.Unit} for additional scoring when the @{Wrapper.Unit} is destroyed.
|
--- Removes a @{Wrapper.Unit} for scoring when the @{Wrapper.Unit} is destroyed.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given.
|
-- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
@@ -392,10 +398,26 @@ end
|
|||||||
-- Note that if there was already a @{Wrapper.Static} declared within the scoring with the same name,
|
-- Note that if there was already a @{Wrapper.Static} declared within the scoring with the same name,
|
||||||
-- then the old @{Wrapper.Static} will be replaced with the new @{Wrapper.Static}.
|
-- then the old @{Wrapper.Static} will be replaced with the new @{Wrapper.Static}.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
-- @param Wrapper.Static#STATIC ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||||
-- @param #number Score The Score value.
|
-- @param #number Score The Score value.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:AddStaticScore( ScoreStatic, Score )
|
function SCORING:AddStaticScore( ScoreStatic, Score )
|
||||||
|
return self:AddScoreStatic( ScoreStatic, Score )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
|
||||||
|
-- Note that if there was already a @{Wrapper.Static} declared within the scoring with the same name,
|
||||||
|
-- then the old @{Wrapper.Static} will be replaced with the new @{Wrapper.Static}.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Wrapper.Static#STATIC ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddScoreStatic( ScoreStatic, Score )
|
||||||
|
|
||||||
|
if ScoreStatic == nil then
|
||||||
|
BASE:E("SCORING.AddStaticScore: Parameter ScoreStatic is nil!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
local StaticName = ScoreStatic:GetName()
|
local StaticName = ScoreStatic:GetName()
|
||||||
|
|
||||||
@@ -404,7 +426,61 @@ function SCORING:AddStaticScore( ScoreStatic, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
|
--- Add a @{Wrapper.Scenery} for additional scoring when the @{Wrapper.Scenery} is destroyed.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Wrapper.Scenery#SCENERY ScoreScenery The @{Wrapper.Scenery} for which the Score needs to be given.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddScoreScenery( ScoreScenery, Score )
|
||||||
|
|
||||||
|
if ScoreScenery == nil then
|
||||||
|
self:E("SCORING.ScoreScenery: Parameter ScoreScenery is nil!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self.ScoringScenery then
|
||||||
|
self.ScoringScenery = SET_SCENERY:New() -- Core.Set#SET_SCENERY
|
||||||
|
end
|
||||||
|
|
||||||
|
local StaticName = ScoreScenery:GetName()
|
||||||
|
self:T("Scenery name = ".. StaticName)
|
||||||
|
|
||||||
|
self.ScoringScenery:AddScenery(ScoreScenery)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes a @{Wrapper.Scenery} for scoring when the @{Wrapper.Scenery} is destroyed.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Wrapper.Scenery#SCENERY ScoreStatic The @{Wrapper.Scenery} for which the Score needs to be given.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:RemoveSceneryScore( ScoreScenery )
|
||||||
|
|
||||||
|
local StaticName = ScoreScenery:GetName()
|
||||||
|
|
||||||
|
self.ScoringObjects[StaticName] = nil
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Specify a special additional score for a @{Core.Set#SET_SCENERY}.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Core.Set#SET_SCENERY Set The @{Core.Set#SET_SCENERY} for which each @{Wrapper.Scenery} in the SET a Score is given.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddScoreSetScenery(Set, Score)
|
||||||
|
local set = Set.Set
|
||||||
|
|
||||||
|
for _,_static in pairs (set) do
|
||||||
|
if _static ~= nil then
|
||||||
|
self:AddScoreScenery(_static,Score)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes a @{Wrapper.Static} for scoring when the @{Wrapper.Static} is destroyed.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
@@ -459,6 +535,31 @@ function SCORING:AddScoreSetGroup(Set, Score)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Specify a special additional score for a @{Core.Set#SET_STATIC}.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Core.Set#SET_STATIC Set The @{Core.Set#SET_STATIC} for which each @{Wrapper.Static} in the SET a Score is given.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddScoreSetStatic(Set, Score)
|
||||||
|
local set = Set:GetSetObjects()
|
||||||
|
|
||||||
|
for _,_static in pairs (set) do
|
||||||
|
if _static and _static:IsAlive() then
|
||||||
|
self:AddStaticScore(_static,Score)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function AddScore(static)
|
||||||
|
self:AddStaticScore(static,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.
|
||||||
@@ -478,7 +579,24 @@ function SCORING:AddZoneScore( ScoreZone, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a @{Core.Zone} for additional scoring.
|
--- Add a @{Core.Set#SET_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!
|
||||||
|
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Core.Set#SET_ZONE ScoreZoneSet The @{Core.Set#SET_ZONE} which defines the destruction score perimeters.
|
||||||
|
-- Note that a zone can be a polygon or a moving zone.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddZoneScoreSet( ScoreZoneSet, Score )
|
||||||
|
|
||||||
|
for _,_zone in pairs(ScoreZoneSet.Set or {}) do
|
||||||
|
self:AddZoneScore(_zone,Score)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove a @{Core.Zone} for scoring.
|
||||||
-- The scoring will search if any @{Core.Zone} is added with the given name, and will remove that zone from the scoring.
|
-- The scoring will search if any @{Core.Zone} is added with the given name, and will remove that zone from the scoring.
|
||||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
@@ -956,7 +1074,7 @@ end
|
|||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
function SCORING:_EventOnHit( Event )
|
function SCORING:_EventOnHit( Event )
|
||||||
self:F( { Event } )
|
--self:F( { Event } )
|
||||||
|
|
||||||
local InitUnit = nil
|
local InitUnit = nil
|
||||||
local InitUNIT = nil
|
local InitUNIT = nil
|
||||||
@@ -985,6 +1103,8 @@ function SCORING:_EventOnHit( Event )
|
|||||||
local TargetUnitCoalition = nil
|
local TargetUnitCoalition = nil
|
||||||
local TargetUnitCategory = nil
|
local TargetUnitCategory = nil
|
||||||
local TargetUnitType = nil
|
local TargetUnitType = nil
|
||||||
|
local TargetIsScenery = false
|
||||||
|
local TargetSceneryObject = nil
|
||||||
|
|
||||||
if Event.IniDCSUnit then
|
if Event.IniDCSUnit then
|
||||||
|
|
||||||
@@ -1006,7 +1126,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
InitUnitCategory = _SCORINGCategory[InitCategory]
|
InitUnitCategory = _SCORINGCategory[InitCategory]
|
||||||
InitUnitType = InitType
|
InitUnitType = InitType
|
||||||
|
|
||||||
self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType, InitUnitCoalition, InitUnitCategory, InitUnitType } )
|
--self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType, InitUnitCoalition, InitUnitCategory, InitUnitType } )
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.TgtDCSUnit then
|
if Event.TgtDCSUnit then
|
||||||
@@ -1025,11 +1145,22 @@ function SCORING:_EventOnHit( Event )
|
|||||||
TargetCategory = Event.TgtCategory
|
TargetCategory = Event.TgtCategory
|
||||||
TargetType = Event.TgtTypeName
|
TargetType = Event.TgtTypeName
|
||||||
|
|
||||||
|
|
||||||
|
-- Scenery hit
|
||||||
|
if TargetUNIT ~= nil and TargetUNIT:IsInstanceOf("SCENERY") then
|
||||||
|
TargetCategory = Unit.Category.STRUCTURE
|
||||||
|
TargetIsScenery = true
|
||||||
|
TargetType = "Scenery"
|
||||||
|
TargetSceneryObject = TargetUNIT
|
||||||
|
self:T("***** Target is Scenery and TargetUNIT is SCENERY object!")
|
||||||
|
UTILS.PrintTableToLog(TargetSceneryObject)
|
||||||
|
end
|
||||||
|
|
||||||
TargetUnitCoalition = _SCORINGCoalition[TargetCoalition]
|
TargetUnitCoalition = _SCORINGCoalition[TargetCoalition]
|
||||||
TargetUnitCategory = _SCORINGCategory[TargetCategory]
|
TargetUnitCategory = _SCORINGCategory[TargetCategory]
|
||||||
TargetUnitType = TargetType
|
TargetUnitType = TargetType
|
||||||
|
|
||||||
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType, TargetUnitCoalition, TargetUnitCategory, TargetUnitType } )
|
--self:T( { TargetUnitName=TargetUnitName, TargetGroupName=TargetGroupName, TargetPlayerName=TargetPlayerName, TargetCoalition=TargetCoalition, TargetCategory=TargetCategory, TargetType=TargetType, TargetUnitCoalition=TargetUnitCoalition, TargetUnitCategory=TargetUnitCategory, TargetUnitType=TargetUnitType } )
|
||||||
end
|
end
|
||||||
|
|
||||||
if InitPlayerName ~= nil then -- It is a player that is hitting something
|
if InitPlayerName ~= nil then -- It is a player that is hitting something
|
||||||
@@ -1042,7 +1173,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
self:T( "Hitting Something" )
|
self:T( "Hitting Something" )
|
||||||
|
|
||||||
-- What is he hitting?
|
-- What is he hitting?
|
||||||
if TargetCategory then
|
if (TargetCategory ~=nil) and (TargetIsScenery == false) then
|
||||||
|
|
||||||
-- A target got hit, score it.
|
-- A target got hit, score it.
|
||||||
-- Player contains the score data from self.Players[InitPlayerName]
|
-- Player contains the score data from self.Players[InitPlayerName]
|
||||||
@@ -1062,7 +1193,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
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 threat 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 and 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
|
||||||
if PlayerHit.ThreatType == nil or PlayerHit.ThreatType == "" then
|
if PlayerHit.ThreatType == nil or PlayerHit.ThreatType == "" then
|
||||||
@@ -1117,17 +1248,22 @@ function SCORING:_EventOnHit( Event )
|
|||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
else
|
elseif TargetIsScenery ~= true then
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
elseif TargetIsScenery == true then
|
||||||
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object." .. " Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
|
MESSAGE.Type.Update )
|
||||||
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
end
|
end
|
||||||
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
end
|
end
|
||||||
else -- A scenery object was hit.
|
else -- A scenery object was hit.
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit nothing special.",
|
||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
@@ -1143,21 +1279,21 @@ function SCORING:_EventOnHit( Event )
|
|||||||
|
|
||||||
-- It is a weapon initiated by a player, that is hitting something
|
-- It is a weapon initiated by a player, that is hitting something
|
||||||
-- This seems to occur only with scenery and static objects.
|
-- This seems to occur only with scenery and static objects.
|
||||||
if Event.WeaponPlayerName ~= nil then
|
if Event.WeaponPlayerName ~= nil or TargetIsScenery == true then
|
||||||
self:_AddPlayerFromUnit( Event.WeaponUNIT )
|
|
||||||
if self.Players[Event.WeaponPlayerName] then -- This should normally not happen, but i'll test it anyway.
|
|
||||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
|
||||||
self:_AddPlayerFromUnit( TargetUNIT )
|
|
||||||
end
|
|
||||||
|
|
||||||
self:T( "Hitting Scenery" )
|
local playername = Event.WeaponPlayerName or Event.IniPlayerName or "Ghost"
|
||||||
|
|
||||||
|
--self:_AddPlayerFromUnit( Event.WeaponUNIT )
|
||||||
|
if self.Players[playername] then -- This should normally not happen, but i'll test it anyway.
|
||||||
|
|
||||||
|
self:T( "Hitting Scenery or Static" )
|
||||||
|
|
||||||
-- What is he hitting?
|
-- What is he hitting?
|
||||||
if TargetCategory then
|
if Event.TgtObjectCategory then
|
||||||
|
|
||||||
-- A scenery or static got hit, score it.
|
-- A scenery or static got hit, score it.
|
||||||
-- Player contains the score data from self.Players[WeaponPlayerName]
|
-- Player contains the score data from self.Players[WeaponPlayerName]
|
||||||
local Player = self.Players[Event.WeaponPlayerName]
|
local Player = self.Players[playername]
|
||||||
|
|
||||||
-- Ensure there is a hit table per TargetCategory and TargetUnitName.
|
-- Ensure there is a hit table per TargetCategory and TargetUnitName.
|
||||||
Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {}
|
Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {}
|
||||||
@@ -1166,14 +1302,16 @@ function SCORING:_EventOnHit( Event )
|
|||||||
-- PlayerHit contains the score counters and data per unit that was hit.
|
-- PlayerHit contains the score counters and data per unit that was hit.
|
||||||
local PlayerHit = Player.Hit[TargetCategory][TargetUnitName]
|
local PlayerHit = Player.Hit[TargetCategory][TargetUnitName]
|
||||||
|
|
||||||
|
-- Init player scores
|
||||||
PlayerHit.Score = PlayerHit.Score or 0
|
PlayerHit.Score = PlayerHit.Score or 0
|
||||||
PlayerHit.Penalty = PlayerHit.Penalty or 0
|
PlayerHit.Penalty = PlayerHit.Penalty or 0
|
||||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0
|
PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0
|
||||||
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 threat 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 and 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
|
||||||
if PlayerHit.ThreatType == nil then
|
if PlayerHit.ThreatType == nil then
|
||||||
@@ -1181,8 +1319,8 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.ThreatType = "Unknown"
|
PlayerHit.ThreatType = "Unknown"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
PlayerHit.ThreatLevel = PlayerHit.UNIT.ThreatLevel
|
PlayerHit.ThreatLevel = PlayerHit.UNIT and PlayerHit.UNIT.ThreatLevel or 1
|
||||||
PlayerHit.ThreatType = PlayerHit.UNIT.ThreatType
|
PlayerHit.ThreatType = PlayerHit.UNIT and PlayerHit.UNIT.ThreatType or "Unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Only grant hit scores if there was more than one second between the last hit.
|
-- Only grant hit scores if there was more than one second between the last hit.
|
||||||
@@ -1191,49 +1329,67 @@ function SCORING:_EventOnHit( Event )
|
|||||||
|
|
||||||
local Score = 0
|
local Score = 0
|
||||||
|
|
||||||
if InitCoalition then -- A coalition object was hit, probably a static.
|
local TgtName = Event.TgtDCSUnit and Event.TgtDCSUnit.getName and Event.TgtDCSUnit:getName() or "Unknown"
|
||||||
if InitCoalition == TargetCoalition then
|
|
||||||
-- TODO: Penalty according scale
|
|
||||||
local Penalty = 10
|
|
||||||
Player.Penalty = Player.Penalty + Penalty --* self.ScaleDestroyPenalty
|
|
||||||
PlayerHit.Penalty = PlayerHit.Penalty + Penalty --* self.ScaleDestroyPenalty
|
|
||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
|
||||||
|
|
||||||
MESSAGE
|
--if InitCoalition then -- A coalition object was hit, probably a static.
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
if TargetIsScenery == true and self.ScoringScenery:IsInSet(TargetSceneryObject) then
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
|
||||||
"Penalty: -" .. Penalty .. " = " .. Player.Score - Player.Penalty,
|
|
||||||
MESSAGE.Type.Update
|
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
|
||||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
|
||||||
else
|
|
||||||
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||||
PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit
|
PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit
|
||||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. playername .. "' hit scenery target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( playername, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
end
|
elseif TargetIsScenery == false and Event.TgtObjectCategory == Object.Category.STATIC and self.ScoringObjects[TgtName] then
|
||||||
else -- A scenery object was hit.
|
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
|
PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit
|
||||||
|
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||||
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. playername .. "' hit static target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||||
|
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType )
|
self:ScoreCSV( playername, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E("Hit unregistered scenery or static object - NO target! ("..TgtName..")")
|
||||||
|
end
|
||||||
|
--end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check if there are Zones where the destruction happened.
|
||||||
|
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
|
||||||
|
self:F( { ScoringZone = ScoreZoneData } )
|
||||||
|
local hit=Event.TgtUnit
|
||||||
|
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
|
||||||
|
local Score = ScoreZoneData.Score
|
||||||
|
if TargetUNIT and ScoreZone:IsVec2InZone( TargetUNIT:GetVec2() ) then
|
||||||
|
-- A scenery or static got hit, score it.
|
||||||
|
-- Player contains the score data from self.Players[WeaponPlayerName]
|
||||||
|
local PlayerName = Event.IniPlayerName or "Ghost"
|
||||||
|
local Player = self.Players[PlayerName]
|
||||||
|
|
||||||
|
Player.Score = Player.Score + Score
|
||||||
|
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||||
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "hit in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||||
|
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty,
|
||||||
|
MESSAGE.Type.Information )
|
||||||
|
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
||||||
|
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
|
self:ScoreCSV( PlayerName, "", "HIT_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Zone", TargetUnitType )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Track DEAD or CRASH events for the scoring.
|
--- Track DEAD or CRASH events for the scoring.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
@@ -1291,7 +1447,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
local Destroyed = false
|
local Destroyed = false
|
||||||
|
|
||||||
-- What is the player destroying?
|
-- What is the player destroying?
|
||||||
if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] and Player.Hit[TargetCategory][TargetUnitName].TimeStamp ~= 0 and (TargetUnit.BirthTime == nil or Player.Hit[TargetCategory][TargetUnitName].TimeStamp > TargetUnit.BirthTime) then -- Was there a hit for this unit for this player before registered???
|
if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] and Player.Hit[TargetCategory][TargetUnitName].TimeStamp ~= 0 and TargetUnit and (TargetUnit.BirthTime == nil or Player.Hit[TargetCategory][TargetUnitName].TimeStamp > TargetUnit.BirthTime) then -- Was there a hit for this unit for this player before registered???
|
||||||
|
|
||||||
local TargetThreatLevel = Player.Hit[TargetCategory][TargetUnitName].ThreatLevel
|
local TargetThreatLevel = Player.Hit[TargetCategory][TargetUnitName].ThreatLevel
|
||||||
local TargetThreatType = Player.Hit[TargetCategory][TargetUnitName].ThreatType
|
local TargetThreatType = Player.Hit[TargetCategory][TargetUnitName].ThreatType
|
||||||
@@ -1923,7 +2079,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
|||||||
TargetUnitType = TargetUnitType or ""
|
TargetUnitType = TargetUnitType or ""
|
||||||
TargetUnitName = TargetUnitName or ""
|
TargetUnitName = TargetUnitName or ""
|
||||||
|
|
||||||
if lfs and io and os and self.AutoSave then
|
if lfs and io and os and self.AutoSave == true and self.CSVFile ~= nil then
|
||||||
self.CSVFile:write(
|
self.CSVFile:write(
|
||||||
'"' .. self.GameName .. '"' .. ',' ..
|
'"' .. self.GameName .. '"' .. ',' ..
|
||||||
'"' .. self.RunTime .. '"' .. ',' ..
|
'"' .. self.RunTime .. '"' .. ',' ..
|
||||||
|
|||||||
@@ -4247,6 +4247,16 @@ function WAREHOUSE:_AssetItemInfo(asset)
|
|||||||
self:T3({Template=asset.template})
|
self:T3({Template=asset.template})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||||
|
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||||
|
--- Uses UTILS.ValidateAndRepositionGroundUnits.
|
||||||
|
-- @param #boolean Enabled Enable/disable the feature.
|
||||||
|
function WAREHOUSE:SetValidateAndRepositionGroundUnits(Enabled)
|
||||||
|
self.ValidateAndRepositionGroundUnits = Enabled
|
||||||
|
end
|
||||||
|
|
||||||
--- On after "NewAsset" event. A new asset has been added to the warehouse stock.
|
--- On after "NewAsset" event. A new asset has been added to the warehouse stock.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -5965,6 +5975,10 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late
|
|||||||
template.y = coord.z
|
template.y = coord.z
|
||||||
template.alt = coord.y
|
template.alt = coord.y
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(template.units)
|
||||||
|
end
|
||||||
|
|
||||||
-- Spawn group.
|
-- Spawn group.
|
||||||
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
|||||||
@@ -39,11 +39,13 @@
|
|||||||
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_\(LHA-6\)) (LHA-6)
|
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_\(LHA-6\)) (LHA-6)
|
||||||
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61)
|
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61)
|
||||||
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_\(L02\)) (L02)
|
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_\(L02\)) (L02)
|
||||||
|
-- * BONHOMMERICHARD [VWV Mod]
|
||||||
|
-- * ENTERPRISE66 [VWV Mod]
|
||||||
--
|
--
|
||||||
-- **Supported Aircraft:**
|
-- **Supported Aircraft:**
|
||||||
--
|
--
|
||||||
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI)
|
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI)
|
||||||
-- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
-- * [F-14A/B/A Early Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
||||||
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
|
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
|
||||||
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI)
|
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI)
|
||||||
-- * [T-45C Goshawk](https://forum.dcs.world/topic/203816-vnao-t-45-goshawk/) (VNAO mod) (Player & AI)
|
-- * [T-45C Goshawk](https://forum.dcs.world/topic/203816-vnao-t-45-goshawk/) (VNAO mod) (Player & AI)
|
||||||
@@ -61,7 +63,7 @@
|
|||||||
-- no other fixed wing aircraft (human or AI controlled) are supposed to land on these ships. Currently only Case I is supported. Case II/III take slightly different steps from the CVN carrier.
|
-- no other fixed wing aircraft (human or AI controlled) are supposed to land on these ships. Currently only Case I is supported. Case II/III take slightly different steps from the CVN carrier.
|
||||||
-- However, if no offset is used for the holding radial this provides a very close representation of the V/STOL Case III, allowing for an approach to over the deck and a vertical landing.
|
-- However, if no offset is used for the holding radial this provides a very close representation of the V/STOL Case III, allowing for an approach to over the deck and a vertical landing.
|
||||||
--
|
--
|
||||||
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well. Same goes for the A version.
|
-- Heatblur's mighty F-14A/B/A Early Tomcat has been added as well.
|
||||||
--
|
--
|
||||||
-- The [DCS Supercarriers](https://www.digitalcombatsimulator.com/de/shop/modules/supercarrier/) are also supported.
|
-- The [DCS Supercarriers](https://www.digitalcombatsimulator.com/de/shop/modules/supercarrier/) are also supported.
|
||||||
--
|
--
|
||||||
@@ -1274,6 +1276,7 @@ AIRBOSS = {
|
|||||||
-- @field #string A4EC A-4E Community mod.
|
-- @field #string A4EC A-4E Community mod.
|
||||||
-- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics.
|
-- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics.
|
||||||
-- @field #string F14A F-14A by Heatblur.
|
-- @field #string F14A F-14A by Heatblur.
|
||||||
|
-- @field #string F14A_Early F-14A-135-GR-Early by Heatblur.
|
||||||
-- @field #string F14B F-14B by Heatblur.
|
-- @field #string F14B F-14B by Heatblur.
|
||||||
-- @field #string F14A_AI F-14A Tomcat (AI).
|
-- @field #string F14A_AI F-14A Tomcat (AI).
|
||||||
-- @field #string FA18C F/A-18C Hornet (AI).
|
-- @field #string FA18C F/A-18C Hornet (AI).
|
||||||
@@ -1292,6 +1295,7 @@ AIRBOSS.AircraftCarrier={
|
|||||||
HORNET="FA-18C_hornet",
|
HORNET="FA-18C_hornet",
|
||||||
A4EC="A-4E-C",
|
A4EC="A-4E-C",
|
||||||
F14A="F-14A-135-GR",
|
F14A="F-14A-135-GR",
|
||||||
|
F14A_Early="F-14A-135-GR-Early",
|
||||||
F14B="F-14B",
|
F14B="F-14B",
|
||||||
F14A_AI="F-14A",
|
F14A_AI="F-14A",
|
||||||
FA18C="F/A-18C",
|
FA18C="F/A-18C",
|
||||||
@@ -1317,6 +1321,10 @@ AIRBOSS.AircraftCarrier={
|
|||||||
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
||||||
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
|
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
|
||||||
-- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module]
|
-- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module]
|
||||||
|
-- @field #string BONHOMMERICHARD USS Bon Homme Richard carrier [VWV Mod]
|
||||||
|
-- @field #string ESSEXSCB125 Generic Essex class carrier with angled deck (SCB-125 upgrade) [VWV Mod]
|
||||||
|
-- @field #string ENTERPRISE66 USS Enterprise in the 1966 configuration [VWV Mod]
|
||||||
|
-- @field #string ENTERPRISEMODERN USS Enterprise in a modern configuration [Derived VWV Mod]
|
||||||
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
||||||
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
||||||
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
||||||
@@ -1331,8 +1339,12 @@ AIRBOSS.CarrierType = {
|
|||||||
TRUMAN = "CVN_75",
|
TRUMAN = "CVN_75",
|
||||||
STENNIS = "Stennis",
|
STENNIS = "Stennis",
|
||||||
FORRESTAL = "Forrestal",
|
FORRESTAL = "Forrestal",
|
||||||
|
ENTERPRISE66 = "USS Enterprise 1966",
|
||||||
|
ENTERPRISEMODERN = "cvn-65",
|
||||||
VINSON = "VINSON",
|
VINSON = "VINSON",
|
||||||
ESSEX = "Essex",
|
ESSEX = "Essex",
|
||||||
|
BONHOMMERICHARD = "USS Bon Homme Richard",
|
||||||
|
ESSEXSCB125 = "essex_scb125",
|
||||||
HERMES = "HERMES81",
|
HERMES = "HERMES81",
|
||||||
INVINCIBLE = "hms_invincible",
|
INVINCIBLE = "hms_invincible",
|
||||||
TARAWA = "LHA_Tarawa",
|
TARAWA = "LHA_Tarawa",
|
||||||
@@ -1756,7 +1768,7 @@ AIRBOSS.MenuF10Root = nil
|
|||||||
|
|
||||||
--- Airboss class version.
|
--- Airboss class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRBOSS.version = "1.4.1"
|
AIRBOSS.version = "1.4.2"
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -2019,11 +2031,19 @@ function AIRBOSS:New( carriername, alias )
|
|||||||
self:_InitNimitz()
|
self:_InitNimitz()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
|
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
|
||||||
self:_InitForrestal()
|
self:_InitForrestal()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.ENTERPRISE66 then
|
||||||
|
self:_InitEnterprise()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.ENTERPRISEMODERN then
|
||||||
|
self:_InitEnterprise()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
||||||
-- Carl Vinson is legacy now.
|
-- Carl Vinson is legacy now.
|
||||||
self:_InitStennis()
|
self:_InitStennis()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then
|
elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then
|
||||||
self:_InitEssex()
|
self:_InitEssex()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.BONHOMMERICHARD then
|
||||||
|
self:_InitBonHommeRichard()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.ESSEXSCB125 then
|
||||||
|
self:_InitEssexSCB125()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
||||||
-- Hermes parameters.
|
-- Hermes parameters.
|
||||||
self:_InitHermes()
|
self:_InitHermes()
|
||||||
@@ -2412,6 +2432,16 @@ end
|
|||||||
-- USER API Functions
|
-- USER API Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set the carrier illumination mode.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number Mode Options are: -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetCarrierIllumination(Mode)
|
||||||
|
self.carrier:SetCarrierIlluminationMode(Mode)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set welcome messages for players.
|
--- Set welcome messages for players.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #boolean Switch If true, display welcome message to player.
|
-- @param #boolean Switch If true, display welcome message to player.
|
||||||
@@ -3100,8 +3130,8 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
|||||||
self.SRS:SetCulture(Culture or "en-US")
|
self.SRS:SetCulture(Culture or "en-US")
|
||||||
--self.SRS:SetFrequencies(Frequencies)
|
--self.SRS:SetFrequencies(Frequencies)
|
||||||
self.SRS:SetGender(Gender or "male")
|
self.SRS:SetGender(Gender or "male")
|
||||||
self.SRS:SetPath(PathToSRS)
|
--self.SRS:SetPath(PathToSRS)
|
||||||
self.SRS:SetPort(Port or 5002)
|
self.SRS:SetPort(Port or MSRS.port or 5002)
|
||||||
self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS")
|
self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS")
|
||||||
self.SRS:SetCoordinate(self.carrier:GetCoordinate())
|
self.SRS:SetCoordinate(self.carrier:GetCoordinate())
|
||||||
self.SRS:SetVolume(Volume or 1)
|
self.SRS:SetVolume(Volume or 1)
|
||||||
@@ -3112,7 +3142,10 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
|||||||
if Voice then
|
if Voice then
|
||||||
self.SRS:SetVoice(Voice)
|
self.SRS:SetVoice(Voice)
|
||||||
end
|
end
|
||||||
self.SRS:SetVolume(Volume or 1.0)
|
if (not Voice) and self.SRS and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then
|
||||||
|
self.SRS.voice = MSRS.poptions["gcloud"].voice or MSRS.Voices.Google.Standard.en_US_Standard_B
|
||||||
|
end
|
||||||
|
--self.SRS:SetVolume(Volume or 1.0)
|
||||||
-- SRSQUEUE
|
-- SRSQUEUE
|
||||||
self.SRSQ = MSRSQUEUE:New("AIRBOSS")
|
self.SRSQ = MSRSQUEUE:New("AIRBOSS")
|
||||||
self.SRSQ:SetTransmitOnlyWithPlayers(true)
|
self.SRSQ:SetTransmitOnlyWithPlayers(true)
|
||||||
@@ -4643,6 +4676,26 @@ function AIRBOSS:_InitForrestal()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Init parameters for Enterprise carrier.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitEnterprise()
|
||||||
|
-- Using Forrestal as template
|
||||||
|
self:_InitForrestal()
|
||||||
|
|
||||||
|
self.carrierparam.sterndist = -164.30
|
||||||
|
self.carrierparam.deckheight = 19.52
|
||||||
|
|
||||||
|
self.carrierparam.totlength = 335
|
||||||
|
self.carrierparam.rwylength = 223
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = 57.7
|
||||||
|
self.carrierparam.wire2 = 69.6
|
||||||
|
self.carrierparam.wire3 = 79.5
|
||||||
|
self.carrierparam.wire4 = 90.0
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Init parameters for Essec class carriers.
|
--- Init parameters for Essec class carriers.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitEssex()
|
function AIRBOSS:_InitEssex()
|
||||||
@@ -4688,6 +4741,35 @@ function AIRBOSS:_InitEssex()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Init parameters for CVA-31 Bon Homme Richard carriers.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitBonHommeRichard()
|
||||||
|
-- Init Essex as default
|
||||||
|
self:_InitEssex()
|
||||||
|
|
||||||
|
self.carrierparam.deckheight = 16.95
|
||||||
|
|
||||||
|
-- Landing runway.
|
||||||
|
-- from BHR EssexRunwayAndRoutes.lua
|
||||||
|
self.carrierparam.rwyangle = -11.4
|
||||||
|
self.carrierparam.rwylength = 97
|
||||||
|
self.carrierparam.rwywidth = 20
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = 40.4 -- Distance from stern to first wire. Original from Frank - 42
|
||||||
|
self.carrierparam.wire2 = 45
|
||||||
|
self.carrierparam.wire3 = 51
|
||||||
|
self.carrierparam.wire4 = 58.1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Init parameters for Generic Essex SC125 class carriers.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitEssexSCB125()
|
||||||
|
-- Init Bon Homme Richard as default
|
||||||
|
self:_InitBonHommeRichard()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Init parameters for R12 HMS Hermes carrier.
|
--- Init parameters for R12 HMS Hermes carrier.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitHermes()
|
function AIRBOSS:_InitHermes()
|
||||||
@@ -5393,7 +5475,7 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
|
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
|
||||||
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
|
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
|
||||||
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
||||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early
|
||||||
local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW
|
local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW
|
||||||
|
|
||||||
-- Table with AoA values.
|
-- Table with AoA values.
|
||||||
@@ -5418,15 +5500,15 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5
|
aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5
|
||||||
aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14
|
aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14
|
||||||
aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13
|
aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13
|
||||||
elseif goshawk then
|
elseif goshawk then --These parameters edited by CIRCUIT to support new VNAO flight model
|
||||||
-- T-45C Goshawk parameters.
|
-- T-45C Goshawk parameters.
|
||||||
aoa.SLOW = 8.00 -- 19
|
aoa.SLOW = 9.5 -- 8.00 -- 19
|
||||||
aoa.Slow = 7.75 -- 18
|
aoa.Slow = 9.25 -- 7.75 -- 18
|
||||||
aoa.OnSpeedMax = 7.25 -- 17.5
|
aoa.OnSpeedMax = 9.0 --7.25 -- 17.5
|
||||||
aoa.OnSpeed = 7.00 -- 17
|
aoa.OnSpeed = 8.5 -- 7.00 -- 17
|
||||||
aoa.OnSpeedMin = 6.75 -- 16.5
|
aoa.OnSpeedMin = 8.25 -- 6.75 -- 16.5
|
||||||
aoa.Fast = 6.25 -- 16
|
aoa.Fast = 7.75 -- 6.25 -- 16
|
||||||
aoa.FAST = 6.00 -- 15
|
aoa.FAST = 5.5 -- 6.00 -- 15
|
||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
|
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
|
||||||
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
|
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
|
||||||
@@ -5472,7 +5554,7 @@ function AIRBOSS:_AoAUnit2Deg( playerData, aoaunits )
|
|||||||
local degrees = aoaunits
|
local degrees = aoaunits
|
||||||
|
|
||||||
-- Check aircraft type of player.
|
-- Check aircraft type of player.
|
||||||
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
|
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||||
|
|
||||||
-------------
|
-------------
|
||||||
-- F-14A/B --
|
-- F-14A/B --
|
||||||
@@ -5515,7 +5597,7 @@ function AIRBOSS:_AoADeg2Units( playerData, degrees )
|
|||||||
local aoaunits = degrees
|
local aoaunits = degrees
|
||||||
|
|
||||||
-- Check aircraft type of player.
|
-- Check aircraft type of player.
|
||||||
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
|
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||||
|
|
||||||
-------------
|
-------------
|
||||||
-- F-14A/B --
|
-- F-14A/B --
|
||||||
@@ -6870,6 +6952,9 @@ function AIRBOSS:_AddMarshalGroup( flight, stack )
|
|||||||
-- Convert to clock string.
|
-- Convert to clock string.
|
||||||
local Ccharlie = UTILS.SecondsToClock( flight.Tcharlie )
|
local Ccharlie = UTILS.SecondsToClock( flight.Tcharlie )
|
||||||
|
|
||||||
|
-- Make sure brc is never above 360
|
||||||
|
brc = brc % 360
|
||||||
|
|
||||||
-- Combined marshal call.
|
-- Combined marshal call.
|
||||||
self:_MarshalCallArrived( flight.onboard, flight.case, brc, alt, Ccharlie, P )
|
self:_MarshalCallArrived( flight.onboard, flight.case, brc, alt, Ccharlie, P )
|
||||||
|
|
||||||
@@ -7523,7 +7608,7 @@ function AIRBOSS:_InitPlayer( playerData, step )
|
|||||||
playerData.landed = false
|
playerData.landed = false
|
||||||
playerData.Tlso = timer.getTime()
|
playerData.Tlso = timer.getTime()
|
||||||
playerData.Tgroove = nil
|
playerData.Tgroove = nil
|
||||||
playerData.TIG0 = nil
|
playerData.TIG0 = 0 --changed to prevent errors in script when player is not in correct spot
|
||||||
playerData.wire = nil
|
playerData.wire = nil
|
||||||
playerData.flag = -100
|
playerData.flag = -100
|
||||||
playerData.debriefschedulerID = nil
|
playerData.debriefschedulerID = nil
|
||||||
@@ -8062,7 +8147,6 @@ end
|
|||||||
--- Check current player status.
|
--- Check current player status.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_CheckPlayerStatus()
|
function AIRBOSS:_CheckPlayerStatus()
|
||||||
|
|
||||||
-- Loop over all players.
|
-- Loop over all players.
|
||||||
for _playerName, _playerData in pairs( self.players ) do
|
for _playerName, _playerData in pairs( self.players ) do
|
||||||
local playerData = _playerData -- #AIRBOSS.PlayerData
|
local playerData = _playerData -- #AIRBOSS.PlayerData
|
||||||
@@ -8079,8 +8163,14 @@ function AIRBOSS:_CheckPlayerStatus()
|
|||||||
-- TODO: This might cause problems if the CCA is set to be very small!
|
-- TODO: This might cause problems if the CCA is set to be very small!
|
||||||
if unit:IsInZone( self.zoneCCA ) then
|
if unit:IsInZone( self.zoneCCA ) then
|
||||||
|
|
||||||
-- VNAO Edit - Added wrapped up call to LSO grading
|
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
|
||||||
if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added
|
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
|
||||||
|
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||||
|
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||||
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||||
|
|
||||||
|
-- VNAO Edit - Added wrapped up call to LSO grading Hornet
|
||||||
|
if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added
|
||||||
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
||||||
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
||||||
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
||||||
@@ -8104,6 +8194,30 @@ function AIRBOSS:_CheckPlayerStatus()
|
|||||||
end -- VNAO Edit - Added
|
end -- VNAO Edit - Added
|
||||||
end-- VNAO Edit - Added
|
end-- VNAO Edit - Added
|
||||||
|
|
||||||
|
-- VNAO Edit - Added wrapped up call to LSO grading Tomcat
|
||||||
|
if playerData.step==AIRBOSS.PatternStep.WAKE and tomcat then-- VNAO Edit - Added
|
||||||
|
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
||||||
|
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
||||||
|
playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added
|
||||||
|
playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||||
|
playerData.AAatWakeLittle = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||||
|
playerData.AAatWakeFull = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||||
|
playerData.AAatWakeUnderline = true -- VNAO Edit - Added
|
||||||
|
else -- VNAO Edit - Added
|
||||||
|
end -- VNAO Edit - Added
|
||||||
|
|
||||||
|
if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added
|
||||||
|
playerData.AFU = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added
|
||||||
|
playerData.AFU = true -- VNAO Edit - Added
|
||||||
|
else -- VNAO Edit - Added
|
||||||
|
end -- VNAO Edit - Added
|
||||||
|
end-- VNAO Edit - Added
|
||||||
|
|
||||||
-- Display aircraft attitude and other parameters as message text.
|
-- Display aircraft attitude and other parameters as message text.
|
||||||
if playerData.attitudemonitor then
|
if playerData.attitudemonitor then
|
||||||
@@ -9564,7 +9678,7 @@ end
|
|||||||
--- Break entry for case I/II recoveries.
|
--- Break entry for case I/II recoveries.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #AIRBOSS.PlayerData playerData Player data table.
|
-- @param #AIRBOSS.PlayerData playerData Player data table.
|
||||||
function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23
|
function AIRBOSS:_BreakEntry( playerData )
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
local X, Z = self:_GetDistances( playerData.unit )
|
local X, Z = self:_GetDistances( playerData.unit )
|
||||||
@@ -9575,111 +9689,16 @@ function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local stern = self:_GetSternCoord()
|
|
||||||
local coord = playerData.unit:GetCoordinate()
|
|
||||||
local dist = coord:Get2DDistance( stern )
|
|
||||||
|
|
||||||
--adam edits
|
|
||||||
local playerCallsign = playerData.unit:GetCallsign()
|
|
||||||
--trigger.action.outText(' Hornet is hook down on pre-break entry for testing hook argument ', 5)
|
|
||||||
--trigger.action.outText(' Hornet callsign is '..playerCallsign, 5)
|
|
||||||
local playerName = playerData.name
|
|
||||||
local unit = playerData.unit
|
|
||||||
|
|
||||||
--local playerName = unit:GetName()
|
|
||||||
--trigger.action.outText(' Hornet name is '..playerName, 5)
|
|
||||||
local unitClient = Unit.getByName(unit:GetName())
|
|
||||||
local hookArgument = unitClient:getDrawArgumentValue(25)
|
|
||||||
local hookArgument_Tomcat = unitClient:getDrawArgumentValue(1305)
|
|
||||||
local speedMPS = playerData.unit:GetVelocityMPS()
|
|
||||||
local speedKTS = UTILS.MpsToKnots( speedMPS )
|
|
||||||
local player_alt = playerData.unit:GetAltitude()
|
|
||||||
|
|
||||||
player_alt_feet = player_alt * 3.28
|
|
||||||
player_alt_feet = player_alt_feet/10
|
|
||||||
player_alt_feet = math.floor(player_alt_feet)*10
|
|
||||||
|
|
||||||
local player_velocity_round = speedKTS * 1.00
|
|
||||||
player_velocity_round = player_velocity_round/10
|
|
||||||
player_velocity_round = math.floor(player_velocity_round)*10
|
|
||||||
|
|
||||||
local player_alt_feet = player_alt * 3.28
|
|
||||||
player_alt_feet = player_alt_feet/10
|
|
||||||
player_alt_feet = math.floor(player_alt_feet)*10
|
|
||||||
|
|
||||||
local Play_SH_Sound = USERSOUND:New( "Airboss Soundfiles/GreatBallsOfFire.ogg" )
|
|
||||||
local Play_666SH_Sound = USERSOUND:New( "Airboss Soundfiles/Runninwiththedevil.ogg" )
|
|
||||||
local playerType = playerData.actype
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if dist <1000 and clientSHBFlag == false then
|
|
||||||
|
|
||||||
if speedKTS > 450 and speedKTS < 590 then
|
|
||||||
if player_alt_feet < 1500 then
|
|
||||||
if hookArgument > 0 or hookArgument_Tomcat > 0 then
|
|
||||||
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = true
|
|
||||||
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10)
|
|
||||||
local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
|
||||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
|
||||||
Play_SH_Sound:ToAll()
|
|
||||||
clientSHBFlag = true
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = false
|
|
||||||
end
|
|
||||||
-- Next step: Early Break.
|
|
||||||
else
|
|
||||||
end
|
|
||||||
elseif speedKTS > 589 then
|
|
||||||
if player_alt_feet < 625 and player_alt_feet >575 then --SHB 666
|
|
||||||
if hookArgument > 0 or hookArgument_Tomcat > 0 then
|
|
||||||
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = true
|
|
||||||
trigger.action.outText(playerName..' performing a 666 Sierra Hotel Break in a '..playerType, 10)
|
|
||||||
local sh_message_to_discord = ('**'..playerName..' is performing a 666 Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
|
||||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
|
||||||
Play_666SH_Sound:ToAll()
|
|
||||||
clientSHBFlag = true
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = false
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if hookArgument > 0 or hookArgument_Tomcat > 0 then
|
|
||||||
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = true
|
|
||||||
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10)
|
|
||||||
local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
|
||||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
|
||||||
Play_SH_Sound:ToAll()
|
|
||||||
clientSHBFlag = true
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is less than 400 kts so not SHB.... ', 5)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' ******TEST OF of Break Entry and distance to CVN is: '..dist, 5)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Check if we are in front of the boat (diffX > 0).
|
-- Check if we are in front of the boat (diffX > 0).
|
||||||
if self:_CheckLimits( X, Z, self.BreakEntry ) then
|
if self:_CheckLimits( X, Z, self.BreakEntry ) then
|
||||||
--trigger.action.outText(' 2 - Hornet is hook down on break entry for testing hook argument ', 5)
|
|
||||||
|
|
||||||
-- Hint for player about altitude, AoA etc.
|
-- Hint for player about altitude, AoA etc.
|
||||||
self:_PlayerHint( playerData )
|
self:_PlayerHint( playerData )
|
||||||
|
-- Next step: Early Break.
|
||||||
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK )
|
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK )
|
||||||
clientSHBFlag = false
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end--Adam Edits end 7/24/23
|
end
|
||||||
|
|
||||||
--- Break.
|
--- Break.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
@@ -11576,7 +11595,7 @@ function AIRBOSS:_AttitudeMonitor( playerData )
|
|||||||
|
|
||||||
local unitClient = Unit.getByName(unit:GetName()) -- VNAO Edit - Added
|
local unitClient = Unit.getByName(unit:GetName()) -- VNAO Edit - Added
|
||||||
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET -- VNAO Edit - Added
|
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET -- VNAO Edit - Added
|
||||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B -- VNAO Edit - Added
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early -- VNAO Edit - Added
|
||||||
|
|
||||||
if hornet then -- VNAO Edit - Added
|
if hornet then -- VNAO Edit - Added
|
||||||
local nozzlePosL = 0 -- VNAO Edit - Added
|
local nozzlePosL = 0 -- VNAO Edit - Added
|
||||||
@@ -11809,7 +11828,7 @@ function AIRBOSS:_NozzleArgumentLeft( unit ) -- VNAO Edit - Added
|
|||||||
else -- VNAO Edit - Added
|
else -- VNAO Edit - Added
|
||||||
nozzlePosL = 0 -- VNAO Edit - Added
|
nozzlePosL = 0 -- VNAO Edit - Added
|
||||||
end -- VNAO Edit - Added
|
end -- VNAO Edit - Added
|
||||||
elseif typeName == "F-14A-135-GR" or typeName == "F-14B" then -- VNAO Edit - Added
|
elseif typeName == "F-14A-135-GR" or typeName == "F-14B" or typeName == "F-14A-135-GR-Early" then -- VNAO Edit - Added
|
||||||
nozzlePosL = unitClient:getDrawArgumentValue(434) -- VNAO Edit - Added
|
nozzlePosL = unitClient:getDrawArgumentValue(434) -- VNAO Edit - Added
|
||||||
end -- VNAO Edit - Added
|
end -- VNAO Edit - Added
|
||||||
|
|
||||||
@@ -11834,7 +11853,7 @@ function AIRBOSS:_NozzleArgumentRight( unit ) -- VNAO Edit - Added
|
|||||||
else -- VNAO Edit - Added
|
else -- VNAO Edit - Added
|
||||||
nozzlePosR = 0 -- VNAO Edit - Added
|
nozzlePosR = 0 -- VNAO Edit - Added
|
||||||
end -- VNAO Edit - Added
|
end -- VNAO Edit - Added
|
||||||
elseif typeName == "F-14A-135-GR" or typeName == "F-14B" then -- VNAO Edit - Added
|
elseif typeName == "F-14A-135-GR" or typeName == "F-14B" or typeName == "F-14A-135-GR-Early" then -- VNAO Edit - Added
|
||||||
nozzlePosR = unitClient:getDrawArgumentValue(433) -- VNAO Edit - Added
|
nozzlePosR = unitClient:getDrawArgumentValue(433) -- VNAO Edit - Added
|
||||||
end -- VNAO Edit - Added
|
end -- VNAO Edit - Added
|
||||||
return nozzlePosR -- VNAO Edit - Added
|
return nozzlePosR -- VNAO Edit - Added
|
||||||
@@ -11971,10 +11990,12 @@ function AIRBOSS:GetHeading( magnetic )
|
|||||||
hdg = hdg - self.magvar
|
hdg = hdg - self.magvar
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Adjust negative values.
|
-- -- Adjust negative values.
|
||||||
if hdg < 0 then
|
-- if hdg < 0 then
|
||||||
hdg = hdg + 360
|
-- hdg = hdg + 360
|
||||||
end
|
-- end
|
||||||
|
|
||||||
|
hdg = hdg % 360 -- using this to replace the above function to prevent negative values and BRC higher than 360
|
||||||
|
|
||||||
return hdg
|
return hdg
|
||||||
end
|
end
|
||||||
@@ -12240,8 +12261,8 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord )
|
|||||||
local magvar= magnetic and self.magvar or 0
|
local magvar= magnetic and self.magvar or 0
|
||||||
|
|
||||||
-- Ship heading so cross wind is min for the given wind.
|
-- Ship heading so cross wind is min for the given wind.
|
||||||
-- local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 -- VNAO Edit: Using old heading into wind algorithm
|
local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360
|
||||||
local intowind = self:GetHeadingIntoWind_old(vdeck) -- VNAO Edit: Using old heading into wind algorithm
|
|
||||||
|
|
||||||
return intowind, v
|
return intowind, v
|
||||||
end
|
end
|
||||||
@@ -12671,7 +12692,7 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
local TIG = ""
|
local TIG = ""
|
||||||
-- Analyse flight data and convert to LSO text.
|
-- Analyse flight data and convert to LSO text.
|
||||||
if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added
|
if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added
|
||||||
TIG = self:_EvalGrooveTime( playerData ) --Circuit Added
|
TIG = self:_EvalGrooveTime( playerData ) or "N/A" --Circuit Added
|
||||||
end --Circuit Added
|
end --Circuit Added
|
||||||
local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX )
|
local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX )
|
||||||
local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM )
|
local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM )
|
||||||
@@ -12694,6 +12715,7 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
local nS=count(G, '%(')
|
local nS=count(G, '%(')
|
||||||
local nN=N-nS-nL
|
local nN=N-nS-nL
|
||||||
|
|
||||||
|
if TIG=="_OK_" then nL = nL -1 end --Circuit added to prevent grade deduction for perfect groove
|
||||||
|
|
||||||
-- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn.
|
-- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn.
|
||||||
local Tgroove=playerData.Tgroove
|
local Tgroove=playerData.Tgroove
|
||||||
@@ -12723,7 +12745,6 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
else
|
else
|
||||||
|
|
||||||
if vtol then
|
if vtol then
|
||||||
|
|
||||||
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe.--Pene testing
|
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe.--Pene testing
|
||||||
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
||||||
|
|
||||||
@@ -12865,16 +12886,21 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore.
|
-- -- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore.
|
||||||
if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added
|
-- if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added
|
||||||
if points == 4 then -- VNAO EDIT: added
|
-- if points == 4 then -- VNAO EDIT: added
|
||||||
points = 3 -- VNAO EDIT: added
|
-- points = 3 -- VNAO EDIT: added
|
||||||
grade = "(OK)" -- VNAO EDIT: added
|
-- grade = "(OK)" -- VNAO EDIT: added
|
||||||
elseif points == 3 then -- VNAO EDIT: added
|
-- elseif points == 3 then -- VNAO EDIT: added
|
||||||
points = 2 -- VNAO EDIT: added
|
-- points = 2 -- VNAO EDIT: added
|
||||||
grade = "--" -- VNAO EDIT: added
|
-- grade = "--" -- VNAO EDIT: added
|
||||||
end -- VNAO EDIT: added
|
-- end -- VNAO EDIT: added
|
||||||
end -- VNAO EDIT: added
|
-- end -- VNAO EDIT: added
|
||||||
|
|
||||||
|
-- Circuit edit only take points awary from a 1 wire if there are more than 4 other deviations
|
||||||
|
if playerData.wire == 1 and points >= 3 and N > 4 then
|
||||||
|
points = points -1
|
||||||
|
end
|
||||||
|
|
||||||
env.info("Returning: " .. grade .. " " .. points .. " " .. G)
|
env.info("Returning: " .. grade .. " " .. points .. " " .. G)
|
||||||
|
|
||||||
@@ -12950,6 +12976,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
|
|||||||
|
|
||||||
-- Speed via AoA. Depends on aircraft type.
|
-- Speed via AoA. Depends on aircraft type.
|
||||||
local S = nil
|
local S = nil
|
||||||
|
local A = nil --circuit moved this line to be seen outside of this scope
|
||||||
if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires
|
if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires
|
||||||
if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added
|
if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added
|
||||||
-- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added
|
-- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added
|
||||||
@@ -12970,7 +12997,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Glideslope/altitude. Good [-0.3, 0.4] asymmetric!
|
-- Glideslope/altitude. Good [-0.3, 0.4] asymmetric!
|
||||||
local A = nil
|
|
||||||
if GSE > self.gle.HIGH then
|
if GSE > self.gle.HIGH then
|
||||||
A = underline( "H" )
|
A = underline( "H" )
|
||||||
elseif GSE > self.gle.High then
|
elseif GSE > self.gle.High then
|
||||||
@@ -15041,7 +15068,7 @@ function AIRBOSS:_GetACNickname( actype )
|
|||||||
nickname = "Hawkeye"
|
nickname = "Hawkeye"
|
||||||
elseif actype == AIRBOSS.AircraftCarrier.C2A then
|
elseif actype == AIRBOSS.AircraftCarrier.C2A then
|
||||||
nickname = "Greyhound"
|
nickname = "Greyhound"
|
||||||
elseif actype == AIRBOSS.AircraftCarrier.F14A_AI or actype == AIRBOSS.AircraftCarrier.F14A or actype == AIRBOSS.AircraftCarrier.F14B then
|
elseif actype == AIRBOSS.AircraftCarrier.F14A_AI or actype == AIRBOSS.AircraftCarrier.F14A or actype == AIRBOSS.AircraftCarrier.F14B or actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||||
nickname = "Tomcat"
|
nickname = "Tomcat"
|
||||||
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
|
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
|
||||||
nickname = "Hornet"
|
nickname = "Hornet"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
-- @image OPS_CSAR.jpg
|
-- @image OPS_CSAR.jpg
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Last Update May 2025
|
-- Last Update Oct 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
@@ -305,6 +305,7 @@ CSAR.AircraftType["Mi-24P"] = 8
|
|||||||
CSAR.AircraftType["Mi-24V"] = 8
|
CSAR.AircraftType["Mi-24V"] = 8
|
||||||
CSAR.AircraftType["Bell-47"] = 2
|
CSAR.AircraftType["Bell-47"] = 2
|
||||||
CSAR.AircraftType["UH-60L"] = 10
|
CSAR.AircraftType["UH-60L"] = 10
|
||||||
|
CSAR.AircraftType["UH-60L_DAP"] = 2
|
||||||
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.AircraftType["MH-60R"] = 10
|
||||||
@@ -314,7 +315,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31
|
|||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.33"
|
CSAR.version="1.0.34"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -1149,11 +1150,11 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
local initdcscoord = nil
|
local initdcscoord = nil
|
||||||
local initcoord = nil
|
local initcoord = nil
|
||||||
if _event.id == EVENTS.Ejection then
|
if _event.id == EVENTS.Ejection and _event.TgtDCSUnit then
|
||||||
initdcscoord = _event.TgtDCSUnit:getPoint()
|
initdcscoord = _event.TgtDCSUnit:getPoint()
|
||||||
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
||||||
self:T({initdcscoord})
|
self:T({initdcscoord})
|
||||||
else
|
elseif _event.IniDCSUnit then
|
||||||
initdcscoord = _event.IniDCSUnit:getPoint()
|
initdcscoord = _event.IniDCSUnit:getPoint()
|
||||||
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
||||||
self:T({initdcscoord})
|
self:T({initdcscoord})
|
||||||
@@ -1199,7 +1200,7 @@ function CSAR:_EventHandler(EventData)
|
|||||||
-- all checks passed, get going.
|
-- all checks passed, get going.
|
||||||
if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land
|
if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land
|
||||||
local _freq = self:_GenerateADFFrequency()
|
local _freq = self:_GenerateADFFrequency()
|
||||||
self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
|
self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, self.suppressmessages, "none")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1243,7 +1244,10 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
||||||
self:__Landed(2,_event.IniUnitName, _place)
|
self:__Landed(2,_event.IniUnitName, _place)
|
||||||
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true)
|
local IsHeloBase = false
|
||||||
|
local ABName = _place:GetName()
|
||||||
|
if ABName and string.find(ABName,"^H") then IsHeloBase = true end -- if name starts with an H it's an (possibly elevated) helo base on current maps
|
||||||
|
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true,IsHeloBase)
|
||||||
else
|
else
|
||||||
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
||||||
end
|
end
|
||||||
@@ -1264,7 +1268,7 @@ function CSAR:_EventHandler(EventData)
|
|||||||
if _coalition == self.coalition then
|
if _coalition == self.coalition then
|
||||||
local _freq = self:_GenerateADFFrequency()
|
local _freq = self:_GenerateADFFrequency()
|
||||||
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
|
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
|
||||||
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location.
|
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, self.suppressmessages, "none")--shagrat add CSAR at Parachute location.
|
||||||
|
|
||||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||||
end
|
end
|
||||||
@@ -1730,8 +1734,9 @@ end
|
|||||||
-- @param #string heliname Heli name
|
-- @param #string heliname Heli name
|
||||||
-- @param #string groupname Group name
|
-- @param #string groupname Group name
|
||||||
-- @param #boolean isairport If true, EVENT.Landing took place at an airport or FARP
|
-- @param #boolean isairport If true, EVENT.Landing took place at an airport or FARP
|
||||||
-- @param #boolean noreschedule If true, do not try to reschedule this is distances are not ok (coming from landing event)
|
-- @param #boolean noreschedule If true, do not try to reschedule this if distances are not ok (coming from landing event)
|
||||||
function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
|
-- @param #boolean IsHeloBase If true, landing took place at a Helo Base (name "H ..." on current maps)
|
||||||
|
function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule, IsHeloBase)
|
||||||
self:T(self.lid .. " _ScheduledSARFlight")
|
self:T(self.lid .. " _ScheduledSARFlight")
|
||||||
self:T({heliname,groupname})
|
self:T({heliname,groupname})
|
||||||
local _heliUnit = self:_GetSARHeli(heliname)
|
local _heliUnit = self:_GetSARHeli(heliname)
|
||||||
@@ -1757,7 +1762,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
|
|||||||
|
|
||||||
self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
|
self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
|
||||||
|
|
||||||
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
|
if ( _dist < self.FARPRescueDistance or isairport ) and ((_heliUnit:InAir() == false) or (IsHeloBase == true)) then
|
||||||
self:T(self.lid.."[Drop off debug] Distance ok, door check")
|
self:T(self.lid.."[Drop off debug] Distance ok, door check")
|
||||||
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
|
||||||
@@ -1772,7 +1777,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
|
|||||||
--queue up
|
--queue up
|
||||||
if not noreschedule then
|
if not noreschedule then
|
||||||
self:__Returning(5,heliname,_woundedGroupName, isairport)
|
self:__Returning(5,heliname,_woundedGroupName, isairport)
|
||||||
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule)
|
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule, IsHeloBase)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -3006,7 +3011,7 @@ function CSAR:onafterLoad(From, Event, To, path, filename)
|
|||||||
local unitName = dataset[9]
|
local unitName = dataset[9]
|
||||||
local freq = tonumber(dataset[10])
|
local freq = tonumber(dataset[10])
|
||||||
|
|
||||||
self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, nil, description, nil)
|
self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, false, description, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -72,7 +72,7 @@ end
|
|||||||
|
|
||||||
--- Checks if a point is contained within the circle.
|
--- Checks if a point is contained within the circle.
|
||||||
-- @param #table point The point to check
|
-- @param #table point The point to check
|
||||||
-- @return #bool True if the point is contained, false otherwise
|
-- @return #boolean True if the point is contained, false otherwise
|
||||||
function CIRCLE:ContainsPoint(point)
|
function CIRCLE:ContainsPoint(point)
|
||||||
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
||||||
return true
|
return true
|
||||||
@@ -226,6 +226,11 @@ end
|
|||||||
--- Returns a random Vec2 within the circle.
|
--- Returns a random Vec2 within the circle.
|
||||||
-- @return #table The random Vec2
|
-- @return #table The random Vec2
|
||||||
function CIRCLE:GetRandomVec2()
|
function CIRCLE:GetRandomVec2()
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
local angle = math.random() * 2 * math.pi
|
local angle = math.random() * 2 * math.pi
|
||||||
|
|
||||||
local rx = math.random(0, self.Radius) * math.cos(angle) + self.CenterVec2.x
|
local rx = math.random(0, self.Radius) * math.cos(angle) + self.CenterVec2.x
|
||||||
@@ -237,6 +242,11 @@ end
|
|||||||
--- Returns a random Vec2 on the border of the circle.
|
--- Returns a random Vec2 on the border of the circle.
|
||||||
-- @return #table The random Vec2
|
-- @return #table The random Vec2
|
||||||
function CIRCLE:GetRandomVec2OnBorder()
|
function CIRCLE:GetRandomVec2OnBorder()
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
local angle = math.random() * 2 * math.pi
|
local angle = math.random() * 2 * math.pi
|
||||||
|
|
||||||
local rx = self.Radius * math.cos(angle) + self.CenterVec2.x
|
local rx = self.Radius * math.cos(angle) + self.CenterVec2.x
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ end
|
|||||||
--- Returns a random Vec2 within the polygon. The Vec2 is weighted by the areas of the triangles that make up the polygon.
|
--- Returns a random Vec2 within the polygon. The Vec2 is weighted by the areas of the triangles that make up the polygon.
|
||||||
-- @return #table The random Vec2
|
-- @return #table The random Vec2
|
||||||
function POLYGON:GetRandomVec2()
|
function POLYGON:GetRandomVec2()
|
||||||
|
|
||||||
local weights = {}
|
local weights = {}
|
||||||
for _, triangle in pairs(self.Triangles) do
|
for _, triangle in pairs(self.Triangles) do
|
||||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ end
|
|||||||
-- @param #table points The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
-- @param #table points The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
||||||
-- @return #table The random Vec2
|
-- @return #table The random Vec2
|
||||||
function TRIANGLE:GetRandomVec2(points)
|
function TRIANGLE:GetRandomVec2(points)
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
points = points or self.Points
|
points = points or self.Points
|
||||||
local pt = {math.random(), math.random()}
|
local pt = {math.random(), math.random()}
|
||||||
table.sort(pt)
|
table.sort(pt)
|
||||||
|
|||||||
@@ -443,28 +443,32 @@ MSRS.Voices = {
|
|||||||
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
||||||
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
||||||
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
||||||
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE
|
-- IN
|
||||||
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE
|
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- Female
|
||||||
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE
|
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- Male
|
||||||
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE
|
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- Male
|
||||||
|
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- Female
|
||||||
|
["en_IN_Standard_E"] = 'en-IN-Standard-E', -- Female
|
||||||
|
["en_IN_Standard_F"] = 'en-IN-Standard-F', -- Male
|
||||||
-- 2025 changes
|
-- 2025 changes
|
||||||
["en_GB_Standard_A"] = 'en-GB-Standard-N', -- [9] FEMALE
|
["en_GB_Standard_A"] = 'en-GB-Standard-A', -- Female
|
||||||
["en_GB_Standard_B"] = 'en-GB-Standard-O', -- [10] MALE
|
["en_GB_Standard_B"] = 'en-GB-Standard-B', -- Male
|
||||||
["en_GB_Standard_C"] = 'en-GB-Standard-N', -- [11] FEMALE
|
["en_GB_Standard_C"] = 'en-GB-Standard-C', -- Female
|
||||||
["en_GB_Standard_D"] = 'en-GB-Standard-O', -- [12] MALE
|
["en_GB_Standard_D"] = 'en-GB-Standard-D', -- Male
|
||||||
["en_GB_Standard_F"] = 'en-GB-Standard-N', -- [13] FEMALE
|
["en_GB_Standard_F"] = 'en-GB-Standard-F', -- Female
|
||||||
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- [12] MALE
|
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- Female
|
||||||
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- [13] FEMALE
|
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- Male
|
||||||
["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE
|
-- US
|
||||||
["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE
|
["en_US_Standard_A"] = 'en-US-Standard-A', -- Male
|
||||||
["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE
|
["en_US_Standard_B"] = 'en-US-Standard-B', -- Male
|
||||||
["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE
|
["en_US_Standard_C"] = 'en-US-Standard-C', -- Female
|
||||||
["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE
|
["en_US_Standard_D"] = 'en-US-Standard-D', -- Male
|
||||||
["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE
|
["en_US_Standard_E"] = 'en-US-Standard-E', -- Female
|
||||||
["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE
|
["en_US_Standard_F"] = 'en-US-Standard-F', -- Female
|
||||||
["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE
|
["en_US_Standard_G"] = 'en-US-Standard-G', -- Female
|
||||||
["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE
|
["en_US_Standard_H"] = 'en-US-Standard-H', -- Female
|
||||||
["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE
|
["en_US_Standard_I"] = 'en-US-Standard-I', -- Male
|
||||||
|
["en_US_Standard_J"] = 'en-US-Standard-J', -- Male
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female
|
["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female
|
||||||
["fr_FR_Standard_B"] = "fr-FR-Standard-G", -- Male
|
["fr_FR_Standard_B"] = "fr-FR-Standard-G", -- Male
|
||||||
@@ -474,14 +478,15 @@ MSRS.Voices = {
|
|||||||
["fr_FR_Standard_G"] = "fr-FR-Standard-G", -- Male
|
["fr_FR_Standard_G"] = "fr-FR-Standard-G", -- Male
|
||||||
["fr_FR_Standard_F"] = "fr-FR-Standard-F", -- Female
|
["fr_FR_Standard_F"] = "fr-FR-Standard-F", -- Female
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["de_DE_Standard_A"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_A"] = 'de-DE-Standard-A', -- Female
|
||||||
["de_DE_Standard_B"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_B"] = 'de-DE-Standard-B', -- Male
|
||||||
["de_DE_Standard_C"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_C"] = 'de-DE-Standard-C', -- Female
|
||||||
["de_DE_Standard_D"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_D"] = 'de-DE-Standard-D', -- Male
|
||||||
["de_DE_Standard_E"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_E"] = 'de-DE-Standard-E', -- Male
|
||||||
["de_DE_Standard_F"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_F"] = 'de-DE-Standard-F', -- Female
|
||||||
["de_DE_Standard_H"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_G"] = 'de-DE-Standard-G', -- Female
|
||||||
["de_DE_Standard_G"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_H"] = 'de-DE-Standard-H', -- Male
|
||||||
|
-- ES
|
||||||
["es_ES_Standard_A"] = "es-ES-Standard-E", -- Female
|
["es_ES_Standard_A"] = "es-ES-Standard-E", -- Female
|
||||||
["es_ES_Standard_B"] = "es-ES-Standard-F", -- Male
|
["es_ES_Standard_B"] = "es-ES-Standard-F", -- Male
|
||||||
["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female
|
["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female
|
||||||
@@ -497,32 +502,36 @@ MSRS.Voices = {
|
|||||||
["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male
|
["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male
|
||||||
},
|
},
|
||||||
Wavenet = {
|
Wavenet = {
|
||||||
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
|
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- Female
|
||||||
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE
|
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- Male
|
||||||
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
|
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- Female
|
||||||
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE
|
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- Male
|
||||||
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
|
-- IN
|
||||||
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE
|
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- Female
|
||||||
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE
|
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- Male
|
||||||
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
|
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- Male
|
||||||
|
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- Female
|
||||||
|
["en_IN_Wavenet_E"] = 'en-IN-Wavenet-E', -- Female
|
||||||
|
["en_IN_Wavenet_F"] = 'en-IN-Wavenet-F', -- Male
|
||||||
-- 2025 changes
|
-- 2025 changes
|
||||||
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-N', -- [9] FEMALE
|
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
|
||||||
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-O', -- [10] MALE
|
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE
|
||||||
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-N', -- [11] FEMALE
|
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
|
||||||
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-O', -- [12] MALE
|
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE
|
||||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
|
||||||
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
|
-- US
|
||||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- Male
|
||||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- Male
|
||||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- Female
|
||||||
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE
|
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- Male
|
||||||
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE
|
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- Female
|
||||||
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE
|
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- Female
|
||||||
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE
|
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- Female
|
||||||
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE
|
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- Female
|
||||||
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE
|
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- Male
|
||||||
|
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- Male
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female
|
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female
|
||||||
["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-G", -- Male
|
["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-G", -- Male
|
||||||
@@ -532,14 +541,15 @@ MSRS.Voices = {
|
|||||||
["fr_FR_Wavenet_G"] = "fr-FR-Wavenet-G", -- Male
|
["fr_FR_Wavenet_G"] = "fr-FR-Wavenet-G", -- Male
|
||||||
["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female
|
["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["de_DE_Wavenet_A"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female
|
||||||
["de_DE_Wavenet_B"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male
|
||||||
["de_DE_Wavenet_C"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female
|
||||||
["de_DE_Wavenet_D"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male
|
||||||
["de_DE_Wavenet_E"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male
|
||||||
["de_DE_Wavenet_F"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- Female
|
||||||
["de_DE_Wavenet_H"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_G"] = 'de-DE-Wavenet-G', -- Female
|
||||||
["de_DE_Wavenet_G"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_H"] = 'de-DE-Wavenet-H', -- Male
|
||||||
|
-- ES
|
||||||
["es_ES_Wavenet_B"] = "es-ES-Wavenet-E", -- Male
|
["es_ES_Wavenet_B"] = "es-ES-Wavenet-E", -- Male
|
||||||
["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female
|
["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female
|
||||||
["es_ES_Wavenet_D"] = "es-ES-Wavenet-E", -- Female
|
["es_ES_Wavenet_D"] = "es-ES-Wavenet-E", -- Female
|
||||||
@@ -553,6 +563,134 @@ MSRS.Voices = {
|
|||||||
["it_IT_Wavenet_E"] = "it-IT-Wavenet-E", -- Female
|
["it_IT_Wavenet_E"] = "it-IT-Wavenet-E", -- Female
|
||||||
["it_IT_Wavenet_F"] = "it-IT-Wavenet-F", -- Male
|
["it_IT_Wavenet_F"] = "it-IT-Wavenet-F", -- Male
|
||||||
} ,
|
} ,
|
||||||
|
Chirp3HD = {
|
||||||
|
["en_GB_Chirp3_HD_Aoede"] = 'en-GB-Chirp3-HD-Aoede', -- Female
|
||||||
|
["en_GB_Chirp3_HD_Charon"] = 'en-GB-Chirp3-HD-Charon', -- Male
|
||||||
|
["en_GB_Chirp3_HD_Fenrir"] = 'en-GB-Chirp3-HD-Fenrir', -- Male
|
||||||
|
["en_GB_Chirp3_HD_Kore"] = 'en-GB-Chirp3-HD-Kore', -- Female
|
||||||
|
["en_GB_Chirp3_HD_Leda"] = 'en-GB-Chirp3-HD-Leda', -- Female
|
||||||
|
["en_GB_Chirp3_HD_Orus"] = 'en-GB-Chirp3-HD-Orus', -- Male
|
||||||
|
["en_GB_Chirp3_HD_Puck"] = 'en-GB-Chirp3-HD-Puck', -- Male
|
||||||
|
["en_GB_Chirp3_HD_Zephyr"] = 'en-GB-Chirp3-HD-Zephyr', -- Female
|
||||||
|
--["de_DE_Chirp3_HD_Aoede"] = 'de-DE-Chirp3-HD-Aoede', -- Female (Datenfehler im Original)
|
||||||
|
["en_US_Chirp3_HD_Charon"] = 'en-US-Chirp3-HD-Charon', -- Male
|
||||||
|
["en_US_Chirp3_HD_Fenrir"] = 'en-US-Chirp3-HD-Fenrir', -- Male
|
||||||
|
["en_US_Chirp3_HD_Kore"] = 'en-US-Chirp3-HD-Kore', -- Female
|
||||||
|
["en_US_Chirp3_HD_Leda"] = 'en-US-Chirp3-HD-Leda', -- Female
|
||||||
|
["en_US_Chirp3_HD_Orus"] = 'en-US-Chirp3-HD-Orus', -- Male
|
||||||
|
["en_US_Chirp3_HD_Puck"] = 'en-US-Chirp3-HD-Puck', -- Male
|
||||||
|
--["de_DE_Chirp3_HD_Zephyr"] = 'de-DE-Chirp3-HD-Zephyr', -- Female (Datenfehler im Original)
|
||||||
|
-- DE
|
||||||
|
["de_DE_Chirp3_HD_Aoede"] = 'de-DE-Chirp3-HD-Aoede', -- Female
|
||||||
|
["de_DE_Chirp3_HD_Charon"] = 'de-DE-Chirp3-HD-Charon', -- Male
|
||||||
|
["de_DE_Chirp3_HD_Fenrir"] = 'de-DE-Chirp3-HD-Fenrir', -- Male
|
||||||
|
["de_DE_Chirp3_HD_Kore"] = 'de-DE-Chirp3-HD-Kore', -- Female
|
||||||
|
["de_DE_Chirp3_HD_Leda"] = 'de-DE-Chirp3-HD-Leda', -- Female
|
||||||
|
["de_DE_Chirp3_HD_Orus"] = 'de-DE-Chirp3-HD-Orus', -- Male
|
||||||
|
["de_DE_Chirp3_HD_Puck"] = 'de-DE-Chirp3-HD-Puck', -- Male
|
||||||
|
["de_DE_Chirp3_HD_Zephyr"] = 'de-DE-Chirp3-HD-Zephyr', -- Female
|
||||||
|
-- AU
|
||||||
|
["en_AU_Chirp3_HD_Aoede"] = 'en-AU-Chirp3-HD-Aoede', -- Female
|
||||||
|
["en_AU_Chirp3_HD_Charon"] = 'en-AU-Chirp3-HD-Charon', -- Male
|
||||||
|
["en_AU_Chirp3_HD_Fenrir"] = 'en-AU-Chirp3-HD-Fenrir', -- Male
|
||||||
|
["en_AU_Chirp3_HD_Kore"] = 'en-AU-Chirp3-HD-Kore', -- Female
|
||||||
|
["en_AU_Chirp3_HD_Leda"] = 'en-AU-Chirp3-HD-Leda', -- Female
|
||||||
|
["en_AU_Chirp3_HD_Orus"] = 'en-AU-Chirp3-HD-Orus', -- Male
|
||||||
|
["en_AU_Chirp3_HD_Puck"] = 'en-AU-Chirp3-HD-Puck', -- Male
|
||||||
|
["en_AU_Chirp3_HD_Zephyr"] = 'en-AU-Chirp3-HD-Zephyr', -- Female
|
||||||
|
-- IN
|
||||||
|
["en_IN_Chirp3_HD_Aoede"] = 'en-IN-Chirp3-HD-Aoede', -- Female
|
||||||
|
["en_IN_Chirp3_HD_Charon"] = 'en-IN-Chirp3-HD-Charon', -- Male
|
||||||
|
["en_IN_Chirp3_HD_Fenrir"] = 'en-IN-Chirp3-HD-Fenrir', -- Male
|
||||||
|
["en_IN_Chirp3_HD_Kore"] = 'en-IN-Chirp3-HD-Kore', -- Female
|
||||||
|
["en_IN_Chirp3_HD_Leda"] = 'en-IN-Chirp3-HD-Leda', -- Female
|
||||||
|
["en_IN_Chirp3_HD_Orus"] = 'en-IN-Chirp3-HD-Orus', -- Male
|
||||||
|
},
|
||||||
|
ChirpHD = {
|
||||||
|
["en_US_Chirp_HD_D"] = 'en-US-Chirp-HD-D', -- Male
|
||||||
|
["en_US_Chirp_HD_F"] = 'en-US-Chirp-HD-F', -- Female
|
||||||
|
["en_US_Chirp_HD_O"] = 'en-US-Chirp-HD-O', -- Female
|
||||||
|
-- DE
|
||||||
|
["de_DE_Chirp_HD_D"] = 'de-DE-Chirp-HD-D', -- Male
|
||||||
|
["de_DE_Chirp_HD_F"] = 'de-DE-Chirp-HD-F', -- Female
|
||||||
|
["de_DE_Chirp_HD_O"] = 'de-DE-Chirp-HD-O', -- Female
|
||||||
|
-- AU
|
||||||
|
["en_AU_Chirp_HD_D"] = 'en-AU-Chirp-HD-D', -- Male
|
||||||
|
["en_AU_Chirp_HD_F"] = 'en-AU-Chirp-HD-F', -- Female
|
||||||
|
["en_AU_Chirp_HD_O"] = 'en-AU-Chirp-HD-O', -- Female
|
||||||
|
-- IN
|
||||||
|
["en_IN_Chirp_HD_D"] = 'en-IN-Chirp-HD-D', -- Male
|
||||||
|
["en_IN_Chirp_HD_F"] = 'en-IN-Chirp-HD-F', -- Female
|
||||||
|
["en_IN_Chirp_HD_O"] = 'en-IN-Chirp-HD-O', -- Female
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Neural2 = {
|
||||||
|
["en_GB_Neural2_A"] = 'en-GB-Neural2-A', -- Female
|
||||||
|
["en_GB_Neural2_B"] = 'en-GB-Neural2-B', -- Male
|
||||||
|
["en_GB_Neural2_C"] = 'en-GB-Neural2-C', -- Female
|
||||||
|
["en_GB_Neural2_D"] = 'en-GB-Neural2-D', -- Male
|
||||||
|
["en_GB_Neural2_F"] = 'en-GB-Neural2-F', -- Female
|
||||||
|
["en_GB_Neural2_N"] = 'en-GB-Neural2-N', -- Female
|
||||||
|
["en_GB_Neural2_O"] = 'en-GB-Neural2-O', -- Male
|
||||||
|
-- US
|
||||||
|
["en_US_Neural2_A"] = 'en-US-Neural2-A', -- Male
|
||||||
|
["en_US_Neural2_C"] = 'en-US-Neural2-C', -- Female
|
||||||
|
["en_US_Neural2_D"] = 'en-US-Neural2-D', -- Male
|
||||||
|
["en_US_Neural2_E"] = 'en-US-Neural2-E', -- Female
|
||||||
|
["en_US_Neural2_F"] = 'en-US-Neural2-F', -- Female
|
||||||
|
["en_US_Neural2_G"] = 'en-US-Neural2-G', -- Female
|
||||||
|
["en_US_Neural2_H"] = 'en-US-Neural2-H', -- Female
|
||||||
|
["en_US_Neural2_I"] = 'en-US-Neural2-I', -- Male
|
||||||
|
["en_US_Neural2_J"] = 'en-US-Neural2-J', -- Male
|
||||||
|
-- DE
|
||||||
|
["de_DE_Neural2_G"] = 'de-DE-Neural2-G', -- Female
|
||||||
|
["de_DE_Neural2_H"] = 'de-DE-Neural2-H', -- Male
|
||||||
|
-- AU
|
||||||
|
["en_AU_Neural2_A"] = 'en-AU-Neural2-A', -- Female
|
||||||
|
["en_AU_Neural2_B"] = 'en-AU-Neural2-B', -- Male
|
||||||
|
["en_AU_Neural2_C"] = 'en-AU-Neural2-C', -- Female
|
||||||
|
["en_AU_Neural2_D"] = 'en-AU-Neural2-D', -- Male
|
||||||
|
-- IN
|
||||||
|
["en_IN_Neural2_A"] = 'en-IN-Neural2-A', -- Female
|
||||||
|
["en_IN_Neural2_B"] = 'en-IN-Neural2-B', -- Male
|
||||||
|
["en_IN_Neural2_C"] = 'en-IN-Neural2-C', -- Male
|
||||||
|
["en_IN_Neural2_D"] = 'en-IN-Neural2-D', -- Female
|
||||||
|
},
|
||||||
|
News = {
|
||||||
|
["en_GB_News_G"] = 'en-GB-News-G', -- Female
|
||||||
|
["en_GB_News_H"] = 'en-GB-News-H', -- Female
|
||||||
|
["en_GB_News_I"] = 'en-GB-News-I', -- Female
|
||||||
|
["en_GB_News_J"] = 'en-GB-News-J', -- Male
|
||||||
|
["en_GB_News_K"] = 'en-GB-News-K', -- Male
|
||||||
|
["en_GB_News_L"] = 'en-GB-News-L', -- Male
|
||||||
|
["en_GB_News_M"] = 'en-GB-News-M', -- Male
|
||||||
|
-- US
|
||||||
|
["en_US_News_K"] = 'en-US-News-K', -- Female
|
||||||
|
["en_US_News_L"] = 'en-US-News-L', -- Female
|
||||||
|
["en_US_News_N"] = 'en-US-News-N', -- Male
|
||||||
|
-- AU
|
||||||
|
["en_AU_News_E"] = 'en-AU-News-E', -- Female
|
||||||
|
["en_AU_News_F"] = 'en-AU-News-F', -- Female
|
||||||
|
["en_AU_News_G"] = 'en-AU-News-G', -- Male
|
||||||
|
},
|
||||||
|
Casual = {
|
||||||
|
["en_US_Casual_K"] = 'en-US-Casual-K', -- Male
|
||||||
|
},
|
||||||
|
Polyglot = {
|
||||||
|
["en_US_Polyglot_1"] = 'en-US-Polyglot-1', -- Male
|
||||||
|
["de_DE_Polyglot_1"] = 'de-DE-Polyglot-1', -- Male
|
||||||
|
["en_AU_Polyglot_1"] = 'en-AU-Polyglot-1', -- Male
|
||||||
|
},
|
||||||
|
Studio = {
|
||||||
|
-- Englisch (UK) - Studio
|
||||||
|
["en_GB_Studio_B"] = 'en-GB-Studio-B', -- Male
|
||||||
|
["en_GB_Studio_C"] = 'en-GB-Studio-C', -- Female
|
||||||
|
-- Englisch (USA) - Studio
|
||||||
|
["en_US_Studio_O"] = 'en-US-Studio-O', -- Female
|
||||||
|
["en_US_Studio_Q"] = 'en-US-Studio-Q', -- Male
|
||||||
|
-- DE
|
||||||
|
["de_DE_Studio_B"] = 'de-DE-Studio-B', -- Male
|
||||||
|
["de_DE_Studio_C"] = 'de-DE-Studio-C', -- Female
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1586,12 +1586,12 @@ function UTILS.HdgDiff(h1, h2)
|
|||||||
return math.abs(delta)
|
return math.abs(delta)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the heading from one vec3 to another vec3.
|
--- Returns the heading from one vec2/vec3 to another vec2/vec3.
|
||||||
-- @param DCS#Vec3 a From vec3.
|
-- @param DCS#Vec3 a From Vec2 or Vec3.
|
||||||
-- @param DCS#Vec3 b To vec3.
|
-- @param DCS#Vec3 b To Vec2 or Vec3.
|
||||||
-- @return #number Heading in degrees.
|
-- @return #number Heading in degrees.
|
||||||
function UTILS.HdgTo(a, b)
|
function UTILS.HdgTo(a, b)
|
||||||
local dz=b.z-a.z
|
local dz=(b.z or b.y) - (a.z or a.y)
|
||||||
local dx=b.x-a.x
|
local dx=b.x-a.x
|
||||||
local heading=math.deg(math.atan2(dz, dx))
|
local heading=math.deg(math.atan2(dz, dx))
|
||||||
if heading < 0 then
|
if heading < 0 then
|
||||||
@@ -2330,6 +2330,16 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then
|
||||||
|
BASE:T(unit_name .. " cargo door is open")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(38) > 0 or unit:getDrawArgumentValue(400) == 1 ) then
|
||||||
|
BASE:T(unit_name .. " front door(s) are open")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
if type_name == "AH-64D_BLK_II" then
|
if type_name == "AH-64D_BLK_II" then
|
||||||
BASE:T(unit_name .. " front door(s) are open")
|
BASE:T(unit_name .. " front door(s) are open")
|
||||||
return true -- no doors on this one ;)
|
return true -- no doors on this one ;)
|
||||||
@@ -4127,6 +4137,45 @@ function UTILS.LCGRandom()
|
|||||||
return UTILS.lcg.seed / UTILS.lcg.m
|
return UTILS.lcg.seed / UTILS.lcg.m
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Create a table of grid-points for n points.
|
||||||
|
-- @param #number startVec2 Starting DCS#Vec2 map coordinate, e.g. `{x=63598575,y=-63598575}`
|
||||||
|
-- @param #number n Number of points to generate.
|
||||||
|
-- @param #number spacingX Horizonzal spacing (meters).
|
||||||
|
-- @param #number spacingY Vertical spacing (meters).
|
||||||
|
-- @return #table Grid Table of DCS#Vec2 entries.
|
||||||
|
function UTILS.GenerateGridPoints(startVec2, n, spacingX, spacingY)
|
||||||
|
local points = {}
|
||||||
|
local gridSize = math.ceil(math.sqrt(n))
|
||||||
|
local count = 0
|
||||||
|
local n = n or 1
|
||||||
|
local spacingX = spacingX or 100
|
||||||
|
local spacingY = spacingY or 100
|
||||||
|
local startX = startVec2.x or 100
|
||||||
|
local startY = startVec2.y or 100
|
||||||
|
|
||||||
|
for row = 0, gridSize - 1 do
|
||||||
|
for col = 0, gridSize - 1 do
|
||||||
|
if count >= n then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local point = {
|
||||||
|
x = startX + (col * spacingX),
|
||||||
|
y = startY + (row * spacingY)
|
||||||
|
}
|
||||||
|
|
||||||
|
table.insert(points, point)
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if count >= n then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return points
|
||||||
|
end
|
||||||
|
|
||||||
--- Spawns a new FARP of a defined type and coalition and functional statics (fuel depot, ammo storage, tent, windsock) around that FARP to make it operational.
|
--- Spawns a new FARP of a defined type and coalition and functional statics (fuel depot, ammo storage, tent, windsock) around that FARP to make it operational.
|
||||||
-- Adds vehicles from template if given. Fills the FARP warehouse with liquids and known materiels.
|
-- Adds vehicles from template if given. Fills the FARP warehouse with liquids and known materiels.
|
||||||
-- References: [DCS Forum Topic](https://forum.dcs.world/topic/282989-farp-equipment-to-run-it)
|
-- References: [DCS Forum Topic](https://forum.dcs.world/topic/282989-farp-equipment-to-run-it)
|
||||||
@@ -4147,10 +4196,38 @@ end
|
|||||||
-- @param #string F10Text Text to display on F10 map if given. Handy to post things like the ADF beacon Frequency, Callsign and ATC Frequency.
|
-- @param #string F10Text Text to display on F10 map if given. Handy to post things like the ADF beacon Frequency, Callsign and ATC Frequency.
|
||||||
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP.
|
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP.
|
||||||
-- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP.
|
-- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP.
|
||||||
|
-- @param #number NumberPads If given, spawn this number of pads.
|
||||||
|
-- @param #number SpacingX For NumberPads > 1, space this many meters horizontally. Defaults to 100.
|
||||||
|
-- @param #number SpacingY For NumberPads > 1, space this many meters vertically. Defaults to 100.
|
||||||
-- @return #list<Wrapper.Static#STATIC> Table of spawned objects and vehicle object (if given).
|
-- @return #list<Wrapper.Static#STATIC> Table of spawned objects and vehicle object (if given).
|
||||||
-- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later.
|
-- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later.
|
||||||
-- @return #number MarkerID ID of the F10 Text, to be able to remove it later.
|
-- @return #number MarkerID ID of the F10 Text, to be able to remove it later.
|
||||||
function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart)
|
function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart,NumberPads,SpacingX,SpacingY)
|
||||||
|
|
||||||
|
local function PopulateStorage(Name,liquids,equip,airframes)
|
||||||
|
local newWH = STORAGE:New(Name)
|
||||||
|
if liquids and liquids > 0 then
|
||||||
|
-- Storage fill-up
|
||||||
|
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons
|
||||||
|
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
|
||||||
|
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
|
||||||
|
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
|
||||||
|
end
|
||||||
|
|
||||||
|
if equip and equip > 0 then
|
||||||
|
for cat,nitem in pairs(ENUMS.Storage.weapons) do
|
||||||
|
for name,item in pairs(nitem) do
|
||||||
|
newWH:SetItem(item,equip)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if airframes and airframes > 0 then
|
||||||
|
for typename in pairs (CSAR.AircraftType) do
|
||||||
|
newWH:SetItem(typename,airframes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Set Defaults
|
-- Set Defaults
|
||||||
local farplocation = Coordinate
|
local farplocation = Coordinate
|
||||||
@@ -4171,12 +4248,74 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
|||||||
local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
|
local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
|
||||||
local ReturnObjects = {}
|
local ReturnObjects = {}
|
||||||
|
|
||||||
|
-- many FARPs
|
||||||
|
local NumberPads = NumberPads or 1
|
||||||
|
local SpacingX = SpacingX or 100
|
||||||
|
local SpacingY = SpacingY or 100
|
||||||
|
local FarpVec2 = Coordinate:GetVec2()
|
||||||
|
|
||||||
|
if NumberPads > 1 then
|
||||||
|
local Grid = UTILS.GenerateGridPoints(FarpVec2, NumberPads, SpacingX, SpacingY)
|
||||||
|
local groupData = {
|
||||||
|
["visible"] = true,
|
||||||
|
["hidden"] = false,
|
||||||
|
["units"] = {},
|
||||||
|
["y"] = 0, -- Group center latitude
|
||||||
|
["x"] = 0, -- Group center longitude
|
||||||
|
["name"] = Name,
|
||||||
|
}
|
||||||
|
local unitData = {
|
||||||
|
["category"] = "Heliports",
|
||||||
|
["type"] = STypeName, -- FARP type
|
||||||
|
["y"] = 0, -- Latitude coordinate (meters)
|
||||||
|
["x"] = 0, -- Longitude coordinate (meters)
|
||||||
|
["name"] = Name,
|
||||||
|
["heading"] = 0, -- Heading in radians
|
||||||
|
["heliport_modulation"] = mod, -- 0 = AM, 1 = FM
|
||||||
|
["heliport_frequency"] = freq, -- Radio frequency in MHz
|
||||||
|
["heliport_callsign_id"] = callsign, -- Callsign ID
|
||||||
|
["dead"] = false,
|
||||||
|
["shape_name"] = SShapeName,
|
||||||
|
["dynamicSpawn"] = DynamicSpawns,
|
||||||
|
["allowHotStart"] = HotStart,
|
||||||
|
}
|
||||||
|
for id,gridpoint in ipairs(Grid) do
|
||||||
|
-- Spawn FARP
|
||||||
|
local UnitTemplate = UTILS.DeepCopy(unitData)
|
||||||
|
UnitTemplate.x = gridpoint.x
|
||||||
|
UnitTemplate.y = gridpoint.y
|
||||||
|
if id > 1 then UnitTemplate.name = Name.."-"..id end
|
||||||
|
table.insert(groupData.units,UnitTemplate)
|
||||||
|
if id==1 then
|
||||||
|
groupData.x = gridpoint.x
|
||||||
|
groupData.y = gridpoint.y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--BASE:I("Spawning FARP")
|
||||||
|
--UTILS.PrintTableToLog(groupData,1)
|
||||||
|
local Static=coalition.addGroup(Country, -1, groupData)
|
||||||
|
-- Currently DCS >= 2.8 does not trigger birth events if FARPS are spawned!
|
||||||
|
-- We create such an event. The airbase is registered in Core.Event
|
||||||
|
local Event = {
|
||||||
|
id = EVENTS.Birth,
|
||||||
|
time = timer.getTime(),
|
||||||
|
initiator = Static
|
||||||
|
}
|
||||||
|
-- Create BIRTH event.
|
||||||
|
world.onEvent(Event)
|
||||||
|
|
||||||
|
PopulateStorage(Name.."-1",liquids,equip,airframes)
|
||||||
|
else
|
||||||
-- Spawn FARP
|
-- Spawn FARP
|
||||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
||||||
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
||||||
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
||||||
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
||||||
table.insert(ReturnObjects,spawnedfarp)
|
table.insert(ReturnObjects,spawnedfarp)
|
||||||
|
|
||||||
|
PopulateStorage(Name,liquids,equip,airframes)
|
||||||
|
end
|
||||||
|
|
||||||
-- Spawn Objects
|
-- Spawn Objects
|
||||||
local FARPStaticObjectsNato = {
|
local FARPStaticObjectsNato = {
|
||||||
["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"},
|
["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"},
|
||||||
@@ -4210,29 +4349,6 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
|||||||
table.insert(ReturnObjects,spawnedvehicle)
|
table.insert(ReturnObjects,spawnedvehicle)
|
||||||
end
|
end
|
||||||
|
|
||||||
local newWH = STORAGE:New(Name)
|
|
||||||
if liquids and liquids > 0 then
|
|
||||||
-- Storage fill-up
|
|
||||||
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons
|
|
||||||
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
|
|
||||||
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
|
|
||||||
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
|
|
||||||
end
|
|
||||||
|
|
||||||
if equip and equip > 0 then
|
|
||||||
for cat,nitem in pairs(ENUMS.Storage.weapons) do
|
|
||||||
for name,item in pairs(nitem) do
|
|
||||||
newWH:SetItem(item,equip)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if airframes and airframes > 0 then
|
|
||||||
for typename in pairs (CSAR.AircraftType) do
|
|
||||||
newWH:SetItem(typename,airframes)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local ADFName
|
local ADFName
|
||||||
if ADF and type(ADF) == "number" then
|
if ADF and type(ADF) == "number" then
|
||||||
local ADFFreq = ADF*1000 -- KHz to Hz
|
local ADFFreq = ADF*1000 -- KHz to Hz
|
||||||
@@ -4598,16 +4714,16 @@ function UTILS.DoStringIn(State,DoString)
|
|||||||
return net.dostring_in(State,DoString)
|
return net.dostring_in(State,DoString)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Show a picture on the screen
|
--- Show a picture on the screen to all
|
||||||
-- @param #string FileName File name of the picture
|
-- @param #string FileName File name of the picture
|
||||||
-- @param #number Duration Duration in seconds, defaults to 10
|
-- @param #number Duration Duration in seconds, defaults to 10
|
||||||
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
||||||
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||||
-- @param #number HorizontalAlign Horizontal alignment of the picture, defaults to 1 (left), can be 0 (center) or 2 (right)
|
-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right
|
||||||
-- @param #number VerticalAlign Vertical alignment of the picture, defaults to 1 (top), can be 0 (center) or 2 (bottom)
|
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||||
-- @param #number SizeUnits Size units, defaults to 0 (percent), can be 1 (pixels)
|
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||||
function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
function UTILS.ShowPictureToAll(FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||||
ClearView = ClearView or false
|
ClearView = ClearView or false
|
||||||
StartDelay = StartDelay or 0
|
StartDelay = StartDelay or 0
|
||||||
HorizontalAlign = HorizontalAlign or 1
|
HorizontalAlign = HorizontalAlign or 1
|
||||||
@@ -4617,16 +4733,142 @@ function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, Horizontal
|
|||||||
|
|
||||||
if ClearView then ClearView = "true" else ClearView = "false" end
|
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||||
|
|
||||||
net.dostring_in("mission", string.format("a_out_picture(getValueResourceByKey(\"%s\"), %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FileName, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
net.dostring_in("mission", string.format("a_out_picture(\"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Show a picture on the screen to Coalition
|
||||||
|
-- @param #number Coalition Coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL
|
||||||
|
-- @param #string FileName File name of the picture
|
||||||
|
-- @param #number Duration Duration in seconds, defaults to 10
|
||||||
|
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
||||||
|
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||||
|
-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right
|
||||||
|
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||||
|
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||||
|
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||||
|
function UTILS.ShowPictureToCoalition(Coalition, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||||
|
ClearView = ClearView or false
|
||||||
|
StartDelay = StartDelay or 0
|
||||||
|
HorizontalAlign = HorizontalAlign or 1
|
||||||
|
VerticalAlign = VerticalAlign or 1
|
||||||
|
Size = Size or 100
|
||||||
|
SizeUnits = SizeUnits or 0
|
||||||
|
|
||||||
|
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||||
|
|
||||||
|
local coalName = string.lower(UTILS.GetCoalitionName(Coalition))
|
||||||
|
|
||||||
|
net.dostring_in("mission", string.format("a_out_picture_s(\"%s\", \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", coalName, FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Show a picture on the screen to Country
|
||||||
|
-- @param #number Country Country ID, can be country.id.USA, country.id.RUSSIA, etc.
|
||||||
|
-- @param #string FileName File name of the picture
|
||||||
|
-- @param #number Duration Duration in seconds, defaults to 10
|
||||||
|
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
||||||
|
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||||
|
-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right
|
||||||
|
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||||
|
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||||
|
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||||
|
function UTILS.ShowPictureToCountry(Country, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||||
|
ClearView = ClearView or false
|
||||||
|
StartDelay = StartDelay or 0
|
||||||
|
HorizontalAlign = HorizontalAlign or 1
|
||||||
|
VerticalAlign = VerticalAlign or 1
|
||||||
|
Size = Size or 100
|
||||||
|
SizeUnits = SizeUnits or 0
|
||||||
|
|
||||||
|
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||||
|
|
||||||
|
net.dostring_in("mission", string.format("a_out_picture_c(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Country, FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Show a picture on the screen to Group
|
||||||
|
-- @param Wrapper.Group#GROUP Group Group to show the picture to
|
||||||
|
-- @param #string FileName File name of the picture
|
||||||
|
-- @param #number Duration Duration in seconds, defaults to 10
|
||||||
|
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
||||||
|
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||||
|
-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right
|
||||||
|
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||||
|
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||||
|
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||||
|
function UTILS.ShowPictureToGroup(Group, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||||
|
ClearView = ClearView or false
|
||||||
|
StartDelay = StartDelay or 0
|
||||||
|
HorizontalAlign = HorizontalAlign or 1
|
||||||
|
VerticalAlign = VerticalAlign or 1
|
||||||
|
Size = Size or 100
|
||||||
|
SizeUnits = SizeUnits or 0
|
||||||
|
|
||||||
|
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||||
|
|
||||||
|
net.dostring_in("mission", string.format("a_out_picture_g(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Group:GetID(), FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Show a picture on the screen to Unit
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit Unit to show the picture to
|
||||||
|
-- @param #string FileName File name of the picture
|
||||||
|
-- @param #number Duration Duration in seconds, defaults to 10
|
||||||
|
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
||||||
|
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||||
|
-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right
|
||||||
|
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||||
|
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||||
|
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||||
|
function UTILS.ShowPictureToUnit(Unit, FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||||
|
ClearView = ClearView or false
|
||||||
|
StartDelay = StartDelay or 0
|
||||||
|
HorizontalAlign = HorizontalAlign or 1
|
||||||
|
VerticalAlign = VerticalAlign or 1
|
||||||
|
Size = Size or 100
|
||||||
|
SizeUnits = SizeUnits or 0
|
||||||
|
|
||||||
|
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||||
|
|
||||||
|
net.dostring_in("mission", string.format("a_out_picture_u(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Unit:GetID(), FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Load a mission file. This will replace the current mission with the one given carrying along the online clients.
|
||||||
|
-- @param #string FileName Mission filename
|
||||||
|
function UTILS.LoadMission(FileName)
|
||||||
|
net.dostring_in("mission", string.format("a_load_mission(\"%s\")", FileName))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the mission briefing for a coalition.
|
||||||
|
-- @param #number Coalition Briefing coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL
|
||||||
|
-- @param #string Text Briefing text, can contain newlines, will be converted formatted properly for DCS
|
||||||
|
-- @param #string Picture Picture file path, can be a file in the DEFAULT folder inside the .miz
|
||||||
|
function UTILS.SetMissionBriefing(Coalition, Text, Picture)
|
||||||
|
Text = Text or ""
|
||||||
|
Text = Text:gsub("\n", "\\n")
|
||||||
|
Picture = Picture or ""
|
||||||
|
local coalName = string.lower(UTILS.GetCoalitionName(Coalition))
|
||||||
|
net.dostring_in("mission", string.format("a_set_briefing(\"%s\", \"%s\", \"%s\")", coalName, Picture, Text))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Show a helper gate at a DCS#Vec3 position
|
--- Show a helper gate at a DCS#Vec3 position
|
||||||
-- @param DCS#Vec3 pos The position
|
-- @param DCS#Vec3 pos The position
|
||||||
-- @param number heading Heading in degrees, can be 0..359 degrees
|
-- @param #number heading Heading in degrees, can be 0..359 degrees
|
||||||
function UTILS.ShowHelperGate(pos, heading)
|
function UTILS.ShowHelperGate(pos, heading)
|
||||||
net.dostring_in("mission",string.format("a_show_helper_gate(%s, %s, %s, %f)", pos.x, pos.y, pos.z, math.rad(heading)))
|
net.dostring_in("mission",string.format("a_show_helper_gate(%s, %s, %s, %f)", pos.x, pos.y, pos.z, math.rad(heading)))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Show a helper gate for a unit.
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The unit to show the gate for
|
||||||
|
-- @param #number Flag Helper gate flag
|
||||||
|
function UTILS.ShowHelperGateForUnit(Unit, Flag)
|
||||||
|
net.dostring_in("mission",string.format("a_show_route_gates_for_unit(%d, \"%d\")", Unit:GetID(), Flag))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the carrier illumination mode. -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||||
|
-- @param #number UnitID Carrier unit ID ( UNIT:GetID() )
|
||||||
|
-- @param #number Mode Illumination mode, can be -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||||
|
function UTILS.SetCarrierIlluminationMode(UnitID, Mode)
|
||||||
|
net.dostring_in("mission",string.format("a_set_carrier_illumination_mode(%d, %d)", UnitID, Mode))
|
||||||
|
end
|
||||||
|
|
||||||
--- Shell a zone, zone must ME created
|
--- Shell a zone, zone must ME created
|
||||||
-- @param #string name The name of the ME created zone
|
-- @param #string name The name of the ME created zone
|
||||||
-- @param #number power Equals kg of TNT, e.g. 75
|
-- @param #number power Equals kg of TNT, e.g. 75
|
||||||
@@ -4745,3 +4987,274 @@ function UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
|||||||
|
|
||||||
return {x=qx, y=qy}
|
return {x=qx, y=qy}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||||
|
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||||
|
-- @param #table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template.
|
||||||
|
-- @param DCS#Vec2 Anchor (Optional) DCS#Vec2 or DCS#Vec3 as anchor point to calculate offset of the units.
|
||||||
|
-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units.
|
||||||
|
-- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger.
|
||||||
|
function UTILS.ValidateAndRepositionGroundUnits(Positions, Anchor, MaxRadius, Spacing)
|
||||||
|
local units = Positions
|
||||||
|
Anchor = Anchor or UTILS.GetCenterPoint(units)
|
||||||
|
local gPos = { x = Anchor.x, y = Anchor.z or Anchor.y }
|
||||||
|
local maxRadius = 0
|
||||||
|
local unitCount = 0
|
||||||
|
for _, unit in pairs(units) do
|
||||||
|
local pos = { x = unit.x, y = unit.z or unit.y }
|
||||||
|
local dist = UTILS.VecDist2D(pos, gPos)
|
||||||
|
if dist > maxRadius then
|
||||||
|
maxRadius = dist
|
||||||
|
end
|
||||||
|
unitCount = unitCount + 1
|
||||||
|
end
|
||||||
|
maxRadius = MaxRadius or math.max(maxRadius * 2, 10)
|
||||||
|
local spacing = Spacing or math.max(maxRadius * 0.05, 5)
|
||||||
|
if unitCount > 0 and maxRadius > 5 then
|
||||||
|
local spots = UTILS.GetSimpleZones(UTILS.Vec2toVec3(gPos), maxRadius, spacing, 1000)
|
||||||
|
if spots and #spots > 0 then
|
||||||
|
local validSpots = {}
|
||||||
|
for _, spot in pairs(spots) do -- Disposition sometimes returns points on roads, hence this filter.
|
||||||
|
if land.getSurfaceType(spot) == land.SurfaceType.LAND then
|
||||||
|
table.insert(validSpots, spot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
spots = validSpots
|
||||||
|
end
|
||||||
|
|
||||||
|
local step = spacing
|
||||||
|
for _, unit in pairs(units) do
|
||||||
|
local pos = { x = unit.x, y = unit.z or unit.y }
|
||||||
|
local isOnLand = land.getSurfaceType(pos) == land.SurfaceType.LAND
|
||||||
|
local isValid = false
|
||||||
|
if spots and #spots > 0 then
|
||||||
|
local si = 1
|
||||||
|
local sid = 0
|
||||||
|
local closestDist = 100000000
|
||||||
|
local closestSpot
|
||||||
|
for _, spot in pairs(spots) do
|
||||||
|
local dist = UTILS.VecDist2D(pos, spot)
|
||||||
|
if dist < closestDist then
|
||||||
|
closestDist = dist
|
||||||
|
closestSpot = spot
|
||||||
|
sid = si
|
||||||
|
end
|
||||||
|
si = si + 1
|
||||||
|
end
|
||||||
|
if closestSpot then
|
||||||
|
if closestDist >= spacing then
|
||||||
|
pos = closestSpot
|
||||||
|
end
|
||||||
|
isValid = true
|
||||||
|
table.remove(spots, sid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Failsafe calculation
|
||||||
|
if not isValid and not isOnLand then
|
||||||
|
|
||||||
|
local h = UTILS.HdgTo(pos, gPos)
|
||||||
|
local retries = 0
|
||||||
|
while not isValid and retries < 500 do
|
||||||
|
|
||||||
|
local dist = UTILS.VecDist2D(pos, gPos)
|
||||||
|
pos = UTILS.Vec2Translate(pos, step, h)
|
||||||
|
|
||||||
|
local skip = false
|
||||||
|
for _, unit2 in pairs(units) do
|
||||||
|
if unit ~= unit2 then
|
||||||
|
local pos2 = { x = unit2.x, y = unit2.z or unit2.y }
|
||||||
|
local dist2 = UTILS.VecDist2D(pos, pos2)
|
||||||
|
if dist2 < 12 then
|
||||||
|
isValid = false
|
||||||
|
skip = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not skip and dist > step and land.getSurfaceType(pos) == land.SurfaceType.LAND then
|
||||||
|
isValid = true
|
||||||
|
break
|
||||||
|
elseif dist <= step then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
retries = retries + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if isValid then
|
||||||
|
unit.x = pos.x
|
||||||
|
if unit.z then
|
||||||
|
unit.z = pos.y
|
||||||
|
else
|
||||||
|
unit.y = pos.y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- This function uses Disposition and other fallback logic to find better ground positions for statics.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||||
|
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||||
|
-- @param #table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template.
|
||||||
|
-- @param DCS#Vec2 Position DCS#Vec2 or DCS#Vec3 initial spawn location.
|
||||||
|
-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the static.
|
||||||
|
-- @return DCS#Vec2 Initial Position if it's valid, else a valid spawn position. nil if no valid position found.
|
||||||
|
function UTILS.ValidateAndRepositionStatic(Country, Category, Type, Position, ShapeName, MaxRadius)
|
||||||
|
local coord = COORDINATE:NewFromVec2(Position)
|
||||||
|
local st = SPAWNSTATIC:NewFromType(Type, Category, Country)
|
||||||
|
if ShapeName then
|
||||||
|
st:InitShape(ShapeName)
|
||||||
|
end
|
||||||
|
local sName = "s-"..timer.getTime().."-"..math.random(1,10000)
|
||||||
|
local tempStatic = st:SpawnFromCoordinate(coord, 0, sName)
|
||||||
|
if tempStatic then
|
||||||
|
local sRadius = tempStatic:GetBoundingRadius(2) or 3
|
||||||
|
tempStatic:Destroy()
|
||||||
|
sRadius = sRadius * 0.5
|
||||||
|
MaxRadius = MaxRadius or math.max(sRadius * 10, 100)
|
||||||
|
local positions = UTILS.GetSimpleZones(coord:GetVec3(), MaxRadius, sRadius, 20)
|
||||||
|
if positions and #positions > 0 then
|
||||||
|
local closestSpot
|
||||||
|
local closestDist = math.huge
|
||||||
|
for _, spot in pairs(positions) do -- Disposition sometimes returns points on roads, hence this filter.
|
||||||
|
if land.getSurfaceType(spot) == land.SurfaceType.LAND then
|
||||||
|
local dist = UTILS.VecDist2D(Position, spot)
|
||||||
|
if dist < closestDist then
|
||||||
|
closestDist = dist
|
||||||
|
closestSpot = spot
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if closestSpot then
|
||||||
|
if closestDist >= sRadius then
|
||||||
|
return closestSpot
|
||||||
|
else
|
||||||
|
return Position
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- This function can be used to scan all airdromes of a map and write the Moose enums to a file.
|
||||||
|
function UTILS.CreateAirbaseEnum()
|
||||||
|
|
||||||
|
-- Save file function
|
||||||
|
local function _savefile( filename, data )
|
||||||
|
local file=lfs.writedir() .. filename
|
||||||
|
local f = io.open(file , "wb")
|
||||||
|
if f then
|
||||||
|
f:write( data )
|
||||||
|
f:close()
|
||||||
|
env.info(string.format("Saving to file %s", tostring(file) ))
|
||||||
|
else
|
||||||
|
env.info(string.format("ERROR: Could not save results to file %s", tostring(file) ))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get all airbases
|
||||||
|
local airbases=world.getAirbases()
|
||||||
|
|
||||||
|
-- Get map name
|
||||||
|
local mapname=env.mission.theatre
|
||||||
|
|
||||||
|
-- Put airbases in a table
|
||||||
|
local myab={}
|
||||||
|
for i,_airbase in pairs(airbases) do
|
||||||
|
local airbase=_airbase --DCS#Airbase
|
||||||
|
|
||||||
|
|
||||||
|
local cat=airbase:getDesc().category
|
||||||
|
|
||||||
|
if cat==Airbase.Category.AIRDROME then
|
||||||
|
|
||||||
|
-- Get airbase name
|
||||||
|
local name=airbase:getName()
|
||||||
|
|
||||||
|
-- Key is the name with illigal characters replaced
|
||||||
|
local key=name
|
||||||
|
|
||||||
|
-- Germany map specifics
|
||||||
|
if name=="Airracing Lubeck" then
|
||||||
|
key="Airracing_Luebeck"
|
||||||
|
elseif name=="Bad Durkheim" then
|
||||||
|
key="Bad_Duerkheim"
|
||||||
|
elseif name=="Buchel" then
|
||||||
|
key="Buechel"
|
||||||
|
elseif name=="Buckeburg" then
|
||||||
|
key="Bueckeburg"
|
||||||
|
elseif name=="Dusseldorf" then
|
||||||
|
key="Duesseldorf"
|
||||||
|
elseif name=="Gutersloh" then
|
||||||
|
key="Guetersloh"
|
||||||
|
elseif name=="Kothen" then
|
||||||
|
key="Koethen"
|
||||||
|
elseif name=="Larz" then
|
||||||
|
key="Laerz"
|
||||||
|
elseif name=="Lubeck" then
|
||||||
|
key="Luebeck"
|
||||||
|
elseif name=="Luneburg" then
|
||||||
|
key="Lueneburg"
|
||||||
|
elseif name=="Norvenich" then
|
||||||
|
key="Noervenich"
|
||||||
|
elseif name=="Ober-Morlen" then
|
||||||
|
key="Ober_Moerlen"
|
||||||
|
elseif name=="Peenemunde" then
|
||||||
|
key="Peenemuende"
|
||||||
|
elseif name=="Pottschutthohe" then
|
||||||
|
key="Pottschutthoehe"
|
||||||
|
elseif name=="Schonefeld" then
|
||||||
|
key="Schoenefeld"
|
||||||
|
elseif name=="Weser Wumme" then
|
||||||
|
key="Weser_Wuemme"
|
||||||
|
elseif name=="Zollschen" then
|
||||||
|
key="Zoellschen"
|
||||||
|
elseif name=="Zweibrucken" then
|
||||||
|
key="Zweibruecken"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Replace blanks, hyphens by underscores
|
||||||
|
key=key:gsub(" ", "_")
|
||||||
|
key=key:gsub("-", "_")
|
||||||
|
key=key:gsub("'", "_")
|
||||||
|
key=UTILS.ReplaceIllegalCharacters(key, "_")
|
||||||
|
|
||||||
|
local entry={}
|
||||||
|
entry.key=key
|
||||||
|
entry.name=name
|
||||||
|
table.insert(myab, entry)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort by name
|
||||||
|
table.sort(myab, function(a,b) return a.name < b.name end)
|
||||||
|
|
||||||
|
local text=string.format("\n--- Airbases of the %s map", mapname)
|
||||||
|
text=text.."\n--"
|
||||||
|
for _,ab in pairs(myab) do
|
||||||
|
text=text..string.format("\n-- * `AIRBASE.%s.%s` %s", mapname, ab.key, ab.name)
|
||||||
|
end
|
||||||
|
text=text.."\n--"
|
||||||
|
text=text..string.format("\n-- @field %s", mapname)
|
||||||
|
text=text..string.format("\nAIRBASE.%s = {", mapname)
|
||||||
|
for _,ab in pairs(myab) do
|
||||||
|
text=text..string.format('\n\t["%s"] = "%s",', ab.key, ab.name)
|
||||||
|
end
|
||||||
|
text=text.."\n}"
|
||||||
|
|
||||||
|
_savefile(string.format("%s-enums.txt", env.mission.theatre), text)
|
||||||
|
--env.info(text)
|
||||||
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2855,7 +2855,7 @@ do -- Route methods
|
|||||||
-- @param Core.Zone#ZONE Zone The zone where to route to.
|
-- @param Core.Zone#ZONE Zone The zone where to route to.
|
||||||
-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone.
|
-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone.
|
||||||
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
||||||
-- @param Core.Base#FORMATION Formation The formation string.
|
-- @param DCS#FORMATION Formation The formation string.
|
||||||
function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
|
function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
|
||||||
self:F2( Zone )
|
self:F2( Zone )
|
||||||
|
|
||||||
@@ -2915,7 +2915,7 @@ do -- Route methods
|
|||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Vec2 Vec2 The Vec2 where to route to.
|
-- @param DCS#Vec2 Vec2 The Vec2 where to route to.
|
||||||
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
||||||
-- @param Core.Base#FORMATION Formation The formation string.
|
-- @param DCS#FORMATION Formation The formation string.
|
||||||
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
||||||
|
|
||||||
local DCSControllable = self:GetDCSObject()
|
local DCSControllable = self:GetDCSObject()
|
||||||
@@ -4163,7 +4163,7 @@ function CONTROLLABLE:OptionRestrictBurner( RestrictBurner )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets Controllable Option for A2A attack range for AIR FIGHTER units.
|
--- [AIR] Sets Controllable Option for A2A attack range for AIR FIGHTER units.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number range Defines the range
|
-- @param #number range Defines the range
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -4188,6 +4188,66 @@ function CONTROLLABLE:OptionAAAttackRange( range )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number meters The minimum height in meters.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:OptionAAAMinFiringHeightMeters(meters)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
local meters = meters or 20
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
if self:IsGround() then
|
||||||
|
self:SetOption(27, meters)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number meters The maximum height in meters.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:OptionAAAMaxFiringHeightMeters(meters)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
local meters = meters or 1000
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
if self:IsGround() then
|
||||||
|
self:SetOption(29, meters)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number feet The minimum height in feet.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:OptionAAAMinFiringHeightFeet(feet)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
local feet = feet or 60
|
||||||
|
return self:OptionAAAMinFiringHeightMeters(UTILS.FeetToMeters(feet))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number feet The maximum height in feet.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:OptionAAAMaxFiringHeightfeet(feet)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
local feet = feet or 3000
|
||||||
|
return self:OptionAAAMaxFiringHeightMeters(UTILS.FeetToMeters(feet))
|
||||||
|
end
|
||||||
|
|
||||||
--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically.
|
--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ DYNAMICCARGO.State = {
|
|||||||
-- @type DYNAMICCARGO.AircraftTypes
|
-- @type DYNAMICCARGO.AircraftTypes
|
||||||
DYNAMICCARGO.AircraftTypes = {
|
DYNAMICCARGO.AircraftTypes = {
|
||||||
["CH-47Fbl1"] = "CH-47Fbl1",
|
["CH-47Fbl1"] = "CH-47Fbl1",
|
||||||
|
["Mi-8MTV2"] = "Mi-8MTV2",
|
||||||
|
["Mi-8MT"] = "Mi-8MT",
|
||||||
|
["C-130J-30"] = "C-130J-30",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Helo types possible.
|
--- Helo types possible.
|
||||||
@@ -120,17 +123,36 @@ DYNAMICCARGO.AircraftDimensions = {
|
|||||||
["length"] = 11,
|
["length"] = 11,
|
||||||
["ropelength"] = 30,
|
["ropelength"] = 30,
|
||||||
},
|
},
|
||||||
|
["Mi-8MTV2"] = {
|
||||||
|
["width"] = 6,
|
||||||
|
["height"] = 6,
|
||||||
|
["length"] = 15,
|
||||||
|
["ropelength"] = 30,
|
||||||
|
},
|
||||||
|
["Mi-8MT"] = {
|
||||||
|
["width"] = 6,
|
||||||
|
["height"] = 6,
|
||||||
|
["length"] = 15,
|
||||||
|
["ropelength"] = 30,
|
||||||
|
},
|
||||||
|
["C-130J-30"] = {
|
||||||
|
["width"] = 4,
|
||||||
|
["height"] = 12,
|
||||||
|
["length"] = 35,
|
||||||
|
["ropelength"] = 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- DYNAMICCARGO class version.
|
--- DYNAMICCARGO class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
DYNAMICCARGO.version="0.0.7"
|
DYNAMICCARGO.version="0.1.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: A lot...
|
-- TODO: A lot...
|
||||||
|
-- DONE: Added Mi-8 type and dimensions
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -512,7 +534,10 @@ function DYNAMICCARGO:_UpdatePosition()
|
|||||||
---------------
|
---------------
|
||||||
-- REMOVED Cargo
|
-- REMOVED Cargo
|
||||||
---------------
|
---------------
|
||||||
if self.timer and self.timer:IsRunning() then self.timer:Stop() end
|
if self.timer and self.timer:IsRunning() then
|
||||||
|
self.timer:Stop()
|
||||||
|
self.timer=nil
|
||||||
|
end
|
||||||
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
|
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
|
||||||
self.CargoState = DYNAMICCARGO.State.REMOVED
|
self.CargoState = DYNAMICCARGO.State.REMOVED
|
||||||
_DATABASE:CreateEventDynamicCargoRemoved(self)
|
_DATABASE:CreateEventDynamicCargoRemoved(self)
|
||||||
@@ -520,6 +545,24 @@ function DYNAMICCARGO:_UpdatePosition()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [USER] Destroy a DYNAMICCARGO object.
|
||||||
|
-- @param #DYNAMICCARGO self
|
||||||
|
-- @param #boolean GenerateEvent Set to false to remove an item silently. Defaults to true.
|
||||||
|
-- @return #boolean Return Returns nil if the object could not be found, else returns true.
|
||||||
|
function DYNAMICCARGO:Destroy(GenerateEvent)
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
local GenerateEvent = (GenerateEvent ~= nil and GenerateEvent == false) and false or true
|
||||||
|
if GenerateEvent and GenerateEvent == true then
|
||||||
|
self:CreateEventDead( timer.getTime(), DCSObject )
|
||||||
|
end
|
||||||
|
DCSObject:destroy()
|
||||||
|
self:_UpdatePosition()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] Track helos for loaded/unloaded decision making.
|
--- [Internal] Track helos for loaded/unloaded decision making.
|
||||||
-- @param Wrapper.Client#CLIENT client
|
-- @param Wrapper.Client#CLIENT client
|
||||||
-- @return #boolean IsIn
|
-- @return #boolean IsIn
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ GROUP.Attribute = {
|
|||||||
GROUND_AAA="Ground_AAA",
|
GROUND_AAA="Ground_AAA",
|
||||||
GROUND_SAM="Ground_SAM",
|
GROUND_SAM="Ground_SAM",
|
||||||
GROUND_SHORAD="Ground_SHORAD",
|
GROUND_SHORAD="Ground_SHORAD",
|
||||||
|
GROUND_BALLISTICMISSILE="Ground_BallisticMissile",
|
||||||
GROUND_OTHER="Ground_OtherGround",
|
GROUND_OTHER="Ground_OtherGround",
|
||||||
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
||||||
NAVAL_WARSHIP="Naval_WarShip",
|
NAVAL_WARSHIP="Naval_WarShip",
|
||||||
@@ -1057,10 +1058,13 @@ function GROUP:GetTypeName()
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
local unit = DCSGroup:getUnit(1)
|
||||||
|
if unit then
|
||||||
|
local GroupTypeName = unit:getTypeName()
|
||||||
--self:T3( GroupTypeName )
|
--self:T3( GroupTypeName )
|
||||||
return( GroupTypeName )
|
return( GroupTypeName )
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -1074,10 +1078,13 @@ function GROUP:GetNatoReportingName()
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
local unit = DCSGroup:getUnit(1)
|
||||||
|
if unit then
|
||||||
|
local GroupTypeName = unit:getTypeName()
|
||||||
--self:T3( GroupTypeName )
|
--self:T3( GroupTypeName )
|
||||||
return UTILS.GetReportingName(GroupTypeName)
|
return UTILS.GetReportingName(GroupTypeName)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return "Bogey"
|
return "Bogey"
|
||||||
|
|
||||||
@@ -1092,10 +1099,13 @@ function GROUP:GetPlayerName()
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local PlayerName = DCSGroup:getUnit(1):getPlayerName()
|
local unit = DCSGroup:getUnit(1)
|
||||||
|
if unit then
|
||||||
|
local PlayerName = unit:getPlayerName()
|
||||||
--self:T3( PlayerName )
|
--self:T3( PlayerName )
|
||||||
return( PlayerName )
|
return( PlayerName )
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -1110,10 +1120,13 @@ function GROUP:GetCallsign()
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local GroupCallSign = DCSGroup:getUnit(1):getCallsign()
|
local unit = DCSGroup:getUnit(1)
|
||||||
|
if unit then
|
||||||
|
local GroupCallSign = unit:getCallsign()
|
||||||
--self:T3( GroupCallSign )
|
--self:T3( GroupCallSign )
|
||||||
return GroupCallSign
|
return GroupCallSign
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetCallsign", Positionable = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetCallsign", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
@@ -2231,6 +2244,10 @@ function GROUP:Respawn( Template, Reset )
|
|||||||
|
|
||||||
--UTILS.PrintTableToLog(Template)
|
--UTILS.PrintTableToLog(Template)
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(Template.units)
|
||||||
|
end
|
||||||
|
|
||||||
-- Spawn new group.
|
-- Spawn new group.
|
||||||
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
||||||
--_DATABASE:Spawn(Template)
|
--_DATABASE:Spawn(Template)
|
||||||
@@ -2639,6 +2656,8 @@ function GROUP:GetAttribute()
|
|||||||
local artillery=self:HasAttribute("Artillery")
|
local artillery=self:HasAttribute("Artillery")
|
||||||
local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks") or self:HasAttribute("Tanks")
|
local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks") or self:HasAttribute("Tanks")
|
||||||
local aaa=self:HasAttribute("AAA") and (not self:HasAttribute("SAM elements"))
|
local aaa=self:HasAttribute("AAA") and (not self:HasAttribute("SAM elements"))
|
||||||
|
local ballisticMissile=artillery and self:HasAttribute("SS_missile")
|
||||||
|
local shorad=self:HasAttribute("SR SAM")
|
||||||
local ewr=self:HasAttribute("EWR")
|
local ewr=self:HasAttribute("EWR")
|
||||||
local ifv=self:HasAttribute("IFV")
|
local ifv=self:HasAttribute("IFV")
|
||||||
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
||||||
@@ -2680,6 +2699,8 @@ function GROUP:GetAttribute()
|
|||||||
attribute=GROUP.Attribute.GROUND_SAM
|
attribute=GROUP.Attribute.GROUND_SAM
|
||||||
elseif aaa then
|
elseif aaa then
|
||||||
attribute=GROUP.Attribute.GROUND_AAA
|
attribute=GROUP.Attribute.GROUND_AAA
|
||||||
|
elseif artillery and ballisticMissile then
|
||||||
|
attribute=GROUP.Attribute.GROUND_BALLISTICMISSILE
|
||||||
elseif artillery then
|
elseif artillery then
|
||||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||||
elseif tank then
|
elseif tank then
|
||||||
@@ -3192,3 +3213,60 @@ function GROUP:IsAAA()
|
|||||||
end
|
end
|
||||||
return isAAA
|
return isAAA
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||||
|
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||||
|
--- Uses UTILS.ValidateAndRepositionGroundUnits.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #boolean Enabled Enable/disable the feature.
|
||||||
|
function GROUP:SetValidateAndRepositionGroundUnits(Enabled)
|
||||||
|
self.ValidateAndRepositionGroundUnits = Enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the bounding box of the group combining UNIT:GetBoundingBox() units.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return DCS#Box3 The bounding box of the GROUP.
|
||||||
|
-- @return #nil The GROUP does not have any alive units.
|
||||||
|
function GROUP:GetBoundingBox()
|
||||||
|
local bbox = { min = { x = math.huge, y = math.huge, z = math.huge },
|
||||||
|
max = { x = -math.huge, y = -math.huge, z = -math.huge }
|
||||||
|
}
|
||||||
|
|
||||||
|
local Units = self:GetUnits() or {}
|
||||||
|
if #Units == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, unit in pairs(Units) do
|
||||||
|
if unit and unit:IsAlive() then
|
||||||
|
local ubox = unit:GetBoundingBox()
|
||||||
|
|
||||||
|
if ubox then
|
||||||
|
if ubox.min.x < bbox.min.x then
|
||||||
|
bbox.min.x = ubox.min.x
|
||||||
|
end
|
||||||
|
if ubox.min.y < bbox.min.y then
|
||||||
|
bbox.min.y = ubox.min.y
|
||||||
|
end
|
||||||
|
if ubox.min.z < bbox.min.z then
|
||||||
|
bbox.min.z = ubox.min.z
|
||||||
|
end
|
||||||
|
|
||||||
|
if ubox.max.x > bbox.max.x then
|
||||||
|
bbox.max.x = ubox.max.x
|
||||||
|
end
|
||||||
|
if ubox.max.y > bbox.max.y then
|
||||||
|
bbox.max.y = ubox.max.y
|
||||||
|
end
|
||||||
|
if ubox.max.z > bbox.max.z then
|
||||||
|
bbox.max.z = ubox.max.z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return bbox
|
||||||
|
end
|
||||||
|
|||||||
@@ -170,6 +170,27 @@ function IDENTIFIABLE:GetCoalition()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns true if identifiable is of RED coalition.
|
||||||
|
-- @param #IDENTIFIABLE self
|
||||||
|
-- @return #boolean If the identifiable is red.
|
||||||
|
function IDENTIFIABLE:IsRed()
|
||||||
|
return self:GetCoalition() == coalition.side.RED
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns true if identifiable is of BLUE coalition.
|
||||||
|
-- @param #IDENTIFIABLE self
|
||||||
|
-- @return #boolean If the identifiable is blue.
|
||||||
|
function IDENTIFIABLE:IsBlue()
|
||||||
|
return self:GetCoalition() == coalition.side.BLUE
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns true if identifiable is of NEUTRAL coalition.
|
||||||
|
-- @param #IDENTIFIABLE self
|
||||||
|
-- @return #boolean If the identifiable is neutral.
|
||||||
|
function IDENTIFIABLE:IsNeutral()
|
||||||
|
return self:GetCoalition() == coalition.side.NEUTRAL
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the name of the coalition of the Identifiable.
|
--- Returns the name of the coalition of the Identifiable.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @return #string The name of the coalition.
|
-- @return #string The name of the coalition.
|
||||||
|
|||||||
@@ -361,6 +361,7 @@ function POSITIONABLE:GetCoord()
|
|||||||
-- Get the current position.
|
-- Get the current position.
|
||||||
local PositionableVec3 = self:GetVec3()
|
local PositionableVec3 = self:GetVec3()
|
||||||
|
|
||||||
|
if PositionableVec3 then
|
||||||
if self.coordinate then
|
if self.coordinate then
|
||||||
-- Update COORDINATE from 3D vector.
|
-- Update COORDINATE from 3D vector.
|
||||||
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
||||||
@@ -371,6 +372,7 @@ function POSITIONABLE:GetCoord()
|
|||||||
|
|
||||||
return self.coordinate
|
return self.coordinate
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Error message.
|
-- Error message.
|
||||||
BASE:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
|
||||||
@@ -1863,6 +1865,7 @@ do -- Cargo
|
|||||||
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||||
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
||||||
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
||||||
|
["Sd_Kfz_251"] = 10*POSITIONABLE.DefaultInfantryWeight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,13 @@
|
|||||||
-- @field #string SceneryName Name of the scenery object.
|
-- @field #string SceneryName Name of the scenery object.
|
||||||
-- @field DCS#Object SceneryObject DCS scenery object.
|
-- @field DCS#Object SceneryObject DCS scenery object.
|
||||||
-- @field #number Life0 Initial life points.
|
-- @field #number Life0 Initial life points.
|
||||||
-- @field #table Properties
|
-- @field #table Properties.
|
||||||
|
-- @field #number ID.
|
||||||
|
-- @field Core.Zone#ZONE_POLYGON SceneryZone.
|
||||||
|
-- @field Core.Point#COORDINATE Coordinate.
|
||||||
|
-- @field DCS#Vec2 Vec2.
|
||||||
|
-- @field DCS#Vec3 Vec3.
|
||||||
|
-- @field Core.Vector#VECTOR Vector.
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
|
|
||||||
@@ -35,27 +41,72 @@ SCENERY = {
|
|||||||
ClassName = "SCENERY",
|
ClassName = "SCENERY",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_SCENERY = {}
|
||||||
|
|
||||||
--- Register scenery object as POSITIONABLE.
|
--- Register scenery object as POSITIONABLE.
|
||||||
--@param #SCENERY self
|
--@param #SCENERY self
|
||||||
--@param #string SceneryName Scenery name.
|
--@param #string SceneryName Scenery name.
|
||||||
--@param DCS#Object SceneryObject DCS scenery object.
|
--@param DCS#Object SceneryObject DCS scenery object.
|
||||||
|
--@param Core.Zone#ZONE_POLYGON SceneryZone (optional) The zone object.
|
||||||
--@return #SCENERY Scenery object.
|
--@return #SCENERY Scenery object.
|
||||||
function SCENERY:Register( SceneryName, SceneryObject )
|
function SCENERY:Register( SceneryName, SceneryObject, SceneryZone )
|
||||||
|
|
||||||
|
local ID = (SceneryObject and SceneryObject.getID) and SceneryObject:getID() or SceneryName
|
||||||
|
|
||||||
|
if _SCENERY[ID] and _SCENERY[ID].SceneryObject == nil then
|
||||||
|
|
||||||
|
_SCENERY[ID].SceneryObject=SceneryObject
|
||||||
|
SCENERY._UpdateFromDCSObject(_SCENERY[ID])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if _SCENERY[ID] then return _SCENERY[ID] end
|
||||||
|
|
||||||
local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) )
|
local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) )
|
||||||
|
|
||||||
self.SceneryName = tostring(SceneryName)
|
self.SceneryName = tostring(SceneryName)
|
||||||
|
self.ID = ID
|
||||||
self.SceneryObject = SceneryObject
|
self.SceneryObject = SceneryObject
|
||||||
|
self.SceneryZone = SceneryZone
|
||||||
|
|
||||||
|
if SceneryZone then
|
||||||
|
self.Vec3 = SceneryZone:GetVec3()
|
||||||
|
self.Vec2 = SceneryZone:GetVec2()
|
||||||
|
self.Vector = (self.Vec3 and VECTOR) and VECTOR:NewFromVec(self.Vec3) or nil
|
||||||
|
end
|
||||||
|
|
||||||
if self.SceneryObject and self.SceneryObject.getLife then -- fix some objects do not have all functions
|
if self.SceneryObject and self.SceneryObject.getLife then -- fix some objects do not have all functions
|
||||||
self.Life0 = self.SceneryObject:getLife() or 0
|
self.Life0 = self.SceneryObject:getLife() or 1
|
||||||
else
|
else
|
||||||
self.Life0 = 0
|
self.Life0 = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
self.Properties = {}
|
self.Properties = {}
|
||||||
|
|
||||||
|
_SCENERY[self.ID] = self
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- [INTERNAL] Update data
|
||||||
|
-- @param Wrapper.Scenery#SCENERY Scenery The object to update.
|
||||||
|
function SCENERY._UpdateFromDCSObject(Scenery)
|
||||||
|
env.info("APPLE _UpdateFromDCSObject "..tostring(Scenery.SceneryName))
|
||||||
|
local self=Scenery
|
||||||
|
if self.Vec2 == nil and self.SceneryObject ~= nil then
|
||||||
|
self.Vec3 = self.SceneryObject:getPoint()
|
||||||
|
if self.Vec3 then
|
||||||
|
self.Vec2 = {x=self.Vec3.x,y=self.Vec3.z}
|
||||||
|
self.Vector = VECTOR:NewFromVec(self.Vec3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not self.Life0 or self.Life0 == 1 then
|
||||||
|
if self.SceneryObject and self.SceneryObject.getLife() then
|
||||||
|
self.Life = self.SceneryObject:getLife() or 1
|
||||||
|
self.Life0 = self.Life
|
||||||
|
end
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -99,6 +150,39 @@ function SCENERY:GetName()
|
|||||||
return self.SceneryName
|
return self.SceneryName
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Obtain object coordinate.
|
||||||
|
--@param #SCENERY self
|
||||||
|
--@return Core.Point#COORDINATE Coordinate
|
||||||
|
function SCENERY:GetCoordinate()
|
||||||
|
if self.Coordinate then
|
||||||
|
return self.Coordinate
|
||||||
|
elseif self.Vec3 then
|
||||||
|
self.Coordinate = COORDINATE:NewFromVec3(self.Vec3):SetAlt()
|
||||||
|
end
|
||||||
|
return self.Coordinate
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Obtain object coordinate.
|
||||||
|
--@param #SCENERY self
|
||||||
|
--@return DCS#Vec3 Vec3
|
||||||
|
function SCENERY:GetVec3()
|
||||||
|
return self.Vec3
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Obtain object coordinate.
|
||||||
|
--@param #SCENERY self
|
||||||
|
--@return DCS#Vec2 Vec2
|
||||||
|
function SCENERY:GetVec2()
|
||||||
|
return self.Vec2
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Obtain object coordinate.
|
||||||
|
--@param #SCENERY self
|
||||||
|
--@return Core.Vector#VECTOR Vector
|
||||||
|
function SCENERY:GetVector()
|
||||||
|
return self.Vector
|
||||||
|
end
|
||||||
|
|
||||||
--- Obtain DCS Object from the SCENERY Object.
|
--- Obtain DCS Object from the SCENERY Object.
|
||||||
--@param #SCENERY self
|
--@param #SCENERY self
|
||||||
--@return DCS#Object DCS scenery object.
|
--@return DCS#Object DCS scenery object.
|
||||||
@@ -106,6 +190,13 @@ function SCENERY:GetDCSObject()
|
|||||||
return self.SceneryObject
|
return self.SceneryObject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Obtain object ID.
|
||||||
|
--@param #SCENERY self
|
||||||
|
--@return #string Name
|
||||||
|
function SCENERY:GetID()
|
||||||
|
return self.ID
|
||||||
|
end
|
||||||
|
|
||||||
--- Get current life points from the SCENERY Object. Note - Some scenery objects always have 0 life points.
|
--- Get current life points from the SCENERY Object. Note - Some scenery objects always have 0 life points.
|
||||||
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the life0 value to 120%
|
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the life0 value to 120%
|
||||||
-- of the last life value if life exceeds life0 (initial life) at any point. Thus will will get a smooth percentage decrease, if you use this e.g. as success
|
-- of the last life value if life exceeds life0 (initial life) at any point. Thus will will get a smooth percentage decrease, if you use this e.g. as success
|
||||||
@@ -113,12 +204,14 @@ end
|
|||||||
--@param #SCENERY self
|
--@param #SCENERY self
|
||||||
--@return #number life
|
--@return #number life
|
||||||
function SCENERY:GetLife()
|
function SCENERY:GetLife()
|
||||||
local life = 0
|
local life = 1
|
||||||
if self.SceneryObject and self.SceneryObject.getLife then
|
if self.SceneryObject and self.SceneryObject.getLife then
|
||||||
life = self.SceneryObject:getLife()
|
life = self.SceneryObject:getLife()
|
||||||
if life > self.Life0 then
|
if life > self.Life0 then
|
||||||
self.Life0 = math.floor(life * 1.2)
|
self.Life0 = math.floor(life * 1.2)
|
||||||
end
|
end
|
||||||
|
elseif self.Life then
|
||||||
|
life = self.Life
|
||||||
end
|
end
|
||||||
return life
|
return life
|
||||||
end
|
end
|
||||||
@@ -176,11 +269,18 @@ end
|
|||||||
--- Find a SCENERY object from its name or id. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
--- Find a SCENERY object from its name or id. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
||||||
-- to find the correct object.
|
-- to find the correct object.
|
||||||
--@param #SCENERY self
|
--@param #SCENERY self
|
||||||
--@param #string Name The name/id of the scenery object as taken from the ME. Ex. '595785449'
|
--@param #string Name The name/id of the scenery object as taken from the ME. Ex. '595785449'.
|
||||||
--@param Core.Point#COORDINATE Coordinate Where to find the scenery object
|
--@param Core.Point#COORDINATE Coordinate Where to find the scenery object.
|
||||||
--@param #number Radius (optional) Search radius around coordinate, defaults to 100
|
--@param #number Radius (optional) Search radius around coordinate, defaults to 100.
|
||||||
--@return #SCENERY Scenery Object or `nil` if it cannot be found
|
--@param #string Role (optional) The role if set on the zone object.
|
||||||
function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
--@param Core.Zone#ZONE_POLYGON Zone (optional) The Zone where the scenery is located.
|
||||||
|
--@return #SCENERY Scenery Object or `nil` if it cannot be found.
|
||||||
|
function SCENERY:FindByName(Name, Coordinate, Radius, Role, Zone)
|
||||||
|
|
||||||
|
--BASE:I("Coordinate x = "..Coordinate.x .. " y = "..Coordinate.y.." z = "..Coordinate.z)
|
||||||
|
|
||||||
|
local findme = self:_FindByName(Name)
|
||||||
|
if findme then return findme end
|
||||||
|
|
||||||
local radius = Radius or 100
|
local radius = Radius or 100
|
||||||
local name = Name or "unknown"
|
local name = Name or "unknown"
|
||||||
@@ -193,12 +293,13 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
|||||||
local function SceneryScan(scoordinate, sradius, sname)
|
local function SceneryScan(scoordinate, sradius, sname)
|
||||||
if scoordinate ~= nil then
|
if scoordinate ~= nil then
|
||||||
local Vec2 = scoordinate:GetVec2()
|
local Vec2 = scoordinate:GetVec2()
|
||||||
local scanzone = ZONE_RADIUS:New("Zone-"..sname,Vec2,sradius,true)
|
local scanzone = ZONE_RADIUS:New("Zone-"..sname,Vec2,sradius)
|
||||||
scanzone:Scan({Object.Category.SCENERY})
|
scanzone:Scan({Object.Category.SCENERY})
|
||||||
local scanned = scanzone:GetScannedSceneryObjects()
|
local scanned = scanzone:GetScannedSceneryObjects()
|
||||||
local rscenery = nil -- Wrapper.Scenery#SCENERY
|
local rscenery = nil -- Wrapper.Scenery#SCENERY
|
||||||
for _,_scenery in pairs(scanned) do
|
for _,_scenery in pairs(scanned) do
|
||||||
local scenery = _scenery -- Wrapper.Scenery#SCENERY
|
local scenery = _scenery -- Wrapper.Scenery#SCENERY
|
||||||
|
--BASE:I({tostring(scenery.SceneryName),tostring(sname)})
|
||||||
if tostring(scenery.SceneryName) == tostring(sname) then
|
if tostring(scenery.SceneryName) == tostring(sname) then
|
||||||
rscenery = scenery
|
rscenery = scenery
|
||||||
if Role then rscenery:SetProperty("ROLE",Role) end
|
if Role then rscenery:SetProperty("ROLE",Role) end
|
||||||
@@ -211,13 +312,36 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Coordinate then
|
if Coordinate then
|
||||||
--BASE:I("Coordinate Scenery Scan")
|
|
||||||
scenery = SceneryScan(Coordinate, radius, name)
|
scenery = SceneryScan(Coordinate, radius, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not scenery then scenery = SCENERY:Register(Name,nil,Zone) end
|
||||||
|
|
||||||
return scenery
|
return scenery
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find a SCENERY object that was previously registered(!) by it's ID.
|
||||||
|
-- @param #SCENERY self
|
||||||
|
-- @param #number ID
|
||||||
|
-- @return Wrapper.Scenery#SCENERY Scenery or nil if it could not be found
|
||||||
|
function SCENERY:FindByID(ID)
|
||||||
|
return _SCENERY[ID]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find a SCENERY object that was previously registered(!) by it's name.
|
||||||
|
-- @param #SCENERY self
|
||||||
|
-- @param #string Name
|
||||||
|
-- @return Wrapper.Scenery#SCENERY Scenery or nil if it could not be found
|
||||||
|
function SCENERY:_FindByName(Name)
|
||||||
|
for _id,_object in pairs(_SCENERY) do
|
||||||
|
if _object and _object.GetName and _object:GetName() then
|
||||||
|
local name = _object:GetName()
|
||||||
|
if Name == name then return _object end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Find a SCENERY object from its name or id. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
--- Find a SCENERY object from its name or id. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
||||||
-- to find the correct object.
|
-- to find the correct object.
|
||||||
--@param #SCENERY self
|
--@param #SCENERY self
|
||||||
@@ -231,8 +355,8 @@ function SCENERY:FindByNameInZone(Name, Zone, Radius)
|
|||||||
if type(Zone) == "string" then
|
if type(Zone) == "string" then
|
||||||
Zone = ZONE:FindByName(Zone)
|
Zone = ZONE:FindByName(Zone)
|
||||||
end
|
end
|
||||||
local coordinate = Zone:GetCoordinate()
|
local coordinate = Zone:GetCoordinate():SetAlt()
|
||||||
return self:FindByName(Name,coordinate,Radius,Zone:GetProperty("ROLE"))
|
return self:FindByName(Name,coordinate,Radius,Zone:GetProperty("ROLE"),Zone)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Find a SCENERY object from its zone name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
--- Find a SCENERY object from its zone name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
||||||
@@ -241,14 +365,18 @@ end
|
|||||||
--@param #string ZoneName The name of the scenery zone as created with a right-click on the map in the mission editor and select "assigned to...". Can be handed over as ZONE object.
|
--@param #string ZoneName The name of the scenery zone as created with a right-click on the map in the mission editor and select "assigned to...". Can be handed over as ZONE object.
|
||||||
--@return #SCENERY First found Scenery Object or `nil` if it cannot be found
|
--@return #SCENERY First found Scenery Object or `nil` if it cannot be found
|
||||||
function SCENERY:FindByZoneName( ZoneName )
|
function SCENERY:FindByZoneName( ZoneName )
|
||||||
|
--BASE:I(ZoneName)
|
||||||
|
|
||||||
local zone = ZoneName -- Core.Zone#ZONE_BASE
|
local zone = ZoneName -- Core.Zone#ZONE_BASE
|
||||||
|
|
||||||
if type(ZoneName) == "string" then
|
if type(ZoneName) == "string" then
|
||||||
zone = ZONE:FindByName(ZoneName) -- Core.Zone#ZONE_POLYGON
|
zone = ZONE:FindByName(ZoneName) -- Core.Zone#ZONE_POLYGON
|
||||||
end
|
end
|
||||||
|
|
||||||
local _id = zone:GetProperty('OBJECT ID')
|
local _id = zone:GetProperty('OBJECT ID')
|
||||||
--local properties = zone:GetAllProperties() or {}
|
|
||||||
--BASE:I(string.format("Object ID is: %s",_id or "none"))
|
--BASE:I("Object ID ".._id)
|
||||||
--BASE:T("Object ID ".._id)
|
|
||||||
if not _id then
|
if not _id then
|
||||||
-- this zone has no object ID
|
-- this zone has no object ID
|
||||||
BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName))
|
BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName))
|
||||||
@@ -257,23 +385,27 @@ function SCENERY:FindByZoneName( ZoneName )
|
|||||||
local scanned = zone:GetScannedSceneryObjects()
|
local scanned = zone:GetScannedSceneryObjects()
|
||||||
for _,_scenery in (scanned) do
|
for _,_scenery in (scanned) do
|
||||||
local scenery = _scenery -- Wrapper.Scenery#SCENERY
|
local scenery = _scenery -- Wrapper.Scenery#SCENERY
|
||||||
if scenery:IsAlive() then
|
--if scenery:IsAlive() then
|
||||||
local role = zone:GetProperty("ROLE")
|
local role = zone:GetProperty("ROLE")
|
||||||
if role then scenery:SetProperty("ROLE",role) end
|
if role then scenery:SetProperty("ROLE",role) end
|
||||||
return scenery
|
return scenery
|
||||||
end
|
--end
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
else
|
else
|
||||||
return self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE"))
|
local coordinate = zone:GetCoordinate()
|
||||||
|
coordinate:SetAlt()
|
||||||
|
return self:FindByName(_id, coordinate,nil,zone:GetProperty("ROLE"),zone)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE"))
|
local coordinate = zone:GetCoordinate()
|
||||||
|
coordinate:SetAlt()
|
||||||
|
return self:FindByName(_id, coordinate,nil,zone:GetProperty("ROLE"),zone)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Scan and find all SCENERY objects from a zone by zone-name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
--- Scan and find all SCENERY objects from a zone by zone-name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
|
||||||
-- to find the correct object.
|
-- to find the correct object. Might return nil!
|
||||||
--@param #SCENERY self
|
--@param #SCENERY self
|
||||||
--@param #string ZoneName The name of the zone, can be handed as ZONE_RADIUS or ZONE_POLYGON object
|
--@param #string ZoneName The name of the zone, can be handed as ZONE_RADIUS or ZONE_POLYGON object
|
||||||
--@return #table of SCENERY Objects, or `nil` if nothing found
|
--@return #table of SCENERY Objects, or `nil` if nothing found
|
||||||
@@ -295,7 +427,7 @@ function SCENERY:FindAllByZoneName( ZoneName )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local obj = self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE"))
|
local obj = self:FindByName(_id, zone:GetCoordinate():SetAlt(),nil,zone:GetProperty("ROLE"), zone)
|
||||||
if obj then
|
if obj then
|
||||||
return {obj}
|
return {obj}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ function STATIC:Register( StaticName )
|
|||||||
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cache position
|
||||||
|
self._vec3 = self:GetVec3()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -86,6 +89,30 @@ function STATIC:GetLife()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the position of the STATIC even if it is not alive.
|
||||||
|
-- @param #STATIC self
|
||||||
|
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE.
|
||||||
|
-- @return #nil The position was not cached.
|
||||||
|
function STATIC:GetVec2Cached()
|
||||||
|
local vec2 = self:GetVec2()
|
||||||
|
if not vec2 and self._vec3 then
|
||||||
|
vec2 = {x = self._vec3.x, y = self._vec3.z }
|
||||||
|
end
|
||||||
|
return vec2
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the position of the STATIC even if it is not alive.
|
||||||
|
-- @param #STATIC self
|
||||||
|
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE.
|
||||||
|
-- @return #nil The position was not cached.
|
||||||
|
function STATIC:GetVec3Cached()
|
||||||
|
local vec3 = self:GetVec3()
|
||||||
|
if not vec3 and self._vec3 then
|
||||||
|
vec3 = self._vec3
|
||||||
|
end
|
||||||
|
return vec3
|
||||||
|
end
|
||||||
|
|
||||||
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
||||||
@@ -232,6 +259,8 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
|||||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
|
||||||
|
|
||||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||||
|
-- Cache position
|
||||||
|
self._vec3 = self:GetVec3()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -255,6 +284,8 @@ function STATIC:ReSpawn(CountryID, Delay)
|
|||||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||||
|
|
||||||
SpawnStatic:Spawn(nil, self.StaticName)
|
SpawnStatic:Spawn(nil, self.StaticName)
|
||||||
|
-- Cache position
|
||||||
|
self._vec3 = self:GetVec3()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -278,6 +309,8 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
|||||||
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)
|
||||||
|
-- Cache position
|
||||||
|
self._vec3 = self:GetVec3()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -753,7 +753,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename"_Liquids.csv"))
|
self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -773,7 +773,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename"_Aircraft.csv"))
|
self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -805,7 +805,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename"_Weapons.csv"))
|
self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -377,6 +377,10 @@ function UNIT:ReSpawnAt(Coordinate, Heading)
|
|||||||
|
|
||||||
--self:T( SpawnGroupTemplate )
|
--self:T( SpawnGroupTemplate )
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(SpawnGroupTemplate.units)
|
||||||
|
end
|
||||||
|
|
||||||
_DATABASE:Spawn(SpawnGroupTemplate)
|
_DATABASE:Spawn(SpawnGroupTemplate)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1931,3 +1935,21 @@ end
|
|||||||
function UNIT:SetLife(Percent)
|
function UNIT:SetLife(Percent)
|
||||||
net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent))
|
net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the carrier illumination mode. -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @param #number Mode Illumination mode, can be -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||||
|
function UNIT:SetCarrierIlluminationMode(Mode)
|
||||||
|
UTILS.SetCarrierIlluminationMode(self:GetID(), Mode)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||||
|
--- NOTE: This is not a spawn randomizer.
|
||||||
|
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||||
|
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||||
|
--- Uses UTILS.ValidateAndRepositionGroundUnits.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @param #boolean Enabled Enable/disable the feature.
|
||||||
|
function UNIT:SetValidateAndRepositionGroundUnits(Enabled)
|
||||||
|
self.ValidateAndRepositionGroundUnits = Enabled
|
||||||
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user