mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-07-18 20:12:45 +00:00
Compare commits
338 Commits
2.9.11
...
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 | |||
| f172f6efeb | |||
| b6b6686873 | |||
| 5e724e7a3f | |||
| 90f1d1df2a | |||
| a5726c0ed8 | |||
| 23ff128ac8 | |||
| 7d3fc1740a | |||
| b2a084d669 | |||
| 30203668e4 | |||
| ebecc70693 | |||
| 74712b6e27 | |||
| 40253ea8bb | |||
| 4e56078d2a | |||
| 4bbf20ca4e | |||
| a462c5a493 | |||
| 367014ebf3 | |||
| 326b20b08d | |||
| 11b0ce6275 | |||
| 03763e16d6 | |||
| c1e8ee12e0 | |||
| ac8cc408c1 | |||
| ada38fa3ea | |||
| 2ee0597d48 | |||
| 7ae4cdc8f1 | |||
| 8c92a578ed | |||
| 096f2caf9c | |||
| 0b37c909b3 | |||
| 1b18ae1597 | |||
| c9ac6d73e6 | |||
| 0e836973fd | |||
| be40d7be9a | |||
| f3b7740041 | |||
| 7d7488db6f | |||
| 4964cc2f2d | |||
| f0a4c5b008 | |||
| 1b6412821b | |||
| 926a0733e4 | |||
| da70f4ce6c | |||
| 727cb3276c | |||
| 33e63a4819 | |||
| 3543b2c79a | |||
| 4489efff94 | |||
| 6a4bddde99 | |||
| dc2511942c | |||
| f0c257c4a5 | |||
| 068d21612f | |||
| 773461aad9 | |||
| f9257b2b0d | |||
| 9e0f03a3cd | |||
| a467fabdc8 | |||
| a2ab84c45a | |||
| 9fd6729967 | |||
| f1d4f1753a | |||
| 6d9c3fd0aa | |||
| 28ae63bd8d | |||
| 42e7e3f94f | |||
| 6466c5e95e | |||
| 829f5af25f | |||
| 0d1147bac4 | |||
| 24b47b02e0 | |||
| 3cabc07d58 | |||
| b0546b1e60 | |||
| a988e67490 | |||
| 2594c5bbf0 | |||
| db70fa341c | |||
| 763e3852ac | |||
| 8ec86973c6 | |||
| eb2c6ac6f2 | |||
| cbcc893ce5 | |||
| 382b049c5f | |||
| a53763221c | |||
| b7bac28113 | |||
| a9edb16554 | |||
| 0aeb1fc6af | |||
| eeeeda4e5e | |||
| f5881eda53 | |||
| c1997d9f70 | |||
| bb1caa6642 | |||
| dd5ca93f26 | |||
| 1889df4952 | |||
| 7ca219748d | |||
| 2fc16ba694 | |||
| a4feafab8e | |||
| 997baf21a0 | |||
| b126cc00d0 | |||
| 09b7922b84 | |||
| 7a5b9a75f3 | |||
| 4bab2ee1de | |||
| d7defe6f7f | |||
| db869bcb6d | |||
| ea4a1f9ff9 | |||
| 20406e40ca | |||
| 3b50fee5a0 | |||
| 804004198b | |||
| 5b8b8a5566 | |||
| 0468bacc0b | |||
| 7eba1349ae | |||
| b6074a4795 | |||
| 36c9f551d9 | |||
| 89c3f7310b | |||
| a6b622ed31 | |||
| f1af3a50b8 | |||
| 0c90e90c18 | |||
| f97ef25104 | |||
| 069c0aa03f | |||
| b145588ed5 | |||
| 3ad60a95ce | |||
| ac4b620f16 | |||
| ccada18a6a | |||
| 1547d66327 | |||
| 8042e8bfaf | |||
| dd7b87e9cd | |||
| 460d2768ff | |||
| 3c74272749 | |||
| 82c409d77a | |||
| 195aac4504 | |||
| 08d8f3e25f | |||
| 6f72697e26 | |||
| 0f6439cf9f | |||
| 2c10943cb1 | |||
| 544db963ea | |||
| 207698a2dd | |||
| d1ae2c0f5e | |||
| 0392417189 | |||
| be4beea9d0 | |||
| 5da899138b | |||
| 1ec1e00bde | |||
| 5d93b33d42 | |||
| b2077bfc74 | |||
| 6fdf9a649f | |||
| d013bbc751 | |||
| e0092fdba0 | |||
| fbeada439f | |||
| 6c8858d2f5 | |||
| e2b77878df | |||
| 53d7972858 | |||
| 04a55e4104 | |||
| d11acecdac | |||
| 49c11073e6 | |||
| 1a156e7e12 | |||
| 1856754614 | |||
| 6ac452ff15 | |||
| d707a4775c | |||
| ffccc31e38 | |||
| 0405af2bde | |||
| e50e572c78 | |||
| 3083599158 | |||
| b7b6c1ea19 | |||
| 5b107ce2da | |||
| 5c1e342a79 | |||
| ddf33da787 | |||
| b0a192a767 | |||
| 986c340211 | |||
| 2109537f86 | |||
| 690db7f12f | |||
| 4f3fd06cc9 | |||
| 4074023ed3 | |||
| 6c00b0c7eb | |||
| 76dc0d690a | |||
| d783f7be99 | |||
| b66e91b11f |
@@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID)
|
||||
unsigned = refct.unsigned,
|
||||
size = bit.band(bit.rshift(ctype.info, 16), 127),
|
||||
}
|
||||
refct.bool, refct.const, refct.volatile, refct.unsigned = nil
|
||||
refct.bool, refct.const, refct.volatile, refct.unsigned = nil, nil, nil, nil
|
||||
end
|
||||
|
||||
if CT[4] then -- Merge sibling attributes onto this type.
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- There are basically two classes available to model an A2A defense system.
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The following class is available to model an A2G defense system.
|
||||
--
|
||||
-- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system.
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) AI_AIR constructor
|
||||
--
|
||||
@@ -657,8 +658,8 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
--- Create a route point of type air.
|
||||
local FromRTBRoutePoint = FromCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
RTBSpeed,
|
||||
true
|
||||
)
|
||||
@@ -666,8 +667,8 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
--- Create a route point of type air.
|
||||
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
RTBSpeed,
|
||||
true
|
||||
)
|
||||
@@ -761,10 +762,10 @@ function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
||||
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local FromRefuelRoutePoint = FromRefuelCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToRefuelSpeed, true)
|
||||
local FromRefuelRoutePoint = FromRefuelCoord:WaypointAir(self.PatrolAltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToRefuelSpeed, true)
|
||||
|
||||
--- Create a route point of type air. NOT used!
|
||||
local ToRefuelRoutePoint = Tanker:GetCoordinate():WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToRefuelSpeed, true)
|
||||
local ToRefuelRoutePoint = Tanker:GetCoordinate():WaypointAir(self.PatrolAltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToRefuelSpeed, true)
|
||||
|
||||
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The following class is available to model an AIR defense system.
|
||||
--
|
||||
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
|
||||
|
||||
|
||||
-- @type AI_AIR_ENGAGE
|
||||
--- @type AI_AIR_ENGAGE
|
||||
-- @extends AI.AI_AIR#AI_AIR
|
||||
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event.
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
@@ -453,7 +455,7 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local FromWP = DefenderCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
||||
local FromWP = DefenderCoord:WaypointAir(self.PatrolAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = FromWP
|
||||
|
||||
@@ -462,7 +464,7 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
||||
local ToCoord=DefenderCoord:Translate( EngageDistance, FromEngageAngle, true )
|
||||
|
||||
local ToWP = ToCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
||||
local ToWP = ToCoord:WaypointAir(self.PatrolAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToWP
|
||||
|
||||
@@ -536,7 +538,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
local EngageRoute = {}
|
||||
local AttackTasks = {}
|
||||
|
||||
local FromWP = DefenderCoord:WaypointAir(self.EngageAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
||||
local FromWP = DefenderCoord:WaypointAir(self.EngageAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||
EngageRoute[#EngageRoute+1] = FromWP
|
||||
|
||||
self:SetTargetDistance( TargetCoord ) -- For RTB status check
|
||||
@@ -544,7 +546,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
||||
local ToCoord=DefenderCoord:Translate( EngageDistance, FromEngageAngle, true )
|
||||
|
||||
local ToWP = ToCoord:WaypointAir(self.EngageAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
||||
local ToWP = ToCoord:WaypointAir(self.EngageAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||
EngageRoute[#EngageRoute+1] = ToWP
|
||||
|
||||
-- TODO: A factor of * 3 this way too low. This causes the AI NOT to engage until very close or even merged sometimes. Some A2A missiles have a much longer range! Needs more frequent updates of the task!
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}
|
||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event.
|
||||
@@ -309,7 +311,7 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
local speedkmh=ToTargetSpeed
|
||||
|
||||
local FromWP = CurrentCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
||||
local FromWP = CurrentCoord:WaypointAir(self.PatrolAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToTargetSpeed, true)
|
||||
PatrolRoute[#PatrolRoute+1] = FromWP
|
||||
|
||||
if self.racetrack then
|
||||
@@ -359,9 +361,9 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
else
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
||||
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToTargetSpeed, true)
|
||||
PatrolRoute[#PatrolRoute+1] = ToWP
|
||||
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
|
||||
|
||||
-- @type AI_AIR_SQUADRON
|
||||
--- @type AI_AIR_SQUADRON
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||
--
|
||||
-- 
|
||||
@@ -521,12 +523,12 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
@@ -577,13 +579,13 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
self:T2( ToTargetVec2 )
|
||||
|
||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -33,8 +33,9 @@
|
||||
-- @field Wrapper.Group#GROUP Test
|
||||
-- @extends Core.Fsm#FSM_SET
|
||||
|
||||
|
||||
--- Monitors and manages as many replacement AI groups as there are
|
||||
--- 
|
||||
--
|
||||
-- Monitors and manages as many replacement AI groups as there are
|
||||
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
|
||||
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
||||
--
|
||||
@@ -220,16 +221,9 @@ function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup )
|
||||
AIGroup:MessageToRed( "Returning to home base ...", 30 )
|
||||
else
|
||||
-- Okay, we need to send this Group back to the nearest base of the Coalition of the AI.
|
||||
--TODO: i need to rework the POINT_VEC2 thing.
|
||||
local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y )
|
||||
local PointVec2 = COORDINATE:New(AIGroup:GetVec2().x, 0, AIGroup:GetVec2().y)
|
||||
local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 )
|
||||
self:T( ClosestAirbase.AirbaseName )
|
||||
--[[
|
||||
AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 )
|
||||
local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase )
|
||||
AIGroupTemplate.route = RTBRoute
|
||||
AIGroup:Respawn( AIGroupTemplate )
|
||||
]]
|
||||
AIGroup:RouteRTB(ClosestAirbase)
|
||||
end
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
||||
@@ -423,12 +425,12 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToEngageZoneSpeed,
|
||||
true
|
||||
)
|
||||
@@ -445,13 +447,13 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||
|
||||
--- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||
--
|
||||
-- 
|
||||
@@ -466,12 +469,12 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
@@ -508,13 +511,13 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
self:T2( ToTargetVec2 )
|
||||
|
||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
-- @module AI.AI_Cargo
|
||||
-- @image Cargo.JPG
|
||||
|
||||
-- @type AI_CARGO
|
||||
--- @type AI_CARGO
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
|
||||
--- Base class for the dynamic cargo handling capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
-- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
-- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for an AI vehicle group.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
|
||||
--- Brings a dynamic cargo handling capability for an AI airplane group.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases.
|
||||
--
|
||||
@@ -440,7 +442,7 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Height, Uncontrolled
|
||||
|
||||
-- To point.
|
||||
local AirbasePointVec2 = Airbase:GetPointVec2()
|
||||
local ToWaypoint = AirbasePointVec2:WaypointAir(POINT_VEC3.RoutePointAltType.BARO, "Land", "Landing", Speed or Airplane:GetSpeedMax()*0.8, true, Airbase)
|
||||
local ToWaypoint = AirbasePointVec2:WaypointAir(COORDINATE.WaypointAltType.BARO, "Land", "Landing", Speed or Airplane:GetSpeedMax()*0.8, true, Airbase)
|
||||
|
||||
--ToWaypoint["airdromeId"] = Airbase:GetID()
|
||||
--ToWaypoint["speed_locked"] = true
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The dispatcher concept.
|
||||
--
|
||||
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
--- A dynamic cargo transportation capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module.
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
--- A dynamic cargo handling capability for AI helicopter groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
--
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
--- A dynamic cargo transportation capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for an AI helicopter group.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
@@ -367,8 +369,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
||||
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
||||
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
||||
-- "RADIO",
|
||||
-- POINT_VEC3.RoutePointType.TurningPoint,
|
||||
-- POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
-- COORDINATE.WaypointType.TurningPoint,
|
||||
-- COORDINATE.WaypointAction.TurningPoint,
|
||||
-- Speed,
|
||||
-- true
|
||||
-- )
|
||||
@@ -380,8 +382,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
||||
|
||||
local WaypointTo = CoordinateTo:WaypointAir(
|
||||
"RADIO",
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
50,
|
||||
true
|
||||
)
|
||||
@@ -427,7 +429,7 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, 50, true)
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, 50, true)
|
||||
Route[#Route+1] = WaypointTo
|
||||
|
||||
local Tasks = {}
|
||||
@@ -496,14 +498,14 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin
|
||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||
|
||||
--- Create a route point of type air.
|
||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, _speed, true)
|
||||
|
||||
--- Create a route point of type air.
|
||||
local CoordinateTo = Coordinate
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,_speed, true)
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint,_speed, true)
|
||||
|
||||
Route[#Route+1] = WaypointFrom
|
||||
Route[#Route+1] = WaypointTo
|
||||
@@ -563,7 +565,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
||||
|
||||
--- Create a route point of type air.
|
||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, _speed, true)
|
||||
Route[#Route+1] = WaypointFrom
|
||||
Route[#Route+1] = WaypointFrom
|
||||
|
||||
@@ -573,7 +575,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, _speed, true)
|
||||
|
||||
Route[#Route+1] = WaypointTo
|
||||
Route[#Route+1] = WaypointTo
|
||||
@@ -631,7 +633,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
||||
--- Create a route point of type air.
|
||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||
|
||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
|
||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true)
|
||||
Route[#Route+1] = WaypointFrom
|
||||
|
||||
--- Create a route point of type air.
|
||||
@@ -639,7 +641,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
CoordinateTo.y = landheight + Height -- flight height should be 50m above ground
|
||||
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
|
||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true)
|
||||
|
||||
Route[#Route+1] = WaypointTo
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for an AI naval group.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Naval ships can be utilized to transport cargo around the map following naval shipping lanes.
|
||||
-- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
-- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo.
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
--
|
||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
||||
--
|
||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
--
|
||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
||||
--
|
||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
|
||||
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions.
|
||||
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
||||
@@ -158,7 +160,6 @@ AI_FORMATION.__Enum.Mode = {
|
||||
-- @field #number GroundRadar
|
||||
-- @field #number Ground
|
||||
AI_FORMATION.__Enum.ReportType = {
|
||||
Airborne = "*",
|
||||
Airborne = "A",
|
||||
GroundRadar = "R",
|
||||
Ground = "G",
|
||||
@@ -725,7 +726,7 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X
|
||||
|
||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||
|
||||
local PointVec3 = POINT_VEC3:New()
|
||||
local PointVec3 = COORDINATE:New()
|
||||
PointVec3:SetX( XStart + i * XSpace )
|
||||
PointVec3:SetY( YStart + i * YSpace )
|
||||
PointVec3:SetZ( ZStart + i * ZSpace )
|
||||
@@ -877,7 +878,7 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event ,
|
||||
|
||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||
|
||||
local PointVec3 = POINT_VEC3:New()
|
||||
local PointVec3 = COORDINATE:New()
|
||||
|
||||
local Side = ( i % 2 == 0 ) and 1 or -1
|
||||
local Row = i / 2 + 1
|
||||
@@ -936,7 +937,7 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS
|
||||
|
||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||
|
||||
local PointVec3 = POINT_VEC3:New()
|
||||
local PointVec3 = COORDINATE:New()
|
||||
|
||||
local ZIndex = i % ZLevels
|
||||
local XIndex = math.floor( i / ZLevels )
|
||||
@@ -1222,7 +1223,6 @@ function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
||||
local CVI = {
|
||||
x = CV2.x + CS * 10 * math.sin(Ca),
|
||||
y = GH2.y + Inclination, -- + FollowFormation.y,
|
||||
y = GH2.y,
|
||||
z = CV2.z + CS * 10 * math.cos(Ca),
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
|
||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
||||
@@ -751,12 +753,12 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
if not CurrentVec2 then return end
|
||||
--Done: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TakeOffParking,
|
||||
POINT_VEC3.RoutePointAction.FromParkingArea,
|
||||
COORDINATE.WaypointType.TakeOffParking,
|
||||
COORDINATE.WaypointAction.FromParkingArea,
|
||||
ToPatrolZoneSpeed,
|
||||
true
|
||||
)
|
||||
@@ -767,12 +769,12 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
if not CurrentVec2 then return end
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToPatrolZoneSpeed,
|
||||
true
|
||||
)
|
||||
@@ -792,13 +794,13 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
@@ -890,12 +892,12 @@ function AI_PATROL_ZONE:onafterRTB()
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
--local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToPatrolZoneSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
||||
--
|
||||
-- 
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -8,9 +8,11 @@
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
do -- ACT_ACCOUNT
|
||||
|
||||
|
||||
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## ACT_ACCOUNT state machine:
|
||||
--
|
||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||
@@ -133,7 +135,7 @@ do -- ACT_ACCOUNT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event )
|
||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To )
|
||||
|
||||
self:__NoMore( 1 )
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
||||
--
|
||||
-- 
|
||||
-- ## ACT_ASSIST state machine:
|
||||
--
|
||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
-- ## ACT_ROUTE state machine:
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) MOOSE Cargo System.
|
||||
--
|
||||
-- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities.
|
||||
@@ -275,14 +277,14 @@
|
||||
-- The cargo must be in the **Loaded** state.
|
||||
-- @function [parent=#CARGO] UnBoard
|
||||
-- @param #CARGO self
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
||||
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
||||
|
||||
--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier.
|
||||
-- The cargo must be in the **Loaded** state.
|
||||
-- @function [parent=#CARGO] __UnBoard
|
||||
-- @param #CARGO self
|
||||
-- @param #number DelaySeconds The amount of seconds to delay the action.
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
||||
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
||||
|
||||
|
||||
-- Load
|
||||
@@ -307,14 +309,14 @@
|
||||
-- The cargo must be in the **Loaded** state.
|
||||
-- @function [parent=#CARGO] UnLoad
|
||||
-- @param #CARGO self
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
||||
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
||||
|
||||
--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading.
|
||||
-- The cargo must be in the **Loaded** state.
|
||||
-- @function [parent=#CARGO] __UnLoad
|
||||
-- @param #CARGO self
|
||||
-- @param #number DelaySeconds The amount of seconds to delay the action.
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
||||
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
||||
|
||||
-- State Transition Functions
|
||||
|
||||
@@ -467,7 +469,7 @@ do -- CARGO
|
||||
self.Type = Type
|
||||
self.Name = Name
|
||||
self.Weight = Weight or 0
|
||||
self.CargoObject = nil
|
||||
self.CargoObject = nil -- Wrapper.Group#GROUP
|
||||
self.CargoCarrier = nil -- Wrapper.Client#CLIENT
|
||||
self.Representable = false
|
||||
self.Slingloadable = false
|
||||
@@ -897,7 +899,7 @@ do -- CARGO
|
||||
|
||||
--- Get the current PointVec2 of the cargo.
|
||||
-- @param #CARGO self
|
||||
-- @return Core.Point#POINT_VEC2
|
||||
-- @return Core.Point#COORDINATE
|
||||
function CARGO:GetPointVec2()
|
||||
return self.CargoObject:GetPointVec2()
|
||||
end
|
||||
@@ -1094,7 +1096,7 @@ do -- CARGO_REPRESENTABLE
|
||||
|
||||
--- Route a cargo unit to a PointVec2.
|
||||
-- @param #CARGO_REPRESENTABLE self
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number Speed
|
||||
-- @return #CARGO_REPRESENTABLE
|
||||
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
|
||||
|
||||
@@ -22,6 +22,9 @@ do -- CARGO_CRATE
|
||||
-- @type CARGO_CRATE
|
||||
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
|
||||
|
||||
---
|
||||
-- 
|
||||
--
|
||||
--- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
|
||||
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
||||
--
|
||||
@@ -114,7 +117,7 @@ do -- CARGO_CRATE
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2
|
||||
-- @param Core.Point#COORDINATE
|
||||
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||
--self:T( { ToPointVec2, From, Event, To } )
|
||||
|
||||
|
||||
@@ -22,9 +22,12 @@ do -- CARGO_GROUP
|
||||
--- @type CARGO_GROUP
|
||||
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
||||
-- @field #string GroupName The name of the CargoGroup.
|
||||
-- @field Wrapper.Group#GROUÜ CargoCarrier The carrier group.
|
||||
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||
|
||||
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
||||
--
|
||||
-- 
|
||||
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
||||
--
|
||||
-- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
||||
@@ -410,7 +413,7 @@ do -- CARGO_GROUP
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||
self:T( {From, Event, To, ToPointVec2, NearRadius } )
|
||||
@@ -453,7 +456,7 @@ do -- CARGO_GROUP
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||
--self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
@@ -491,7 +494,7 @@ do -- CARGO_GROUP
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
||||
--self:T( { From, Event, To, ToPointVec2 } )
|
||||
|
||||
@@ -771,3 +774,4 @@ do -- CARGO_GROUP
|
||||
|
||||
|
||||
end -- CARGO_GROUP
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ do -- CARGO_SLINGLOAD
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
|
||||
@@ -30,6 +30,8 @@ do -- CARGO_UNIT
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
@@ -72,7 +74,7 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius (optional) Defaut 25 m.
|
||||
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
@@ -145,7 +147,7 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
@@ -171,7 +173,7 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
@@ -197,7 +199,7 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2
|
||||
-- @param Core.Point#COORDINATE
|
||||
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||
self:T( { ToPointVec2, From, Event, To } )
|
||||
|
||||
|
||||
@@ -974,7 +974,7 @@ do -- Scheduling
|
||||
-- @param #BASE self
|
||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||
-- @param ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||
-- @return #string The Schedule ID of the planned schedule.
|
||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||
|
||||
|
||||
@@ -577,13 +577,19 @@ do -- Zones and Pathlines
|
||||
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
||||
local w=objectData.width
|
||||
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 points={}
|
||||
points[1]={x=vec2.x-h/2, y=vec2.y+w/2} --Upper left
|
||||
points[2]={x=vec2.x+h/2, y=vec2.y+w/2} --Upper right
|
||||
points[3]={x=vec2.x+h/2, y=vec2.y-w/2} --Lower right
|
||||
points[4]={x=vec2.x-h/2, y=vec2.y-w/2} --Lower left
|
||||
local sinRot = math.sin(rotation)
|
||||
local cosRot = math.cos(rotation)
|
||||
local dx = h / 2
|
||||
local dy = w / 2
|
||||
|
||||
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")
|
||||
|
||||
@@ -872,6 +878,8 @@ end
|
||||
-- @return Wrapper.Group#GROUP The found GROUP.
|
||||
function DATABASE:FindGroup( GroupName )
|
||||
|
||||
if type(GroupName) ~= "string" or GroupName == "" then return end
|
||||
|
||||
local GroupFound = self.GROUPS[GroupName]
|
||||
|
||||
if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then
|
||||
@@ -1110,7 +1118,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
else
|
||||
self.STNS[stn] = UnitTemplate.name
|
||||
self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
self:T("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
end
|
||||
end
|
||||
if UnitTemplate.AddPropAircraft.SADL_TN then
|
||||
@@ -1119,7 +1127,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
else
|
||||
self.SADL[sadl] = UnitTemplate.name
|
||||
self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
self:T("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1380,7 +1388,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CoalitionID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1392,7 +1400,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CategoryID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1404,7 +1412,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CountryID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1697,7 +1705,7 @@ function DATABASE:_EventOnBirth( Event )
|
||||
if PlayerName then
|
||||
|
||||
-- Debug info.
|
||||
self:I(string.format("Player '%s' joined unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
||||
self:I(string.format("Player '%s' joined unit '%s' (%s) of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniTypeName), tostring(Event.IniDCSGroupName)))
|
||||
|
||||
-- Add client in case it does not exist already.
|
||||
if client == nil or (client and client:CountPlayers() == 0) then
|
||||
|
||||
@@ -1372,11 +1372,12 @@ function EVENT:onEvent( Event )
|
||||
-- Scenery
|
||||
---
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
Event.IniDCSUnitName = Event.IniDCSUnit.getName and Event.IniDCSUnit:getName() or "Scenery no name "..math.random(1,20000)
|
||||
Event.IniDCSUnitName = ( Event.IniDCSUnit and Event.IniDCSUnit.getName ) and Event.IniDCSUnit:getName() or "Scenery no name "..math.random(1,20000)
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||
Event.IniCategory = Event.IniDCSUnit.getDesc and Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||
Event.IniCategory = (Event.IniDCSUnit and Event.IniDCSUnit.getDesc ) and Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = (Event.initiator and Event.initiator.isExist
|
||||
and Event.initiator:isExist() and Event.IniDCSUnit and Event.IniDCSUnit.getTypeName) and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||
|
||||
elseif Event.IniObjectCategory == Object.Category.BASE then
|
||||
---
|
||||
@@ -1474,7 +1475,7 @@ function EVENT:onEvent( Event )
|
||||
-- SCENERY
|
||||
---
|
||||
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
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||
@@ -1507,7 +1508,9 @@ function EVENT:onEvent( Event )
|
||||
else
|
||||
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
||||
Event.Place=AIRBASE:Find(Event.place)
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
if Event.Place then
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
||||
ClassName = "MARKEROPS",
|
||||
Tag = "mytag",
|
||||
Keywords = {},
|
||||
version = "0.1.3",
|
||||
version = "0.1.4",
|
||||
debug = false,
|
||||
Casesensitive = true,
|
||||
}
|
||||
@@ -154,14 +154,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||
return true
|
||||
end
|
||||
--position
|
||||
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
|
||||
local coord=COORDINATE:NewFromVec3(vec3)
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
|
||||
local coalition = Event.MarkCoalition
|
||||
-- decision
|
||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||
@@ -170,8 +163,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||
@@ -180,8 +179,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark changed at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||
|
||||
@@ -206,7 +206,7 @@ end
|
||||
function MESSAGE:ToGroup( Group, Settings )
|
||||
self:F( Group.GroupName )
|
||||
|
||||
if Group then
|
||||
if Group and Group:IsAlive() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
@@ -231,7 +231,7 @@ end
|
||||
function MESSAGE:ToUnit( Unit, Settings )
|
||||
self:F( Unit.IdentifiableName )
|
||||
|
||||
if Unit then
|
||||
if Unit and Unit:IsAlive() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
@@ -452,7 +452,7 @@ end
|
||||
_MESSAGESRS = {}
|
||||
|
||||
--- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||
-- @param #string PathToSRS (optional) Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" or your configuration file setting.
|
||||
-- @param #string PathToSRS (optional) Path to SRS TTS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio" or your configuration file setting.
|
||||
-- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting.
|
||||
-- @param #string PathToCredentials (optional) Path to credentials file for Google.
|
||||
-- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies.
|
||||
@@ -468,13 +468,13 @@ _MESSAGESRS = {}
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate,Backend)
|
||||
|
||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
|
||||
_MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243
|
||||
_MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM
|
||||
@@ -535,7 +535,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
@@ -567,7 +567,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue()
|
||||
--
|
||||
@@ -589,7 +589,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed()
|
||||
--
|
||||
@@ -611,7 +611,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll()
|
||||
--
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
do -- COORDINATE
|
||||
|
||||
---
|
||||
--- Coordinate class
|
||||
-- @type COORDINATE
|
||||
-- @field #string ClassName Name of the class
|
||||
-- @field #number x Component of the 3D vector.
|
||||
@@ -59,6 +59,10 @@ do -- COORDINATE
|
||||
-- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange.
|
||||
-- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white.
|
||||
-- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green.
|
||||
-- * @{#COORDINATE.SetSmokeOffsetDirection}(): To set an offset point direction for smoke.
|
||||
-- * @{#COORDINATE.SetSmokeOffsetDistance}(): To set an offset point distance for smoke.
|
||||
-- * @{#COORDINATE.SwitchSmokeOffsetOn}(): To set an offset point for smoke to on.
|
||||
-- * @{#COORDINATE.SwitchSmokeOffsetOff}(): To set an offset point for smoke to off.
|
||||
--
|
||||
-- ## 2.2) Flare
|
||||
--
|
||||
@@ -773,7 +777,9 @@ do -- COORDINATE
|
||||
-- @return DCS#Vec2 Vec2
|
||||
function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius )
|
||||
self:F2( { OuterRadius, InnerRadius } )
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
local Theta = 2 * math.pi * math.random()
|
||||
local Radials = math.random() + math.random()
|
||||
if Radials > 1 then
|
||||
@@ -833,6 +839,26 @@ do -- COORDINATE
|
||||
return land.getHeight( Vec2 )
|
||||
end
|
||||
|
||||
--- Returns a table of DCS#Vec3 points representing the terrain profile between two points.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Destination DCS#Vec3 Ending point of the profile.
|
||||
-- @return #table DCS#Vec3 table of the profile
|
||||
function COORDINATE:GetLandProfileVec3(Destination)
|
||||
return land.profile(self:GetVec3(), Destination)
|
||||
end
|
||||
|
||||
--- Returns a table of #COORDINATE representing the terrain profile between two points.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Destination #COORDINATE Ending coordinate of the profile.
|
||||
-- @return #table #COORDINATE table of the profile
|
||||
function COORDINATE:GetLandProfileCoordinates(Destination)
|
||||
local points = self:GetLandProfileVec3(Destination:GetVec3())
|
||||
local coords = {}
|
||||
for _, point in ipairs(points) do
|
||||
table.insert(coords, COORDINATE:NewFromVec3(point))
|
||||
end
|
||||
return coords
|
||||
end
|
||||
|
||||
--- Set the heading of the coordinate, if applicable.
|
||||
-- @param #COORDINATE self
|
||||
@@ -1157,6 +1183,162 @@ do -- COORDINATE
|
||||
return vec3
|
||||
end
|
||||
|
||||
--- Return the x coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number The x coordinate.
|
||||
function COORDINATE:GetX()
|
||||
return self.x
|
||||
end
|
||||
|
||||
--- Return the y coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number The y coordinate.
|
||||
function COORDINATE:GetY()
|
||||
if self:IsInstanceOf("POINT_VEC2") then
|
||||
return self.z
|
||||
end
|
||||
return self.y
|
||||
end
|
||||
|
||||
--- Return the z coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number The z coordinate.
|
||||
function COORDINATE:GetZ()
|
||||
return self.z
|
||||
end
|
||||
|
||||
--- Set the x coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number x The x coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:SetX( x )
|
||||
self.x = x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the y coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number y The y coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:SetY( y )
|
||||
if self:IsInstanceOf("POINT_VEC2") then
|
||||
self.z = y
|
||||
else
|
||||
self.y = y
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the z coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number z The z coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:SetZ( z )
|
||||
self.z = z
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the x coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number x The x coordinate value to add to the current x coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:AddX( x )
|
||||
self.x = self.x + x
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Return Return the Lat(itude) coordinate of the COORDINATE (ie: (parent)COORDINATE.x).
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number The x coordinate.
|
||||
function COORDINATE:GetLat()
|
||||
return self.x
|
||||
end
|
||||
|
||||
--- Set the Lat(itude) coordinate of the COORDINATE (ie: COORDINATE.x).
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number x The x coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:SetLat( x )
|
||||
self.x = x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the Lon(gitude) coordinate of the COORDINATE (ie: (parent)COORDINATE.z).
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number The y coordinate.
|
||||
function COORDINATE:GetLon()
|
||||
return self.z
|
||||
end
|
||||
|
||||
--- Set the Lon(gitude) coordinate of the COORDINATE (ie: COORDINATE.z).
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number y The y coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:SetLon( z )
|
||||
self.z = z
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the altitude (height) of the land at the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number The land altitude.
|
||||
function COORDINATE:GetAlt()
|
||||
return self.y ~= 0 or land.getHeight( { x = self.x, y = self.z } )
|
||||
end
|
||||
|
||||
--- Set the altitude of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Altitude The land altitude. If nothing (nil) is given, then the current land altitude is set.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:SetAlt( Altitude )
|
||||
self.y = Altitude or land.getHeight( { x = self.x, y = self.z } )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the current land height an altitude.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Altitude The Altitude to add. If nothing (nil) is given, then the current land altitude is set.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:AddAlt( Altitude )
|
||||
self.y = land.getHeight( { x = self.x, y = self.z } ) + Altitude or 0
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Return a random COORDINATE within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Distance OuterRadius
|
||||
-- @param DCS#Distance InnerRadius
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:GetRandomPointVec2InRadius( OuterRadius, InnerRadius )
|
||||
self:F2( { OuterRadius, InnerRadius } )
|
||||
|
||||
return COORDINATE:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) )
|
||||
end
|
||||
|
||||
--- Add to the y coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number y The y coordinate value to add to the current y coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:AddY( y )
|
||||
if self:IsInstanceOf("POINT_VEC2") then
|
||||
return self:AddZ(y)
|
||||
else
|
||||
self.y = self.y + y
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the z coordinate of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number z The z coordinate value to add to the current z coordinate.
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:AddZ( z )
|
||||
self.z = self.z +z
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Core.Settings}.
|
||||
-- The text will reflect the wind like this:
|
||||
@@ -1455,6 +1637,7 @@ do -- COORDINATE
|
||||
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
||||
RoutePoint.linkUnit = AirbaseID
|
||||
RoutePoint.helipadId = AirbaseID
|
||||
RoutePoint.airdromeId = airbase:IsAirdrome() and AirbaseID or nil
|
||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||
RoutePoint.airdromeId = AirbaseID
|
||||
else
|
||||
@@ -1962,14 +2145,112 @@ do -- COORDINATE
|
||||
end
|
||||
|
||||
|
||||
--- Smokes the point in a color.
|
||||
--- Create colored smoke the point. The smoke we last up to 5 min (DCS limitation) but you can optionally specify a shorter duration or stop it manually.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Utilities.Utils#SMOKECOLOR SmokeColor
|
||||
-- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||
function COORDINATE:Smoke( SmokeColor, name )
|
||||
self:F2( { SmokeColor } )
|
||||
self.firename = name or "Smoke-"..math.random(1,100000)
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
||||
-- @param #number SmokeColor Color of smoke, e.g. `SMOKECOLOR.Green` for green smoke.
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||
-- @param #boolean Offset (Optional) If true, offset the smokle a bit.
|
||||
-- @param #number Direction (Optional) If Offset is true this is the direction of the offset, 1-359 (degrees). Default random.
|
||||
-- @param #number Distance (Optional) If Offset is true this is the distance of the offset in meters. Default random 10-20.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name, Offset,Direction,Distance)
|
||||
self:F2( { SmokeColor, Name, Duration, Delay, Offset } )
|
||||
|
||||
SmokeColor=SmokeColor or SMOKECOLOR.Green
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name, Direction,Distance)
|
||||
else
|
||||
|
||||
-- Create a name which is used to stop the smoke manually
|
||||
self.firename = Name or "Smoke-"..math.random(1,100000)
|
||||
|
||||
-- Create smoke
|
||||
if Offset or self.SmokeOffset then
|
||||
local Angle = Direction or self:GetSmokeOffsetDirection()
|
||||
local Distance = Distance or self:GetSmokeOffsetDistance()
|
||||
local newpos = self:Translate(Distance,Angle,true,false)
|
||||
local newvec3 = newpos:GetVec3()
|
||||
trigger.action.smoke( newvec3, SmokeColor, self.firename )
|
||||
else
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
||||
end
|
||||
|
||||
-- Stop smoke
|
||||
if Duration and Duration>0 then
|
||||
self:ScheduleOnce(Duration, COORDINATE.StopSmoke, self, self.firename )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the offset direction when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number Direction in degrees.
|
||||
function COORDINATE:GetSmokeOffsetDirection()
|
||||
local direction = self.SmokeOffsetDirection or math.random(1,359)
|
||||
return direction
|
||||
end
|
||||
|
||||
--- Set the offset direction when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Direction (Optional) This is the direction of the offset, 1-359 (degrees). Default random.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SetSmokeOffsetDirection(Direction)
|
||||
if self then
|
||||
self.SmokeOffsetDirection = Direction or math.random(1,359)
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffsetDirection = Direction or math.random(1,359)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the offset distance when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number Distance Distance in meters.
|
||||
function COORDINATE:GetSmokeOffsetDistance()
|
||||
local distance = self.SmokeOffsetDistance or math.random(10,20)
|
||||
return distance
|
||||
end
|
||||
|
||||
--- Set the offset distance when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Distance (Optional) This is the distance of the offset in meters. Default random 10-20.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SetSmokeOffsetDistance(Distance)
|
||||
if self then
|
||||
self.SmokeOffsetDistance = Distance or math.random(10,20)
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffsetDistance = Distance or math.random(10,20)
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the offset on when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SwitchSmokeOffsetOn()
|
||||
if self then
|
||||
self.SmokeOffset = true
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffset = true
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the offset off when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SwitchSmokeOffsetOff()
|
||||
if self then
|
||||
self.SmokeOffset = false
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffset = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Stops smoking the point in a color.
|
||||
@@ -1981,49 +2262,83 @@ do -- COORDINATE
|
||||
|
||||
--- Smoke the COORDINATE Green.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeGreen()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Green )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeGreen(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Green, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE Red.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeRed()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Red )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeRed(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Red, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE White.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeWhite()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.White )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeWhite(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.White, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE Orange.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeOrange()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Orange )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeOrange(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Orange, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE Blue.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeBlue()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Blue )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeBlue(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Blue, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Big smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke).
|
||||
-- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeAndFire( preset, density, name )
|
||||
self:F2( { preset=preset, density=density } )
|
||||
density=density or 0.5
|
||||
self.firename = name or "Fire-"..math.random(1,10000)
|
||||
trigger.action.effectSmokeBig( self:GetVec3(), preset, density, self.firename )
|
||||
-- @param #number Preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke).
|
||||
-- @param #number Density (Optional) Smoke density. Number in [0,...,1]. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFire( Preset, Density, Duration, Delay, Name )
|
||||
self:F2( { preset=Preset, density=Density } )
|
||||
|
||||
Preset=Preset or BIGSMOKEPRESET.SmallSmokeAndFire
|
||||
Density=Density or 0.5
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, COORDINATE.BigSmokeAndFire, self, Preset, Density, Duration, 0, Name)
|
||||
else
|
||||
|
||||
self.firename = Name or "Fire-"..math.random(1,10000)
|
||||
|
||||
trigger.action.effectSmokeBig( self:GetVec3(), Preset, Density, self.firename )
|
||||
|
||||
-- Stop smoke
|
||||
if Duration and Duration>0 then
|
||||
self:ScheduleOnce(Duration, COORDINATE.StopBigSmokeAndFire, self, self.firename )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop big smoke and fire at the coordinate.
|
||||
@@ -2036,82 +2351,98 @@ do -- COORDINATE
|
||||
|
||||
--- Small smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeAndFireSmall( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density, name)
|
||||
-- @param #number Density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireSmall( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Medium smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeAndFireMedium( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireMedium( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Large smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeAndFireLarge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireLarge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Huge smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeAndFireHuge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireHuge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Small smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeSmall( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeSmall( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Medium smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeMedium( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeMedium( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Large smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeLarge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density,name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeLarge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Huge smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||
function COORDINATE:BigSmokeHuge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density,name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeHuge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Flares the point in a color.
|
||||
@@ -2765,8 +3096,10 @@ do -- COORDINATE
|
||||
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||
local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||
|
||||
if sunrise == "N/R" then return false end
|
||||
if sunrise == "N/S" then return true end
|
||||
if type(sunrise) == "string" or type(sunset) == "string" then
|
||||
if sunrise == "N/R" then return false end
|
||||
if sunset == "N/S" then return true end
|
||||
end
|
||||
|
||||
local time=UTILS.ClockToSeconds(clock)
|
||||
|
||||
@@ -2784,6 +3117,11 @@ do -- COORDINATE
|
||||
|
||||
-- Todays sun set in sec.
|
||||
local sunset=self:GetSunset(true)
|
||||
|
||||
if type(sunrise) == "string" or type(sunset) == "string" then
|
||||
if sunrise == "N/R" then return false end
|
||||
if sunset == "N/S" then return true end
|
||||
end
|
||||
|
||||
-- Seconds passed since midnight.
|
||||
local time=UTILS.SecondsOfToday()
|
||||
@@ -3474,9 +3812,37 @@ do -- COORDINATE
|
||||
return flat, elev
|
||||
end
|
||||
|
||||
--- Return a random COORDINATE within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Distance OuterRadius
|
||||
-- @param DCS#Distance InnerRadius
|
||||
-- @return #COORDINATE
|
||||
function COORDINATE:GetRandomPointVec3InRadius( OuterRadius, InnerRadius )
|
||||
return COORDINATE:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) )
|
||||
end
|
||||
|
||||
|
||||
--- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #number SearchRadius Radius of the search area.
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. nil if no positions are found.
|
||||
function COORDINATE:GetSimpleZones(SearchRadius, PosRadius, NumPositions)
|
||||
local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), SearchRadius, PosRadius, NumPositions)
|
||||
if clearPositions and #clearPositions > 0 then
|
||||
local coords = {}
|
||||
for _, pos in pairs(clearPositions) do
|
||||
local coord = COORDINATE:NewFromVec2(pos)
|
||||
table.insert(coords, coord)
|
||||
end
|
||||
return coords
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- POINT_VEC3
|
||||
do
|
||||
|
||||
--- The POINT_VEC3 class
|
||||
-- @type POINT_VEC3
|
||||
@@ -3493,6 +3859,8 @@ do -- POINT_VEC3
|
||||
|
||||
--- Defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space.
|
||||
--
|
||||
-- **DEPRECATED - PLEASE USE COORDINATE!**
|
||||
--
|
||||
-- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts.
|
||||
-- In order to keep the credibility of the the author,
|
||||
-- I want to emphasize that the formulas embedded in the MIST framework were created by Grimes or previous authors,
|
||||
@@ -3580,130 +3948,19 @@ do -- POINT_VEC3
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new POINT_VEC3 object from Vec2 coordinates.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param DCS#Vec2 Vec2 The Vec2 point.
|
||||
-- @param DCS#Distance LandHeightAdd (optional) Add a landheight.
|
||||
-- @return Core.Point#POINT_VEC3 self
|
||||
function POINT_VEC3:NewFromVec2( Vec2, LandHeightAdd )
|
||||
|
||||
local self = BASE:Inherit( self, COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) ) -- Core.Point#POINT_VEC3
|
||||
self:F2( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Create a new POINT_VEC3 object from Vec3 coordinates.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param DCS#Vec3 Vec3 The Vec3 point.
|
||||
-- @return Core.Point#POINT_VEC3 self
|
||||
function POINT_VEC3:NewFromVec3( Vec3 )
|
||||
|
||||
local self = BASE:Inherit( self, COORDINATE:NewFromVec3( Vec3 ) ) -- Core.Point#POINT_VEC3
|
||||
self:F2( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Return the x coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @return #number The x coordinate.
|
||||
function POINT_VEC3:GetX()
|
||||
return self.x
|
||||
end
|
||||
|
||||
--- Return the y coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @return #number The y coordinate.
|
||||
function POINT_VEC3:GetY()
|
||||
return self.y
|
||||
end
|
||||
|
||||
--- Return the z coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @return #number The z coordinate.
|
||||
function POINT_VEC3:GetZ()
|
||||
return self.z
|
||||
end
|
||||
|
||||
--- Set the x coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number x The x coordinate.
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:SetX( x )
|
||||
self.x = x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the y coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number y The y coordinate.
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:SetY( y )
|
||||
self.y = y
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the z coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number z The z coordinate.
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:SetZ( z )
|
||||
self.z = z
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the x coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number x The x coordinate value to add to the current x coordinate.
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:AddX( x )
|
||||
self.x = self.x + x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the y coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number y The y coordinate value to add to the current y coordinate.
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:AddY( y )
|
||||
self.y = self.y + y
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the z coordinate of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number z The z coordinate value to add to the current z coordinate.
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:AddZ( z )
|
||||
self.z = self.z +z
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return a random POINT_VEC3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param DCS#Distance OuterRadius
|
||||
-- @param DCS#Distance InnerRadius
|
||||
-- @return #POINT_VEC3
|
||||
function POINT_VEC3:GetRandomPointVec3InRadius( OuterRadius, InnerRadius )
|
||||
|
||||
return POINT_VEC3:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- POINT_VEC2
|
||||
do
|
||||
|
||||
-- @type POINT_VEC2
|
||||
--- @type POINT_VEC2
|
||||
-- @field DCS#Distance x The x coordinate in meters.
|
||||
-- @field DCS#Distance y the y coordinate in meters.
|
||||
-- @extends Core.Point#COORDINATE
|
||||
|
||||
--- Defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified.
|
||||
--
|
||||
-- **DEPRECATED - PLEASE USE COORDINATE!**
|
||||
--
|
||||
-- ## POINT_VEC2 constructor
|
||||
--
|
||||
-- A new POINT_VEC2 instance can be created with:
|
||||
@@ -3751,166 +4008,4 @@ do -- POINT_VEC2
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new POINT_VEC2 object from Vec2 coordinates.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param DCS#Vec2 Vec2 The Vec2 point.
|
||||
-- @return Core.Point#POINT_VEC2 self
|
||||
function POINT_VEC2:NewFromVec2( Vec2, LandHeightAdd )
|
||||
|
||||
local LandHeight = land.getHeight( Vec2 )
|
||||
|
||||
LandHeightAdd = LandHeightAdd or 0
|
||||
LandHeight = LandHeight + LandHeightAdd
|
||||
|
||||
local self = BASE:Inherit( self, COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) ) -- #POINT_VEC2
|
||||
self:F2( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new POINT_VEC2 object from Vec3 coordinates.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param DCS#Vec3 Vec3 The Vec3 point.
|
||||
-- @return Core.Point#POINT_VEC2 self
|
||||
function POINT_VEC2:NewFromVec3( Vec3 )
|
||||
|
||||
local self = BASE:Inherit( self, COORDINATE:NewFromVec3( Vec3 ) ) -- #POINT_VEC2
|
||||
self:F2( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the x coordinate of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @return #number The x coordinate.
|
||||
function POINT_VEC2:GetX()
|
||||
return self.x
|
||||
end
|
||||
|
||||
--- Return the y coordinate of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @return #number The y coordinate.
|
||||
function POINT_VEC2:GetY()
|
||||
return self.z
|
||||
end
|
||||
|
||||
--- Set the x coordinate of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number x The x coordinate.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:SetX( x )
|
||||
self.x = x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the y coordinate of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number y The y coordinate.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:SetY( y )
|
||||
self.z = y
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return Return the Lat(itude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.x).
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @return #number The x coordinate.
|
||||
function POINT_VEC2:GetLat()
|
||||
return self.x
|
||||
end
|
||||
|
||||
--- Set the Lat(itude) coordinate of the POINT_VEC2 (ie: POINT_VEC3.x).
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number x The x coordinate.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:SetLat( x )
|
||||
self.x = x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the Lon(gitude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.z).
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @return #number The y coordinate.
|
||||
function POINT_VEC2:GetLon()
|
||||
return self.z
|
||||
end
|
||||
|
||||
--- Set the Lon(gitude) coordinate of the POINT_VEC2 (ie: POINT_VEC3.z).
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number y The y coordinate.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:SetLon( z )
|
||||
self.z = z
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the altitude (height) of the land at the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @return #number The land altitude.
|
||||
function POINT_VEC2:GetAlt()
|
||||
return self.y ~= 0 or land.getHeight( { x = self.x, y = self.z } )
|
||||
end
|
||||
|
||||
--- Set the altitude of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number Altitude The land altitude. If nothing (nil) is given, then the current land altitude is set.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:SetAlt( Altitude )
|
||||
self.y = Altitude or land.getHeight( { x = self.x, y = self.z } )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the x coordinate of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number x The x coordinate.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:AddX( x )
|
||||
self.x = self.x + x
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the y coordinate of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number y The y coordinate.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:AddY( y )
|
||||
self.z = self.z + y
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add to the current land height an altitude.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #number Altitude The Altitude to add. If nothing (nil) is given, then the current land altitude is set.
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:AddAlt( Altitude )
|
||||
self.y = land.getHeight( { x = self.x, y = self.z } ) + Altitude or 0
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC2.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param DCS#Distance OuterRadius
|
||||
-- @param DCS#Distance InnerRadius
|
||||
-- @return #POINT_VEC2
|
||||
function POINT_VEC2:GetRandomPointVec2InRadius( OuterRadius, InnerRadius )
|
||||
self:F2( { OuterRadius, InnerRadius } )
|
||||
|
||||
return POINT_VEC2:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) )
|
||||
end
|
||||
|
||||
-- TODO: Check this to replace
|
||||
--- Calculate the distance from a reference @{#POINT_VEC2}.
|
||||
-- @param #POINT_VEC2 self
|
||||
-- @param #POINT_VEC2 PointVec2Reference The reference @{#POINT_VEC2}.
|
||||
-- @return DCS#Distance The distance from the reference @{#POINT_VEC2} in meters.
|
||||
function POINT_VEC2:DistanceFromPointVec2( PointVec2Reference )
|
||||
self:F2( PointVec2Reference )
|
||||
|
||||
local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5
|
||||
|
||||
self:T2( Distance )
|
||||
return Distance
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -175,7 +175,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local Name = Info.name or "?"
|
||||
|
||||
local ErrorHandler = function( errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg or "" )
|
||||
if BASE.Debug ~= nil then
|
||||
env.info( BASE.Debug.traceback() )
|
||||
end
|
||||
@@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
||||
if Schedule.ScheduleID then
|
||||
if Schedule and Schedule.ScheduleID then
|
||||
|
||||
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||
|
||||
|
||||
+1393
-1371
File diff suppressed because it is too large
Load Diff
@@ -1049,6 +1049,23 @@ function SPAWN:InitSetUnitAbsolutePositions(Positions)
|
||||
return self
|
||||
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 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.
|
||||
@@ -1631,7 +1648,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
|
||||
if SpawnTemplate then
|
||||
|
||||
local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y )
|
||||
local PointVec3 = COORDINATE:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y )
|
||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
|
||||
|
||||
-- If RandomizePosition, then Randomize the formation in the zone band, keeping the template.
|
||||
@@ -1829,7 +1846,13 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
if self.SpawnHiddenOnMap then
|
||||
SpawnTemplate.hidden=self.SpawnHiddenOnMap
|
||||
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.
|
||||
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
||||
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
||||
@@ -2830,7 +2853,7 @@ end
|
||||
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||
--self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
||||
|
||||
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
|
||||
local PointVec3 = COORDINATE:NewFromVec3( Vec3 )
|
||||
--self:T2( PointVec3 )
|
||||
|
||||
if SpawnIndex then
|
||||
@@ -2906,7 +2929,7 @@ end
|
||||
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
||||
-- You can use the returned group to further define the route to be followed.
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
|
||||
-- @param Core.Point#COORDINATE PointVec3 The COORDINATE coordinates where to spawn the group.
|
||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||
-- @usage
|
||||
@@ -2954,12 +2977,12 @@ function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex )
|
||||
return self:SpawnFromVec3( { x = Vec2.x, y = Height, z = Vec2.y }, SpawnIndex ) -- y can be nil. In this case, spawn on the ground for vehicles, and in the template altitude for air.
|
||||
end
|
||||
|
||||
--- Will spawn a group from a POINT_VEC2 in 3D space.
|
||||
--- Will spawn a group from a COORDINATE in 3D space.
|
||||
-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles.
|
||||
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
||||
-- You can use the returned group to further define the route to be followed.
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 coordinates where to spawn the group.
|
||||
-- @param Core.Point#COORDINATE PointVec2 The coordinates where to spawn the group.
|
||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
--
|
||||
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
||||
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a COORDINATE coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
||||
--
|
||||
-- @field #SPAWNSTATIC SPAWNSTATIC
|
||||
@@ -149,6 +149,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||
self.CategoryID = CategoryID
|
||||
self.CoalitionID = CoalitionID
|
||||
self.SpawnIndex = 0
|
||||
self.StaticCopyFrom = SpawnTemplateName
|
||||
else
|
||||
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||
end
|
||||
@@ -302,12 +303,16 @@ end
|
||||
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
||||
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
||||
-- @param #number Modulation Modulation 0=AM, 1=FM.
|
||||
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns
|
||||
-- @param #boolean DynamicHotStarts If true, and DynamicSpawns is true, then allow Dynamic Spawns with hot starts.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation)
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts)
|
||||
self.InitFarp=true
|
||||
self.InitFarpCallsignID=CallsignID or 1
|
||||
self.InitFarpFreq=Frequency or 127.5
|
||||
self.InitFarpModu=Modulation or 0
|
||||
self.InitFarpDynamicSpawns = DynamicSpawns
|
||||
self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -373,6 +378,20 @@ function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle)
|
||||
return self
|
||||
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.
|
||||
-- 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.
|
||||
@@ -411,9 +430,9 @@ function SPAWNSTATIC:Spawn(Heading, NewName)
|
||||
|
||||
end
|
||||
|
||||
--- Creates a new @{Wrapper.Static} from a POINT_VEC2.
|
||||
--- Creates a new @{Wrapper.Static} from a COORDINATE.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
||||
-- @param Core.Point#COORDINATE PointVec2 The 2D coordinate where to spawn the static.
|
||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
||||
-- @param #string NewName (Optional) The name of the new static.
|
||||
-- @return Wrapper.Static#STATIC The static spawned.
|
||||
@@ -459,8 +478,9 @@ end
|
||||
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||
|
||||
-- Spawn the new static at the center of the zone.
|
||||
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||
|
||||
--local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||
local Static = self:SpawnFromCoordinate(Zone:GetCoordinate(), Heading, NewName)
|
||||
|
||||
return Static
|
||||
end
|
||||
|
||||
@@ -538,6 +558,14 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
-- Add static to the game.
|
||||
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
|
||||
|
||||
local TemplateGroup={}
|
||||
@@ -549,6 +577,13 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
|
||||
if self.InitFarpDynamicSpawns == true then
|
||||
TemplateGroup.units[1].dynamicSpawn = true
|
||||
if self.InitFarpDynamicHotStarts == true then
|
||||
TemplateGroup.units[1].allowHotStart = true
|
||||
end
|
||||
end
|
||||
|
||||
self:T("Spawning FARP")
|
||||
self:T({Template=Template})
|
||||
@@ -556,7 +591,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
|
||||
-- ED's dirty way to spawn FARPS.
|
||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||
|
||||
--Static=coalition.addStaticObject(CountryID, Template)
|
||||
|
||||
-- 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 = {
|
||||
@@ -594,6 +630,18 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
|
||||
self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments))
|
||||
end
|
||||
|
||||
if self.StaticCopyFrom ~= nil then
|
||||
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
||||
end
|
||||
|
||||
local TemplateGroup={}
|
||||
TemplateGroup.units={}
|
||||
TemplateGroup.units[1]=Template
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
||||
|
||||
return mystatic
|
||||
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 #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 #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
|
||||
|
||||
|
||||
@@ -213,7 +214,7 @@ end
|
||||
|
||||
--- Returns if a PointVec3 is within the zone.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test.
|
||||
-- @param Core.Point#COORDINATE PointVec3 The PointVec3 to test.
|
||||
-- @return #boolean true if the PointVec3 is within the zone.
|
||||
function ZONE_BASE:IsPointVec3InZone( PointVec3 )
|
||||
local InZone = self:IsPointVec2InZone( PointVec3 )
|
||||
@@ -227,16 +228,16 @@ function ZONE_BASE:GetVec2()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC2} of the zone.
|
||||
--- Returns a @{Core.Point#COORDINATE} of the zone.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located.
|
||||
-- @return Core.Point#POINT_VEC2 The PointVec2 of the zone.
|
||||
-- @return Core.Point#COORDINATE The COORDINATE of the zone.
|
||||
function ZONE_BASE:GetPointVec2()
|
||||
--self:F2( self.ZoneName )
|
||||
|
||||
local Vec2 = self:GetVec2()
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 )
|
||||
local PointVec2 = COORDINATE:NewFromVec2( Vec2 )
|
||||
|
||||
--self:T2( { PointVec2 } )
|
||||
|
||||
@@ -261,16 +262,16 @@ function ZONE_BASE:GetVec3( Height )
|
||||
return Vec3
|
||||
end
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC3} of the zone.
|
||||
--- Returns a @{Core.Point#COORDINATE} of the zone.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located.
|
||||
-- @return Core.Point#POINT_VEC3 The PointVec3 of the zone.
|
||||
-- @return Core.Point#COORDINATE The PointVec3 of the zone.
|
||||
function ZONE_BASE:GetPointVec3( Height )
|
||||
--self:F2( self.ZoneName )
|
||||
|
||||
local Vec3 = self:GetVec3( Height )
|
||||
|
||||
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
|
||||
local PointVec3 = COORDINATE:NewFromVec3( Vec3 )
|
||||
|
||||
--self:T2( { PointVec3 } )
|
||||
|
||||
@@ -330,16 +331,16 @@ function ZONE_BASE:GetRandomVec2()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||
function ZONE_BASE:GetRandomPointVec2()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Define a random @{Core.Point#POINT_VEC3} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates.
|
||||
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||
function ZONE_BASE:GetRandomPointVec3()
|
||||
return nil
|
||||
end
|
||||
@@ -534,6 +535,19 @@ function ZONE_BASE:GetZoneProbability()
|
||||
return self.ZoneProbability
|
||||
end
|
||||
|
||||
--- Get the coordinate on the radius of the zone nearest to Outsidecoordinate. Useto e.g. find an ingress point.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param Core.Point#COORDINATE Outsidecoordinate The coordinate outside of the zone from where to look.
|
||||
-- @return Core.Point#COORDINATE CoordinateOnRadius
|
||||
function ZONE_BASE:FindNearestCoordinateOnRadius(Outsidecoordinate)
|
||||
local Vec1 = self:GetVec2()
|
||||
local Radius = self:GetRadius()
|
||||
local Vec2 = Outsidecoordinate:GetVec2()
|
||||
local Point = UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
||||
local rc = COORDINATE:NewFromVec2(Point)
|
||||
return rc
|
||||
end
|
||||
|
||||
--- Get the zone taking into account the randomization probability of a zone to be selected.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor.
|
||||
@@ -599,6 +613,8 @@ end
|
||||
--
|
||||
-- -- Stop watching the zone after 1 hour
|
||||
-- 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)
|
||||
--self:I("Added Zone Trigger")
|
||||
self:SetStartState("TriggerStopped")
|
||||
@@ -667,6 +683,16 @@ function ZONE_BASE:Trigger(Objects)
|
||||
|
||||
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
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param #boolean fromstart If true, do the init of the objects
|
||||
@@ -705,7 +731,12 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
||||
obj.TriggerInZone[self.ZoneName] = false
|
||||
end
|
||||
-- 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))
|
||||
if inzone and obj.TriggerInZone[self.ZoneName] then
|
||||
-- just count
|
||||
@@ -814,8 +845,8 @@ end
|
||||
-- Various functions exist to find random points within the zone.
|
||||
--
|
||||
-- * @{#ZONE_RADIUS.GetRandomVec2}(): Gets a random 2D point in the zone.
|
||||
-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Core.Point#POINT_VEC2} object representing a random 2D point in the zone.
|
||||
-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Core.Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight.
|
||||
-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Core.Point#COORDINATE} object representing a random 2D point in the zone.
|
||||
-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Core.Point#COORDINATE} object representing a random 3D point in the zone. Note that the height of the point is at landheight.
|
||||
--
|
||||
-- ## Draw zone
|
||||
--
|
||||
@@ -1010,7 +1041,7 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
|
||||
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
|
||||
COORDINATE:New( Point.x, AddHeight, Point.y ):Smoke( SmokeColor )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -1040,7 +1071,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight )
|
||||
local Radial = Angle * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
|
||||
COORDINATE:New( Point.x, AddHeight, Point.y ):Flare( FlareColor, Azimuth )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -1134,7 +1165,7 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||
self.ScanData.SceneryTable = {}
|
||||
self.ScanData.Units = {}
|
||||
|
||||
local ZoneCoord = self:GetCoordinate()
|
||||
local ZoneCoord = self:GetCoordinate():SetAlt()
|
||||
local ZoneRadius = self:GetRadius()
|
||||
|
||||
--self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
|
||||
@@ -1149,15 +1180,13 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
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 then
|
||||
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||
|
||||
-- Get object category.
|
||||
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
|
||||
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
|
||||
local Include = false
|
||||
if not UnitCategories then
|
||||
-- Anything found is included.
|
||||
@@ -1509,6 +1538,26 @@ function ZONE_RADIUS:IsVec3InZone( Vec3 )
|
||||
return InZone
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions)
|
||||
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Returns a random Vec2 location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||
@@ -1520,6 +1569,10 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
||||
local Vec2 = self:GetVec2()
|
||||
local _inner = inner or 0
|
||||
local _outer = outer or self:GetRadius()
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
if surfacetypes and type(surfacetypes)~="table" then
|
||||
surfacetypes={surfacetypes}
|
||||
@@ -1561,15 +1614,15 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
||||
return point
|
||||
end
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
||||
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||
function ZONE_RADIUS:GetRandomPointVec2( inner, outer )
|
||||
--self:F( self.ZoneName, inner, outer )
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
||||
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
||||
|
||||
--self:T3( { PointVec2 } )
|
||||
|
||||
@@ -1592,15 +1645,15 @@ function ZONE_RADIUS:GetRandomVec3( inner, outer )
|
||||
end
|
||||
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#POINT_VEC3 The @{Core.Point#POINT_VEC3} object reflecting the random 3D location within the zone.
|
||||
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||
function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
|
||||
--self:F( self.ZoneName, inner, outer )
|
||||
|
||||
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
||||
local PointVec3 = COORDINATE:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
||||
|
||||
--self:T3( { PointVec3 } )
|
||||
|
||||
@@ -1881,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
|
||||
return self
|
||||
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}.
|
||||
-- @param #ZONE_UNIT self
|
||||
@@ -2018,6 +2086,22 @@ function ZONE_GROUP:GetVec2()
|
||||
return ZoneVec2
|
||||
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}.
|
||||
-- @param #ZONE_GROUP self
|
||||
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
||||
@@ -2036,15 +2120,15 @@ function ZONE_GROUP:GetRandomVec2()
|
||||
return Point
|
||||
end
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
-- @param #ZONE_GROUP self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
||||
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||
function ZONE_GROUP:GetRandomPointVec2( inner, outer )
|
||||
--self:F( self.ZoneName, inner, outer )
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
||||
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
--self:T3( { PointVec2 } )
|
||||
|
||||
@@ -2192,8 +2276,8 @@ end
|
||||
-- Various functions exist to find random points within the zone.
|
||||
--
|
||||
-- * @{#ZONE_POLYGON_BASE.GetRandomVec2}(): Gets a random 2D point in the zone.
|
||||
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Core.Point#POINT_VEC2} object representing a random 2D point within the zone.
|
||||
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone.
|
||||
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Core.Point#COORDINATE} object representing a random 2D point within the zone.
|
||||
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Core.Point#COORDINATE} object representing a random 3D point at landheight within the zone.
|
||||
--
|
||||
-- ## Draw zone
|
||||
--
|
||||
@@ -2487,6 +2571,26 @@ function ZONE_POLYGON_BASE:Flush()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function ZONE_POLYGON_BASE:GetClearZonePositions(PosRadius, NumPositions)
|
||||
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function ZONE_POLYGON_BASE:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Smokes the zone boundaries in a color.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #boolean UnBound If true, the tyres will be destroyed.
|
||||
@@ -2769,7 +2873,7 @@ function ZONE_POLYGON_BASE:SmokeZone( SmokeColor, Segments )
|
||||
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
|
||||
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
|
||||
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
|
||||
POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor )
|
||||
COORDINATE:New( PointX, 0, PointY ):Smoke( SmokeColor )
|
||||
end
|
||||
j = i
|
||||
i = i + 1
|
||||
@@ -2804,7 +2908,7 @@ function ZONE_POLYGON_BASE:FlareZone( FlareColor, Segments, Azimuth, AddHeight )
|
||||
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
|
||||
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
|
||||
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
|
||||
POINT_VEC2:New( PointX, PointY, AddHeight ):Flare(FlareColor, Azimuth)
|
||||
COORDINATE:New( PointX, AddHeight, PointY ):Flare(FlareColor, Azimuth)
|
||||
end
|
||||
j = i
|
||||
i = i + 1
|
||||
@@ -2865,6 +2969,11 @@ end
|
||||
function ZONE_POLYGON_BASE:GetRandomVec2()
|
||||
-- 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
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
local weights = {}
|
||||
for _, triangle in pairs(self._Triangles) do
|
||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||
@@ -2880,26 +2989,26 @@ function ZONE_POLYGON_BASE:GetRandomVec2()
|
||||
end
|
||||
end
|
||||
|
||||
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
--- Return a @{Core.Point#COORDINATE} object representing a random 2D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @return @{Core.Point#POINT_VEC2}
|
||||
-- @return @{Core.Point#COORDINATE}
|
||||
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
||||
--self:F2()
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
||||
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
--self:T2( PointVec2 )
|
||||
|
||||
return PointVec2
|
||||
end
|
||||
|
||||
--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
--- Return a @{Core.Point#COORDINATE} object representing a random 3D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @return @{Core.Point#POINT_VEC3}
|
||||
-- @return @{Core.Point#COORDINATE}
|
||||
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
||||
--self:F2()
|
||||
|
||||
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2() )
|
||||
local PointVec3 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
--self:T2( PointVec3 )
|
||||
|
||||
@@ -3204,12 +3313,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local vectors = self:GetBoundingSquare()
|
||||
|
||||
local minVec3 = {x=vectors.x1, y=0, z=vectors.y1}
|
||||
local maxVec3 = {x=vectors.x2, y=0, z=vectors.y2}
|
||||
|
||||
local minmarkcoord = COORDINATE:NewFromVec3(minVec3)
|
||||
local maxmarkcoord = COORDINATE:NewFromVec3(maxVec3)
|
||||
local ZoneRadius = minmarkcoord:Get2DDistance(maxmarkcoord)/2
|
||||
local ZoneRadius = UTILS.VecDist2D({x=vectors.x1, y=vectors.y1}, {x=vectors.x2, y=vectors.y2})/2
|
||||
-- self:I("Scan Radius:" ..ZoneRadius)
|
||||
local CenterVec3 = self:GetCoordinate():GetVec3()
|
||||
|
||||
@@ -3233,14 +3337,12 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local function EvaluateZone( ZoneObject )
|
||||
|
||||
if ZoneObject then
|
||||
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||
|
||||
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
|
||||
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
|
||||
local Include = false
|
||||
if not UnitCategories then
|
||||
-- Anything found is included.
|
||||
@@ -3272,7 +3374,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
end
|
||||
|
||||
-- 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 SceneryName = ZoneObject:getName()
|
||||
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
||||
@@ -3931,18 +4033,18 @@ function ZONE_OVAL:GetRandomVec2()
|
||||
return {x=rx, y=ry}
|
||||
end
|
||||
|
||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
-- @param #ZONE_OVAL self
|
||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||
function ZONE_OVAL:GetRandomPointVec2()
|
||||
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
||||
return COORDINATE:NewFromVec2(self:GetRandomVec2())
|
||||
end
|
||||
|
||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||
-- @param #ZONE_OVAL self
|
||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||
function ZONE_OVAL:GetRandomPointVec3()
|
||||
return POINT_VEC3:NewFromVec3(self:GetRandomVec2())
|
||||
return COORDINATE:NewFromVec3(self:GetRandomVec2())
|
||||
end
|
||||
|
||||
--- Draw the zone on the F10 map.
|
||||
@@ -4082,15 +4184,15 @@ do -- ZONE_AIRBASE
|
||||
return ZoneVec2
|
||||
end
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||
-- @param #ZONE_AIRBASE self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
||||
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||
function ZONE_AIRBASE:GetRandomPointVec2( inner, outer )
|
||||
--self:F( self.ZoneName, inner, outer )
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
||||
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
--self:T3( { PointVec2 } )
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
-- @module Core.Zone_Detection
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
--- @type ZONE_DETECTION
|
||||
---
|
||||
-- @type ZONE_DETECTION
|
||||
-- @field DCS#Vec2 Vec2 The current location of the zone.
|
||||
-- @field DCS#Distance Radius The radius of the zone.
|
||||
-- @extends #ZONE_BASE
|
||||
@@ -106,7 +107,7 @@ function ZONE_DETECTION:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
|
||||
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
|
||||
COORDINATE:New( Point.x, AddHeight, Point.y):Smoke( SmokeColor )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -137,7 +138,7 @@ function ZONE_DETECTION:FlareZone( FlareColor, Points, Azimuth, AddHeight )
|
||||
local Radial = Angle * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
|
||||
COORDINATE:New( Point.x, AddHeight, Point.y ):Flare( FlareColor, Azimuth )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -201,4 +202,3 @@ function ZONE_DETECTION:IsVec3InZone( Vec3 )
|
||||
|
||||
return InZone
|
||||
end
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ end -- env
|
||||
|
||||
do -- radio
|
||||
|
||||
---@type radio
|
||||
--@type radio
|
||||
-- @field #radio.modulation modulation
|
||||
|
||||
---
|
||||
|
||||
@@ -141,7 +141,6 @@ FOX = {
|
||||
explosiondist = 200,
|
||||
explosiondist2 = 500,
|
||||
bigmissilemass = 50,
|
||||
destroy = nil,
|
||||
dt50 = 5,
|
||||
dt10 = 1,
|
||||
dt05 = 0.5,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: Mar 2025
|
||||
-- Last Update: August 2025
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -62,7 +62,9 @@
|
||||
-- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects.
|
||||
-- @field #boolean SmokeDecoy If true, smoke short range SAM units as decoy if a plane is in firing range.
|
||||
-- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White
|
||||
-- @field #number checkcounter Counter for SAM Table refreshes
|
||||
-- @field #number checkcounter Counter for SAM Table refreshes.
|
||||
-- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay.
|
||||
-- @field #boolean logsamstatus Log SAM status in dcs.log every cycle if true
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
@@ -74,10 +76,9 @@
|
||||
--
|
||||
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
|
||||
-- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy.
|
||||
-- * **Automatic mode** (default since 0.8) will set-up your SAM site network automatically for you
|
||||
-- * **Classic mode** behaves like before
|
||||
-- * Leverage evasiveness from SEAD, leverage attack range setting
|
||||
-- * Automatic setup of SHORAD based on groups of the class "short-range"
|
||||
-- * **Automatic mode** (default) will set-up your SAM site network automatically for you.
|
||||
-- * Leverage evasiveness from SEAD, leverage attack range setting.
|
||||
-- * Automatic setup of SHORAD based on groups of the class "short-range".
|
||||
--
|
||||
-- # 0. Base considerations and naming conventions
|
||||
--
|
||||
@@ -107,10 +108,15 @@
|
||||
-- * Patriot
|
||||
-- * Rapier
|
||||
-- * Roland
|
||||
-- * IRIS-T SLM
|
||||
-- * Pantsir S1
|
||||
-- * TOR M2
|
||||
-- * C-RAM
|
||||
-- * 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
|
||||
-- * 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
|
||||
-- * 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
|
||||
-- **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"
|
||||
@@ -124,19 +130,20 @@
|
||||
-- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS")
|
||||
-- * SA-2 (with HQ-2 launcher, use HQ-2 in the group name, e.g. "Red SAM HQ-2" )
|
||||
-- * SA-3 (with V601P missile, e.g. "Red SAM SA-3 HDS")
|
||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS")
|
||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS")
|
||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS")
|
||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS")
|
||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS" with 5P85CE launcher)
|
||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS" with 5P85SE launcher)
|
||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS 2" for the 9A82 variant and "Red SAM SA-12 HDS 1" for the 9A83 variant)
|
||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 1" for the 9A83ME variant)
|
||||
-- * SAMP/T (launcher dependent range, e.g. "Blue SAM SAMPT Block 1 HDS" for Block 1, "Blue SAM SAMPT Block 1INT HDS", "Blue SAM SAMPT Block 2 HDS")
|
||||
--
|
||||
-- The other HDS types work like the rest of the known SAM systems.
|
||||
--
|
||||
-- # 0.1 Set-up in the mission editor
|
||||
--
|
||||
-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.
|
||||
-- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
||||
-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
||||
-- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself.
|
||||
-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one** group per SAM location. SA-15 TOR systems offer a good missile defense.
|
||||
-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location.
|
||||
-- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense.
|
||||
--
|
||||
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
|
||||
--
|
||||
@@ -188,7 +195,7 @@
|
||||
--
|
||||
-- ## 2.1 Auto mode features
|
||||
--
|
||||
-- ### 2.1.1 You can now add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
||||
-- ### 2.1.1 You can add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
||||
--
|
||||
-- -- Parameters are tables of Core.Zone#ZONE objects!
|
||||
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
||||
@@ -205,9 +212,6 @@
|
||||
-- ### 2.1.3 SHORAD/Point defense will automatically be added from SAM sites of type "point" or if the range is less than 5km or if the type is AAA.
|
||||
--
|
||||
-- ### 2.1.4 Advanced features
|
||||
--
|
||||
-- -- Option to switch off auto mode **before** you start MANTIS (not recommended)
|
||||
-- mybluemantis.automode = false
|
||||
--
|
||||
-- -- Option to set the scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
||||
-- -- also see engagerange below.
|
||||
@@ -220,6 +224,12 @@
|
||||
--
|
||||
-- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire.
|
||||
-- mybluemantis.checkforfriendlies = true
|
||||
--
|
||||
-- ### 2.1.6 Shoot & Scoot
|
||||
--
|
||||
-- -- Option to make the (driveable) SHORAD units drive around and shuffle positions
|
||||
-- -- We use a SET_ZONE for that, number of zones to consider defaults to three, Random is true for random coordinates and Formation is e.g. "Vee".
|
||||
-- mybluemantis:AddScootZones(ZoneSet, Number, Random, Formation)
|
||||
--
|
||||
-- # 3. Default settings [both modes unless stated otherwise]
|
||||
--
|
||||
@@ -242,26 +252,8 @@
|
||||
-- E.g. mymantis:SetAdvancedMode( true, 90 )
|
||||
--
|
||||
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
||||
--
|
||||
-- # 5. Integrate SHORAD [classic mode, not necessary in automode, not recommended for manual setup]
|
||||
--
|
||||
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs manually. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in
|
||||
-- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so:
|
||||
--
|
||||
-- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
|
||||
-- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")
|
||||
-- -- now set up MANTIS
|
||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||
-- mymantis:AddShorad(myshorad,720)
|
||||
-- mymantis:Start()
|
||||
--
|
||||
-- If you systematically name your SHORAD groups starting with "Blue SHORAD" you'll need exactly **one** SHORAD instance to manage all SHORAD groups.
|
||||
--
|
||||
-- (Optionally) you can remove the link later on with
|
||||
--
|
||||
-- mymantis:RemoveShorad()
|
||||
--
|
||||
-- # 6. Integrated SEAD
|
||||
-- # 5. Integrated SEAD
|
||||
--
|
||||
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
|
||||
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||
@@ -288,6 +280,7 @@
|
||||
MANTIS = {
|
||||
ClassName = "MANTIS",
|
||||
name = "mymantis",
|
||||
version = "0.9.34",
|
||||
SAM_Templates_Prefix = "",
|
||||
SAM_Group = nil,
|
||||
EWR_Templates_Prefix = "",
|
||||
@@ -336,6 +329,8 @@ MANTIS = {
|
||||
SmokeDecoy = false,
|
||||
SmokeDecoyColor = SMOKECOLOR.White,
|
||||
checkcounter = 1,
|
||||
DLinkCacheTime = 120,
|
||||
logsamstatus = false,
|
||||
}
|
||||
|
||||
--- Advanced state enumerator
|
||||
@@ -374,7 +369,7 @@ MANTIS.radiusscale[MANTIS.SamType.POINT] = 3
|
||||
MANTIS.SamData = {
|
||||
["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km
|
||||
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B
|
||||
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" },
|
||||
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot str" },
|
||||
["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
||||
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
||||
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
||||
@@ -382,7 +377,8 @@ MANTIS.SamData = {
|
||||
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
||||
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
||||
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
||||
["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Point", Radar="Roland" },
|
||||
["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland" },
|
||||
["Gepard"] = { Range=5, Blindspot=0, Height=4, Type="Point", Radar="Gepard" },
|
||||
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
||||
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" },
|
||||
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
||||
@@ -393,14 +389,21 @@ MANTIS.SamData = {
|
||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||
["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" },
|
||||
["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
|
||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
||||
["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" },
|
||||
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
||||
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
|
||||
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
|
||||
["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" },
|
||||
["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
|
||||
@@ -416,13 +419,17 @@ MANTIS.SamDataHDS = {
|
||||
-- group name MUST contain HDS to ID launcher type correctly!
|
||||
["SA-2 HDS"] = { Range=56, Blindspot=7, Height=30, Type="Medium", Radar="V759" },
|
||||
["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" },
|
||||
["SA-10C HDS 2"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85DE ln"}, -- V55RUD
|
||||
["SA-10C HDS 1"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=10, Height=25, Type="Long" , Radar="S-300V 9A82 l"},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=1, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||
["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||
["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln"}, -- V55RUD
|
||||
["SA-17 HDS"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17 " },
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l"},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||
["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" },
|
||||
["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" },
|
||||
["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||
["SAMPT Block 1 HDS"] = { Range=120, Blindspot=1, Height=20, Type="long", Radar="SAMPT_MLT_Blk1" }, -- Block 1 Launcher
|
||||
["SAMPT Block 1INT HDS"] = { Range=150, Blindspot=1, Height=25, Type="long", Radar="SAMPT_MLT_Blk1NT" }, -- Block 1-INT Launcher
|
||||
["SAMPT Block 2 HDS"] = { Range=200, Blindspot=10, Height=70, Type="long", Radar="SAMPT_MLT_Blk2" }, -- Block 2 Launcher
|
||||
}
|
||||
|
||||
--- SAM data SMA
|
||||
@@ -437,16 +444,16 @@ MANTIS.SamDataSMA = {
|
||||
-- units from SMA Mod (Sweedish Military Assets)
|
||||
-- https://forum.dcs.world/topic/295202-swedish-military-assets-for-dcs-by-currenthill/
|
||||
-- group name MUST contain SMA to ID launcher type correctly!
|
||||
["RBS98M SMA"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
|
||||
["RBS70 SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
|
||||
["RBS70M SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="BV410_RBS70" },
|
||||
["RBS90 SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
|
||||
["RBS90M SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="BV410_RBS90" },
|
||||
["RBS103A SMA"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||
["RBS103B SMA"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
|
||||
["RBS103AM SMA"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||
["RBS103BM SMA"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||
["Lvkv9040M SMA"] = { Range=4, Blindspot=0, Height=2.5, Type="Point", Radar="LvKv9040",Point="true" },
|
||||
["RBS98M SMA"] = { Range=20, Blindspot=0.2, Height=8, Type="Short", Radar="RBS-98" },
|
||||
["RBS70 SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-70" },
|
||||
["RBS70M SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS70" },
|
||||
["RBS90 SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-90" },
|
||||
["RBS90M SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS90" },
|
||||
["RBS103A SMA"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||
["RBS103B SMA"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103B" },
|
||||
["RBS103AM SMA"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||
["RBS103BM SMA"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||
["Lvkv9040M SMA"] = { Range=2, Blindspot=0.1, Height=1.2, Type="Point", Radar="LvKv9040",Point="true" },
|
||||
}
|
||||
|
||||
--- SAM data CH
|
||||
@@ -461,47 +468,49 @@ MANTIS.SamDataCH = {
|
||||
-- units from CH (Military Assets by Currenthill)
|
||||
-- https://www.currenthill.com/
|
||||
-- group name MUST contain CHM to ID launcher type correctly!
|
||||
["2S38 CHM"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
|
||||
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
||||
["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" },
|
||||
["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" },
|
||||
["PGL-625 CHM"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
|
||||
["HQ-17A CHM"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
||||
["M903PAC2 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
||||
["M903PAC3 CHM"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
||||
["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" },
|
||||
["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" },
|
||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" },
|
||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2K", Point="true" },
|
||||
["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-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" },
|
||||
["PGZ-09 CHM"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="CH_PGZ09", Point="true" },
|
||||
["S350-9M100 CHM"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
|
||||
["PGZ-09 CHM"] = { Range=4, Blindspot=0.5, Height=3, Type="Point", Radar="CH_PGZ09", Point="true" },
|
||||
["S350-9M100 CHM"] = { Range=15, Blindspot=1, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
|
||||
["S350-9M96D CHM"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
|
||||
["LAV-AD CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
|
||||
["LAV-AD CHM"] = { Range=8, Blindspot=0.16, Height=4.8, Type="Short", Radar="CH_LAVAD" },
|
||||
["HQ-22 CHM"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
|
||||
["PGZ-95 CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_PGZ95",Point="true" },
|
||||
["LD-3000 CHM"] = { Range=3, Blindspot=0, Height=3, Type="Point", Radar="CH_LD3000_stationary", Point="true" },
|
||||
["LD-3000M CHM"] = { Range=3, Blindspot=0, Height=3, Type="Point", Radar="CH_LD3000", Point="true" },
|
||||
["FlaRakRad CHM"] = { Range=8, Blindspot=1.5, Height=6, Type="Short", Radar="HQ17A" },
|
||||
["PGZ-95 CHM"] = { Range=2.5, Blindspot=0.5, Height=2, Type="Point", Radar="CH_PGZ95",Point="true" },
|
||||
["LD-3000 CHM"] = { Range=2.5, Blindspot=0.1, Height=3, Type="Point", Radar="CH_LD3000_stationary", Point="true" },
|
||||
["LD-3000M CHM"] = { Range=2.5, Blindspot=0.1, Height=3, Type="Point", Radar="CH_LD3000", Point="true" },
|
||||
["FlaRakRad CHM"] = { Range=8, Blindspot=1.5, Height=6, Type="Short", Radar="CH_FlaRakRad" },
|
||||
["IRIS-T SLM CHM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
|
||||
["M903PAC2KAT1 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="CH_MIM104_M903_PAC2_KAT1" },
|
||||
["Skynex CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Point", Radar="CH_SkynexHX", Point="true" },
|
||||
["Skyshield CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Point", Radar="CH_Skyshield_Gun", Point="true" },
|
||||
["WieselOzelot CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_Wiesel2Ozelot" },
|
||||
["M903PAC2KAT1 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="CH_MIM104_M903_PAC2_KAT1" },
|
||||
["Skynex CHM"] = { Range=3.5, Blindspot=0.1, Height=3.5, Type="Point", Radar="CH_SkynexHX", Point="true" },
|
||||
["Skyshield CHM"] = { Range=3.5, Blindspot=0.1, Height=3.5, Type="Point", Radar="CH_Skyshield_Gun", Point="true" },
|
||||
["WieselOzelot CHM"] = { Range=8, Blindspot=0.16, Height=4.8, Type="Short", Radar="CH_Wiesel2Ozelot" },
|
||||
["BukM3-9M317M CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317M" },
|
||||
["BukM3-9M317MA CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317MA" },
|
||||
["SkySabre CHM"] = { Range=30, Blindspot=0.5, Height=10, Type="Medium", Radar="CH_SkySabreLN" },
|
||||
["Stormer CHM"] = { Range=7.5, Blindspot=0.3, Height=7, Type="Short", Radar="CH_StormerHVM" },
|
||||
["THAAD CHM"] = { Range=200, Blindspot=40, Height=150, Type="Long", Radar="CH_THAAD_M1120" },
|
||||
["USInfantryFIM92K CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_USInfantry_FIM92" },
|
||||
["RBS98M CHM"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
|
||||
["RBS70 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
|
||||
["RBS90 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
|
||||
["RBS103A CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||
["RBS103B CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
|
||||
["RBS103AM CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||
["RBS103BM CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||
["Lvkv9040M CHM"] = { Range=4, Blindspot=0, Height=2.5, Type="Point", Radar="LvKv9040", Point="true" },
|
||||
["USInfantryFIM92K CHM"] = { Range=8, Blindspot=0.16, Height=4.8, Type="Short", Radar="CH_USInfantry_FIM92" },
|
||||
["RBS98M CHM"] = { Range=20, Blindspot=0.2, Height=8, Type="Short", Radar="RBS-98" },
|
||||
["RBS70 CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-70" },
|
||||
["RBS70M CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS70" },
|
||||
["RBS90 CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-90" },
|
||||
["RBS90M CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS90" },
|
||||
["RBS103A CHM"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||
["RBS103B CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103B" },
|
||||
["RBS103AM CHM"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||
["RBS103BM CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||
["Lvkv9040M CHM"] = { Range=2, Blindspot=0.1, Height=1.2, Type="Point", Radar="LvKv9040",Point="true" },
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
@@ -623,7 +632,8 @@ do
|
||||
self.advAwacs = false
|
||||
end
|
||||
|
||||
|
||||
self:SetDLinkCacheTime()
|
||||
|
||||
-- Set the string id for output to DCS.log file.
|
||||
self.lid=string.format("MANTIS %s | ", self.name)
|
||||
|
||||
@@ -656,6 +666,8 @@ do
|
||||
table.insert(self.ewr_templates,awacs)
|
||||
end
|
||||
|
||||
self.logsamstatus = false
|
||||
|
||||
self:T({self.ewr_templates})
|
||||
|
||||
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition)
|
||||
@@ -685,9 +697,6 @@ do
|
||||
-- counter for SAM table updates
|
||||
self.checkcounter = 1
|
||||
|
||||
-- TODO Version
|
||||
-- @field #string version
|
||||
self.version="0.9.27"
|
||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||
|
||||
--- FSM Functions ---
|
||||
@@ -884,7 +893,11 @@ do
|
||||
self.AcceptZones = AcceptZones or {}
|
||||
self.RejectZones = RejectZones 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
|
||||
end
|
||||
return self
|
||||
@@ -1037,6 +1050,16 @@ do
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Function to set how long INTEL DLINK remembers contacts.
|
||||
-- @param #MANTIS self
|
||||
-- @param #number seconds Remember this many seconds, at least 5 seconds.
|
||||
-- @return #MANTIS self
|
||||
function MANTIS:SetDLinkCacheTime(seconds)
|
||||
self.DLinkCacheTime = math.abs(seconds or 120)
|
||||
if self.DLinkCacheTime < 5 then self.DLinkCacheTime = 5 end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Function to set the detection interval
|
||||
-- @param #MANTIS self
|
||||
@@ -1266,7 +1289,8 @@ do
|
||||
self:T(self.lid.."_CheckCoordinateInZones")
|
||||
local inzone = false
|
||||
-- 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
|
||||
local zone = _zone -- Core.Zone#ZONE
|
||||
if zone:IsCoordinateInZone(coord) then
|
||||
@@ -1277,7 +1301,7 @@ do
|
||||
end
|
||||
end
|
||||
-- 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
|
||||
local zone = _zone -- Core.Zone#ZONE
|
||||
if zone:IsCoordinateInZone(coord) then
|
||||
@@ -1288,7 +1312,7 @@ do
|
||||
end
|
||||
end
|
||||
-- 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
|
||||
local zone = _zone -- Core.Zone#ZONE
|
||||
if zone:IsCoordinateInZone(coord) then
|
||||
@@ -1354,6 +1378,7 @@ do
|
||||
end
|
||||
-- check accept/reject zones
|
||||
local zonecheck = true
|
||||
self:T("self.usezones = "..tostring(self.usezones))
|
||||
if self.usezones then
|
||||
-- DONE
|
||||
zonecheck = self:_CheckCoordinateInZones(coord)
|
||||
@@ -1429,7 +1454,9 @@ do
|
||||
--IntelTwo:SetClusterRadius(5000)
|
||||
IntelTwo:Start()
|
||||
|
||||
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,300)
|
||||
local CacheTime = self.DLinkCacheTime or 120
|
||||
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,CacheTime)
|
||||
|
||||
IntelDlink:__Start(1)
|
||||
|
||||
self:SetUsingDLink(IntelDlink)
|
||||
@@ -1491,7 +1518,7 @@ do
|
||||
elseif chm then
|
||||
SAMData = self.SamDataCH
|
||||
end
|
||||
--self:T("Looking to auto-match for "..grpname)
|
||||
--self:I("Looking to auto-match for "..grpname)
|
||||
for _,_unit in pairs(units) do
|
||||
local unit = _unit -- Wrapper.Unit#UNIT
|
||||
local type = string.lower(unit:GetTypeName())
|
||||
@@ -1692,7 +1719,9 @@ do
|
||||
local grpname = group:GetName()
|
||||
local grpcoord = group:GetCoordinate()
|
||||
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||
local radaralive = group:IsSAM()
|
||||
-- TODO the below might stop working at some point after some hours, needs testing
|
||||
--local radaralive = group:IsSAM()
|
||||
local radaralive = true
|
||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type}) -- make the table lighter, as I don't really use the zone here
|
||||
table.insert( SEAD_Grps, grpname )
|
||||
if type == MANTIS.SamType.LONG and radaralive then
|
||||
@@ -1789,7 +1818,7 @@ do
|
||||
if self.Shorad and self.Shorad.ActiveGroups and self.Shorad.ActiveGroups[name] then
|
||||
activeshorad = true
|
||||
end
|
||||
if IsInZone and not suppressed and not activeshorad then --check any target in zone and not currently managed by SEAD
|
||||
if IsInZone and (not suppressed) and (not activeshorad) then --check any target in zone and not currently managed by SEAD
|
||||
if samgroup:IsAlive() then
|
||||
-- switch on SAM
|
||||
local switch = false
|
||||
@@ -1821,7 +1850,7 @@ do
|
||||
-- link in to SHORAD if available
|
||||
-- DONE: Test integration fully
|
||||
if self.ShoradLink and (Distance < self.ShoradActDistance or Distance < blind ) then -- don't give SHORAD position away too early
|
||||
local Shorad = self.Shorad
|
||||
local Shorad = self.Shorad --Functional.Shorad#SHORAD
|
||||
local radius = self.checkradius
|
||||
local ontime = self.ShoradTime
|
||||
Shorad:WakeUpShorad(name, radius, ontime)
|
||||
@@ -1854,7 +1883,7 @@ do
|
||||
end --end alive
|
||||
end --end check
|
||||
end --for loop
|
||||
if self.debug or self.verbose then
|
||||
if self.debug or self.verbose or self.logsamstatus then
|
||||
for _,_status in pairs(self.SamStateTracker) do
|
||||
if _status == "GREEN" then
|
||||
instatusgreen=instatusgreen+1
|
||||
@@ -1875,8 +1904,9 @@ do
|
||||
-- @param #MANTIS self
|
||||
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
|
||||
-- @param #boolean dlink
|
||||
-- @param #boolean reporttolog
|
||||
-- @return #MANTIS self
|
||||
function MANTIS:_Check(detection,dlink)
|
||||
function MANTIS:_Check(detection,dlink,reporttolog)
|
||||
self:T(self.lid .. "Check")
|
||||
--get detected set
|
||||
local detset = detection:GetDetectedItemCoordinates()
|
||||
@@ -1903,7 +1933,8 @@ do
|
||||
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||
instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic)
|
||||
end
|
||||
if self.debug or self.verbose then
|
||||
|
||||
local function GetReport()
|
||||
local statusreport = REPORT:New("\nMANTIS Status "..self.name)
|
||||
statusreport:Add("+-----------------------------+")
|
||||
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
||||
@@ -1912,7 +1943,15 @@ do
|
||||
statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads))
|
||||
end
|
||||
statusreport:Add("+-----------------------------+")
|
||||
return statusreport
|
||||
end
|
||||
|
||||
if self.debug or self.verbose then
|
||||
local statusreport = GetReport()
|
||||
MESSAGE:New(statusreport:Text(),10):ToAll():ToLog()
|
||||
elseif reporttolog == true then
|
||||
local statusreport = GetReport()
|
||||
MESSAGE:New(statusreport:Text(),10):ToLog()
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -2020,7 +2059,7 @@ do
|
||||
self:T({From, Event, To})
|
||||
-- check detection
|
||||
if not self.state2flag then
|
||||
self:_Check(self.Detection,self.DLink)
|
||||
self:_Check(self.Detection,self.DLink,self.logsamstatus)
|
||||
end
|
||||
|
||||
local EWRAlive = self:_CheckAnyEWRAlive()
|
||||
@@ -2091,7 +2130,7 @@ do
|
||||
if self.debug and self.verbose then
|
||||
self:I(self.lid .. "Status Report")
|
||||
for _name,_state in pairs(self.SamStateTracker) do
|
||||
self:I(string.format("Site %s\tStatus %s",_name,_state))
|
||||
self:I(string.format("Site %s | Status %s",_name,_state))
|
||||
end
|
||||
end
|
||||
local interval = self.detectinterval * -1
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE.
|
||||
-- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality.
|
||||
--
|
||||
|
||||
+1420
-1302
File diff suppressed because it is too large
Load Diff
@@ -2102,7 +2102,12 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
||||
result.attackHdg = attackHdg
|
||||
result.attackVel = attackVel
|
||||
result.attackAlt = attackAlt
|
||||
result.date=os and os.date() or "n/a"
|
||||
if os and os.date then
|
||||
result.date=os.date()
|
||||
else
|
||||
self:E(self.lid.."os or os.date() not available")
|
||||
result.date = "n/a"
|
||||
end
|
||||
|
||||
-- Add to table.
|
||||
table.insert( _results, result )
|
||||
|
||||
@@ -90,7 +90,8 @@
|
||||
-- @image Scoring.JPG
|
||||
|
||||
--- @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
|
||||
|
||||
--- SCORING class
|
||||
@@ -229,7 +230,8 @@ SCORING = {
|
||||
ClassID = 0,
|
||||
Players = {},
|
||||
AutoSave = true,
|
||||
version = "1.18.4"
|
||||
version = "1.18.4",
|
||||
ScoringScenery = nil, -- Core.Set#SET_SCENERY
|
||||
}
|
||||
|
||||
local _SCORINGCoalition = {
|
||||
@@ -320,8 +322,12 @@ function SCORING:New( GameName, SavePath, AutoSave )
|
||||
|
||||
-- Create the CSV file.
|
||||
self.AutoSavePath = SavePath
|
||||
self.AutoSave = AutoSave or true
|
||||
self:OpenCSV( GameName )
|
||||
self.AutoSave = (AutoSave == nil or AutoSave == true) and true or false
|
||||
if self.AutoSavePath and self.AutoSave == true then
|
||||
self:OpenCSV( GameName )
|
||||
end
|
||||
|
||||
self:I("SCORING "..tostring(GameName).." started! v"..self.version)
|
||||
|
||||
return self
|
||||
|
||||
@@ -375,7 +381,7 @@ function SCORING:AddUnitScore( ScoreUnit, Score )
|
||||
return self
|
||||
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 Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given.
|
||||
-- @return #SCORING
|
||||
@@ -392,10 +398,26 @@ end
|
||||
-- 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#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.
|
||||
-- @return #SCORING
|
||||
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()
|
||||
|
||||
@@ -404,7 +426,61 @@ function SCORING:AddStaticScore( ScoreStatic, Score )
|
||||
return self
|
||||
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 Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||
-- @return #SCORING
|
||||
@@ -459,6 +535,31 @@ function SCORING:AddScoreSetGroup(Set, Score)
|
||||
return self
|
||||
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.
|
||||
-- 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.
|
||||
@@ -478,7 +579,24 @@ function SCORING:AddZoneScore( ScoreZone, Score )
|
||||
return self
|
||||
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.
|
||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||
-- @param #SCORING self
|
||||
@@ -956,7 +1074,7 @@ end
|
||||
-- @param #SCORING self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function SCORING:_EventOnHit( Event )
|
||||
self:F( { Event } )
|
||||
--self:F( { Event } )
|
||||
|
||||
local InitUnit = nil
|
||||
local InitUNIT = nil
|
||||
@@ -985,6 +1103,8 @@ function SCORING:_EventOnHit( Event )
|
||||
local TargetUnitCoalition = nil
|
||||
local TargetUnitCategory = nil
|
||||
local TargetUnitType = nil
|
||||
local TargetIsScenery = false
|
||||
local TargetSceneryObject = nil
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
|
||||
@@ -1006,7 +1126,7 @@ function SCORING:_EventOnHit( Event )
|
||||
InitUnitCategory = _SCORINGCategory[InitCategory]
|
||||
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
|
||||
|
||||
if Event.TgtDCSUnit then
|
||||
@@ -1024,12 +1144,23 @@ function SCORING:_EventOnHit( Event )
|
||||
-- TargetCategory = TargetUnit:getDesc().category
|
||||
TargetCategory = Event.TgtCategory
|
||||
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]
|
||||
TargetUnitCategory = _SCORINGCategory[TargetCategory]
|
||||
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
|
||||
|
||||
if InitPlayerName ~= nil then -- It is a player that is hitting something
|
||||
@@ -1042,7 +1173,7 @@ function SCORING:_EventOnHit( Event )
|
||||
self:T( "Hitting Something" )
|
||||
|
||||
-- What is he hitting?
|
||||
if TargetCategory then
|
||||
if (TargetCategory ~=nil) and (TargetIsScenery == false) then
|
||||
|
||||
-- A target got hit, score it.
|
||||
-- Player contains the score data from self.Players[InitPlayerName]
|
||||
@@ -1062,7 +1193,7 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||
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
|
||||
if PlayerHit.UNIT.ThreatType == nil then
|
||||
if PlayerHit.UNIT and PlayerHit.UNIT.ThreatType == nil then
|
||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||
-- if this fails for some reason, set a good default value
|
||||
if PlayerHit.ThreatType == nil or PlayerHit.ThreatType == "" then
|
||||
@@ -1117,17 +1248,22 @@ function SCORING:_EventOnHit( Event )
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
: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. " ..
|
||||
"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() )
|
||||
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
|
||||
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||
end
|
||||
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 )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
: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
|
||||
-- This seems to occur only with scenery and static objects.
|
||||
if Event.WeaponPlayerName ~= nil 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
|
||||
if Event.WeaponPlayerName ~= nil or TargetIsScenery == true then
|
||||
|
||||
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" )
|
||||
self:T( "Hitting Scenery or Static" )
|
||||
|
||||
-- What is he hitting?
|
||||
if TargetCategory then
|
||||
if Event.TgtObjectCategory then
|
||||
|
||||
-- A scenery or static got hit, score it.
|
||||
-- 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.
|
||||
Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {}
|
||||
@@ -1165,15 +1301,17 @@ function SCORING:_EventOnHit( Event )
|
||||
|
||||
-- PlayerHit contains the score counters and data per unit that was hit.
|
||||
local PlayerHit = Player.Hit[TargetCategory][TargetUnitName]
|
||||
|
||||
|
||||
-- Init player scores
|
||||
PlayerHit.Score = PlayerHit.Score or 0
|
||||
PlayerHit.Penalty = PlayerHit.Penalty or 0
|
||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0
|
||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||
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
|
||||
if PlayerHit.UNIT.ThreatType == nil then
|
||||
if PlayerHit.UNIT and PlayerHit.UNIT.ThreatType == nil then
|
||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||
-- if this fails for some reason, set a good default value
|
||||
if PlayerHit.ThreatType == nil then
|
||||
@@ -1181,8 +1319,8 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.ThreatType = "Unknown"
|
||||
end
|
||||
else
|
||||
PlayerHit.ThreatLevel = PlayerHit.UNIT.ThreatLevel
|
||||
PlayerHit.ThreatType = PlayerHit.UNIT.ThreatType
|
||||
PlayerHit.ThreatLevel = PlayerHit.UNIT and PlayerHit.UNIT.ThreatLevel or 1
|
||||
PlayerHit.ThreatType = PlayerHit.UNIT and PlayerHit.UNIT.ThreatType or "Unknown"
|
||||
end
|
||||
|
||||
-- Only grant hit scores if there was more than one second between the last hit.
|
||||
@@ -1190,50 +1328,68 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.TimeStamp = timer.getTime()
|
||||
|
||||
local Score = 0
|
||||
|
||||
if InitCoalition then -- A coalition object was hit, probably a static.
|
||||
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
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
||||
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
|
||||
|
||||
local TgtName = Event.TgtDCSUnit and Event.TgtDCSUnit.getName and Event.TgtDCSUnit:getName() or "Unknown"
|
||||
|
||||
--if InitCoalition then -- A coalition object was hit, probably a static.
|
||||
if TargetIsScenery == true and self.ScoringScenery:IsInSet(TargetSceneryObject) then
|
||||
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||
PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit
|
||||
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,
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
: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 )
|
||||
end
|
||||
else -- A scenery object was hit.
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
self:ScoreCSV( playername, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||
elseif TargetIsScenery == false and Event.TgtObjectCategory == Object.Category.STATIC and self.ScoringObjects[TgtName] then
|
||||
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||
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 )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
: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 )
|
||||
end
|
||||
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
|
||||
|
||||
-- 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
|
||||
|
||||
--- Track DEAD or CRASH events for the scoring.
|
||||
-- @param #SCORING self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
@@ -1291,7 +1447,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
local Destroyed = false
|
||||
|
||||
-- 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 TargetThreatType = Player.Hit[TargetCategory][TargetUnitName].ThreatType
|
||||
@@ -1923,7 +2079,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
||||
TargetUnitType = TargetUnitType 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.GameName .. '"' .. ',' ..
|
||||
'"' .. self.RunTime .. '"' .. ',' ..
|
||||
|
||||
@@ -3153,7 +3153,7 @@ end
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return Core.Point#COORDINATE The coordinate of the warehouse.
|
||||
function WAREHOUSE:GetCoordinate()
|
||||
return self.warehouse:GetCoordinate()
|
||||
return self.warehouse:GetCoord()
|
||||
end
|
||||
|
||||
--- Get 3D vector of warehouse static.
|
||||
@@ -4247,6 +4247,16 @@ function WAREHOUSE:_AssetItemInfo(asset)
|
||||
self:T3({Template=asset.template})
|
||||
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.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @param #string From From state.
|
||||
@@ -5965,6 +5975,10 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late
|
||||
template.y = coord.z
|
||||
template.alt = coord.y
|
||||
|
||||
if self.ValidateAndRepositionGroundUnits then
|
||||
UTILS.ValidateAndRepositionGroundUnits(template.units)
|
||||
end
|
||||
|
||||
-- Spawn group.
|
||||
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
||||
|
||||
@@ -6893,7 +6907,7 @@ function WAREHOUSE:_CheckConquered()
|
||||
for _,_unit in pairs(units) do
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
local distance=coord:Get2DDistance(unit:GetCoordinate())
|
||||
local distance=coord:Get2DDistance(unit:GetCoord())
|
||||
|
||||
-- Filter only alive groud units. Also check distance again, because the scan routine might give some larger distances.
|
||||
if unit:IsGround() and unit:IsAlive() and distance <= radius then
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
|
||||
@@ -501,6 +501,7 @@ ATIS.Alphabet = {
|
||||
-- @field #number Kola +15° (East).
|
||||
-- @field #number Afghanistan +3° (East).
|
||||
-- @field #number Iraq +4.4° (East).
|
||||
-- @field #number GermanyCW +0.1° (East).
|
||||
ATIS.RunwayM2T = {
|
||||
Caucasus = 0,
|
||||
Nevada = 12,
|
||||
@@ -513,7 +514,8 @@ ATIS.RunwayM2T = {
|
||||
SinaiMap = 5,
|
||||
Kola = 15,
|
||||
Afghanistan = 3,
|
||||
Iraq=4.4
|
||||
Iraq=4.4,
|
||||
GermanyCW=0.1,
|
||||
}
|
||||
|
||||
--- Whether ICAO phraseology is used for ATIS broadcasts.
|
||||
@@ -530,6 +532,7 @@ ATIS.RunwayM2T = {
|
||||
-- @field #boolean Kola true.
|
||||
-- @field #boolean Afghanistan true.
|
||||
-- @field #boolean Iraq true.
|
||||
-- @field #boolean GermanyCW true.
|
||||
ATIS.ICAOPhraseology = {
|
||||
Caucasus = true,
|
||||
Nevada = false,
|
||||
@@ -543,6 +546,7 @@ ATIS.ICAOPhraseology = {
|
||||
Kola = true,
|
||||
Afghanistan = true,
|
||||
Iraq = true,
|
||||
GermanyCW = true,
|
||||
}
|
||||
|
||||
--- Nav point data.
|
||||
@@ -2794,7 +2798,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
|
||||
end
|
||||
_RUNACT = subtitle
|
||||
alltext = alltext .. ";\n" .. subtitle
|
||||
--alltext = alltext .. ";\n" .. subtitle
|
||||
|
||||
-- Runway length.
|
||||
if self.rwylength then
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1708
-501
File diff suppressed because it is too large
Load Diff
@@ -72,7 +72,7 @@ end
|
||||
|
||||
--- Checks if a point is contained within the circle.
|
||||
-- @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)
|
||||
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
||||
return true
|
||||
@@ -226,6 +226,11 @@ end
|
||||
--- Returns a random Vec2 within the circle.
|
||||
-- @return #table The random Vec2
|
||||
function CIRCLE:GetRandomVec2()
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
local angle = math.random() * 2 * math.pi
|
||||
|
||||
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.
|
||||
-- @return #table The random Vec2
|
||||
function CIRCLE:GetRandomVec2OnBorder()
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
local angle = math.random() * 2 * math.pi
|
||||
|
||||
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.
|
||||
-- @return #table The random Vec2
|
||||
function POLYGON:GetRandomVec2()
|
||||
|
||||
local weights = {}
|
||||
for _, triangle in pairs(self.Triangles) do
|
||||
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
|
||||
-- @return #table The random Vec2
|
||||
function TRIANGLE:GetRandomVec2(points)
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
points = points or self.Points
|
||||
local pt = {math.random(), math.random()}
|
||||
table.sort(pt)
|
||||
|
||||
@@ -380,7 +380,8 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
|
||||
|
||||
|
||||
if not self.senderinit then
|
||||
--if not self.senderinit then
|
||||
-- TODO Seems to be a DCS bug - if I explode ANY unit in a group the BC assignment gets lost
|
||||
|
||||
-- Command to set the Frequency for the transmission.
|
||||
local commandFrequency={
|
||||
@@ -394,7 +395,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
sender:SetCommand(commandFrequency)
|
||||
|
||||
self.senderinit=true
|
||||
end
|
||||
--end
|
||||
|
||||
-- Set subtitle only if duration>0 sec.
|
||||
local subtitle=nil
|
||||
|
||||
@@ -443,28 +443,32 @@ MSRS.Voices = {
|
||||
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
||||
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
||||
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
||||
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE
|
||||
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE
|
||||
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE
|
||||
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE
|
||||
-- IN
|
||||
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- Female
|
||||
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- Male
|
||||
["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
|
||||
["en_GB_Standard_A"] = 'en-GB-Standard-N', -- [9] FEMALE
|
||||
["en_GB_Standard_B"] = 'en-GB-Standard-O', -- [10] MALE
|
||||
["en_GB_Standard_C"] = 'en-GB-Standard-N', -- [11] FEMALE
|
||||
["en_GB_Standard_D"] = 'en-GB-Standard-O', -- [12] MALE
|
||||
["en_GB_Standard_F"] = 'en-GB-Standard-N', -- [13] FEMALE
|
||||
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- [12] MALE
|
||||
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- [13] FEMALE
|
||||
["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE
|
||||
["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE
|
||||
["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE
|
||||
["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE
|
||||
["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE
|
||||
["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE
|
||||
["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE
|
||||
["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE
|
||||
["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE
|
||||
["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE
|
||||
["en_GB_Standard_A"] = 'en-GB-Standard-A', -- Female
|
||||
["en_GB_Standard_B"] = 'en-GB-Standard-B', -- Male
|
||||
["en_GB_Standard_C"] = 'en-GB-Standard-C', -- Female
|
||||
["en_GB_Standard_D"] = 'en-GB-Standard-D', -- Male
|
||||
["en_GB_Standard_F"] = 'en-GB-Standard-F', -- Female
|
||||
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- Female
|
||||
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- Male
|
||||
-- US
|
||||
["en_US_Standard_A"] = 'en-US-Standard-A', -- Male
|
||||
["en_US_Standard_B"] = 'en-US-Standard-B', -- Male
|
||||
["en_US_Standard_C"] = 'en-US-Standard-C', -- Female
|
||||
["en_US_Standard_D"] = 'en-US-Standard-D', -- Male
|
||||
["en_US_Standard_E"] = 'en-US-Standard-E', -- Female
|
||||
["en_US_Standard_F"] = 'en-US-Standard-F', -- Female
|
||||
["en_US_Standard_G"] = 'en-US-Standard-G', -- Female
|
||||
["en_US_Standard_H"] = 'en-US-Standard-H', -- Female
|
||||
["en_US_Standard_I"] = 'en-US-Standard-I', -- Male
|
||||
["en_US_Standard_J"] = 'en-US-Standard-J', -- Male
|
||||
-- 2025 catalog changes
|
||||
["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female
|
||||
["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_F"] = "fr-FR-Standard-F", -- Female
|
||||
-- 2025 catalog changes
|
||||
["de_DE_Standard_A"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_B"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_C"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_D"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_E"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_F"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_H"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_G"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_A"] = 'de-DE-Standard-A', -- Female
|
||||
["de_DE_Standard_B"] = 'de-DE-Standard-B', -- Male
|
||||
["de_DE_Standard_C"] = 'de-DE-Standard-C', -- Female
|
||||
["de_DE_Standard_D"] = 'de-DE-Standard-D', -- Male
|
||||
["de_DE_Standard_E"] = 'de-DE-Standard-E', -- Male
|
||||
["de_DE_Standard_F"] = 'de-DE-Standard-F', -- 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_B"] = "es-ES-Standard-F", -- Male
|
||||
["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female
|
||||
@@ -497,32 +502,36 @@ MSRS.Voices = {
|
||||
["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male
|
||||
},
|
||||
Wavenet = {
|
||||
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
|
||||
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE
|
||||
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
|
||||
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE
|
||||
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
|
||||
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE
|
||||
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE
|
||||
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
|
||||
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- Female
|
||||
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- Male
|
||||
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- Female
|
||||
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- Male
|
||||
-- IN
|
||||
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- Female
|
||||
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- Male
|
||||
["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
|
||||
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-N', -- [9] FEMALE
|
||||
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-O', -- [10] MALE
|
||||
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-N', -- [11] FEMALE
|
||||
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
|
||||
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE
|
||||
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
|
||||
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE
|
||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
|
||||
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-N', -- [14] MALE
|
||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
||||
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE
|
||||
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE
|
||||
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE
|
||||
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE
|
||||
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE
|
||||
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE
|
||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
-- US
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- Male
|
||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- Male
|
||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- Female
|
||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- Male
|
||||
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- Female
|
||||
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- Female
|
||||
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- Female
|
||||
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- Female
|
||||
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- Male
|
||||
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- Male
|
||||
-- 2025 catalog changes
|
||||
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female
|
||||
["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_F"] = "fr-FR-Wavenet-F", -- Female
|
||||
-- 2025 catalog changes
|
||||
["de_DE_Wavenet_A"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_B"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_C"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_D"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_E"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_F"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_H"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_G"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female
|
||||
["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male
|
||||
["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female
|
||||
["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male
|
||||
["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male
|
||||
["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- 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_C"] = "es-ES-Wavenet-F", -- 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_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
|
||||
},
|
||||
}
|
||||
|
||||
@@ -632,7 +770,7 @@ end
|
||||
-- set the path to the exe file via @{#MSRS.SetPath}.
|
||||
--
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone`.
|
||||
-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`.
|
||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
|
||||
-- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations.
|
||||
-- @param #string Backend Backend used: `MSRS.Backend.SRSEXE` (default) or `MSRS.Backend.GRPC`.
|
||||
@@ -767,13 +905,13 @@ end
|
||||
|
||||
--- Set path to SRS install directory. More precisely, path to where the `DCS-SR-ExternalAudio.exe` is located.
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone`.
|
||||
-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`.
|
||||
-- @return #MSRS self
|
||||
function MSRS:SetPath(Path)
|
||||
self:F( {Path=Path} )
|
||||
|
||||
-- Set path.
|
||||
self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
|
||||
-- Remove (back)slashes.
|
||||
local n=1 ; local nmax=1000
|
||||
@@ -1817,7 +1955,7 @@ end
|
||||
--
|
||||
-- -- Moose MSRS default Config
|
||||
-- MSRS_Config = {
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- Path to SRS install directory.
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio", -- Path to SRS install directory.
|
||||
-- Port = 5002, -- Port of SRS server. Default 5002.
|
||||
-- Backend = "srsexe", -- Interface to SRS: "srsexe" or "grpc".
|
||||
-- Frequency = {127, 243}, -- Default frequences. Must be a table 1..n entries!
|
||||
@@ -1837,7 +1975,7 @@ end
|
||||
-- -- Google Cloud
|
||||
-- gcloud = {
|
||||
-- voice = "en-GB-Standard-A", -- The Google Cloud voice to use (see https://cloud.google.com/text-to-speech/docs/voices).
|
||||
-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend)
|
||||
-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend)
|
||||
-- key="Your access Key", -- Google API access key (only for DCS-gRPC backend)
|
||||
-- },
|
||||
-- -- Amazon Web Service
|
||||
@@ -1905,7 +2043,7 @@ function MSRS:LoadConfigFile(Path,Filename)
|
||||
|
||||
local Self = self or MSRS --#MSRS
|
||||
|
||||
Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
Self.port = MSRS_Config.Port or 5002
|
||||
Self.backend = MSRS_Config.Backend or MSRS.Backend.SRSEXE
|
||||
Self.frequencies = MSRS_Config.Frequency or {127,243}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
|
||||
--- Governs multiple missions, the tasking and the reporting.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Command centers govern missions, communicates the task assignments between human players of the coalition, and manages the menu flow.
|
||||
-- It can assign a random task to a player when requested.
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
-- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
|
||||
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 1.1) DETECTION_MANAGER constructor:
|
||||
-- -----------------------------------
|
||||
-- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
--- Models goals to be achieved and can contain multiple tasks to be executed to achieve the goals.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- A mission contains multiple tasks and can be of different task types.
|
||||
-- These tasks need to be assigned to human players to be executed.
|
||||
--
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) Tasking from a player perspective.
|
||||
--
|
||||
-- Tasking can be controlled by using the "other" menu in the radio menu of the player group.
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
---
|
||||
-- # TASKINFO class, extends @{Core.Base#BASE}
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## The TASKINFO class implements the methods to contain information and display information of a task.
|
||||
--
|
||||
-- # Developer Note
|
||||
|
||||
@@ -20,6 +20,9 @@ do -- TASK_A2A
|
||||
|
||||
--- Defines Air To Air tasks for a @{Core.Set} of Target Units,
|
||||
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
|
||||
@@ -30,6 +30,8 @@ do -- TASK_A2A_DISPATCHER
|
||||
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
|
||||
|
||||
--- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
|
||||
@@ -20,6 +20,9 @@ do -- TASK_A2G
|
||||
|
||||
--- The TASK_A2G class defines Air To Ground tasks for a @{Core.Set} of Target Units,
|
||||
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
|
||||
@@ -33,6 +33,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
|
||||
|
||||
--- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Functional.Detection} object.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system.
|
||||
-- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon,
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## Test Missions:
|
||||
--
|
||||
-- Test missions can be located on the main GITHUB site.
|
||||
@@ -1176,7 +1178,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
|
||||
|
||||
---@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green
|
||||
--@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green
|
||||
function TASK_CARGO:SetSmokeColor(SmokeColor)
|
||||
-- Makes sure Coloe is set
|
||||
if SmokeColor == nil then
|
||||
|
||||
@@ -76,6 +76,8 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
|
||||
--- Implements the dynamic dispatching of capture zone tasks.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human
|
||||
-- players capture zones in a co-operation effort.
|
||||
--
|
||||
|
||||
@@ -20,6 +20,8 @@ do -- TASK_ZONE_GOAL
|
||||
|
||||
--- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK}
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone.
|
||||
-- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||
--
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Please read through the @{Tasking.Task_CARGO} process to understand the mechanisms of tasking and cargo tasking and handling.
|
||||
--
|
||||
-- The cargo will be a downed pilot, which is located somwhere on the battlefield. Use the menus system and facilities to
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human
|
||||
-- players transport cargo as part of a task.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The cargo dispatcher will implement for you mechanisms to create cargo transportation tasks:
|
||||
--
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
--- **Tasking** - Models tasks for players to transport cargo.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- **Specific features:**
|
||||
--
|
||||
-- * Creates a task to transport #Cargo.Cargo to and between deployment zones.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 1) @{Tasking.Task_Manager#TASK_MANAGER} class, extends @{Core.Fsm#FSM}
|
||||
-- ===
|
||||
-- The @{Tasking.Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -168,16 +168,25 @@
|
||||
-- * @{#CONTROLLABLE.OptionAlarmStateGreen}
|
||||
-- * @{#CONTROLLABLE.OptionAlarmStateRed}
|
||||
--
|
||||
-- ## 5.4) Jettison weapons:
|
||||
-- ## 5.4) [AIR] Jettison weapons:
|
||||
--
|
||||
-- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat}
|
||||
-- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat}
|
||||
--
|
||||
-- ## 5.5) Air-2-Air missile attack range:
|
||||
-- ## 5.5) [AIR] Air-2-Air missile attack range:
|
||||
-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets.
|
||||
--
|
||||
-- # 6) [GROUND] IR Maker Beacons for GROUPs and UNITs
|
||||
-- * @{#CONTROLLABLE:NewIRMarker}(): Create a blinking IR Marker on a GROUP or UNIT.
|
||||
--
|
||||
-- # 7) [HELICOPTER] Units prefer vertical landing and takeoffs:
|
||||
-- * @{#CONTROLLABLE.OptionPreferVerticalLanding}(): Set aircraft to prefer vertical landing and takeoff.
|
||||
--
|
||||
-- # 8) [AIRCRAFT] Landing approach options
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingStraightIn}(): Landing approach straight in.
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingForcePair}(): Landing approach in pairs for groups > 1 unit.
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingRestrictPair}(): Landing approach single.
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingOverheadBreak}(): Landing approach overhead break.
|
||||
--
|
||||
-- @field #CONTROLLABLE
|
||||
CONTROLLABLE = {
|
||||
@@ -994,6 +1003,65 @@ function CONTROLLABLE:CommandSetFrequencyForUnit(Frequency,Modulation,Power,Unit
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set smoke on or off. See [DCS command smoke on off](https://wiki.hoggitworld.com/view/DCS_command_smoke_on_off)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean OnOff Set to true for on and false for off. Defaults to true.
|
||||
-- @param #number Delay (Optional) Delay the command by this many seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSmokeOnOff(OnOff, Delay)
|
||||
local switch = (OnOff == nil) and true or OnOff
|
||||
local command = {
|
||||
id = 'SMOKE_ON_OFF',
|
||||
params = {
|
||||
value = switch
|
||||
}
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSmokeOnOff,{self,switch},Delay)
|
||||
else
|
||||
self:SetCommand(command)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set smoke on. See [DCS command smoke on off](https://wiki.hoggitworld.com/view/DCS_command_smoke_on_off)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Delay (Optional) Delay the command by this many seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSmokeON(Delay)
|
||||
local command = {
|
||||
id = 'SMOKE_ON_OFF',
|
||||
params = {
|
||||
value = true
|
||||
}
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSmokeON,{self},Delay)
|
||||
else
|
||||
self:SetCommand(command)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set smoke off. See [DCS command smoke on off](https://wiki.hoggitworld.com/view/DCS_command_smoke_on_off)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Delay (Optional) Delay the command by this many seconds.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:CommandSmokeOFF(Delay)
|
||||
local command = {
|
||||
id = 'SMOKE_ON_OFF',
|
||||
params = {
|
||||
value = false
|
||||
}
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSmokeOFF,{self},Delay)
|
||||
else
|
||||
self:SetCommand(command)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set EPLRS data link on/off.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean SwitchOnOff If true (or nil) switch EPLRS on. If false switch off.
|
||||
@@ -1373,7 +1441,7 @@ end
|
||||
-- @param #number Speed The speed [m/s] flying when holding the position.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed )
|
||||
self:F2( { self.ControllableName, Point, Altitude, Speed } )
|
||||
--self:F2( { self.ControllableName, Point, Altitude, Speed } )
|
||||
|
||||
local DCSTask = {
|
||||
id = 'Orbit',
|
||||
@@ -2787,7 +2855,7 @@ do -- Route methods
|
||||
-- @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 #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 )
|
||||
self:F2( Zone )
|
||||
|
||||
@@ -2847,7 +2915,7 @@ do -- Route methods
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @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 Core.Base#FORMATION Formation The formation string.
|
||||
-- @param DCS#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
@@ -3570,6 +3638,26 @@ function CONTROLLABLE:OptionROTPassiveDefense()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Helicopter - prefer vertical landing.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionPreferVerticalLanding()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsAir() then
|
||||
Controller:setOption( AI.Option.Air.id.PREFER_VERTICAL, true )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Can the CONTROLLABLE evade on enemy fire?
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #boolean
|
||||
@@ -4075,7 +4163,7 @@ function CONTROLLABLE:OptionRestrictBurner( RestrictBurner )
|
||||
|
||||
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 #number range Defines the range
|
||||
-- @return #CONTROLLABLE self
|
||||
@@ -4100,6 +4188,66 @@ function CONTROLLABLE:OptionAAAttackRange( range )
|
||||
return nil
|
||||
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.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
||||
@@ -4124,6 +4272,50 @@ function CONTROLLABLE:OptionEngageRange( EngageRange )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: Straight in.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingStraightIn()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","0")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: In pairs (if > 1 aircraft in group)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingForcePair()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","1")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: No landing in pairs.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingRestrictPair()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","2")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: Overhead break.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingOverheadBreak()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","3")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI uses the onboard radar.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Option Options are: `NEVER = 0, FOR_ATTACK_ONLY = 1,FOR_SEARCH_IF_REQUIRED = 2, FOR_CONTINUOUS_SEARCH = 3`
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
--
|
||||
-- ## Main Features:
|
||||
--
|
||||
-- * Convenient access to DCS API functions
|
||||
-- * Convenient access to Ground Crew created cargo items.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Example Missions:
|
||||
--
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Storage).
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist**
|
||||
-- ### Author: **Applevangelist**; additional checks **Chesster**
|
||||
--
|
||||
-- ===
|
||||
-- @module Wrapper.DynamicCargo
|
||||
@@ -108,6 +108,9 @@ DYNAMICCARGO.State = {
|
||||
-- @type DYNAMICCARGO.AircraftTypes
|
||||
DYNAMICCARGO.AircraftTypes = {
|
||||
["CH-47Fbl1"] = "CH-47Fbl1",
|
||||
["Mi-8MTV2"] = "Mi-8MTV2",
|
||||
["Mi-8MT"] = "Mi-8MT",
|
||||
["C-130J-30"] = "C-130J-30",
|
||||
}
|
||||
|
||||
--- Helo types possible.
|
||||
@@ -120,17 +123,36 @@ DYNAMICCARGO.AircraftDimensions = {
|
||||
["length"] = 11,
|
||||
["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.
|
||||
-- @field #string version
|
||||
DYNAMICCARGO.version="0.0.5"
|
||||
DYNAMICCARGO.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
-- DONE: Added Mi-8 type and dimensions
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -183,7 +205,7 @@ end
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return DCS static object
|
||||
function DYNAMICCARGO:GetDCSObject()
|
||||
local DCSStatic = Unit.getByName( self.StaticName )
|
||||
local DCSStatic = StaticObject.getByName( self.StaticName ) or Unit.getByName( self.StaticName )
|
||||
if DCSStatic then
|
||||
return DCSStatic
|
||||
end
|
||||
@@ -227,7 +249,7 @@ end
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:IsUnloaded()
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.REMOVED then
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.UNLOADED then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -238,7 +260,7 @@ end
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:IsRemoved()
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.UNLOADED then
|
||||
if self.CargoState and self.CargoState == DYNAMICCARGO.State.REMOVED then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -376,6 +398,33 @@ end
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- [Internal] _Get helo hovering intel
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param Wrapper.Unit#UNIT Unit The Unit to test
|
||||
-- @param #number ropelength Ropelength to test
|
||||
-- @return #boolean Outcome
|
||||
function DYNAMICCARGO:_HeloHovering(Unit,ropelength)
|
||||
local DCSUnit = Unit:GetDCSObject() --DCS#Unit
|
||||
local hovering = false
|
||||
local Height = 0
|
||||
if DCSUnit then
|
||||
local UnitInAir = DCSUnit:inAir()
|
||||
local UnitCategory = DCSUnit:getDesc().category
|
||||
if UnitInAir == true and UnitCategory == 1 then
|
||||
local VelocityVec3 = DCSUnit:getVelocity()
|
||||
local Velocity = UTILS.VecNorm(VelocityVec3)
|
||||
local Coordinate = DCSUnit:getPoint()
|
||||
local LandHeight = land.getHeight({ x = Coordinate.x, y = Coordinate.z })
|
||||
Height = Coordinate.y - LandHeight
|
||||
if Velocity < 1 and Height <= ropelength and Height > 6 then -- hover lower than ropelength but higher than the normal FARP height.
|
||||
hovering = true
|
||||
end
|
||||
end
|
||||
return hovering, Height
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- [Internal] _Get Possible Player Helo Nearby
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param Core.Point#COORDINATE pos
|
||||
@@ -393,30 +442,37 @@ function DYNAMICCARGO:_GetPossibleHeloNearby(pos,loading)
|
||||
local name = helo:GetPlayerName() or _DATABASE:_FindPlayerNameByUnitName(helo:GetName()) or "None"
|
||||
self:T(self.lid.." Checking: "..name)
|
||||
local hpos = helo:GetCoordinate()
|
||||
-- TODO Unloading via sling load?
|
||||
--local inair = hpos.y-hpos:GetLandHeight() > 4.5 and true or false -- Standard FARP is 4.5m
|
||||
local inair = helo:InAir()
|
||||
self:T(self.lid.." InAir: AGL/InAir: "..hpos.y-hpos:GetLandHeight().."/"..tostring(inair))
|
||||
-- TODO Check unloading via sling load?
|
||||
local typename = helo:GetTypeName()
|
||||
if hpos and typename and inair == false then
|
||||
local dimensions = DYNAMICCARGO.AircraftDimensions[typename]
|
||||
if dimensions then
|
||||
local delta2D = hpos:Get2DDistance(pos)
|
||||
local delta3D = hpos:Get3DDistance(pos)
|
||||
if self.testing then
|
||||
self:T(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D))
|
||||
self:T(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength))
|
||||
end
|
||||
if loading~=true and delta2D > dimensions.length or delta2D > dimensions.width or delta3D > dimensions.ropelength then
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
if loading == true and delta2D < dimensions.length or delta2D < dimensions.width or delta3D < dimensions.ropelength then
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
local dimensions = DYNAMICCARGO.AircraftDimensions[typename]
|
||||
local hovering, height = self:_HeloHovering(helo,dimensions.ropelength)
|
||||
local helolanded = not helo:InAir()
|
||||
self:T(self.lid.." InAir: AGL/Hovering: "..hpos.y-hpos:GetLandHeight().."/"..tostring(hovering))
|
||||
if hpos and typename and dimensions then
|
||||
local delta2D = hpos:Get2DDistance(pos)
|
||||
local delta3D = hpos:Get3DDistance(pos)
|
||||
if self.testing then
|
||||
self:T(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D))
|
||||
self:T(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength))
|
||||
self:T(string.format("Helo hovering: %s at %dm",tostring(hovering),height))
|
||||
end
|
||||
-- unloading from ground
|
||||
if loading~=true and (delta2D > dimensions.length or delta2D > dimensions.width) and helolanded then -- Theoretically the cargo could still be attached to the sling if landed next to the cargo. But once moved again it would go back into loaded state once lifted again.
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
-- unloading from hover/rope
|
||||
if loading~=true and delta3D > dimensions.ropelength then
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
-- loading
|
||||
if loading == true and ((delta2D < dimensions.length and delta2D < dimensions.width and helolanded) or (delta3D == dimensions.ropelength and helo:InAir())) then -- Loaded via ground or sling
|
||||
success = true
|
||||
Helo = helo
|
||||
Playername = name
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -434,20 +490,22 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
self:T(string.format("Cargo position: x=%d, y=%d, z=%d",pos.x,pos.y,pos.z))
|
||||
self:T(string.format("Last position: x=%d, y=%d, z=%d",self.LastPosition.x,self.LastPosition.y,self.LastPosition.z))
|
||||
end
|
||||
if UTILS.Round(UTILS.VecDist3D(pos,self.LastPosition),2) > 0.5 then
|
||||
if UTILS.Round(UTILS.VecDist3D(pos,self.LastPosition),2) > 0.5 then -- This checks if the cargo has moved more than 0.5m since last check. If so then the cargo is loaded
|
||||
---------------
|
||||
-- LOAD Cargo
|
||||
---------------
|
||||
if self.CargoState == DYNAMICCARGO.State.NEW then
|
||||
local isloaded, client, playername = self:_GetPossibleHeloNearby(pos,true)
|
||||
if self.CargoState == DYNAMICCARGO.State.NEW or self.CargoState == DYNAMICCARGO.State.UNLOADED then
|
||||
local isloaded, client, playername = self:_GetPossibleHeloNearby(pos,true)
|
||||
self:T(self.lid.." moved! NEW -> LOADED by "..tostring(playername))
|
||||
self.CargoState = DYNAMICCARGO.State.LOADED
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoLoaded(self)
|
||||
_DATABASE:CreateEventDynamicCargoLoaded(self)
|
||||
end
|
||||
---------------
|
||||
-- UNLOAD Cargo
|
||||
---------------
|
||||
elseif self.CargoState == DYNAMICCARGO.State.LOADED then
|
||||
---------------
|
||||
-- If the cargo is stationary then we need to end this condition here to check whether it is unloaded or still onboard or still hooked if anyone can hover that precisly
|
||||
elseif self.CargoState == DYNAMICCARGO.State.LOADED then
|
||||
-- TODO add checker if we are in flight somehow
|
||||
-- ensure not just the helo is moving
|
||||
local count = _DYNAMICCARGO_HELOS:CountAlive()
|
||||
@@ -459,31 +517,27 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
local isunloaded = true
|
||||
local client
|
||||
local playername = self.Owner
|
||||
if count > 0 and (agl > 0 or self.testing) then
|
||||
self:T(self.lid.." Possible alive helos: "..count or -1)
|
||||
if agl ~= 0 or self.testing then
|
||||
isunloaded, client, playername = self:_GetPossibleHeloNearby(pos,false)
|
||||
end
|
||||
if count > 0 then
|
||||
self:T(self.lid.." Possible alive helos: "..count or -1)
|
||||
isunloaded, client, playername = self:_GetPossibleHeloNearby(pos,false)
|
||||
if isunloaded then
|
||||
self:T(self.lid.." moved! LOADED -> UNLOADED by "..tostring(playername))
|
||||
self.CargoState = DYNAMICCARGO.State.UNLOADED
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoUnloaded(self)
|
||||
end
|
||||
elseif count > 0 and agl == 0 then
|
||||
self:T(self.lid.." moved! LOADED -> UNLOADED by "..tostring(playername))
|
||||
self.CargoState = DYNAMICCARGO.State.UNLOADED
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoUnloaded(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.LastPosition = pos
|
||||
end
|
||||
--end
|
||||
else
|
||||
---------------
|
||||
-- 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.CargoState = DYNAMICCARGO.State.REMOVED
|
||||
_DATABASE:CreateEventDynamicCargoRemoved(self)
|
||||
@@ -491,6 +545,24 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
return self
|
||||
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.
|
||||
-- @param Wrapper.Client#CLIENT client
|
||||
-- @return #boolean IsIn
|
||||
|
||||
@@ -230,6 +230,8 @@ GROUP.Attribute = {
|
||||
GROUND_EWR="Ground_EWR",
|
||||
GROUND_AAA="Ground_AAA",
|
||||
GROUND_SAM="Ground_SAM",
|
||||
GROUND_SHORAD="Ground_SHORAD",
|
||||
GROUND_BALLISTICMISSILE="Ground_BallisticMissile",
|
||||
GROUND_OTHER="Ground_OtherGround",
|
||||
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
||||
NAVAL_WARSHIP="Naval_WarShip",
|
||||
@@ -912,15 +914,18 @@ function GROUP:GetVelocityVec3()
|
||||
|
||||
if DCSGroup and DCSGroup:isExist() then
|
||||
local GroupUnits = DCSGroup:getUnits()
|
||||
local GroupCount = #GroupUnits
|
||||
local GroupCount = 0
|
||||
|
||||
local VelocityVec3 = { x = 0, y = 0, z = 0 }
|
||||
|
||||
for _, DCSUnit in pairs( GroupUnits ) do
|
||||
local UnitVelocityVec3 = DCSUnit:getVelocity()
|
||||
VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x
|
||||
VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y
|
||||
VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z
|
||||
if DCSUnit:isExist() and DCSUnit:isActive() then
|
||||
local UnitVelocityVec3 = DCSUnit:getVelocity()
|
||||
VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x
|
||||
VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y
|
||||
VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z
|
||||
GroupCount = GroupCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
VelocityVec3.x = VelocityVec3.x / GroupCount
|
||||
@@ -1053,9 +1058,12 @@ function GROUP:GetTypeName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return( GroupTypeName )
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupTypeName = unit:getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return( GroupTypeName )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1070,9 +1078,12 @@ function GROUP:GetNatoReportingName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return UTILS.GetReportingName(GroupTypeName)
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupTypeName = unit:getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return UTILS.GetReportingName(GroupTypeName)
|
||||
end
|
||||
end
|
||||
|
||||
return "Bogey"
|
||||
@@ -1088,9 +1099,12 @@ function GROUP:GetPlayerName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local PlayerName = DCSGroup:getUnit(1):getPlayerName()
|
||||
--self:T3( PlayerName )
|
||||
return( PlayerName )
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local PlayerName = unit:getPlayerName()
|
||||
--self:T3( PlayerName )
|
||||
return( PlayerName )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1106,9 +1120,12 @@ function GROUP:GetCallsign()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupCallSign = DCSGroup:getUnit(1):getCallsign()
|
||||
--self:T3( GroupCallSign )
|
||||
return GroupCallSign
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupCallSign = unit:getCallsign()
|
||||
--self:T3( GroupCallSign )
|
||||
return GroupCallSign
|
||||
end
|
||||
end
|
||||
|
||||
BASE:E( { "Cannot GetCallsign", Positionable = self, Alive = self:IsAlive() } )
|
||||
@@ -1179,9 +1196,9 @@ function GROUP:GetAverageVec3()
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns a POINT_VEC2 object indicating the point in 2D of the first UNIT of the GROUP within the mission.
|
||||
--- Returns a COORDINATE object indicating the point in 2D of the first UNIT of the GROUP within the mission.
|
||||
-- @param #GROUP self
|
||||
-- @return Core.Point#POINT_VEC2 The 2D point vector of the first DCS Unit of the GROUP.
|
||||
-- @return Core.Point#COORDINATE The 3D point vector of the first DCS Unit of the GROUP.
|
||||
-- @return #nil The first UNIT is not existing or alive.
|
||||
function GROUP:GetPointVec2()
|
||||
--self:F2(self.GroupName)
|
||||
@@ -1194,7 +1211,7 @@ function GROUP:GetPointVec2()
|
||||
return FirstUnitPointVec2
|
||||
end
|
||||
|
||||
BASE:E( { "Cannot GetPointVec2", Group = self, Alive = self:IsAlive() } )
|
||||
BASE:E( { "Cannot get COORDINATE", Group = self, Alive = self:IsAlive() } )
|
||||
|
||||
return nil
|
||||
end
|
||||
@@ -1754,11 +1771,13 @@ function GROUP:GetMaxVelocity()
|
||||
|
||||
for Index, UnitData in pairs( DCSGroup:getUnits() ) do
|
||||
|
||||
local UnitVelocityVec3 = UnitData:getVelocity()
|
||||
local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z )
|
||||
if UnitData:isExist() and UnitData:isActive() then
|
||||
local UnitVelocityVec3 = UnitData:getVelocity()
|
||||
local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z )
|
||||
|
||||
if UnitVelocity > GroupVelocityMax then
|
||||
GroupVelocityMax = UnitVelocity
|
||||
if UnitVelocity > GroupVelocityMax then
|
||||
GroupVelocityMax = UnitVelocity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1843,7 +1862,10 @@ end
|
||||
-- @return #table
|
||||
function GROUP:GetTemplateRoutePoints()
|
||||
local GroupName = self:GetName()
|
||||
return UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ).route.points )
|
||||
local template = _DATABASE:GetGroupTemplate(GroupName)
|
||||
if template and template.route and template.route.points then
|
||||
return UTILS.DeepCopy(template.route.points)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -2093,7 +2115,7 @@ function GROUP:Respawn( Template, Reset )
|
||||
GroupUnitVec3 = Zone:GetRandomVec3()
|
||||
else
|
||||
if self.InitRespawnRandomizePositionInner and self.InitRespawnRandomizePositionOuter then
|
||||
GroupUnitVec3 = POINT_VEC3:NewFromVec2( From ):GetRandomPointVec3InRadius( self.InitRespawnRandomizePositionsOuter, self.InitRespawnRandomizePositionsInner )
|
||||
GroupUnitVec3 = COORDINATE:NewFromVec3(From):GetRandomVec3InRadius(self.InitRespawnRandomizePositionsOuter, self.InitRespawnRandomizePositionsInner)
|
||||
else
|
||||
GroupUnitVec3 = Zone:GetVec3()
|
||||
end
|
||||
@@ -2144,7 +2166,7 @@ function GROUP:Respawn( Template, Reset )
|
||||
GroupUnitVec3 = Zone:GetRandomVec3()
|
||||
else
|
||||
if self.InitRespawnRandomizePositionInner and self.InitRespawnRandomizePositionOuter then
|
||||
GroupUnitVec3 = POINT_VEC3:NewFromVec2( From ):GetRandomPointVec3InRadius( self.InitRespawnRandomizePositionsOuter, self.InitRespawnRandomizePositionsInner )
|
||||
GroupUnitVec3 = COORDINATE:NewFromVec2( From ):GetRandomPointVec3InRadius( self.InitRespawnRandomizePositionsOuter, self.InitRespawnRandomizePositionsInner )
|
||||
else
|
||||
GroupUnitVec3 = Zone:GetVec3()
|
||||
end
|
||||
@@ -2222,6 +2244,10 @@ function GROUP:Respawn( Template, Reset )
|
||||
|
||||
--UTILS.PrintTableToLog(Template)
|
||||
|
||||
if self.ValidateAndRepositionGroundUnits then
|
||||
UTILS.ValidateAndRepositionGroundUnits(Template.units)
|
||||
end
|
||||
|
||||
-- Spawn new group.
|
||||
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
||||
--_DATABASE:Spawn(Template)
|
||||
@@ -2630,6 +2656,8 @@ function GROUP:GetAttribute()
|
||||
local artillery=self:HasAttribute("Artillery")
|
||||
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 ballisticMissile=artillery and self:HasAttribute("SS_missile")
|
||||
local shorad=self:HasAttribute("SR SAM")
|
||||
local ewr=self:HasAttribute("EWR")
|
||||
local ifv=self:HasAttribute("IFV")
|
||||
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
||||
@@ -2671,6 +2699,8 @@ function GROUP:GetAttribute()
|
||||
attribute=GROUP.Attribute.GROUND_SAM
|
||||
elseif aaa then
|
||||
attribute=GROUP.Attribute.GROUND_AAA
|
||||
elseif artillery and ballisticMissile then
|
||||
attribute=GROUP.Attribute.GROUND_BALLISTICMISSILE
|
||||
elseif artillery then
|
||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||
elseif tank then
|
||||
@@ -3183,3 +3213,60 @@ function GROUP:IsAAA()
|
||||
end
|
||||
return isAAA
|
||||
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
|
||||
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.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #string The name of the coalition.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
--- @type POSITIONABLE
|
||||
-- @field Core.Point#COORDINATE coordinate Coordinate object.
|
||||
-- @field Core.Point#POINT_VEC3 pointvec3 Point Vec3 object.
|
||||
-- @field Core.Point#COORDINATE pointvec3 Point Vec3 object.
|
||||
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
||||
|
||||
|
||||
@@ -246,18 +246,20 @@ end
|
||||
function POSITIONABLE:GetVec3()
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
if DCSPositionable then
|
||||
--local status, vec3 = pcall(
|
||||
-- function()
|
||||
-- local vec3 = DCSPositionable:getPoint()
|
||||
-- return vec3
|
||||
--end
|
||||
--)
|
||||
|
||||
local vec3 = DCSPositionable:getPoint()
|
||||
--if status then
|
||||
return vec3
|
||||
--else
|
||||
--self:E( { "Cannot get Vec3 from DCS Object", Positionable = self, Alive = self:IsAlive() } )
|
||||
--end
|
||||
|
||||
if not vec3 then
|
||||
local pos = DCSPositionable:getPosition()
|
||||
if pos and pos.p then
|
||||
vec3 = pos.p
|
||||
else
|
||||
self:E( { "Cannot get the position from DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||
end
|
||||
end
|
||||
|
||||
return vec3
|
||||
|
||||
end
|
||||
-- ERROR!
|
||||
self:E( { "Cannot get the Positionable DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||
@@ -284,9 +286,9 @@ function POSITIONABLE:GetVec2()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a POINT_VEC2 object indicating the point in 2D of the POSITIONABLE within the mission.
|
||||
--- Returns a COORDINATE object indicating the point in 2D of the POSITIONABLE within the mission.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Point#POINT_VEC2 The 2D point vector of the POSITIONABLE.
|
||||
-- @return Core.Point#COORDINATE The 3D point vector of the POSITIONABLE.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetPointVec2()
|
||||
self:F2( self.PositionableName )
|
||||
@@ -296,20 +298,20 @@ function POSITIONABLE:GetPointVec2()
|
||||
if DCSPositionable then
|
||||
local PositionableVec3 = DCSPositionable:getPosition().p
|
||||
|
||||
local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 )
|
||||
local PositionablePointVec2 = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
|
||||
-- self:F( PositionablePointVec2 )
|
||||
return PositionablePointVec2
|
||||
end
|
||||
|
||||
self:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } )
|
||||
self:E( { "Cannot Coordinate", Positionable = self, Alive = self:IsAlive() } )
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a POINT_VEC3 object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE.
|
||||
-- @return Core.Point#COORDINATE The 3D point vector of the POSITIONABLE.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetPointVec3()
|
||||
|
||||
@@ -329,8 +331,8 @@ function POSITIONABLE:GetPointVec3()
|
||||
|
||||
else
|
||||
|
||||
-- Create a new POINT_VEC3 object.
|
||||
self.pointvec3 = POINT_VEC3:NewFromVec3( PositionableVec3 )
|
||||
-- Create a new COORDINATE object.
|
||||
self.pointvec3 = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
|
||||
end
|
||||
|
||||
@@ -359,15 +361,17 @@ function POSITIONABLE:GetCoord()
|
||||
-- Get the current position.
|
||||
local PositionableVec3 = self:GetVec3()
|
||||
|
||||
if self.coordinate then
|
||||
-- Update COORDINATE from 3D vector.
|
||||
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
||||
else
|
||||
-- New COORDINATE.
|
||||
self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
end
|
||||
if PositionableVec3 then
|
||||
if self.coordinate then
|
||||
-- Update COORDINATE from 3D vector.
|
||||
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
||||
else
|
||||
-- New COORDINATE.
|
||||
self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
end
|
||||
|
||||
return self.coordinate
|
||||
return self.coordinate
|
||||
end
|
||||
end
|
||||
|
||||
-- Error message.
|
||||
@@ -388,13 +392,13 @@ function POSITIONABLE:GetCoordinate()
|
||||
|
||||
-- Get the current position.
|
||||
local PositionableVec3 = self:GetVec3()
|
||||
|
||||
local coord=COORDINATE:NewFromVec3(PositionableVec3)
|
||||
local heading = self:GetHeading()
|
||||
coord.Heading = heading
|
||||
-- Return a new coordiante object.
|
||||
return coord
|
||||
|
||||
if PositionableVec3 then
|
||||
local coord=COORDINATE:NewFromVec3(PositionableVec3)
|
||||
local heading = self:GetHeading()
|
||||
coord.Heading = heading
|
||||
-- Return a new coordiante object.
|
||||
return coord
|
||||
end
|
||||
end
|
||||
|
||||
-- Error message.
|
||||
@@ -1861,6 +1865,7 @@ do -- Cargo
|
||||
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
||||
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
||||
["Sd_Kfz_251"] = 10*POSITIONABLE.DefaultInfantryWeight,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
-- @field #string SceneryName Name of the scenery object.
|
||||
-- @field DCS#Object SceneryObject DCS scenery object.
|
||||
-- @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
|
||||
|
||||
|
||||
@@ -35,27 +41,72 @@ SCENERY = {
|
||||
ClassName = "SCENERY",
|
||||
}
|
||||
|
||||
_SCENERY = {}
|
||||
|
||||
--- Register scenery object as POSITIONABLE.
|
||||
--@param #SCENERY self
|
||||
--@param #string SceneryName Scenery name.
|
||||
--@param DCS#Object SceneryObject DCS scenery object.
|
||||
--@param Core.Zone#ZONE_POLYGON SceneryZone (optional) The zone 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 ) )
|
||||
|
||||
self.SceneryName = tostring(SceneryName)
|
||||
|
||||
self.ID = ID
|
||||
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
|
||||
self.Life0 = self.SceneryObject:getLife() or 0
|
||||
self.Life0 = self.SceneryObject:getLife() or 1
|
||||
else
|
||||
self.Life0 = 0
|
||||
self.Life0 = 1
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
@@ -99,6 +150,39 @@ function SCENERY:GetName()
|
||||
return self.SceneryName
|
||||
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.
|
||||
--@param #SCENERY self
|
||||
--@return DCS#Object DCS scenery object.
|
||||
@@ -106,6 +190,13 @@ function SCENERY:GetDCSObject()
|
||||
return self.SceneryObject
|
||||
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.
|
||||
-- **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
|
||||
@@ -113,12 +204,14 @@ end
|
||||
--@param #SCENERY self
|
||||
--@return #number life
|
||||
function SCENERY:GetLife()
|
||||
local life = 0
|
||||
local life = 1
|
||||
if self.SceneryObject and self.SceneryObject.getLife then
|
||||
life = self.SceneryObject:getLife()
|
||||
if life > self.Life0 then
|
||||
self.Life0 = math.floor(life * 1.2)
|
||||
end
|
||||
elseif self.Life then
|
||||
life = self.Life
|
||||
end
|
||||
return life
|
||||
end
|
||||
@@ -176,12 +269,19 @@ 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
|
||||
-- to find the correct object.
|
||||
--@param #SCENERY self
|
||||
--@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 #number Radius (optional) Search radius around coordinate, defaults to 100
|
||||
--@return #SCENERY Scenery Object or `nil` if it cannot be found
|
||||
function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
||||
|
||||
--@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 #number Radius (optional) Search radius around coordinate, defaults to 100.
|
||||
--@param #string Role (optional) The role if set on the zone object.
|
||||
--@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 name = Name or "unknown"
|
||||
local scenery = nil
|
||||
@@ -193,12 +293,13 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
||||
local function SceneryScan(scoordinate, sradius, sname)
|
||||
if scoordinate ~= nil then
|
||||
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})
|
||||
local scanned = scanzone:GetScannedSceneryObjects()
|
||||
local rscenery = nil -- Wrapper.Scenery#SCENERY
|
||||
for _,_scenery in pairs(scanned) do
|
||||
local scenery = _scenery -- Wrapper.Scenery#SCENERY
|
||||
--BASE:I({tostring(scenery.SceneryName),tostring(sname)})
|
||||
if tostring(scenery.SceneryName) == tostring(sname) then
|
||||
rscenery = scenery
|
||||
if Role then rscenery:SetProperty("ROLE",Role) end
|
||||
@@ -211,13 +312,36 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role)
|
||||
end
|
||||
|
||||
if Coordinate then
|
||||
--BASE:I("Coordinate Scenery Scan")
|
||||
scenery = SceneryScan(Coordinate, radius, name)
|
||||
end
|
||||
|
||||
|
||||
if not scenery then scenery = SCENERY:Register(Name,nil,Zone) end
|
||||
|
||||
return scenery
|
||||
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
|
||||
-- to find the correct object.
|
||||
--@param #SCENERY self
|
||||
@@ -231,8 +355,8 @@ function SCENERY:FindByNameInZone(Name, Zone, Radius)
|
||||
if type(Zone) == "string" then
|
||||
Zone = ZONE:FindByName(Zone)
|
||||
end
|
||||
local coordinate = Zone:GetCoordinate()
|
||||
return self:FindByName(Name,coordinate,Radius,Zone:GetProperty("ROLE"))
|
||||
local coordinate = Zone:GetCoordinate():SetAlt()
|
||||
return self:FindByName(Name,coordinate,Radius,Zone:GetProperty("ROLE"),Zone)
|
||||
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
|
||||
@@ -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.
|
||||
--@return #SCENERY First found Scenery Object or `nil` if it cannot be found
|
||||
function SCENERY:FindByZoneName( ZoneName )
|
||||
--BASE:I(ZoneName)
|
||||
|
||||
local zone = ZoneName -- Core.Zone#ZONE_BASE
|
||||
|
||||
if type(ZoneName) == "string" then
|
||||
zone = ZONE:FindByName(ZoneName) -- Core.Zone#ZONE_POLYGON
|
||||
end
|
||||
|
||||
local _id = zone:GetProperty('OBJECT ID')
|
||||
--local properties = zone:GetAllProperties() or {}
|
||||
--BASE:I(string.format("Object ID is: %s",_id or "none"))
|
||||
--BASE:T("Object ID ".._id)
|
||||
|
||||
--BASE:I("Object ID ".._id)
|
||||
|
||||
if not _id then
|
||||
-- this zone has no object ID
|
||||
BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName))
|
||||
@@ -257,23 +385,27 @@ function SCENERY:FindByZoneName( ZoneName )
|
||||
local scanned = zone:GetScannedSceneryObjects()
|
||||
for _,_scenery in (scanned) do
|
||||
local scenery = _scenery -- Wrapper.Scenery#SCENERY
|
||||
if scenery:IsAlive() then
|
||||
--if scenery:IsAlive() then
|
||||
local role = zone:GetProperty("ROLE")
|
||||
if role then scenery:SetProperty("ROLE",role) end
|
||||
return scenery
|
||||
end
|
||||
--end
|
||||
end
|
||||
return nil
|
||||
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
|
||||
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
|
||||
|
||||
--- 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 #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
|
||||
@@ -295,7 +427,7 @@ function SCENERY:FindAllByZoneName( ZoneName )
|
||||
return nil
|
||||
end
|
||||
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
|
||||
return {obj}
|
||||
else
|
||||
|
||||
@@ -64,6 +64,9 @@ function STATIC:Register( StaticName )
|
||||
else
|
||||
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
||||
end
|
||||
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -86,6 +89,30 @@ function STATIC:GetLife()
|
||||
return nil
|
||||
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.
|
||||
-- @param #STATIC self
|
||||
-- @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)
|
||||
|
||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
@@ -255,6 +284,8 @@ function STATIC:ReSpawn(CountryID, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||
|
||||
SpawnStatic:Spawn(nil, self.StaticName)
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
@@ -278,6 +309,8 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||
|
||||
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -753,7 +753,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
@@ -773,7 +773,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
@@ -805,7 +805,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user