mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-07-17 07:33:56 +00:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c335881b2d | |||
| 993fc45e83 | |||
| 130d358f4a | |||
| 49476abb9f | |||
| a02b99036b | |||
| dab6f48fe9 | |||
| 23c9ea0961 | |||
| d0b04ebbbd | |||
| bd64d084e9 | |||
| c91b59f8cd | |||
| a699300f5f | |||
| 6e12c5c1d0 | |||
| 852fc1d2d5 | |||
| c2c957b859 | |||
| f20c22ab49 | |||
| 1e200511cb | |||
| 80f2a0ef39 | |||
| ae156259c0 | |||
| 39e3f8b646 | |||
| ac61c3a55c | |||
| 1054ffa7ac | |||
| 41503ae625 | |||
| 1ee90e67b2 | |||
| d0ce7f1aa6 | |||
| c387749a81 | |||
| b980c5d93a | |||
| 49332fafec | |||
| 3ab3278db4 | |||
| 7a3ea2918d | |||
| 9c0394f035 | |||
| 9536d368b0 | |||
| 9426905959 | |||
| 99b7b4b057 | |||
| 2fdbdb4058 | |||
| 898405e15f | |||
| 7259038b1c | |||
| 3886351490 | |||
| 3aedf8e5d0 | |||
| aed2f1d8a9 | |||
| 3504797147 | |||
| 3cfaa60ebb | |||
| 2d930ff2dd | |||
| 11a8792398 | |||
| f7556fac0e |
@@ -184,6 +184,7 @@ EVENT = {
|
||||
ClassName = "EVENT",
|
||||
ClassID = 0,
|
||||
MissionEnd = false,
|
||||
CreateMarkCoordinateOnEvent = false,
|
||||
}
|
||||
|
||||
world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
|
||||
@@ -339,14 +340,18 @@ EVENTS = {
|
||||
-- @field #string WeaponName Name of the weapon.
|
||||
-- @field DCS#Unit WeaponTgtDCSUnit Target DCS unit of the weapon.
|
||||
--
|
||||
-- @field Cargo.Cargo#CARGO Cargo The cargo object.
|
||||
-- @field #string CargoName The name of the cargo object.
|
||||
--
|
||||
-- @field Core.Zone#ZONE Zone The zone object.
|
||||
-- @field #string ZoneName The name of the zone.
|
||||
--
|
||||
-- @field Wrapper.DynamicCargo#DYNAMICCARGO IniDynamicCargo The dynamic cargo object.
|
||||
-- @field #string IniDynamicCargoName The dynamic cargo unit name.
|
||||
--
|
||||
-- @field #number MarkCoalition Coalition of a marker (if any)
|
||||
-- @field DCS#Vec3 MarkVec3 Position of a marker
|
||||
-- @field #string MarkText Text content of a marker, if any
|
||||
-- @field #number MarkID ID of the marker, for deletion
|
||||
-- @field #number MarkGroupID Group ID of the group that created the marker
|
||||
-- @field Core.Point#COORDINATE Coordinate object of the marker, only filled if EVENT.CreateMarkCoordinateOnEvent is set to true (off by default)
|
||||
|
||||
|
||||
|
||||
@@ -1063,36 +1068,6 @@ end
|
||||
|
||||
do -- Event Creation
|
||||
|
||||
--- Creation of a New Cargo Event.
|
||||
-- @param #EVENT self
|
||||
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
|
||||
function EVENT:CreateEventNewCargo( Cargo )
|
||||
self:F( { Cargo } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.NewCargo,
|
||||
time = timer.getTime(),
|
||||
cargo = Cargo,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a Cargo Deletion Event.
|
||||
-- @param #EVENT self
|
||||
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
|
||||
function EVENT:CreateEventDeleteCargo( Cargo )
|
||||
self:F( { Cargo } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.DeleteCargo,
|
||||
time = timer.getTime(),
|
||||
cargo = Cargo,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a New Zone Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.Zone#ZONE_BASE Zone The Zone created.
|
||||
@@ -1361,7 +1336,8 @@ function EVENT:onEvent( Event )
|
||||
Event.IniDynamicCargoName = Event.IniUnitName
|
||||
Event.IniPlayerName = string.match(Event.IniUnitName,"^(.+)|%d%d:%d%d|PKG%d+")
|
||||
else
|
||||
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
|
||||
--Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
|
||||
Event.IniUnit = STATIC:FindByName( Event.IniDCSUnitName, false )
|
||||
end
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
@@ -1374,7 +1350,9 @@ function EVENT:onEvent( Event )
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
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 )
|
||||
local ID = (Event.IniDCSUnit and Event.IniDCSUnit.getID) and Event.IniDCSUnit:getID() or Event.IniDCSUnitName
|
||||
Event.IniUnit = (_SCENERY ~= nil) and _SCENERY[ID] or nil
|
||||
--Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||
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"
|
||||
@@ -1478,7 +1456,9 @@ function EVENT:onEvent( Event )
|
||||
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 )
|
||||
local ID = (Event.TgtDCSUnit and Event.TgtDCSUnit.getID) and Event.TgtDCSUnit:getID() or Event.TgtDCSUnitName
|
||||
--Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||
Event.TgtUnit = (_SCENERY ~= nil) and _SCENERY[ID] or nil
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
@@ -1519,7 +1499,9 @@ function EVENT:onEvent( Event )
|
||||
if Event.idx then
|
||||
Event.MarkID=Event.idx
|
||||
Event.MarkVec3=Event.pos
|
||||
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||
if self.CreateMarkCoordinateOnEvent == true then
|
||||
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||
end
|
||||
Event.MarkText=Event.text
|
||||
Event.MarkCoalition=Event.coalition
|
||||
Event.IniCoalition=Event.coalition
|
||||
|
||||
@@ -3281,7 +3281,6 @@ do -- COORDINATE
|
||||
return delta/60
|
||||
end
|
||||
|
||||
|
||||
--- Return a BR string from a COORDINATE to the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||
@@ -3295,6 +3294,20 @@ do -- COORDINATE
|
||||
local Distance = self:Get2DDistance( FromCoordinate )
|
||||
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar, Precision )
|
||||
end
|
||||
|
||||
--- Return a Bearing string from a COORDINATE to the (self) COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
|
||||
-- @param #number Precision Rounding precision, currently full km as default (=0)
|
||||
-- @return #string The BR text.
|
||||
function COORDINATE:ToStringBearing( FromCoordinate, Settings, MagVar, Precision )
|
||||
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||
--local Distance = self:Get2DDistance( FromCoordinate )
|
||||
return self:GetBearingText(AngleRadians,Precision,Settings,MagVar)
|
||||
end
|
||||
|
||||
--- Return a BRA string from a COORDINATE to the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
|
||||
@@ -693,7 +693,7 @@ end
|
||||
function AUTOLASE:GetLosFromUnit(Unit)
|
||||
local lasedistance = self.LaseDistance
|
||||
local unitheight = Unit:GetHeight()
|
||||
local coord = Unit:GetCoordinate()
|
||||
local coord = Unit:GetCoord()
|
||||
local landheight = coord:GetLandHeight()
|
||||
local asl = unitheight - landheight
|
||||
if asl > 100 then
|
||||
@@ -845,7 +845,7 @@ function AUTOLASE:ShowStatus(Group,Unit)
|
||||
locationstring = entry.coordinate:ToStringLLDDM(settings)
|
||||
elseif settings:IsA2G_BR() then
|
||||
-- attention this is the distance from the ASKING unit to target, not from RECCE to target!
|
||||
local startcoordinate = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||
local startcoordinate = Unit:GetCoord() or Group:GetCoord()
|
||||
locationstring = entry.coordinate:ToStringBR(startcoordinate,settings,false,self.RoundingPrecision)
|
||||
end
|
||||
end
|
||||
@@ -963,8 +963,8 @@ function AUTOLASE:CanLase(Recce,Unit)
|
||||
end
|
||||
end
|
||||
-- calculate LOS
|
||||
local reccecoord = Recce:GetCoordinate()
|
||||
local unitcoord = Unit:GetCoordinate()
|
||||
local reccecoord = Recce:GetCoord()
|
||||
local unitcoord = Unit:GetCoord()
|
||||
local islos = reccecoord:IsLOS(unitcoord,2.5)
|
||||
-- calculate distance
|
||||
local distance = math.floor(reccecoord:Get3DDistance(unitcoord))
|
||||
@@ -1020,8 +1020,8 @@ function AUTOLASE:_Prescient()
|
||||
self:T(self.lid.."Checking possibly visible STATICs for Recce "..unit:GetName())
|
||||
for _,_static in pairs(Statics) do -- DCS static object here
|
||||
local static = STATIC:Find(_static)
|
||||
if static and static:GetCoalition() ~= self.coalition and static:GetCoordinate() then
|
||||
local IsLOS = position:IsLOS(static:GetCoordinate())
|
||||
if static and static:GetCoalition() ~= self.coalition and static:GetCoord() then
|
||||
local IsLOS = position:IsLOS(static:GetCoord())
|
||||
if IsLOS then
|
||||
unit:KnowUnit(static,true,true)
|
||||
end
|
||||
@@ -1081,7 +1081,7 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
||||
local threat = contact.threatlevel or 0
|
||||
local reccegrp = UNIT:FindByName(reccename)
|
||||
if reccegrp then
|
||||
local reccecoord = reccegrp:GetCoordinate()
|
||||
local reccecoord = reccegrp:GetCoord()
|
||||
local distance = math.floor(reccecoord:Get3DDistance(coord))
|
||||
local text = string.format("%s of %s | Distance %d km | Threatlevel %d",contact.attribute, contact.groupname, math.floor(distance/1000), contact.threatlevel)
|
||||
report:Add(text)
|
||||
@@ -1120,7 +1120,6 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
||||
local unit = _unit -- Wrapper.Unit#UNIT
|
||||
if unit and unit:IsAlive() then
|
||||
local threat = unit:GetThreatLevel()
|
||||
local coord = unit:GetCoordinate()
|
||||
if threat >= self.minthreatlevel then
|
||||
local unitname = unit:GetName()
|
||||
-- prefer radar units
|
||||
@@ -1176,16 +1175,16 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
||||
local code = self:GetLaserCode(reccename)
|
||||
local spot = SPOT:New(recce)
|
||||
spot:LaseOn(unit,code,self.LaseDuration)
|
||||
local locationstring = unit:GetCoordinate():ToStringLLDDM()
|
||||
local locationstring = unit:GetCoord():ToStringLLDDM()
|
||||
if _SETTINGS:IsA2G_MGRS() then
|
||||
local precision = _SETTINGS:GetMGRS_Accuracy()
|
||||
local settings = {}
|
||||
settings.MGRS_Accuracy = precision
|
||||
locationstring = unit:GetCoordinate():ToStringMGRS(settings)
|
||||
locationstring = unit:GetCoord():ToStringMGRS(settings)
|
||||
elseif _SETTINGS:IsA2G_LL_DMS() then
|
||||
locationstring = unit:GetCoordinate():ToStringLLDMS(_SETTINGS)
|
||||
locationstring = unit:GetCoord():ToStringLLDMS(_SETTINGS)
|
||||
elseif _SETTINGS:IsA2G_BR() then
|
||||
locationstring = unit:GetCoordinate():ToStringBULLS(self.coalition,_SETTINGS)
|
||||
locationstring = unit:GetCoord():ToStringBULLS(self.coalition,_SETTINGS)
|
||||
end
|
||||
|
||||
local laserspot = { -- #AUTOLASE.LaserSpot
|
||||
@@ -1198,7 +1197,7 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
||||
unitname = unitname,
|
||||
reccename = reccename,
|
||||
unittype = unit:GetTypeName(),
|
||||
coordinate = unit:GetCoordinate(),
|
||||
coordinate = unit:GetCoord(),
|
||||
}
|
||||
if self.smoketargets then
|
||||
local coord = unit:GetCoordinate()
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: December 2025
|
||||
-- Last Update: January 2026
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -283,7 +283,7 @@
|
||||
MANTIS = {
|
||||
ClassName = "MANTIS",
|
||||
name = "mymantis",
|
||||
version = "0.9.42",
|
||||
version = "0.9.44",
|
||||
SAM_Templates_Prefix = "",
|
||||
SAM_Group = nil,
|
||||
EWR_Templates_Prefix = "",
|
||||
@@ -337,6 +337,8 @@ MANTIS = {
|
||||
DetectAccoustic = false,
|
||||
DetectAccousticRadius = 2000,
|
||||
DetectAccousticCategories = {Unit.Category.HELICOPTER},
|
||||
ARMWeaponSeen = {},
|
||||
InboundARMs = {},
|
||||
}
|
||||
|
||||
--- Advanced state enumerator
|
||||
@@ -372,24 +374,25 @@ MANTIS.radiusscale[MANTIS.SamType.POINT] = 3
|
||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||
-- @field #string Radar Radar typename on unit level (used as key)
|
||||
-- @field #string Point Point defense capable
|
||||
-- @field ARMCapacit ARMCapacity ie how many (H)ARMs the system can defend at the same time
|
||||
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
|
||||
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS", ARMCapacity=1 }, -- AIM 120B
|
||||
["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" },
|
||||
["SA-5"] = { Range=250, Blindspot=7, Height=40, Type="Long", Radar="5N62V" },
|
||||
["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-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4", ARMCapacity=4},
|
||||
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
||||
["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland" },
|
||||
["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland", ARMCapacity=1 },
|
||||
["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" },
|
||||
["SA-19"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Tunguska" },
|
||||
["SA-15"] = { Range=11, Blindspot=0, Height=6, Type="Point", Radar="Tor 9A331", Point="true" },
|
||||
["SA-15"] = { Range=11, Blindspot=0, Height=6, Type="Point", Radar="Tor 9A331", Point="true", ARMCapacity=2 },
|
||||
["SA-13"] = { Range=5, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" },
|
||||
["Avenger"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Avenger" },
|
||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||
@@ -397,23 +400,23 @@ MANTIS.SamData = {
|
||||
["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=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"},
|
||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B", ARMCapacity=4},
|
||||
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17", ARMCapacity=4 },
|
||||
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1", ARMCapacity=16},
|
||||
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2", ARMCapacity=18},
|
||||
["SA-21"] = { Range=380, Blindspot=5, Height=30, Type="Long" , Radar="92N6E"},
|
||||
["S-300VM"] = { Range=200, Blindspot=5, Height=30, Type="Long" , Radar="9S32M"},
|
||||
["S-300V4"] = { Range=380, Blindspot=5, Height=30, Type="Long" , Radar="9S32M"},
|
||||
["S-400"] = { Range=250, Blindspot=5, Height=27, Type="Long" , Radar="92N6E"},
|
||||
["S-300VM"] = { Range=200, Blindspot=5, Height=30, Type="Long" , Radar="9S32M", ARMCapacity=4},
|
||||
["S-300V4"] = { Range=380, Blindspot=5, Height=30, Type="Long" , Radar="9S32M", ARMCapacity=4},
|
||||
["S-400"] = { Range=250, Blindspot=5, Height=27, Type="Long" , Radar="92N6E", ARMCapacity=4},
|
||||
["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" },
|
||||
["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" },
|
||||
["Pantsir S1"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1" , Point="true", ARMCapacity=3 },
|
||||
["Tor M2"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true", ARMCapacity=4 },
|
||||
["IRIS-T SLM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM", ARMCapacity=12 }, -- 4 per starter, usually 3 starters in a battery
|
||||
}
|
||||
|
||||
--- SAM data HDS
|
||||
@@ -429,13 +432,13 @@ 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-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" },
|
||||
["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln", ARMCapacity=8}, -- V55RUD
|
||||
["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln", ARMCapacity=3}, -- V55RUD
|
||||
["SA-17 HDS"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17", ARMCapacity=4 },
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l", ARMCapacity=12},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l", ARMCapacity=12},
|
||||
["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME", ARMCapacity=14 },
|
||||
["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME", ARMCapacity=14 },
|
||||
["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
|
||||
@@ -479,21 +482,21 @@ MANTIS.SamDataCH = {
|
||||
-- https://www.currenthill.com/
|
||||
-- group name MUST contain CHM to ID launcher type correctly!
|
||||
["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" },
|
||||
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1", Point="true", ARMCapacity=3 },
|
||||
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2", ARMCapacity=4 },
|
||||
["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" },
|
||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true", ARMCapacity=3 },
|
||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2K", Point="true", ARMCapacity=4 },
|
||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Point", Radar="TorM2M", Point="true", ARMCapacity=4 },
|
||||
["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.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" },
|
||||
["S350-9M100 CHM"] = { Range=15, Blindspot=1, Height=8, Type="Short", Radar="CH_S350_50P6_9M100", ARMCapacity=20 },
|
||||
["S350-9M96D CHM"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D", ARMCapacity=20 },
|
||||
["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.5, Blindspot=0.5, Height=2, Type="Point", Radar="CH_PGZ95",Point="true" },
|
||||
@@ -505,8 +508,8 @@ MANTIS.SamDataCH = {
|
||||
["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" },
|
||||
["BukM3-9M317M CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317M", ARMCapacity=20 },
|
||||
["BukM3-9M317MA CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317MA", ARMCapacity=20 },
|
||||
["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" },
|
||||
@@ -625,6 +628,8 @@ do
|
||||
self.autoshorad = true
|
||||
self.ShoradGroupSet = SET_GROUP:New() -- Core.Set#SET_GROUP
|
||||
self.FilterZones = Zones
|
||||
self.LastThreatEval = {}
|
||||
self.InboundARMs = {}
|
||||
|
||||
self.SkateZones = nil
|
||||
self.SkateNumber = 3
|
||||
@@ -1804,6 +1809,7 @@ do
|
||||
local group = GROUP:FindByName(grpname) -- Wrapper.Group#GROUP
|
||||
local units = group:GetUnits()
|
||||
local SAMData = self.SamData
|
||||
local ARMCapacity
|
||||
if mod then
|
||||
SAMData = self.SamDataHDS
|
||||
elseif sma then
|
||||
@@ -1811,22 +1817,23 @@ do
|
||||
elseif chm then
|
||||
SAMData = self.SamDataCH
|
||||
end
|
||||
--self:I("Looking to auto-match for "..grpname)
|
||||
self:T("Looking to auto-match for "..grpname)
|
||||
for _,_unit in pairs(units) do
|
||||
local unit = _unit -- Wrapper.Unit#UNIT
|
||||
local type = string.lower(unit:GetTypeName())
|
||||
--self:I(string.format("Matching typename: %s",type))
|
||||
local typename = string.lower(unit:GetTypeName())
|
||||
self:T(string.format("Matching typename: %s",typename))
|
||||
for idx,entry in pairs(SAMData) do
|
||||
local _entry = entry -- #MANTIS.SamData
|
||||
local _radar = string.lower(_entry.Radar)
|
||||
--self:I(string.format("Trying typename: %s",_radar))
|
||||
if string.find(type,_radar,1,true) then
|
||||
self:T(string.format("Trying typename: %s",_radar))
|
||||
if string.find(typename,_radar,1,true) then
|
||||
type = _entry.Type
|
||||
radiusscale = self.radiusscale[type]
|
||||
range = _entry.Range * 1000 * radiusscale -- max firing range used as switch-on
|
||||
height = _entry.Height * 1000 -- max firing height
|
||||
blind = _entry.Blindspot * 100 -- blind spot range
|
||||
--self:I(string.format("Match: %s - %s",_radar,type))
|
||||
blind = _entry.Blindspot * 100 -- blind spot range
|
||||
ARMCapacity = _entry.ARMCapacity
|
||||
self:T(string.format("Match: %s - %s",_radar,type))
|
||||
found = true
|
||||
break
|
||||
end
|
||||
@@ -1847,7 +1854,7 @@ do
|
||||
if not found then
|
||||
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
||||
end
|
||||
return range, height, type, blind
|
||||
return range, height, type, blind, ARMCapacity
|
||||
end
|
||||
|
||||
--- [Internal] Function to get SAM firing data
|
||||
@@ -1868,6 +1875,7 @@ do
|
||||
local HDSmod = false
|
||||
local SMAMod = false
|
||||
local CHMod = false
|
||||
local ARMCapacity = 0
|
||||
if string.find(grpname,"HDS",1,true) then
|
||||
HDSmod = true
|
||||
elseif string.find(grpname,"SMA",1,true) then
|
||||
@@ -1885,6 +1893,7 @@ do
|
||||
range = _entry.Range * 1000 * radiusscale -- max firing range
|
||||
height = _entry.Height * 1000 -- max firing height
|
||||
blind = _entry.Blindspot
|
||||
ARMCapacity = _entry.ARMCapacity or 0
|
||||
self:T("Matching Groupname = " .. grpname .. " Range= " .. range)
|
||||
found = true
|
||||
break
|
||||
@@ -1904,14 +1913,14 @@ do
|
||||
end
|
||||
--- Tertiary filter if not found
|
||||
if (not found) or HDSmod or SMAMod or CHMod then
|
||||
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
|
||||
range, height, type, blind, ARMCapacity = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
|
||||
elseif not found then
|
||||
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
||||
end
|
||||
if found and string.find(grpname,"SHORAD",1,true) then
|
||||
type = MANTIS.SamType.POINT -- force short on match
|
||||
end
|
||||
return range, height, type, blind
|
||||
return range, height, type, blind, ARMCapacity
|
||||
end
|
||||
|
||||
--- [Internal] Function to set the SAM start state
|
||||
@@ -1946,8 +1955,9 @@ do
|
||||
group:OptionEngageRange(engagerange) --default engagement will be 95% of firing range
|
||||
local grpname = group:GetName()
|
||||
local grpcoord = group:GetCoordinate()
|
||||
local grprange,grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||
local grprange,grpheight,type,blind,ARMCapacity = self:_GetSAMRange(grpname)
|
||||
if ARMCapacity and ARMCapacity>0 then _group:SetProperty("ARMCapacity",ARMCapacity) end
|
||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type, ARMCapacity})
|
||||
--table.insert( SEAD_Grps, grpname )
|
||||
if type == MANTIS.SamType.LONG then
|
||||
table.insert( SAM_Tbl_lg, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||
@@ -2011,12 +2021,15 @@ do
|
||||
if group:IsGround() and group:IsAlive() then
|
||||
local grpname = group:GetName()
|
||||
local grpcoord = group:GetCoordinate()
|
||||
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||
local grprange, grpheight,type,blind, ARMCapacity = self:_GetSAMRange(grpname)
|
||||
-- TODO the below might stop working at some point after some hours, needs testing
|
||||
--local radaralive = group:IsSAM()
|
||||
if ARMCapacity and ARMCapacity>0 then _group:SetProperty("ARMCapacity",ARMCapacity) end
|
||||
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 )
|
||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type, ARMCapacity}) -- make the table lighter, as I don't really use the zone here
|
||||
if type ~= MANTIS.SamType.POINT then
|
||||
table.insert( SEAD_Grps, grpname )
|
||||
end
|
||||
if type == MANTIS.SamType.LONG and radaralive then
|
||||
table.insert( SAM_Tbl_lg, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||
self:T({grpname,grprange, grpheight})
|
||||
@@ -2098,6 +2111,97 @@ do
|
||||
-----------------------------------------------------------------------
|
||||
-- MANTIS main functions
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
--- [Internal] Check if a system can and should defend for HARMs itself
|
||||
-- @param #MANTIS self
|
||||
-- @param Wrapper.Group#GROUP targetGroup
|
||||
-- @param #string targetName
|
||||
-- @param Wrapper.Group#GROUP attackerGroup
|
||||
-- @param #string weaponName
|
||||
-- @param Wrapper.Weapon#WEAPON weaponWrapper
|
||||
-- @param #number tti
|
||||
-- @param #number delay
|
||||
-- @return #boolean Outcome
|
||||
function MANTIS:SeadAllowSuppression(targetGroup, targetName, attackerGroup, weaponName, weaponWrapper, tti, delay)
|
||||
self:T(self.lid.."SeadAllowSuppression")
|
||||
|
||||
--- Thanks to @Goon Jan 2026
|
||||
----------------------------------------------------------------
|
||||
-- LOG INCOMING REQUEST
|
||||
----------------------------------------------------------------
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression REQUEST | target=%s | weapon=%s | tti=%s | delay=%s",tostring(targetName),
|
||||
tostring(weaponName),tostring(tti),tostring(delay)))
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- LOOK UP ARM CAPACITY FOR THIS SAM
|
||||
----------------------------------------------------------------
|
||||
local armcap = targetGroup:GetProperty("ARMCapacity")
|
||||
|
||||
if not armcap then
|
||||
for _, sam in pairs(self.SAM_Table or {}) do
|
||||
if sam[1] == targetName then
|
||||
armcap = sam[7] -- ARMCapacity
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression SAM DATA | target=%s | ARMCapacity=%s",tostring(targetName),armcap and tostring(armcap) or "nil"))
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- TRACK SEAD THREATS (PER TARGET)
|
||||
----------------------------------------------------------------
|
||||
local THREAT_WINDOW = 0.1 -- seconds
|
||||
|
||||
self.LastThreatEval = self.LastThreatEval or {}
|
||||
self.InboundARMs = self.InboundARMs or {}
|
||||
|
||||
local now = timer.getTime()
|
||||
local last = self.LastThreatEval[targetName] or 0
|
||||
|
||||
if (now - last) >= THREAT_WINDOW then
|
||||
self.InboundARMs[targetName] = (self.InboundARMs[targetName] or 0) + 1
|
||||
self.LastThreatEval[targetName] = now
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression NEW threat accepted | Δt=%.3f",now - last))
|
||||
else
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression duplicate evaluation ignored | Δt=%.3f",now - last))
|
||||
end
|
||||
|
||||
local inbound = self.InboundARMs[targetName] or 0
|
||||
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression THREAT COUNT | target=%s | inboundThreats=%d",tostring(targetName),inbound))
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- DECISION GATE
|
||||
----------------------------------------------------------------
|
||||
|
||||
-- No missiles left over → legacy behavior
|
||||
if targetGroup and targetGroup:IsAlive() then
|
||||
local AmmotT, AmmoS, _, _,AmmoM = targetGroup:GetAmmunition()
|
||||
-- TODO Check C-RAM probably needs an exception as it is a gun, need to check its effectiveness
|
||||
if AmmoM and AmmoM == 0 then
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression DECISION -> APPROVED (no MISSILES) | target=%s",tostring(targetName)))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- No ARM capacity defined → legacy behavior
|
||||
if (not armcap) or armcap == 0 then
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression DECISION -> APPROVED (no ARMCAP) | target=%s",tostring(targetName)))
|
||||
return true
|
||||
end
|
||||
|
||||
-- Suppress only once enough threats accumulated
|
||||
if inbound >= armcap then
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression DECISION -> APPROVED (inbound %d >= cap %d) | target=%s",inbound,armcap,tostring(targetName)))
|
||||
return true
|
||||
end
|
||||
|
||||
self:T(string.format("MANTIS:SeadAllowSuppression DECISION -> DENIED (inbound %d < cap %d) | target=%s",inbound,armcap,tostring(targetName)))
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--- [Internal] Check detection function
|
||||
-- @param #MANTIS self
|
||||
@@ -2132,6 +2236,7 @@ do
|
||||
if self.Shorad and self.Shorad.ActiveGroups and self.Shorad.ActiveGroups[name] then
|
||||
activeshorad = true
|
||||
end
|
||||
if samgroup:GetProperty("SHORAD_ACTIVE") == true and activeshorad == false 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 samgroup:IsAlive() then
|
||||
-- switch on SAM
|
||||
@@ -2147,6 +2252,7 @@ do
|
||||
switch = true
|
||||
end
|
||||
if self.SamStateTracker[name] ~= "RED" and switch then
|
||||
self.SamStateTracker[name] = "RED"
|
||||
self:__RedState(1,samgroup)
|
||||
end
|
||||
-- DONE Restrict on Distance
|
||||
@@ -2179,8 +2285,8 @@ do
|
||||
samgroup:OptionAlarmStateGreen()
|
||||
end
|
||||
if self.SamStateTracker[name] ~= "GREEN" then
|
||||
self:__GreenState(1,samgroup)
|
||||
self.SamStateTracker[name] = "GREEN"
|
||||
self:__GreenState(1,samgroup)
|
||||
end
|
||||
if self.debug or self.verbose then
|
||||
local text = string.format("SAM %s in alarm state GREEN!", name)
|
||||
@@ -2190,12 +2296,13 @@ do
|
||||
end --end alive
|
||||
end --end check
|
||||
end --for loop
|
||||
--[[
|
||||
if self.debug or self.verbose or self.logsamstatus then
|
||||
for _,_status in pairs(self.SamStateTracker) do
|
||||
if _status == "GREEN" then
|
||||
instatusgreen=instatusgreen+1
|
||||
elseif _status == "RED" then
|
||||
instatusred=instatusred+1
|
||||
instatusred=instatusred+1
|
||||
end
|
||||
end
|
||||
if self.Shorad then
|
||||
@@ -2204,6 +2311,8 @@ do
|
||||
end
|
||||
end
|
||||
end
|
||||
self:T(self.lid..string.format("SAM State Count: GREEN %d | RED %d | SHORAD %d",instatusred, instatusgreen, activeshorads))
|
||||
--]]
|
||||
return instatusred, instatusgreen, activeshorads
|
||||
end
|
||||
|
||||
@@ -2235,13 +2344,29 @@ do
|
||||
local samset = self.SAM_Table_Short -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||
local instatusreds, instatusgreens, activeshoradss = self:_CheckLoop(samset,detset,dlink,self.maxshortrange)
|
||||
local samset = self.SAM_Table_PointDef -- 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.maxpointdefrange)
|
||||
local instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxpointdefrange)
|
||||
else
|
||||
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)
|
||||
local instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic)
|
||||
end
|
||||
|
||||
local function GetReport()
|
||||
|
||||
if self.debug or self.verbose or self.logsamstatus then
|
||||
for _,_status in pairs(self.SamStateTracker) do
|
||||
if _status == "GREEN" then
|
||||
instatusgreen=instatusgreen+1
|
||||
elseif _status == "RED" then
|
||||
instatusred=instatusred+1
|
||||
end
|
||||
end
|
||||
if self.Shorad then
|
||||
for _,_name in pairs(self.Shorad.ActiveGroups or {}) do
|
||||
activeshorads=activeshorads+1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local statusreport = REPORT:New("\nMANTIS Status "..self.name)
|
||||
statusreport:Add("+-----------------------------+")
|
||||
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
||||
@@ -2344,6 +2469,7 @@ do
|
||||
self.ShoradLink = true
|
||||
self.Shorad.Groupset=self.ShoradGroupSet
|
||||
self.Shorad.debug = self.debug
|
||||
self.Shorad:AddCallBack(self)
|
||||
end
|
||||
if self.shootandscoot and self.SkateZones and self.Shorad then
|
||||
self.Shorad:AddScootZones(self.SkateZones,self.SkateNumber or 3,self.ScootRandom,self.ScootFormation)
|
||||
@@ -2549,6 +2675,7 @@ do
|
||||
function MANTIS:onafterSeadSuppressionEnd(From, Event, To, Group, Name)
|
||||
self:T({From, Event, To, Name})
|
||||
self.SuppressedGroups[Name] = false
|
||||
self.InboundARMs[Name] = 0
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -2212,7 +2212,11 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
||||
local data = self:ReportScoreAllSummary("",true)
|
||||
local text = "-- Playername;;Score;;Penalty\n"
|
||||
for _playername,_data in pairs(data or {}) do
|
||||
text = text..string.format("%s;;%d;;%d\n")
|
||||
-- ReportTable[PlayerName] = {["Score"]=PlayerScore,["Penalty"]=PlayerPenalty}
|
||||
local Playername = _playername or "Ghost"
|
||||
local Score = _data.Score or 0
|
||||
local Penalty = _data.Penalty or 0
|
||||
text = text..string.format("%s;;%d;;%d\n",Playername,Score,Penalty)
|
||||
end
|
||||
UTILS.SaveToFile(path,filename,text)
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
--
|
||||
-- ### Authors: **applevangelist**, **FlightControl**
|
||||
--
|
||||
-- Last Update: Dec 2024
|
||||
-- Last Update: January 2026
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -157,7 +157,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
||||
self:AddTransition("*", "ManageEvasion", "*")
|
||||
self:AddTransition("*", "CalculateHitZone", "*")
|
||||
|
||||
self:I("*** SEAD - Started Version 0.4.9")
|
||||
self:I("*** SEAD - Started Version 0.4.11")
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -318,7 +318,7 @@ function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADG
|
||||
elseif height <= 12500 then
|
||||
Ropt = Ropt * 0.98
|
||||
end
|
||||
|
||||
local WeaponWrapper = WEAPON:New(SEADWeapon)
|
||||
-- look at a couple of zones across the trajectory
|
||||
for n=1,3 do
|
||||
local dist = Ropt - ((n-1)*20000)
|
||||
@@ -342,7 +342,7 @@ function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADG
|
||||
_targetgroupname = tgtgrp:GetName() -- group name
|
||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||
self:T("*** Found Target = ".. _targetgroupname)
|
||||
self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20)
|
||||
self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20, WeaponWrapper)
|
||||
end
|
||||
--end
|
||||
end
|
||||
@@ -442,7 +442,18 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
local SuppressionStartTime = timer.getTime() + delay
|
||||
local SuppressionEndTime = timer.getTime() + delay + _tti + self.Padding + delay
|
||||
local _targetgroupname = _targetgroup:GetName()
|
||||
if not self.SuppressedGroups[_targetgroupname] then
|
||||
local shoradactive = _targetgroup:GetProperty("SHORAD_ACTIVE")
|
||||
if not self.SuppressedGroups[_targetgroupname] and shoradactive ~= true then
|
||||
-- TODO: ask callback if suppression is allowed BEFORE scheduling timers
|
||||
local allow = true
|
||||
if self.UseCallBack and self.CallBack and self.CallBack.SeadAllowSuppression then
|
||||
allow = self.CallBack:SeadAllowSuppression(_targetgroup,_targetgroupname,SEADGroup,SEADWeaponName,Weapon,_tti,delay)
|
||||
end
|
||||
if not allow then
|
||||
self:T(string.format("*** SEAD - %s | Suppression vetoed by callback", _targetgroupname))
|
||||
-- Important: do NOT schedule SuppressionStart/Stop and do NOT flip SuppressedGroups true.
|
||||
return self
|
||||
end
|
||||
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
||||
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname, SEADGroup},SuppressionStartTime)
|
||||
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-- @image Functional.Shorad.jpg
|
||||
--
|
||||
-- Date: Nov 2021
|
||||
-- Last Update: Jan 2025
|
||||
-- Last Update: Jan 2026
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **SHORAD** class, extends Core.Base#BASE
|
||||
@@ -196,7 +196,7 @@ do
|
||||
self.SmokeDecoyColor = SmokeDecoyColor or SMOKECOLOR.White
|
||||
end
|
||||
|
||||
self:I("*** SHORAD - Started Version 0.3.5")
|
||||
self:I("*** SHORAD - Started Version 0.3.6")
|
||||
-- Set the string id for output to DCS.log file.
|
||||
self.lid=string.format("SHORAD %s | ", self.name)
|
||||
self:_InitState()
|
||||
@@ -465,6 +465,17 @@ do
|
||||
return returnname
|
||||
end
|
||||
|
||||
--- Set an object to call back when going evasive.
|
||||
-- @param #SHORAD self
|
||||
-- @param #table Object The object to call.
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:AddCallBack(Object)
|
||||
self:T({Class=Object.ClassName})
|
||||
self.CallBack = Object
|
||||
self.UseCallBack = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke a SHORAD Group
|
||||
-- @param #SHORAD self
|
||||
-- @param Wrapper.Group#GROUP Group The Shorad Group to Smoke
|
||||
@@ -524,7 +535,56 @@ do
|
||||
-- mymantis:Start()
|
||||
function SHORAD:onafterWakeUpShorad(From, Event, To, TargetGroup, Radius, ActiveTimer, TargetCat, ShotAt)
|
||||
self:T(self.lid .. " WakeUpShorad")
|
||||
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
||||
--self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
||||
|
||||
local TDiff = 4
|
||||
|
||||
-- local function to switch off shorad again
|
||||
local function SleepShorad(group)
|
||||
if group and group:IsAlive() then
|
||||
local groupname = group:GetName()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
if self.UseEmOnOff then
|
||||
group:EnableEmission(false)
|
||||
else
|
||||
group:OptionAlarmStateGreen()
|
||||
end
|
||||
group:SetProperty("SHORAD_ACTIVE",false)
|
||||
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(1,group)
|
||||
else
|
||||
--group:RelocateGroundRandomInRadius(30,500,false,true,"Diamond",true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function WakeUp(_group,groupname)
|
||||
-- shot at a group we protect
|
||||
local text = string.format("Waking up SHORAD %s", _group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
if self.UseEmOnOff then
|
||||
_group:EnableEmission(true)
|
||||
end
|
||||
_group:OptionAlarmStateRed()
|
||||
_group:SetProperty("SHORAD_ACTIVE",true)
|
||||
self:_SmokeUnits(_group)
|
||||
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||
self.ActiveGroups[groupname].Timer = TIMER:New(SleepShorad,_group):Start(endtime)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(TDiff,_group)
|
||||
TDiff=TDiff+1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local targetcat = TargetCat or Object.Category.UNIT
|
||||
local targetgroup = TargetGroup
|
||||
local targetvec2 = nil
|
||||
@@ -541,70 +601,41 @@ do
|
||||
local groupset = self.Groupset --Core.Set#SET_GROUP
|
||||
local shoradset = groupset:GetAliveSet() --#table
|
||||
|
||||
-- local function to switch off shorad again
|
||||
local function SleepShorad(group)
|
||||
if group and group:IsAlive() then
|
||||
local groupname = group:GetName()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
if self.UseEmOnOff then
|
||||
group:EnableEmission(false)
|
||||
else
|
||||
group:OptionAlarmStateGreen()
|
||||
end
|
||||
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(1,group)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- go through set and find the one(s) to activate
|
||||
local TDiff = 4
|
||||
|
||||
for _,_group in pairs (shoradset) do
|
||||
|
||||
local groupname = _group:GetName()
|
||||
|
||||
if groupname == TargetGroup and ShotAt==true then
|
||||
-- Shot at a SHORAD group
|
||||
if self.UseEmOnOff then
|
||||
_group:EnableEmission(false)
|
||||
local allow = false
|
||||
if self.CallBack and self.UseCallBack == true then
|
||||
allow = self.CallBack:SeadAllowSuppression(_group,groupname)
|
||||
end
|
||||
_group:OptionAlarmStateGreen()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
local text = string.format("Shot at SHORAD %s! Evading!", _group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
self:_SmokeUnits(_group)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(1,_group)
|
||||
end
|
||||
|
||||
elseif _group:IsAnyInZone(targetzone) or groupname == TargetGroup then
|
||||
-- shot at a group we protect
|
||||
local text = string.format("Waking up SHORAD %s", _group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
if self.UseEmOnOff then
|
||||
_group:EnableEmission(true)
|
||||
end
|
||||
_group:OptionAlarmStateRed()
|
||||
self:_SmokeUnits(_group)
|
||||
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||
self.ActiveGroups[groupname].Timer = TIMER:New(SleepShorad,_group):Start(endtime)
|
||||
if allow == true then
|
||||
if self.UseEmOnOff then
|
||||
_group:EnableEmission(false)
|
||||
end
|
||||
_group:OptionAlarmStateGreen()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
local text = string.format("Shot at SHORAD %s! Evading!", _group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
self:_SmokeUnits(_group)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(TDiff,_group)
|
||||
TDiff=TDiff+1
|
||||
self:__ShootAndScoot(1,_group)
|
||||
else
|
||||
_group:RelocateGroundRandomInRadius(30,500,false,true,"Diamond",true)
|
||||
end
|
||||
else
|
||||
WakeUp(_group,groupname)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif _group:IsAnyInZone(targetzone) or groupname == TargetGroup then
|
||||
WakeUp(_group,groupname)
|
||||
end -- end if
|
||||
end -- end in pairs
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -720,7 +751,7 @@ do
|
||||
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:HandleEventShot( EventData )
|
||||
self:T( { EventData } )
|
||||
--self:T( { EventData.id } )
|
||||
self:T(self.lid .. " HandleEventShot")
|
||||
local ShootingWeapon = EventData.Weapon -- Identify the weapon fired
|
||||
local ShootingWeaponName = EventData.WeaponName -- return weapon type
|
||||
@@ -745,7 +776,7 @@ do
|
||||
-- Is there target data?
|
||||
if not targetdata or self.debug then
|
||||
if string.find(ShootingWeaponName,"AGM_88",1,true) then
|
||||
self:I("**** Tracking AGM-88 with no target data.")
|
||||
self:T("**** Tracking AGM-88 with no target data.")
|
||||
local pos0 = EventData.IniUnit:GetCoordinate()
|
||||
local fheight = EventData.IniUnit:GetHeight()
|
||||
self:__CalculateHitZone(20,ShootingWeapon,pos0,fheight,EventData.IniGroup)
|
||||
|
||||
@@ -8597,8 +8597,8 @@ function WAREHOUSE:_DeleteStockItem(stockitem)
|
||||
local item=self.stock[i] --#WAREHOUSE.Assetitem
|
||||
if item.uid==stockitem.uid then
|
||||
table.remove(self.stock,i)
|
||||
-- remove also from warehouse DB
|
||||
_WAREHOUSEDB.Assets[stockitem.uid]=nil
|
||||
-- remove also from warehouse DB (not good! causes an error if the asset needs to be added to a requesting wherehouse)
|
||||
--_WAREHOUSEDB.Assets[stockitem.uid]=nil
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
@@ -331,19 +331,34 @@ function AIRWING:AddSquadron(Squadron)
|
||||
local airbasename = self:GetAirbaseName()
|
||||
|
||||
if airbasename then
|
||||
local group = GROUP:FindByName(Squadron.templategroup)
|
||||
local Nunits = 1
|
||||
local units
|
||||
if group then units = group:GetUnits() end
|
||||
if units then Nunits = #units end
|
||||
local typename = Squadron.aircrafttype or "none"
|
||||
local NAssets = Squadron.Ngroups * Nunits
|
||||
local storage = STORAGE:New(airbasename)
|
||||
--self:T(self.lid.."Adding "..typename.." #"..NAssets)
|
||||
if storage and storage.warehouse and storage:IsLimitedAircraft() and typename ~= "none" then
|
||||
local NInStore = storage:GetItemAmount(typename) or 0
|
||||
if NAssets > NInStore then
|
||||
storage:AddItem(typename,NAssets)
|
||||
local group = Squadron.templategroup
|
||||
if group then
|
||||
local Nunits = 1
|
||||
local units
|
||||
if group then units = group:GetUnits() end
|
||||
if units then Nunits = #units end
|
||||
local typename = Squadron.aircrafttype or "none"
|
||||
local NAssets = Squadron.Ngroups * Nunits
|
||||
local storage = STORAGE:New(airbasename)
|
||||
|
||||
self:T(self.lid.."Adding "..typename.." #"..NAssets)
|
||||
if storage and storage.warehouse and storage:IsLimitedAircraft() and typename ~= "none" then
|
||||
local NInStore = storage:GetItemAmount(typename) or 0
|
||||
if NAssets > NInStore then
|
||||
storage:AddItem(typename,NAssets)
|
||||
end
|
||||
end
|
||||
|
||||
local unit = group:GetUnit(1)
|
||||
-- if storage is limited, add the amount of liquids needed
|
||||
if unit and storage and storage.warehouse and storage:IsLimitedLiquids() and typename ~= "none" then
|
||||
local fuel = unit:GetFuelMassMax()
|
||||
local neededfuel = (fuel*NAssets) -- kgs of fuel
|
||||
local NInStore = storage:GetLiquidAmount(STORAGE.Liquid.JETFUEL) or 0
|
||||
self:T(string.format(self.lid.."Fuel Needed: %dt | Fuel in store: %dt",neededfuel/1000,NInStore/1000))
|
||||
if neededfuel > NInStore then
|
||||
storage:AddLiquid(STORAGE.Liquid.JETFUEL,neededfuel)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
-- @image OPS_CSAR.jpg
|
||||
|
||||
---
|
||||
-- Last Update Dec 2025
|
||||
-- Last Update Jan 2026
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||
@@ -315,10 +315,12 @@ CSAR.AircraftType["MH-60R"] = 10
|
||||
CSAR.AircraftType["OH-6A"] = 2
|
||||
CSAR.AircraftType["OH58D"] = 2
|
||||
CSAR.AircraftType["CH-47Fbl1"] = 31
|
||||
CSAR.AircraftType["AH-6J"] = 2
|
||||
CSAR.AircraftType["MH-6J"] = 2
|
||||
|
||||
--- CSAR class version.
|
||||
-- @field #string version
|
||||
CSAR.version="1.0.35"
|
||||
CSAR.version="1.0.36"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
-- @module Ops.CTLD
|
||||
-- @image OPS_CTLD.jpg
|
||||
|
||||
-- Last Update Dec 2025
|
||||
-- Last Update Jan 2026
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -193,6 +193,7 @@ CTLD_CARGO = {
|
||||
-- @param Wrapper.Unit#UNIT Unit
|
||||
-- @return #boolean Outcome
|
||||
function CTLD_CARGO:UnitCanCarry(Unit)
|
||||
if not Unit then return false end
|
||||
if self.TypeNames == nil then return true end
|
||||
local typename = Unit:GetTypeName() or "none"
|
||||
if self.TypeNames[typename] then
|
||||
@@ -637,7 +638,7 @@ CTLD_ENGINEERING = {
|
||||
local crate = ctable[1] -- Ops.CTLD#CTLD_CARGO
|
||||
local static = crate:GetPositionable() -- Wrapper.Static#STATIC
|
||||
local crate_pos = static:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local gpos = group:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local gpos = group:GetCoord() -- Core.Point#COORDINATE
|
||||
-- see how far we are from the crate
|
||||
local distance = self:_GetDistance(gpos,crate_pos)
|
||||
self:T(string.format("%s Distance to crate: %d", self.lid, distance))
|
||||
@@ -666,7 +667,7 @@ CTLD_ENGINEERING = {
|
||||
--local COps = self.C_Ops -- Ops.CTLD#CTLD
|
||||
local group = self.Group -- Wrapper.Group#GROUP
|
||||
local tgtpos = self.currwpt -- Core.Point#COORDINATE
|
||||
local gpos = group:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local gpos = group:GetCoord() -- Core.Point#COORDINATE
|
||||
-- see how far we are from the crate
|
||||
local distance = self:_GetDistance(gpos,tgtpos)
|
||||
self:T(string.format("%s Distance remaining: %d", self.lid, distance))
|
||||
@@ -1495,6 +1496,8 @@ CTLD.UnitTypeCapabilities = {
|
||||
["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
||||
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||
["AH-6J"] = {type="AH-6J", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
|
||||
["MH-6J"] = {type="MH-6J", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
|
||||
["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
|
||||
["OH58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
|
||||
["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 10800},
|
||||
@@ -1513,7 +1516,7 @@ CTLD.FixedWingTypes = {
|
||||
|
||||
--- CTLD class version.
|
||||
-- @field #string version
|
||||
CTLD.version="1.3.42"
|
||||
CTLD.version="1.3.43"
|
||||
|
||||
--- Instantiate a new CTLD.
|
||||
-- @param #CTLD self
|
||||
@@ -2910,10 +2913,32 @@ end
|
||||
-- @return #CTLD self
|
||||
function CTLD:_LoadTroopsQuantity(Group, Unit, Cargo, quantity)
|
||||
local n = math.max(1, tonumber(quantity) or 1)
|
||||
|
||||
-- landed or hovering over load zone?
|
||||
local grounded = not self:IsUnitInAir(Unit)
|
||||
local hoverload = self:CanHoverLoad(Unit)
|
||||
|
||||
-- check if we are in LOAD zone
|
||||
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
|
||||
if not inzone then
|
||||
inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
|
||||
end
|
||||
|
||||
if not inzone then
|
||||
self:_SendMessage("You are not close enough to a logistics zone!", 10, false, Group)
|
||||
if not self.debug then return self end
|
||||
elseif not grounded and not hoverload then
|
||||
self:_SendMessage("You need to land or hover in position to load!", 10, false, Group)
|
||||
if not self.debug then return self end
|
||||
elseif self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
||||
self:_SendMessage("You need to open the door(s) to load troops!", 10, false, Group)
|
||||
if not self.debug then return self end
|
||||
end
|
||||
|
||||
local prevSuppress = self.suppressmessages
|
||||
self.suppressmessages = true
|
||||
for i = 1, n do
|
||||
timer.scheduleFunction(function() self:_LoadTroops(Group, Unit, Cargo, true) end, {}, timer.getTime() + 0.2 * i)
|
||||
timer.scheduleFunction(function() self:_LoadTroops(Group, Unit, Cargo) end, {}, timer.getTime() + 0.2 * i)
|
||||
end
|
||||
timer.scheduleFunction(function()
|
||||
self.suppressmessages = prevSuppress
|
||||
@@ -2954,11 +2979,10 @@ function CTLD:_AddTroopQuantityMenus(Group, Unit, parentMenu, cargoObj)
|
||||
if capacitySets < maxQuantity then maxQuantity = capacitySets end
|
||||
end
|
||||
for quantity = 1, maxQuantity do
|
||||
local m = MENU_GROUP:New(Group, tostring(quantity), parentMenu)
|
||||
if quantity == 1 then
|
||||
MENU_GROUP_COMMAND:New(Group, "Load", m, self._LoadTroops, self, Group, Unit, cargoObj)
|
||||
MENU_GROUP_COMMAND:New(Group, tostring(quantity), parentMenu, self._LoadTroops, self, Group, Unit, cargoObj)
|
||||
else
|
||||
MENU_GROUP_COMMAND:New(Group, "Load", m, self._LoadTroopsQuantity, self, Group, Unit, cargoObj, quantity)
|
||||
MENU_GROUP_COMMAND:New(Group, tostring(quantity), parentMenu, self._LoadTroopsQuantity, self, Group, Unit, cargoObj, quantity)
|
||||
end
|
||||
end
|
||||
return self
|
||||
@@ -3137,6 +3161,17 @@ function CTLD:_AddCrateQuantityMenus(Group, Unit, parentMenu, cargoObj, stockSum
|
||||
return self
|
||||
end
|
||||
|
||||
--- User overrideable function to determine if a unit can get crates.
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
-- @param Wrapper.Unit#UNIT Unit
|
||||
-- @param #table Config Configuration entry for the unit.
|
||||
-- @param #number quantity Number of crate sets requested.
|
||||
-- @param #boolean quiet If true, do not send messages to the user.
|
||||
function CTLD:CanGetUnits(Group, Unit, Config, quantity, quiet)
|
||||
return true
|
||||
end
|
||||
|
||||
--- (Internal) Spawn a “Get units” entry for a C-130J-30 at load zone.
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
@@ -3167,6 +3202,9 @@ function CTLD:_C130GetUnits(Group, Unit, Name)
|
||||
self:_SendMessage("You are not close enough to a logistics zone!",10,false,Group)
|
||||
return self
|
||||
end
|
||||
if not self:CanGetUnits(Group, Unit, cfg, 1, false) then
|
||||
return self
|
||||
end
|
||||
|
||||
local coord = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit)
|
||||
@@ -3352,7 +3390,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
local canloadcratesno = capabilities.cratelimit
|
||||
local loaddist = self.CrateDistance or 35
|
||||
local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true,true)
|
||||
local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true,true,true) -- to ignore what's inside
|
||||
if numbernearby >= canloadcratesno and not drop then
|
||||
self:_SendMessage("There are enough crates nearby already! Take care of those first!", 10, false, Group)
|
||||
return false
|
||||
@@ -3514,9 +3552,9 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
|
||||
Cargo:RemoveStock(requestedSets)
|
||||
self:_RefreshCrateQuantityMenus(Group, Unit, Cargo)
|
||||
end
|
||||
local text = string.format("Crates for %s have been positioned near you!",cratename)
|
||||
local text = string.format("%d crates for %s have been positioned near you!",number,cratename)
|
||||
if drop then
|
||||
text = string.format("Crates for %s have been dropped!",cratename)
|
||||
text = string.format("%d crates for %s have been dropped!",number,cratename)
|
||||
self:__CratesDropped(1, Group, Unit, droppedcargo)
|
||||
else
|
||||
if not quiet then
|
||||
@@ -3612,7 +3650,7 @@ end
|
||||
function CTLD:_ListCratesNearby( _group, _unit)
|
||||
self:T(self.lid .. " _ListCratesNearby")
|
||||
local finddist = self.CrateDistance or 35
|
||||
local crates,number,loadedbygc,indexgc = self:_FindCratesNearby(_group,_unit, finddist,true,true) -- #table
|
||||
local crates,number,loadedbygc,indexgc = self:_FindCratesNearby(_group,_unit, finddist,true,true,true) -- #table
|
||||
if number > 0 or indexgc > 0 then
|
||||
local text = REPORT:New("Crates Found Nearby:")
|
||||
text:Add("------------------------------------------------------------")
|
||||
@@ -3711,7 +3749,7 @@ end
|
||||
function CTLD:_RemoveCratesNearby(_group, _unit)
|
||||
self:T(self.lid.." _RemoveCratesNearby")
|
||||
local finddist=self.CrateDistance or 35
|
||||
local crates,number=self:_FindCratesNearby(_group,_unit,finddist,true,true)
|
||||
local crates,number=self:_FindCratesNearby(_group,_unit,finddist,true,true,true)
|
||||
if number>0 then
|
||||
local removedIDs={}
|
||||
local text=REPORT:New("Removing Crates Found Nearby:")
|
||||
@@ -3824,7 +3862,7 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight, ignoretype
|
||||
self:T(self.lid .. " Loading restricted: " .. tostring(restricted))
|
||||
local staticpos = static:GetCoordinate() --or dcsunitpos
|
||||
local cando = cargo:UnitCanCarry(_unit)
|
||||
if ignoretype == true then cando = true end
|
||||
if ignoretype == true then cando = true restricted = false end
|
||||
self:T(self.lid .. " Unit can carry: " .. tostring(cando))
|
||||
--- Testing
|
||||
local distance=self:_GetDistance(location,staticpos)
|
||||
@@ -4361,6 +4399,8 @@ function CTLD:_UnloadTroops(Group, Unit)
|
||||
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
|
||||
-- looking for troops
|
||||
local cargotable = loadedcargo.Cargo
|
||||
local deployedTroopsByName = {}
|
||||
local deployedEngineersByName = {}
|
||||
for _,_cargo in pairs (cargotable) do
|
||||
local cargo = _cargo -- #CTLD_CARGO
|
||||
local type = cargo:GetType() -- #CTLD_CARGO.Enum
|
||||
@@ -4417,12 +4457,22 @@ function CTLD:_UnloadTroops(Group, Unit)
|
||||
self.Engineers = self.Engineers + 1
|
||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
||||
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
||||
self:_SendMessage(string.format("Dropped Engineers %s into action!",name), 10, false, Group)
|
||||
deployedEngineersByName[name] = (deployedEngineersByName[name] or 0) + 1
|
||||
else
|
||||
self:_SendMessage(string.format("Dropped Troops %s into action!",name), 10, false, Group)
|
||||
deployedTroopsByName[name] = (deployedTroopsByName[name] or 0) + 1
|
||||
end
|
||||
end -- if type end
|
||||
end -- cargotable loop
|
||||
local parts = {}
|
||||
for nName,nCount in pairs(deployedTroopsByName) do
|
||||
parts[#parts + 1] = tostring(nCount).."x Troops "..nName
|
||||
end
|
||||
for nName,nCount in pairs(deployedEngineersByName) do
|
||||
parts[#parts + 1] = tostring(nCount).."x Engineers "..nName
|
||||
end
|
||||
if #parts > 0 then
|
||||
self:_SendMessage("Dropped "..table.concat(parts, ", ").." into action!", 10, false, Group)
|
||||
end
|
||||
else -- droppingatbase
|
||||
self:_SendMessage("Troops have returned to base!", 10, false, Group)
|
||||
self:__TroopsRTB(1, Group, Unit, zonename, zone)
|
||||
@@ -4614,11 +4664,10 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
||||
local baseDist = self.CrateDistance or 35
|
||||
local finddist=baseDist
|
||||
--if Engineering and self.EngineerSearch and self.EngineerSearch>baseDist then
|
||||
if self.EngineerSearch and self.EngineerSearch>baseDist then -- this make also helicopter to be able to crates that are further away due to herc airdrop
|
||||
if Engineering and self.EngineerSearch and self.EngineerSearch>baseDist then -- this make also helicopter to be able to crates that are further away due to herc airdrop
|
||||
finddist=self.EngineerSearch
|
||||
finddist=self.EngineerSearch
|
||||
end
|
||||
local crates,number = self:_FindCratesNearby(Group,Unit, finddist,true,true) -- #table
|
||||
local crates,number = self:_FindCratesNearby(Group,Unit,finddist,true,true,not Engineering) -- #table
|
||||
local buildables = {}
|
||||
local foundbuilds = false
|
||||
local canbuild = false
|
||||
@@ -4642,11 +4691,12 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
||||
local isHercDrop=Crate:WasDropped(true)
|
||||
if not isHercDrop and distToUnit>baseDist then
|
||||
elseif self.UseC130LoadAndUnload and self:IsC130J(Unit) and distToUnit<15 then
|
||||
self:_SendMessage("Please unload crates from the C-130 before building!",10,false,Group)
|
||||
return self
|
||||
-- self:_SendMessage("Please unload crates from the C-130 before building!",10,false,Group)
|
||||
-- return self
|
||||
elseif self.UseC130LoadAndUnload and self:IsHook(Unit) and distToUnit<5 then
|
||||
self:_SendMessage("Please unload crates from the CH-47 before building!",10,false,Group)
|
||||
return self
|
||||
-- self:_SendMessage("Please unload crates from the CH-47 before building!",10,false,Group)
|
||||
-- return self
|
||||
elseif self.UseC130LoadAndUnload and (Unit:GetTypeName()=="Mi-8MTV2" or Unit:GetTypeName()=="Mi-8MT") and distToUnit<8 then
|
||||
else
|
||||
--local testmarker = ccoord:MarkToAll("Crate found",true,"Build Position")
|
||||
if not buildables[name] then
|
||||
@@ -4718,7 +4768,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
||||
local base = Unit:GetCoordinate():Translate(20,hdg)
|
||||
|
||||
if full == 1 then
|
||||
local cratesNow, numberNow = self:_FindCratesNearby(Group,Unit, finddist,true,true)
|
||||
local cratesNow, numberNow = self:_FindCratesNearby(Group,Unit, finddist,true,true, not Engineering)
|
||||
self:_CleanUpCrates(cratesNow,build,numberNow)
|
||||
self:_RefreshLoadCratesMenu(Group,Unit)
|
||||
if self.buildtime and self.buildtime > 0 then
|
||||
@@ -4735,7 +4785,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
||||
else
|
||||
local start = -((full-1)*sep)/2
|
||||
for n=1,full do
|
||||
local cratesNow, numberNow = self:_FindCratesNearby(Group,Unit, finddist,true,true)
|
||||
local cratesNow, numberNow = self:_FindCratesNearby(Group,Unit, finddist,true,true, not Engineering)
|
||||
self:_CleanUpCrates(cratesNow,build,numberNow)
|
||||
self:_RefreshLoadCratesMenu(Group,Unit)
|
||||
local off = start + (n-1)*sep
|
||||
@@ -5529,13 +5579,25 @@ function CTLD:_RefreshF10Menus()
|
||||
_group.CTLD_TroopMenus = {}
|
||||
if self.usesubcats then
|
||||
local subcatmenus = {}
|
||||
local subcatcount = 0
|
||||
local onlycat = nil
|
||||
for catName, _ in pairs(self.subcatsTroop) do
|
||||
subcatmenus[catName] = MENU_GROUP:New(_group, catName, troopsmenu)
|
||||
subcatcount = subcatcount + 1
|
||||
onlycat = catName
|
||||
end
|
||||
local useTroopSubcats = subcatcount > 1 or (subcatcount == 1 and onlycat ~= "Other")
|
||||
if useTroopSubcats then
|
||||
for catName, _ in pairs(self.subcatsTroop) do
|
||||
subcatmenus[catName] = MENU_GROUP:New(_group, catName, troopsmenu)
|
||||
end
|
||||
end
|
||||
for _, cargoObj in pairs(self.Cargo_Troops) do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local menutext = cargoObj.Name
|
||||
local parent = subcatmenus[cargoObj.Subcategory] or troopsmenu
|
||||
local parent = troopsmenu
|
||||
if useTroopSubcats and cargoObj.Subcategory and subcatmenus[cargoObj.Subcategory] then
|
||||
parent = subcatmenus[cargoObj.Subcategory]
|
||||
end
|
||||
local mSet = MENU_GROUP:New(_group, menutext, parent)
|
||||
_group.CTLD_TroopMenus[cargoObj.Name] = mSet
|
||||
self:_AddTroopQuantityMenus(_group,_unit,mSet,cargoObj)
|
||||
@@ -6411,9 +6473,11 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
||||
-- @param Wrapper.Unit#UNIT Unit The calling unit.
|
||||
-- @param #number chunkID the Cargo ID
|
||||
-- @return #CTLD self
|
||||
function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
||||
function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID, qty)
|
||||
self:T(self.lid .. " _UnloadSingleTroopByID chunkID=" .. tostring(chunkID))
|
||||
|
||||
qty = qty or 1
|
||||
|
||||
local droppingatbase = false
|
||||
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.LOAD)
|
||||
if not inzone then
|
||||
@@ -6452,80 +6516,92 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
||||
return self
|
||||
end
|
||||
|
||||
local deployedTroopsByName = {}
|
||||
local deployedEngineersByName = {}
|
||||
|
||||
-- Drop the FIRST cargo in that chunk
|
||||
local foundCargo = chunk[1]
|
||||
if not foundCargo then
|
||||
self:_SendMessage(string.format("No troop cargo at chunk %d!", chunkID), 10, false, Group)
|
||||
if not self.debug then return self end
|
||||
return self
|
||||
end
|
||||
for n = 1, qty do
|
||||
local foundCargo = chunk[1]
|
||||
if not foundCargo then break end
|
||||
|
||||
local cType = foundCargo:GetType()
|
||||
local name = foundCargo:GetName() or "none"
|
||||
local tmpl = foundCargo:GetTemplates() or {}
|
||||
local zoneradius = self.troopdropzoneradius or 100
|
||||
local factor = 1
|
||||
if isHerc then
|
||||
factor = foundCargo:GetCratesNeeded() or 1
|
||||
zoneradius = Unit:GetVelocityMPS() or 100
|
||||
end
|
||||
local zone = ZONE_GROUP:New(string.format("Unload zone-%s", unitName), Group, zoneradius * factor)
|
||||
local randomcoord = zone:GetRandomCoordinate(10, 30 * factor)
|
||||
local heading = Group:GetHeading() or 0
|
||||
|
||||
if grounded or hoverunload then
|
||||
randomcoord = Group:GetCoordinate()
|
||||
local Angle = (heading + 270) % 360
|
||||
if isHerc or isHook then
|
||||
Angle = (heading + 180) % 360
|
||||
end
|
||||
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
|
||||
local cType = foundCargo:GetType()
|
||||
local name = foundCargo:GetName() or "none"
|
||||
local tmpl = foundCargo:GetTemplates() or {}
|
||||
local zoneradius = self.troopdropzoneradius or 100
|
||||
local factor = 1
|
||||
if isHerc then
|
||||
offset = self.TroopUnloadDistGroundHerc or 25
|
||||
factor = foundCargo:GetCratesNeeded() or 1
|
||||
zoneradius = Unit:GetVelocityMPS() or 100
|
||||
end
|
||||
if isHook then
|
||||
offset = self.TroopUnloadDistGroundHook or 15
|
||||
if hoverunload and self.TroopUnloadDistHoverHook then
|
||||
offset = self.TroopUnloadDistHoverHook or 5
|
||||
local zone = ZONE_GROUP:New(string.format("Unload zone-%s", unitName), Group, zoneradius * factor)
|
||||
local randomcoord = zone:GetRandomCoordinate(10, 30 * factor)
|
||||
local heading = Group:GetHeading() or 0
|
||||
|
||||
if grounded or hoverunload then
|
||||
randomcoord = Group:GetCoordinate()
|
||||
local Angle = (heading + 270) % 360
|
||||
if isHerc or isHook then
|
||||
Angle = (heading + 180) % 360
|
||||
end
|
||||
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
|
||||
if isHerc then
|
||||
offset = self.TroopUnloadDistGroundHerc or 25
|
||||
end
|
||||
if isHook then
|
||||
offset = self.TroopUnloadDistGroundHook or 15
|
||||
if hoverunload and self.TroopUnloadDistHoverHook then
|
||||
offset = self.TroopUnloadDistHoverHook or 5
|
||||
end
|
||||
end
|
||||
randomcoord:Translate(offset, Angle, nil, true)
|
||||
end
|
||||
|
||||
local tempcount = 0
|
||||
if isHook then
|
||||
tempcount = self.ChinookTroopCircleRadius or 5
|
||||
end
|
||||
for _, _template in pairs(tmpl) do
|
||||
self.TroopCounter = self.TroopCounter + 1
|
||||
tempcount = tempcount + 1
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
local rad = 2.5 + (tempcount * 2)
|
||||
local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template)
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
||||
:InitDelayOff()
|
||||
:InitSetUnitAbsolutePositions(Positions)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
:SpawnFromVec2(randomcoord:GetVec2())
|
||||
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
|
||||
end
|
||||
|
||||
foundCargo:SetWasDropped(true)
|
||||
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||
self.Engineers = self.Engineers + 1
|
||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
||||
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
||||
deployedEngineersByName[name] = (deployedEngineersByName[name] or 0) + 1
|
||||
else
|
||||
deployedTroopsByName[name] = (deployedTroopsByName[name] or 0) + 1
|
||||
end
|
||||
|
||||
table.remove(chunk, 1)
|
||||
if #chunk == 0 then
|
||||
self.TroopsIDToChunk[chunkID] = nil
|
||||
break
|
||||
end
|
||||
randomcoord:Translate(offset, Angle, nil, true)
|
||||
end
|
||||
|
||||
local tempcount = 0
|
||||
if isHook then
|
||||
tempcount = self.ChinookTroopCircleRadius or 5
|
||||
local parts = {}
|
||||
for nName,nCount in pairs(deployedTroopsByName) do
|
||||
parts[#parts + 1] = tostring(nCount).."x Troops "..nName
|
||||
end
|
||||
for _, _template in pairs(tmpl) do
|
||||
self.TroopCounter = self.TroopCounter + 1
|
||||
tempcount = tempcount + 1
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
local rad = 2.5 + (tempcount * 2)
|
||||
local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template)
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
||||
:InitDelayOff()
|
||||
:InitSetUnitAbsolutePositions(Positions)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
:SpawnFromVec2(randomcoord:GetVec2())
|
||||
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
|
||||
for nName,nCount in pairs(deployedEngineersByName) do
|
||||
parts[#parts + 1] = tostring(nCount).."x Engineers "..nName
|
||||
end
|
||||
|
||||
foundCargo:SetWasDropped(true)
|
||||
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||
self.Engineers = self.Engineers + 1
|
||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
||||
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
||||
self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group)
|
||||
else
|
||||
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
|
||||
if #parts > 0 then
|
||||
self:_SendMessage("Dropped "..table.concat(parts, ", ").." into action!", 10, false, Group)
|
||||
end
|
||||
|
||||
table.remove(chunk, 1)
|
||||
if #chunk == 0 then
|
||||
self.TroopsIDToChunk[chunkID] = nil
|
||||
end
|
||||
|
||||
else
|
||||
-- Return to base logic, remove ONLY the first cargo
|
||||
self:_SendMessage("Troops have returned to base!", 10, false, Group)
|
||||
@@ -6533,7 +6609,8 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
||||
|
||||
if self.TroopsIDToChunk and self.TroopsIDToChunk[chunkID] then
|
||||
local chunk = self.TroopsIDToChunk[chunkID]
|
||||
if #chunk > 0 then
|
||||
for n = 1, qty do
|
||||
if #chunk == 0 then break end
|
||||
local firstObj = chunk[1]
|
||||
local cName = firstObj:GetName()
|
||||
local gentroops = self.Cargo_Troops
|
||||
@@ -6548,9 +6625,9 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
||||
end
|
||||
firstObj:SetWasDropped(true)
|
||||
table.remove(chunk, 1)
|
||||
if #chunk == 0 then
|
||||
self.TroopsIDToChunk[chunkID] = nil
|
||||
end
|
||||
end
|
||||
if #chunk == 0 then
|
||||
self.TroopsIDToChunk[chunkID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6597,11 +6674,13 @@ function CTLD:_RefreshDropTroopsMenu(Group, Unit)
|
||||
if not theGroup.CTLDTopmenu then return end
|
||||
local topTroops = theGroup.MyTopTroopsMenu
|
||||
if not topTroops then return end
|
||||
if topTroops.DropTroopsMenu then
|
||||
topTroops.DropTroopsMenu:Remove()
|
||||
local dropTroopsMenu = topTroops.DropTroopsMenu
|
||||
if dropTroopsMenu then
|
||||
dropTroopsMenu:RemoveSubMenus()
|
||||
else
|
||||
dropTroopsMenu = MENU_GROUP:New(theGroup, "Drop Troops", topTroops)
|
||||
topTroops.DropTroopsMenu = dropTroopsMenu
|
||||
end
|
||||
local dropTroopsMenu = MENU_GROUP:New(theGroup, "Drop Troops", topTroops)
|
||||
topTroops.DropTroopsMenu = dropTroopsMenu
|
||||
MENU_GROUP_COMMAND:New(theGroup, "Drop ALL troops", dropTroopsMenu, self._UnloadTroops, self, theGroup, theUnit)
|
||||
|
||||
local loadedData = self.Loaded_Cargo[theUnit:GetName()]
|
||||
@@ -6625,15 +6704,22 @@ function CTLD:_RefreshDropTroopsMenu(Group, Unit)
|
||||
for tName, objList in pairs(troopsByName) do
|
||||
table.sort(objList, function(a,b) return a:GetID() < b:GetID() end)
|
||||
local count = #objList
|
||||
if count > 0 then
|
||||
local chunkID = objList[1]:GetID()
|
||||
self.TroopsIDToChunk[chunkID] = objList
|
||||
|
||||
local chunkID = objList[1]:GetID()
|
||||
self.TroopsIDToChunk[chunkID] = objList
|
||||
|
||||
local label = string.format("Drop %s (%d)", tName, count)
|
||||
MENU_GROUP_COMMAND:New(theGroup, label, dropTroopsMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID)
|
||||
local label = string.format("Drop %s (%d)", tName, count)
|
||||
if count == 1 then
|
||||
MENU_GROUP_COMMAND:New(theGroup, label, dropTroopsMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID, 1)
|
||||
else
|
||||
local parentMenu = MENU_GROUP:New(theGroup, label, dropTroopsMenu)
|
||||
for q = 1, count do
|
||||
MENU_GROUP_COMMAND:New(theGroup, string.format("Drop (%d) %s", q, tName), parentMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID, q)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- [Internal] Function to check if a template exists in the mission.
|
||||
-- @param #CTLD self
|
||||
-- @param #table temptable Table of string names
|
||||
|
||||
@@ -396,7 +396,8 @@ function CHIEF:New(Coalition, AgentSet, Alias)
|
||||
self.TransportCategories = {Group.Category.HELICOPTER}
|
||||
|
||||
-- Create a new COMMANDER.
|
||||
self.commander=COMMANDER:New(Coalition)
|
||||
self.commander=COMMANDER:New(Coalition, Alias)
|
||||
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
@@ -3357,6 +3358,15 @@ function CHIEF._CheckAssetProperties(Asset, Properties)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--- Checks whether or not any of the legions con run a mission.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
-- @return #boolean If `true`, one of the cohorts can run the mission.
|
||||
function CHIEF:CanMission(Mission)
|
||||
return self.commander and self.commander:CanMission(Mission)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1748,6 +1748,70 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
||||
return cohorts
|
||||
end
|
||||
|
||||
--- Checks whether or not any of the legions con run a mission.
|
||||
-- @param #COMMANDER self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
-- @return #boolean If `true`, one of the cohorts can run the mission.
|
||||
function COMMANDER:CanMission(Mission)
|
||||
local commander = self
|
||||
|
||||
-- Target position.
|
||||
local TargetVec2 = Mission:GetTargetVec2()
|
||||
|
||||
local MaxWeight = nil
|
||||
|
||||
if Mission.NcarriersMin then
|
||||
|
||||
local legions = commander.legions
|
||||
local cohorts = nil
|
||||
if Mission.transportLegions or Mission.transportCohorts then
|
||||
legions = Mission.transportLegions
|
||||
cohorts = Mission.transportCohorts
|
||||
end
|
||||
|
||||
-- Get transport cohorts.
|
||||
local Cohorts = LEGION._GetCohorts(legions, cohorts)
|
||||
|
||||
-- Filter cohorts that can actually perform transport missions.
|
||||
local transportcohorts = {}
|
||||
for _, _cohort in pairs(Cohorts) do
|
||||
local cohort = _cohort --Ops.Cohort#COHORT
|
||||
|
||||
-- Check if cohort can perform transport to target.
|
||||
local can = LEGION._CohortCan(cohort, AUFTRAG.Type.OPSTRANSPORT, Mission.carrierCategories, Mission.carrierAttributes, Mission.carrierProperties, nil, TargetVec2)
|
||||
|
||||
-- MaxWeight of cargo assets is limited by the largets available cargo bay. We don't want to select, e.g., tanks that cannot be transported by APCs or helos.
|
||||
if can and (MaxWeight == nil or cohort.cargobayLimit > MaxWeight) then
|
||||
MaxWeight = cohort.cargobayLimit
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local legions = commander.legions
|
||||
local cohorts = nil
|
||||
if Mission.specialLegions or Mission.specialCohorts then
|
||||
legions = Mission.specialLegions
|
||||
cohorts = Mission.specialCohorts
|
||||
end
|
||||
|
||||
-- Get cohorts.
|
||||
local Cohorts = LEGION._GetCohorts(legions, cohorts, Mission.operation, commander.opsqueue)
|
||||
|
||||
for _, _cohort in pairs(Cohorts) do
|
||||
local cohort = _cohort --Ops.Cohort#COHORT
|
||||
|
||||
-- Check if cohort can do the mission.
|
||||
local can = LEGION._CohortCan(cohort, Mission.type, nil, Mission.attributes, Mission.properties, { Mission.engageWeaponType }, TargetVec2, Mission.engageRange, Mission.refuelSystem, nil, MaxWeight)
|
||||
if can then
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Recruit assets for a given mission.
|
||||
-- @param #COMMANDER self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
--
|
||||
-------------------------------------------------------------------------
|
||||
-- Date: Dec 2025
|
||||
-- Last Update: Dec 2025
|
||||
-- Last Update: Jan 2026
|
||||
-------------------------------------------------------------------------
|
||||
--
|
||||
-- ===
|
||||
@@ -293,7 +293,7 @@ EASYA2G = {
|
||||
|
||||
--- EASYA2G class version.
|
||||
-- @field #string version
|
||||
EASYA2G.version="0.1.3"
|
||||
EASYA2G.version="0.1.4"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -319,6 +319,10 @@ function EASYA2G:New(Alias, AirbaseName, Coalition, ScoutName)
|
||||
|
||||
-- defaults
|
||||
self.alias = Alias or AirbaseName.." A2G Wing"
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("EASYA2G %s | ", self.alias)
|
||||
|
||||
self.coalitionname = string.lower(Coalition) or "blue"
|
||||
self.coalition = self.coalitionname == "blue" and coalition.side.BLUE or coalition.side.RED
|
||||
self.wings = {}
|
||||
@@ -352,10 +356,8 @@ function EASYA2G:New(Alias, AirbaseName, Coalition, ScoutName)
|
||||
self.FuelCriticalThreshold = 10
|
||||
self.showpatrolpointmarks = false
|
||||
self.EngageTargetTypes = {"Ground"}
|
||||
self:SetDefaultTurnoverTime()
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("EASYA2G %s | ", self.alias)
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:SetStartState("Stopped")
|
||||
@@ -546,7 +548,7 @@ function EASYA2G:_AddSquadron(TemplateName, SquadName, AirbaseName, AirFrames, S
|
||||
Squadron_One:AddMissionCapability({AUFTRAG.Type.CAS, AUFTRAG.Type.CASENHANCED, AUFTRAG.Type.BAI, AUFTRAG.Type.ALERT5, AUFTRAG.Type.BOMBING, AUFTRAG.Type.STRIKE})
|
||||
--Squadron_One:SetFuelLowRefuel(true)
|
||||
Squadron_One:SetFuelLowThreshold(0.3)
|
||||
Squadron_One:SetTurnoverTime(10,20)
|
||||
Squadron_One:SetTurnoverTime(self.maintenancetime,self.repairtime)
|
||||
Squadron_One:SetModex(Modex)
|
||||
Squadron_One:SetLivery(Livery)
|
||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
--
|
||||
-------------------------------------------------------------------------
|
||||
-- Date: September 2023
|
||||
-- Last Update: Aug 2025
|
||||
-- Last Update: Jan 2026
|
||||
-------------------------------------------------------------------------
|
||||
--
|
||||
--- **Ops** - Easy GCI & CAP Manager
|
||||
@@ -89,6 +89,8 @@
|
||||
-- @field #number FuelCriticalThreshold
|
||||
-- @field #boolean showpatrolpointmarks
|
||||
-- @field #table EngageTargetTypes
|
||||
-- @field #number maintenancetime
|
||||
-- @field #number repairtime
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
||||
@@ -284,7 +286,7 @@ EASYGCICAP = {
|
||||
|
||||
--- EASYGCICAP class version.
|
||||
-- @field #string version
|
||||
EASYGCICAP.version="0.1.33"
|
||||
EASYGCICAP.version="0.1.34"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
@@ -310,6 +312,10 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
||||
|
||||
-- defaults
|
||||
self.alias = Alias or AirbaseName.." CAP Wing"
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
||||
|
||||
self.coalitionname = string.lower(Coalition) or "blue"
|
||||
self.coalition = self.coalitionname == "blue" and coalition.side.BLUE or coalition.side.RED
|
||||
self.wings = {}
|
||||
@@ -343,10 +349,8 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
||||
self.FuelCriticalThreshold = 10
|
||||
self.showpatrolpointmarks = false
|
||||
self.EngageTargetTypes = {"Air"}
|
||||
self:SetDefaultTurnoverTime()
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:SetStartState("Stopped")
|
||||
@@ -608,6 +612,18 @@ function EASYGCICAP:SetDefaultMissionRange(Range)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set default turnover times for squadrons in minutes
|
||||
-- @param #EASYGCICAP self
|
||||
-- @param #number MaintenanceTime Time in minutes it takes until a flight is combat ready again. Default is 5 min.
|
||||
-- @param #number RepairTime Time in minutes it takes to repair a flight for each life point taken. Default is 10 min.
|
||||
-- @return #EASYGCICAP self
|
||||
function EASYGCICAP:SetDefaultTurnoverTime(MaintenanceTime,RepairTime)
|
||||
self:T(self.lid.."SetDefaultTurnoverTime")
|
||||
self.maintenancetime=MaintenanceTime or 5
|
||||
self.repairtime=RepairTime or 10
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set default number of airframes standing by for intercept tasks (visible on the airfield)
|
||||
-- @param #EASYGCICAP self
|
||||
-- @param #number Airframes defaults to 2
|
||||
@@ -1217,7 +1233,7 @@ function EASYGCICAP:_AddSquadron(TemplateName, SquadName, AirbaseName, AirFrames
|
||||
Squadron_One:AddMissionCapability({AUFTRAG.Type.CAP, AUFTRAG.Type.GCICAP, AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.PATROLRACETRACK, AUFTRAG.Type.ALERT5})
|
||||
--Squadron_One:SetFuelLowRefuel(true)
|
||||
Squadron_One:SetFuelLowThreshold(0.3)
|
||||
Squadron_One:SetTurnoverTime(10,20)
|
||||
Squadron_One:SetTurnoverTime(self.maintenancetime,self.repairtime)
|
||||
Squadron_One:SetModex(Modex)
|
||||
Squadron_One:SetLivery(Livery)
|
||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||
@@ -1248,7 +1264,7 @@ function EASYGCICAP:_AddReconSquadron(TemplateName, SquadName, AirbaseName, AirF
|
||||
Squadron_One:AddMissionCapability({AUFTRAG.Type.RECON})
|
||||
--Squadron_One:SetFuelLowRefuel(true)
|
||||
Squadron_One:SetFuelLowThreshold(0.3)
|
||||
Squadron_One:SetTurnoverTime(10,20)
|
||||
Squadron_One:SetTurnoverTime(self.maintenancetime,self.repairtime)
|
||||
Squadron_One:SetModex(Modex)
|
||||
Squadron_One:SetLivery(Livery)
|
||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||
@@ -1282,7 +1298,7 @@ function EASYGCICAP:_AddTankerSquadron(TemplateName, SquadName, AirbaseName, Air
|
||||
Squadron_One:AddMissionCapability({AUFTRAG.Type.TANKER})
|
||||
--Squadron_One:SetFuelLowRefuel(true)
|
||||
Squadron_One:SetFuelLowThreshold(0.3)
|
||||
Squadron_One:SetTurnoverTime(10,20)
|
||||
Squadron_One:SetTurnoverTime(self.maintenancetime,self.repairtime)
|
||||
Squadron_One:SetModex(Modex)
|
||||
Squadron_One:SetLivery(Livery)
|
||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||
@@ -1319,7 +1335,7 @@ function EASYGCICAP:_AddAWACSSquadron(TemplateName, SquadName, AirbaseName, AirF
|
||||
Squadron_One:AddMissionCapability({AUFTRAG.Type.AWACS})
|
||||
--Squadron_One:SetFuelLowRefuel(true)
|
||||
Squadron_One:SetFuelLowThreshold(0.3)
|
||||
Squadron_One:SetTurnoverTime(10,20)
|
||||
Squadron_One:SetTurnoverTime(self.maintenancetime,self.repairtime)
|
||||
Squadron_One:SetModex(Modex)
|
||||
Squadron_One:SetLivery(Livery)
|
||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||
@@ -1626,7 +1642,7 @@ function EASYGCICAP:_StartIntel()
|
||||
if self.usecorridors == true then
|
||||
BlueIntel:SetCorridorZones(self.corridorzones)
|
||||
if self.corridorfloor or self.corridorceiling then
|
||||
BlueIntel:SetCorridorLimitsFeet(self.corridorfloor,self.corridorceiling)
|
||||
BlueIntel:SetCorridorLimits(self.corridorfloor,self.corridorceiling)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1175,7 +1175,7 @@ function INTEL:_CreateContact(Positionable, RecceName)
|
||||
item.category=3 --static:GetCategory()
|
||||
item.categoryname=static:GetCategoryName() or "Unknown"
|
||||
item.threatlevel=static:GetThreatLevel() or 0
|
||||
item.position=static:GetCoordinate()
|
||||
item.position=static:GetCoord()
|
||||
item.velocity=static:GetVelocityVec3()
|
||||
item.speed=0
|
||||
item.recce=RecceName
|
||||
@@ -1282,15 +1282,15 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua
|
||||
local DetectionAccepted = true
|
||||
|
||||
if self.RadarAcceptRange then
|
||||
local reccecoord = Unit:GetCoordinate()
|
||||
local coord = unit:GetCoordinate()
|
||||
local reccecoord = Unit:GetCoord()
|
||||
local coord = unit:GetCoord()
|
||||
local dist = math.floor(coord:Get2DDistance(reccecoord)/1000) -- km
|
||||
if dist > self.RadarAcceptRangeKilometers then DetectionAccepted = false end
|
||||
end
|
||||
|
||||
if self.RadarBlur then
|
||||
local reccecoord = Unit:GetCoordinate()
|
||||
local coord = unit:GetCoordinate()
|
||||
local reccecoord = Unit:GetCoord()
|
||||
local coord = unit:GetCoord()
|
||||
local dist = math.floor(coord:Get2DDistance(reccecoord)/1000) -- km
|
||||
local AGL = unit:GetAltitude(true)
|
||||
local minheight = self.RadarBlurMinHeight or 250 -- meters
|
||||
|
||||
@@ -237,7 +237,7 @@ function PLAYERTASK:New(Type, Target, Repeat, Times, TTSType)
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #boolen Silent If true, suppress message output on cancel.
|
||||
-- @param #boolean Silent If true, suppress message output on cancel.
|
||||
|
||||
--- On After "Planned" event. Task has been planned.
|
||||
-- @function [parent=#PLAYERTASK] OnAfterPilotPlanned
|
||||
@@ -1599,6 +1599,7 @@ do
|
||||
-- ELEVATION = "\nTarget Elevation: %s %s",
|
||||
-- METER = "meter",
|
||||
-- FEET = "feet",
|
||||
-- INTERCEPTCOURSE = "Intercept course",
|
||||
-- },
|
||||
--
|
||||
-- e.g.
|
||||
@@ -1921,6 +1922,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
DESTROYER = "Destroyer",
|
||||
CARRIER = "Aircraft Carrier",
|
||||
RADIOS = "Radios",
|
||||
INTERCEPTCOURSE = "Intercept course",
|
||||
},
|
||||
DE = {
|
||||
TASKABORT = "Auftrag abgebrochen!",
|
||||
@@ -2008,12 +2010,13 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
DESTROYER = "Zerstörer",
|
||||
CARRIER = "Flugzeugträger",
|
||||
RADIOS = "Frequenzen",
|
||||
INTERCEPTCOURSE = "Abfangkurs",
|
||||
},
|
||||
}
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASKCONTROLLER.version="0.1.71"
|
||||
PLAYERTASKCONTROLLER.version="0.1.73"
|
||||
|
||||
--- Create and run a new TASKCONTROLLER instance.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
@@ -3776,6 +3779,41 @@ function PLAYERTASKCONTROLLER:_ShowRadioInfo(Group, Client)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Calculate group future position after given seconds.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Wrapper.Group#GROUP group The group to calculate for.
|
||||
-- @param #number seconds Time interval in seconds. Default is `self.prediction`.
|
||||
-- @return Core.Point#COORDINATE Calculated future position of the cluster.
|
||||
function PLAYERTASKCONTROLLER:_CalcGroupFuturePosition(group, seconds)
|
||||
|
||||
-- Get current position of the cluster.
|
||||
local p=group:GetCoordinate()
|
||||
|
||||
-- Velocity vector in m/s.
|
||||
local v=group:GetVelocityVec3()
|
||||
|
||||
-- Time in seconds.
|
||||
local t=seconds or self.prediction
|
||||
|
||||
-- Extrapolated vec3.
|
||||
local Vec3={x=p.x+v.x*t, y=p.y+v.y*t, z=p.z+v.z*t}
|
||||
|
||||
-- Future position.
|
||||
local futureposition=COORDINATE:NewFromVec3(Vec3)
|
||||
|
||||
-- Create an arrow pointing in the direction of the movement.
|
||||
if self.verbose == true then
|
||||
local markerID = group:GetProperty("PLAYERTASK_ARROW")
|
||||
if markerID then
|
||||
COORDINATE:RemoveMark(markerID)
|
||||
end
|
||||
markerID = p:ArrowToAll(futureposition, self.coalition, {1,0,0}, 1, {1,1,0}, 0.5, 2, true, "Position Calc")
|
||||
group:SetProperty("PLAYERTASK_ARROW",markerID)
|
||||
end
|
||||
|
||||
return futureposition
|
||||
end
|
||||
|
||||
--- [Internal] Flashing directional info for a client
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
@@ -3785,16 +3823,34 @@ function PLAYERTASKCONTROLLER:_FlashInfo()
|
||||
if _client and _client:IsAlive() then
|
||||
if self.TasksPerPlayer:HasUniqueID(_playername) then
|
||||
local task = self.TasksPerPlayer:ReadByID(_playername) -- Ops.PlayerTask#PLAYERTASK
|
||||
local Coordinate = task.Target:GetCoordinate()
|
||||
local Coordinate = task.Target:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local CoordText = ""
|
||||
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A and task.Type~=AUFTRAG.Type.INTERCEPT then
|
||||
CoordText = Coordinate:ToStringA2G(_client, nil, self.ShowMagnetic)
|
||||
local targettxt = self.gettext:GetEntry("TARGET",self.locale)
|
||||
local text = targettxt..": "..CoordText
|
||||
local m = MESSAGE:New(text,10,"Tasking"):ToClient(_client)
|
||||
else
|
||||
CoordText = Coordinate:ToStringA2A(_client, nil, self.ShowMagnetic)
|
||||
local targettxt = self.gettext:GetEntry("TARGET",self.locale)
|
||||
local text = targettxt..": "..CoordText
|
||||
-- calc intercept position
|
||||
local name=task.Target:GetName()
|
||||
local group = GROUP:FindByName(name)
|
||||
local clientcoord = _client:GetCoordinate()
|
||||
if group and clientcoord and group:IsAlive() and task.Type==AUFTRAG.Type.INTERCEPT then
|
||||
local speed = math.max(UTILS.KnotsToMps(350) or _client:GetVelocityMPS())
|
||||
local dist = Coordinate:Get3DDistance(clientcoord)
|
||||
local iTime = math.floor(dist/speed)+5
|
||||
if iTime < 10 then iTime = 10
|
||||
elseif iTime > 600 then iTime = 600 end
|
||||
local npos = self:_CalcGroupFuturePosition(group,iTime)
|
||||
local BR = npos:ToStringBearing(clientcoord,nil,self.ShowMagnetic,0 )
|
||||
local Intercepttext = self.gettext:GetEntry("INTERCEPTCOURSE",self.locale)
|
||||
text = text .. "\n"..Intercepttext.." "..BR
|
||||
end
|
||||
local m = MESSAGE:New(text,10,"Tasking"):ToClient(_client)
|
||||
end
|
||||
local targettxt = self.gettext:GetEntry("TARGET",self.locale)
|
||||
local text = "Target: "..CoordText
|
||||
local m = MESSAGE:New(text,10,"Tasking"):ToClient(_client)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3883,8 +3939,10 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
Elevation = math.floor(UTILS.MetersToFeet(Elevation))
|
||||
end
|
||||
-- ELEVATION = "\nTarget Elevation: %s %s",
|
||||
local elev = self.gettext:GetEntry("ELEVATION",self.locale)
|
||||
text = text .. string.format(elev,tostring(math.floor(Elevation)),elevationmeasure)
|
||||
if task.Type ~= AUFTRAG.Type.INTERCEPT then
|
||||
local elev = self.gettext:GetEntry("ELEVATION",self.locale)
|
||||
text = text .. string.format(elev,tostring(math.floor(Elevation)),elevationmeasure)
|
||||
end
|
||||
-- Prec bombing
|
||||
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
|
||||
if LasingDrone and LasingDrone.playertask then
|
||||
|
||||
@@ -310,7 +310,7 @@ _RECOVERYTANKERID=0
|
||||
|
||||
--- Class version.
|
||||
-- @field #string version
|
||||
RECOVERYTANKER.version="1.0.10"
|
||||
RECOVERYTANKER.version="1.0.11"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -923,6 +923,22 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
|
||||
Spawn:InitRadioCommsOnOff(true)
|
||||
Spawn:InitRadioFrequency(self.RadioFreq)
|
||||
Spawn:InitRadioModulation(self.RadioModu)
|
||||
|
||||
if self.callsignname and self.callsignnumber then
|
||||
local grp = GROUP:FindByName(self.tankergroupname)
|
||||
if grp then
|
||||
local typename = grp:GetTypeName() or ""
|
||||
--self:I(self.lid.."Typename: "..typename)
|
||||
local Name
|
||||
local enumerator = CALLSIGN.Tanker
|
||||
if typename == "A6E" then
|
||||
enumerator = CALLSIGN.Intruder
|
||||
end
|
||||
Name = self:_GetCallsignName(self.callsignname,enumerator)
|
||||
--self:I(self.lid.."CallsignName: "..Name)
|
||||
Spawn:InitCallSign(self.callsignname,Name,self.callsignnumber,self.callsignnumber)
|
||||
end
|
||||
end
|
||||
Spawn:InitModex(self.modex)
|
||||
|
||||
-- Spawn on carrier.
|
||||
@@ -1190,9 +1206,9 @@ function RECOVERYTANKER:onafterPatternUpdate(From, Event, To)
|
||||
-- Task combo.
|
||||
|
||||
-- Be a tanker or be an AWACS.
|
||||
local taskroll = self.tanker:EnRouteTaskTanker()
|
||||
local taskrole = self.tanker:EnRouteTaskTanker()
|
||||
if self.awacs then
|
||||
taskroll=self.tanker:EnRouteTaskAWACS()
|
||||
taskrole=self.tanker:EnRouteTaskAWACS()
|
||||
end
|
||||
|
||||
--local taskeplrs=self.tanker:TaskEPLRS(true, 2)
|
||||
@@ -1201,7 +1217,7 @@ function RECOVERYTANKER:onafterPatternUpdate(From, Event, To)
|
||||
local taskroute = self.tanker:TaskRoute(wp)
|
||||
|
||||
-- Note that the order is important here! tasktanker has to come first. Otherwise it does not work.
|
||||
local taskcombo = self.tanker:TaskCombo({taskroll, taskroute})
|
||||
local taskcombo = self.tanker:TaskCombo({taskrole, taskroute})
|
||||
|
||||
-- Set task.
|
||||
self.tanker:SetTask(taskcombo, 1)
|
||||
@@ -1450,6 +1466,20 @@ function RECOVERYTANKER:_RefuelingStop(EventData)
|
||||
|
||||
end
|
||||
|
||||
--- Get clear name callsign for spawn from enumerator
|
||||
-- @param #RECOVERYTANKER self
|
||||
-- @param #number Callsign
|
||||
-- @param #table Enumerator The table of callsigns, e.g. `CALLSIGN.Tanker`
|
||||
-- @return #string Name Name or "" if not found
|
||||
function RECOVERYTANKER:_GetCallsignName(Callsign, Enumerator)
|
||||
for name, value in pairs(Enumerator or {}) do
|
||||
if value==Callsign then
|
||||
return name
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
--- A unit crashed or died.
|
||||
-- @param #RECOVERYTANKER self
|
||||
-- @param Core.Event#EVENTDATA EventData Event data.
|
||||
|
||||
@@ -1798,6 +1798,273 @@ ENUMS.Storage.weapons.missiles.Igla_S = 'weapons.missiles.Igla_S'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.{AKAN_NO_TRC}'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.{AKAN}'
|
||||
ENUMS.Storage.weapons.shells.M882_9x19 = 'weapons.shells.9x19_m882'
|
||||
ENUMS.Storage.weapons.adapters.HB_F_4E_ORD_LAU_77 = 'weapons.adapters.HB_F-4E_ORD_LAU_77'
|
||||
ENUMS.Storage.weapons.adapters.hb_a_6e_lau7_adu299 = 'weapons.adapters.hb_a-6e_lau7_adu299'
|
||||
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_BLUE = 'weapons.bombs.AH6_SMOKE_BLUE'
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_GREEN = 'weapons.bombs.AH6_SMOKE_GREEN'
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_RED = 'weapons.bombs.AH6_SMOKE_RED'
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_YELLOW = 'weapons.bombs.AH6_SMOKE_YELLOW'
|
||||
|
||||
ENUMS.Storage.weapons.missiles.HB_AGM_78 = 'weapons.missiles.HB_AGM_78'
|
||||
ENUMS.Storage.weapons.missiles.V_1 = 'weapons.missiles.V-1'
|
||||
|
||||
ENUMS.Storage.weapons.shells.Oerlikon_20mm_HE = 'weapons.shells.Oerlikon_20mm_HE'
|
||||
ENUMS.Storage.weapons.shells.RM_15cm_HE = 'weapons.shells.RM_15cm_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_T_MkII_40mm = 'weapons.shells.HE_T_MkII_40mm'
|
||||
ENUMS.Storage.weapons.shells.APCBC = 'weapons.shells.APCBC'
|
||||
ENUMS.Storage.weapons.shells.Sprgr_43_L71 = 'weapons.shells.Sprgr_43_L71'
|
||||
ENUMS.Storage.weapons.shells.Mk_20_HE_shell = 'weapons.shells.Mk_20_HE_shell'
|
||||
ENUMS.Storage.weapons.shells.Pzgr_39_42 = 'weapons.shells.Pzgr_39/42'
|
||||
ENUMS.Storage.weapons.shells.M1_37mm_37AP_T = 'weapons.shells.M1_37mm_37AP-T'
|
||||
ENUMS.Storage.weapons.shells.Sprgr_38 = 'weapons.shells.Sprgr_38'
|
||||
ENUMS.Storage.weapons.shells.Sprgr_39 = 'weapons.shells.Sprgr_39'
|
||||
ENUMS.Storage.weapons.shells.Pzgr_39_43 = 'weapons.shells.Pzgr_39/43'
|
||||
ENUMS.Storage.weapons.shells.Pzgr_39_5cm = 'weapons.shells.Pzgr_39_5cm'
|
||||
ENUMS.Storage.weapons.shells.AP_2A20_115mm = 'weapons.shells.2A20_115mm_AP'
|
||||
ENUMS.Storage.weapons.shells.AP_T_MkI_40mm = 'weapons.shells.AP_T_MkI_40mm'
|
||||
ENUMS.Storage.weapons.shells.AP_37x263 = 'weapons.shells.37x263_AP'
|
||||
ENUMS.Storage.weapons.shells.AP_20x138B = 'weapons.shells.20x138B_AP'
|
||||
ENUMS.Storage.weapons.shells.Besa7_92x57T = 'weapons.shells.Besa7_92x57T'
|
||||
ENUMS.Storage.weapons.shells.Sprgr_34_L70 = 'weapons.shells.Sprgr_34_L70'
|
||||
ENUMS.Storage.weapons.shells.QF94_AA_HE = 'weapons.shells.QF94_AA_HE'
|
||||
ENUMS.Storage.weapons.shells.AH_6762x51mm_M62 = 'weapons.shells.AH-6 7.62x51mm M62'
|
||||
ENUMS.Storage.weapons.shells.AH_6762x51mm_M80 = 'weapons.shells.AH-6 7.62x51mm M80'
|
||||
ENUMS.Storage.weapons.shells.AH_6_762x51mm_M61 = 'weapons.shells.AH-6 7.62x51mm M61'
|
||||
ENUMS.Storage.weapons.shells.leFH18_105HE = 'weapons.shells.leFH18_105HE'
|
||||
ENUMS.Storage.weapons.shells.M63_37HE = 'weapons.shells.M63_37HE'
|
||||
ENUMS.Storage.weapons.shells.QF95_206R_fixed = 'weapons.shells.QF95_206R_fixed'
|
||||
ENUMS.Storage.weapons.shells.UBR_365_85AP = 'weapons.shells.UBR_365_85AP'
|
||||
ENUMS.Storage.weapons.shells.M101 = 'weapons.shells.M101'
|
||||
ENUMS.Storage.weapons.shells.HE_M1_Shell = 'weapons.shells.HE_M1_Shell'
|
||||
ENUMS.Storage.weapons.shells.UO_365K_85HE = 'weapons.shells.UO_365K_85HE'
|
||||
ENUMS.Storage.weapons.shells.Flak41_Sprgr_39 = 'weapons.shells.Flak41_Sprgr_39'
|
||||
ENUMS.Storage.weapons.shells.M1_37mm_HE_T = 'weapons.shells.M1_37mm_HE-T'
|
||||
ENUMS.Storage.weapons.shells.QF17_HE = 'weapons.shells.QF17_HE'
|
||||
ENUMS.Storage.weapons.shells.Pzgr_39 = 'weapons.shells.Pzgr_39'
|
||||
ENUMS.Storage.weapons.shells.Besa7_92x57 = 'weapons.shells.Besa7_92x57'
|
||||
ENUMS.Storage.weapons.shells.I_Gr_33 = 'weapons.shells.I_Gr_33'
|
||||
ENUMS.Storage.weapons.shells.M62_APC = 'weapons.shells.M62_APC'
|
||||
ENUMS.Storage.weapons.shells.Mk_12_HE_shell = 'weapons.shells.Mk_12_HE_shell'
|
||||
ENUMS.Storage.weapons.shells.M51_37AP = 'weapons.shells.M51_37AP'
|
||||
ENUMS.Storage.weapons.shells.M42A1_HE = 'weapons.shells.M42A1_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_20x138B = 'weapons.shells.20x138B_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_37x263 = 'weapons.shells.37x263_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_2A20_115mm = 'weapons.shells.2A20_115mm_HE'
|
||||
|
||||
ENUMS.Storage.weapons.gunmounts.B17_TailTurret_M2_L = 'weapons.gunmounts.B17_TailTurret_M2_L'
|
||||
ENUMS.Storage.weapons.gunmounts.AH6_M134L = 'weapons.gunmounts.{AH6_M134L}'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_Left_Nose_M2 = 'weapons.gunmounts.B17_Left_Nose_M2'
|
||||
ENUMS.Storage.weapons.gunmounts.Ju88_Turret_Top_Right_MG_81 = 'weapons.gunmounts.Ju88_Turret_Top_Right_MG_81'
|
||||
ENUMS.Storage.weapons.gunmounts.Ju88_Turret_Bottom_MG_81_L = 'weapons.gunmounts.Ju88_Turret_Bottom_MG_81_L'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_ChinTurret_M2_R = 'weapons.gunmounts.B17_ChinTurret_M2_R'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_Waist_Right_M2 = 'weapons.gunmounts.B17_Waist_Right_M2'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_Door_Gun = 'weapons.gunmounts.AH-6_Door_Gun'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_BallTurret_M2_L = 'weapons.gunmounts.B17_BallTurret_M2_L'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_BallTurret_M2_R = 'weapons.gunmounts.B17_BallTurret_M2_R'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_TopTurret_M2_R = 'weapons.gunmounts.B17_TopTurret_M2_R'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_Right_Nose_M2 = 'weapons.gunmounts.B17_Right_Nose_M2'
|
||||
ENUMS.Storage.weapons.gunmounts.Ju88_Turret_Bottom_MG_81_R = 'weapons.gunmounts.Ju88_Turret_Bottom_MG_81_R'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_TopTurret_M2_L = 'weapons.gunmounts.B17_TopTurret_M2_L'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_Waist_Left_M2 = 'weapons.gunmounts.B17_Waist_Left_M2'
|
||||
ENUMS.Storage.weapons.gunmounts.Ju88_Turret_ahead_MG_81 = 'weapons.gunmounts.Ju88_Turret_ahead_MG_81'
|
||||
ENUMS.Storage.weapons.gunmounts.AH6_M134R = 'weapons.gunmounts.{AH6_M134R}'
|
||||
ENUMS.Storage.weapons.gunmounts.Ju88_Turret_Top_Left_MG_81 = 'weapons.gunmounts.Ju88_Turret_Top_Left_MG_81'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_TailTurret_M2_R = 'weapons.gunmounts.B17_TailTurret_M2_R'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.AKAN_NO_TRC'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.AKAN'
|
||||
ENUMS.Storage.weapons.gunmounts.B17_ChinTurret_M2_L = 'weapons.gunmounts.B17_ChinTurret_M2_L'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.AKAN'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.AKAN_NO_TRC'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_Door = 'weapons.gunmounts.{AH-6_Door}'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_FN_HMP400 = 'weapons.gunmounts.{AH-6_FN_HMP400}'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_M134L = 'weapons.gunmounts.AH-6_M134L'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_M134R = 'weapons.gunmounts.AH-6_M134R'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_HMP400 = 'weapons.gunmounts.AH-6_HMP400'
|
||||
|
||||
ENUMS.Storage.weapons.droptanks.PTB_800 = 'weapons.droptanks.PTB-800'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_275 = 'weapons.droptanks.PTB-275'
|
||||
ENUMS.Storage.weapons.droptanks.HB_A6E_AERO1D_EMPTY = 'weapons.droptanks.HB_A6E_AERO1D_EMPTY'
|
||||
ENUMS.Storage.weapons.droptanks.Drop_tank_75gal = 'weapons.droptanks.Drop tank 75gal'
|
||||
ENUMS.Storage.weapons.droptanks.S_3_PTB = 'weapons.droptanks.S-3-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_3000 = 'weapons.droptanks.PTB-3000'
|
||||
ENUMS.Storage.weapons.droptanks.HB_A6E_D704 = 'weapons.droptanks.HB_A6E_D704'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_1150_29 = 'weapons.droptanks.PTB-1150-29'
|
||||
ENUMS.Storage.weapons.droptanks.f_18c_ptb = 'weapons.droptanks.f-18c-ptb'
|
||||
ENUMS.Storage.weapons.droptanks.F4_BAK_L = 'weapons.droptanks.F4-BAK-L'
|
||||
ENUMS.Storage.weapons.droptanks.HB_A6E_AERO1D = 'weapons.droptanks.HB_A6E_AERO1D'
|
||||
ENUMS.Storage.weapons.droptanks.IAFS_ComboPak_100 = 'weapons.droptanks.{IAFS_ComboPak_100}'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_2000 = 'weapons.droptanks.PTB-2000'
|
||||
ENUMS.Storage.weapons.droptanks.M2000_PTB = 'weapons.droptanks.M2000-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_150 = 'weapons.droptanks.PTB-150'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_1150 = 'weapons.droptanks.PTB-1150'
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_300gal = 'weapons.droptanks.fuel_tank_300gal'
|
||||
ENUMS.Storage.weapons.droptanks.MIG_25_PTB = 'weapons.droptanks.MIG-25-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_1500 = 'weapons.droptanks.PTB-1500'
|
||||
ENUMS.Storage.weapons.droptanks.MIG_23_PTB = 'weapons.droptanks.MIG-23-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.FT600 = 'weapons.droptanks.FT600'
|
||||
ENUMS.Storage.weapons.droptanks.F15_PTB = 'weapons.droptanks.F15-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.ah6_auxtank = 'weapons.droptanks.ah6_auxtank'
|
||||
ENUMS.Storage.weapons.droptanks.T_PTB = 'weapons.droptanks.T-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_370gal = 'weapons.droptanks.fuel_tank_370gal'
|
||||
ENUMS.Storage.weapons.droptanks.F4_BAK_C = 'weapons.droptanks.F4-BAK-C'
|
||||
ENUMS.Storage.weapons.droptanks.F16_PTB_N2 = 'weapons.droptanks.F-16-PTB-N2'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_800 = 'weapons.droptanks.PTB-800'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_275 = 'weapons.droptanks.PTB-275'
|
||||
ENUMS.Storage.weapons.droptanks.T_PTB = 'weapons.droptanks.T-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.F16_PTB_N2 = 'weapons.droptanks.F-16-PTB-N2'
|
||||
ENUMS.Storage.weapons.droptanks.F4_BAK_C = 'weapons.droptanks.F4-BAK-C'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_1150_29 = 'weapons.droptanks.PTB-1150-29'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_1150 = 'weapons.droptanks.PTB-1150'
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_300gal = 'weapons.droptanks.fuel_tank_300gal'
|
||||
ENUMS.Storage.weapons.droptanks.MIG_25_PTB = 'weapons.droptanks.MIG-25-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_1500 = 'weapons.droptanks.PTB-1500'
|
||||
ENUMS.Storage.weapons.droptanks.FT600 = 'weapons.droptanks.FT600'
|
||||
ENUMS.Storage.weapons.droptanks.Drop_tank_75gal = 'weapons.droptanks.Drop tank 75gal'
|
||||
ENUMS.Storage.weapons.droptanks.F15_PTB = 'weapons.droptanks.F15-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.M2000_PTB = 'weapons.droptanks.M2000-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_150 = 'weapons.droptanks.PTB-150'
|
||||
ENUMS.Storage.weapons.droptanks.F4_BAK_L = 'weapons.droptanks.F4-BAK-L'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_3000 = 'weapons.droptanks.PTB-3000'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_2000 = 'weapons.droptanks.PTB-2000'
|
||||
ENUMS.Storage.weapons.droptanks.S_3_PTB = 'weapons.droptanks.S-3-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_370gal = 'weapons.droptanks.fuel_tank_370gal'
|
||||
ENUMS.Storage.weapons.droptanks.MIG_23_PTB = 'weapons.droptanks.MIG-23-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.f_18c_ptb = 'weapons.droptanks.f-18c-ptb'
|
||||
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400_100 = 'weapons.containers.{FN_HMP400_100}'
|
||||
ENUMS.Storage.weapons.containers.AN_M3 = 'weapons.containers.{AN-M3}'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L500 = 'weapons.containers.OH58D_M3P_L500'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_HE = 'weapons.containers.{GIAT_M621_HE}'
|
||||
ENUMS.Storage.weapons.containers.KORD_12_7_MI24_L = 'weapons.containers.KORD_12_7_MI24_L'
|
||||
ENUMS.Storage.weapons.containers.CH47_STBD_M240H = 'weapons.containers.{CH47_STBD_M240H}'
|
||||
ENUMS.Storage.weapons.containers.CH47_AFT_M60D = 'weapons.containers.{CH47_AFT_M60D}'
|
||||
ENUMS.Storage.weapons.containers.UPK_23_250_MiG_21 = 'weapons.containers.{UPK-23-250 MiG-21}'
|
||||
ENUMS.Storage.weapons.containers.CH47_STBD_M134D = 'weapons.containers.{CH47_STBD_M134D}'
|
||||
ENUMS.Storage.weapons.containers.GAU_12_Equalizer = 'weapons.containers.{GAU_12_Equalizer}'
|
||||
ENUMS.Storage.weapons.containers.PKT_7_62 = 'weapons.containers.PKT_7_62'
|
||||
ENUMS.Storage.weapons.containers.CH47_AFT_M240H = 'weapons.containers.{CH47_AFT_M240H}'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_SAPHEI = 'weapons.containers.{GIAT_M621_SAPHEI}'
|
||||
ENUMS.Storage.weapons.containers.ADEN_GUNPOD = 'weapons.containers.{ADEN_GUNPOD}'
|
||||
ENUMS.Storage.weapons.containers.GAU_12_Equalizer_HE = 'weapons.containers.{GAU_12_Equalizer_HE}'
|
||||
ENUMS.Storage.weapons.containers.M60_SIDE_L = 'weapons.containers.M60_SIDE_L'
|
||||
ENUMS.Storage.weapons.containers.KORD_12_7_MI24_R = 'weapons.containers.KORD_12_7_MI24_R'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_APHE = 'weapons.containers.{GIAT_M621_APHE}'
|
||||
ENUMS.Storage.weapons.containers.MB339_ANM3_L = 'weapons.containers.{MB339_ANM3_L}'
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400 = 'weapons.containers.{FN_HMP400}'
|
||||
ENUMS.Storage.weapons.containers.AH_6_Door = 'weapons.containers.{AH-6_Door}'
|
||||
ENUMS.Storage.weapons.containers.MB339_DEFA553_L = 'weapons.containers.{MB339_DEFA553_L}'
|
||||
ENUMS.Storage.weapons.containers.MB339_ANM3_R = 'weapons.containers.{MB339_ANM3_R}'
|
||||
ENUMS.Storage.weapons.containers.PK_3 = 'weapons.containers.{PK-3}'
|
||||
ENUMS.Storage.weapons.containers.GUV_VOG = 'weapons.containers.GUV_VOG'
|
||||
ENUMS.Storage.weapons.containers.SA342_M134_SIDE_R = 'weapons.containers.{SA342_M134_SIDE_R}'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L100 = 'weapons.containers.OH58D_M3P_L100'
|
||||
ENUMS.Storage.weapons.containers.MXU_648 = 'weapons.containers.MXU-648'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L400 = 'weapons.containers.OH58D_M3P_L400'
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400_200 = 'weapons.containers.{FN_HMP400_200}'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_HE = 'weapons.containers.{GIAT_M621_HE}'
|
||||
ENUMS.Storage.weapons.containers.M134_L = 'weapons.containers.M134_L'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L200 = 'weapons.containers.OH58D_M3P_L200'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_AP = 'weapons.containers.{GIAT_M621_AP}'
|
||||
ENUMS.Storage.weapons.containers.CH47_STBD_M134D = 'weapons.containers.{CH47_STBD_M134D}'
|
||||
ENUMS.Storage.weapons.containers.PKT_7_62 = 'weapons.containers.PKT_7_62'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L300 = 'weapons.containers.OH58D_M3P_L300'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_SAPHEI = 'weapons.containers.{GIAT_M621_SAPHEI}'
|
||||
ENUMS.Storage.weapons.containers.M60_SIDE_L = 'weapons.containers.M60_SIDE_L'
|
||||
ENUMS.Storage.weapons.containers.CH47_PORT_M134D = 'weapons.containers.{CH47_PORT_M134D}'
|
||||
ENUMS.Storage.weapons.containers.CH47_PORT_M60D = 'weapons.containers.{CH47_PORT_M60D}'
|
||||
ENUMS.Storage.weapons.containers.ADEN_GUNPOD = 'weapons.containers.{ADEN_GUNPOD}'
|
||||
ENUMS.Storage.weapons.containers.C_101_DEFA553 = 'weapons.containers.{C-101-DEFA553}'
|
||||
ENUMS.Storage.weapons.containers.MB339_ANM3_R = 'weapons.containers.{MB339_ANM3_R}'
|
||||
ENUMS.Storage.weapons.containers.CH47_AFT_M60D = 'weapons.containers.{CH47_AFT_M60D}'
|
||||
ENUMS.Storage.weapons.containers.KORD_12_7 = 'weapons.containers.KORD_12_7'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_HEAP = 'weapons.containers.{GIAT_M621_HEAP}'
|
||||
ENUMS.Storage.weapons.containers.CH47_AFT_M3M = 'weapons.containers.{CH47_AFT_M3M}'
|
||||
ENUMS.Storage.weapons.containers.GUV_YakB_GSHP = 'weapons.containers.GUV_YakB_GSHP'
|
||||
ENUMS.Storage.weapons.containers.R_73U = 'weapons.containers.R-73U'
|
||||
ENUMS.Storage.weapons.containers.GUV_VOG = 'weapons.containers.GUV_VOG'
|
||||
ENUMS.Storage.weapons.containers.KORD_12_7_MI24_L = 'weapons.containers.KORD_12_7_MI24_L'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L100 = 'weapons.containers.OH58D_M3P_L100'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L400 = 'weapons.containers.OH58D_M3P_L400'
|
||||
ENUMS.Storage.weapons.containers.CH47_STBD_M240H = 'weapons.containers.{CH47_STBD_M240H}'
|
||||
ENUMS.Storage.weapons.containers.CH47_PORT_M240H = 'weapons.containers.{CH47_PORT_M240H}'
|
||||
ENUMS.Storage.weapons.containers.CC420_GUN_POD = 'weapons.containers.{CC420_GUN_POD}'
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400_100 = 'weapons.containers.{FN_HMP400_100}'
|
||||
ENUMS.Storage.weapons.containers.MB339_ANM3_L = 'weapons.containers.{MB339_ANM3_L}'
|
||||
ENUMS.Storage.weapons.containers.MB339_DEFA553_R = 'weapons.containers.{MB339_DEFA553_R}'
|
||||
ENUMS.Storage.weapons.containers.GAU_12_Equalizer_HE = 'weapons.containers.{GAU_12_Equalizer_HE}'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L500 = 'weapons.containers.OH58D_M3P_L500'
|
||||
ENUMS.Storage.weapons.containers.SUU_23_POD = 'weapons.containers.{SUU_23_POD}'
|
||||
ENUMS.Storage.weapons.containers.PK_3 = 'weapons.containers.{PK-3}'
|
||||
ENUMS.Storage.weapons.containers.AKAN = 'weapons.containers.{AKAN}'
|
||||
ENUMS.Storage.weapons.containers.CH47_STBD_M60D = 'weapons.containers.{CH47_STBD_M60D}'
|
||||
ENUMS.Storage.weapons.containers.SA342_M134_SIDE_R = 'weapons.containers.{SA342_M134_SIDE_R}'
|
||||
ENUMS.Storage.weapons.containers.M60_SIDE_R = 'weapons.containers.M60_SIDE_R'
|
||||
ENUMS.Storage.weapons.containers.GAU_12_Equalizer_AP = 'weapons.containers.{GAU_12_Equalizer_AP}'
|
||||
ENUMS.Storage.weapons.containers.GAU_12_Equalizer = 'weapons.containers.{GAU_12_Equalizer}'
|
||||
ENUMS.Storage.weapons.containers.KORD_12_7_MI24_R = 'weapons.containers.KORD_12_7_MI24_R'
|
||||
ENUMS.Storage.weapons.containers.M134_SIDE_R = 'weapons.containers.M134_SIDE_R'
|
||||
ENUMS.Storage.weapons.containers.AKAN_NO_TRC = 'weapons.containers.{AKAN_NO_TRC}'
|
||||
ENUMS.Storage.weapons.containers.oh_58_brauning = 'weapons.containers.oh-58-brauning'
|
||||
ENUMS.Storage.weapons.containers.MXU_648 = 'weapons.containers.MXU-648'
|
||||
ENUMS.Storage.weapons.containers.M134_R = 'weapons.containers.M134_R'
|
||||
ENUMS.Storage.weapons.containers.AN_M3 = 'weapons.containers.{AN-M3}'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_APHE = 'weapons.containers.{GIAT_M621_APHE}'
|
||||
ENUMS.Storage.weapons.containers.AIM_9S = 'weapons.containers.AIM-9S'
|
||||
ENUMS.Storage.weapons.containers.CH47_AFT_M240H = 'weapons.containers.{CH47_AFT_M240H}'
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400 = 'weapons.containers.{FN_HMP400}'
|
||||
ENUMS.Storage.weapons.containers.M134_SIDE_L = 'weapons.containers.M134_SIDE_L'
|
||||
ENUMS.Storage.weapons.containers.MB339_DEFA553_L = 'weapons.containers.{MB339_DEFA553_L}'
|
||||
ENUMS.Storage.weapons.containers.MISC_1 = 'weapons.containers.{05544F1A-C39C-466b-BC37-5BD1D52E57BB}'
|
||||
ENUMS.Storage.weapons.containers.MISC_2 = 'weapons.containers.{E92CBFE5-C153-11d8-9897-000476191836}'
|
||||
ENUMS.Storage.weapons.containers.hvar_SmokeGenerator = 'weapons.containers.hvar_SmokeGenerator'
|
||||
ENUMS.Storage.weapons.containers.INV_SMOKE_RED = 'weapons.containers.{INV-SMOKE-RED}'
|
||||
ENUMS.Storage.weapons.containers.INV_SMOKE_YELLOW = 'weapons.containers.{INV-SMOKE-YELLOW}'
|
||||
ENUMS.Storage.weapons.containers.INV_SMOKE_BLUE = 'weapons.containers.{INV-SMOKE-BLUE}'
|
||||
ENUMS.Storage.weapons.containers.INV_SMOKE_GREEN = 'weapons.containers.{INV-SMOKE-GREEN}'
|
||||
ENUMS.Storage.weapons.containers.INV_SMOKE_WHITE = 'weapons.containers.{INV-SMOKE-WHITE}'
|
||||
ENUMS.Storage.weapons.containers.INV_SMOKE_ORANGE = 'weapons.containers.{INV-SMOKE-ORANGE}'
|
||||
ENUMS.Storage.weapons.containers.GAU_12_Equalizer_AP = 'weapons.containers.{GAU_12_Equalizer_AP}'
|
||||
ENUMS.Storage.weapons.containers.AH_6_Gunners = 'weapons.containers.{AH-6_Gunners}'
|
||||
ENUMS.Storage.weapons.containers.AH_6_FN_HMP400 = 'weapons.containers.{AH-6_FN_HMP400}'
|
||||
ENUMS.Storage.weapons.containers.R_73U = 'weapons.containers.R-73U'
|
||||
ENUMS.Storage.weapons.containers.M60_SIDE_R = 'weapons.containers.M60_SIDE_R'
|
||||
ENUMS.Storage.weapons.containers.CH47_AFT_M3M = 'weapons.containers.{CH47_AFT_M3M}'
|
||||
ENUMS.Storage.weapons.containers.GUV_YakB_GSHP = 'weapons.containers.GUV_YakB_GSHP'
|
||||
ENUMS.Storage.weapons.containers.RKL609_L = 'weapons.containers.{RKL609_L}'
|
||||
ENUMS.Storage.weapons.containers.CH47_PORT_M134D = 'weapons.containers.{CH47_PORT_M134D}'
|
||||
ENUMS.Storage.weapons.containers.CH47_PORT_M60D = 'weapons.containers.{CH47_PORT_M60D}'
|
||||
ENUMS.Storage.weapons.containers.RKL609_R = 'weapons.containers.{RKL609_R}'
|
||||
ENUMS.Storage.weapons.containers.C_101_DEFA553 = 'weapons.containers.{C-101-DEFA553}'
|
||||
ENUMS.Storage.weapons.containers.AH6_M134L = 'weapons.containers.{AH6_M134L}'
|
||||
ENUMS.Storage.weapons.containers.KORD_12_7 = 'weapons.containers.KORD_12_7'
|
||||
ENUMS.Storage.weapons.containers.C130_M18_Sidearm = 'weapons.containers.{C130-M18-Sidearm}'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_HEAP = 'weapons.containers.{GIAT_M621_HEAP}'
|
||||
ENUMS.Storage.weapons.containers.BRU_42_LS = 'weapons.containers.BRU-42_LS'
|
||||
ENUMS.Storage.weapons.containers.CH47_STBD_M60D = 'weapons.containers.{CH47_STBD_M60D}'
|
||||
ENUMS.Storage.weapons.containers.SUU_23_POD = 'weapons.containers.{SUU_23_POD}'
|
||||
ENUMS.Storage.weapons.containers.M134_SIDE_R = 'weapons.containers.M134_SIDE_R'
|
||||
ENUMS.Storage.weapons.containers.AKAN_NO_TRC = 'weapons.containers.{AKAN_NO_TRC}'
|
||||
ENUMS.Storage.weapons.containers.oh_58_brauning = 'weapons.containers.oh-58-brauning'
|
||||
ENUMS.Storage.weapons.containers.AH_6_DOORS = 'weapons.containers.{AH-6_DOORS}'
|
||||
ENUMS.Storage.weapons.containers.CC420_GUN_POD = 'weapons.containers.{CC420_GUN_POD}'
|
||||
ENUMS.Storage.weapons.containers.CH47_PORT_M240H = 'weapons.containers.{CH47_PORT_M240H}'
|
||||
ENUMS.Storage.weapons.containers.MB339_DEFA553_R = 'weapons.containers.{MB339_DEFA553_R}'
|
||||
ENUMS.Storage.weapons.containers.AIM_9S = 'weapons.containers.AIM-9S'
|
||||
ENUMS.Storage.weapons.containers.hvar_SmokeGenerator = 'weapons.containers.hvar_SmokeGenerator'
|
||||
ENUMS.Storage.weapons.containers.M134_L = 'weapons.containers.M134_L'
|
||||
ENUMS.Storage.weapons.containers.AKAN = 'weapons.containers.{AKAN}'
|
||||
ENUMS.Storage.weapons.containers.C130_Cargo_Bay_M4 = 'weapons.containers.{C130-Cargo-Bay-M4}'
|
||||
ENUMS.Storage.weapons.containers.M134_SIDE_L = 'weapons.containers.M134_SIDE_L'
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400_200 = 'weapons.containers.{FN_HMP400_200}'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L200 = 'weapons.containers.OH58D_M3P_L200'
|
||||
ENUMS.Storage.weapons.containers.GIAT_M621_AP = 'weapons.containers.{GIAT_M621_AP}'
|
||||
ENUMS.Storage.weapons.containers.M134_R = 'weapons.containers.M134_R'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L300 = 'weapons.containers.OH58D_M3P_L300'
|
||||
ENUMS.Storage.weapons.containers.AH6_M134R = 'weapons.containers.{AH6_M134R}'
|
||||
|
||||
ENUMS.Storage.weapons.torpedoes.G7A_T1 = 'weapons.torpedoes.G7A_T1'
|
||||
|
||||
|
||||
-- UH-60L Mod
|
||||
ENUMS.Storage.weapons.gunmounts.UH60LGAU19 = 'weapons.gunmounts.UH-60L GAU-19'
|
||||
@@ -1814,6 +2081,15 @@ ENUMS.Storage.weapons.gunmounts.UH60L_M60_GUNNER = 'weapons.gunmounts.{UH60L_M60
|
||||
ENUMS.Storage.weapons.gunmounts.UH60L_M2_GUNNER = 'weapons.gunmounts.{UH60L_M2_GUNNER}'
|
||||
ENUMS.Storage.weapons.gunmounts.UH60_M230_LEFT = 'weapons.gunmounts.{UH60_M230_LEFT}'
|
||||
ENUMS.Storage.weapons.gunmounts.UH60_M230_RIGHT = 'weapons.gunmounts.{UH60_M230_RIGHT}'
|
||||
ENUMS.Storage.weapons.containers.UH60_M134_RIGHT = 'weapons.containers.{UH60_M134_RIGHT}'
|
||||
ENUMS.Storage.weapons.containers.UH60_M134_LEFT = 'weapons.containers.{UH60_M134_LEFT}'
|
||||
ENUMS.Storage.weapons.containers.UH60_M230_LEFT = 'weapons.containers.{UH60_M230_LEFT}'
|
||||
ENUMS.Storage.weapons.containers.UH60L_M134_GUNNER = 'weapons.containers.{UH60L_M134_GUNNER}'
|
||||
ENUMS.Storage.weapons.containers.UH60_GAU19_LEFT = 'weapons.containers.{UH60_GAU19_LEFT}'
|
||||
ENUMS.Storage.weapons.containers.UH60L_M60_GUNNER = 'weapons.containers.{UH60L_M60_GUNNER}'
|
||||
ENUMS.Storage.weapons.containers.UH60_GAU19_RIGHT = 'weapons.containers.{UH60_GAU19_RIGHT}'
|
||||
ENUMS.Storage.weapons.containers.UH60_M230_RIGHT = 'weapons.containers.{UH60_M230_RIGHT}'
|
||||
ENUMS.Storage.weapons.containers.UH60L_M2_GUNNER = 'weapons.containers.{UH60L_M2_GUNNER}'
|
||||
|
||||
---
|
||||
-- @type ENUMS.FARPType
|
||||
|
||||
@@ -1507,6 +1507,14 @@ function UTILS.VecSubstract(a, b)
|
||||
return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z}
|
||||
end
|
||||
|
||||
--- Scale a 3D vectors by multiplication with s.
|
||||
-- @param DCS#Vec3 v A Vector in 3D with x, y, z components.
|
||||
-- @param #number s Scale
|
||||
-- @return DCS#Vec3 Vec3
|
||||
function UTILS.VecScale(v, s)
|
||||
return {x = v.x * s, y = v.y * s, z = v.z * s}
|
||||
end
|
||||
|
||||
--- Substract is not a word, don't want to rename the original function because it's been around since forever
|
||||
function UTILS.VecSubtract(a, b)
|
||||
return UTILS.VecSubstract(a, b)
|
||||
@@ -1520,6 +1528,14 @@ function UTILS.Vec2Substract(a, b)
|
||||
return {x=a.x-b.x, y=a.y-b.y}
|
||||
end
|
||||
|
||||
--- Calculate the difference between two 3D vectors by substracting the x,y,z components from each other.
|
||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||
-- @return DCS#Vec3 Vector in 3D.
|
||||
function UTILS.Vec3Substract(a, b)
|
||||
return {x = a.x - b.x, y = a.y - b.y, z = a.z - b.z}
|
||||
end
|
||||
|
||||
--- Substract is not a word, don't want to rename the original function because it's been around since forever
|
||||
function UTILS.Vec2Subtract(a, b)
|
||||
return UTILS.Vec2Substract(a, b)
|
||||
@@ -1649,6 +1665,13 @@ function UTILS.Vec2Translate(a, distance, angle)
|
||||
return {x=TX, y=TY}
|
||||
end
|
||||
|
||||
--- Calculate the lenght of a 3D vector
|
||||
-- @param DCS#Vec3 v A Vector in 3D with x, y, z components.
|
||||
-- @return #number length
|
||||
function UTILS.Vec3Length(v)
|
||||
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
|
||||
end
|
||||
|
||||
--- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||
-- @param #number angle Rotation angle in degrees.
|
||||
@@ -2900,16 +2923,27 @@ end
|
||||
-- @param #boolean Cinematic (Optional, needs Structured = true) If true, place a fire/smoke effect on the dead static position.
|
||||
-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 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 for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5.
|
||||
-- @param #boolean Resurrection If true, dead units can be restored on load. Defaults to false.
|
||||
-- @param #number ResurrectPercentage Use this percentage of probability to resurrect a unit. [0..100], defaults to 25.
|
||||
-- @param #number Healmin If set, life points of a resurrected unit will be randomly restored to min this percentage. [0..100], defaults to 25.
|
||||
-- @param #number Healmax If set, life points of a resurrected unit will be randomly restored to max this percentage. [0..100], defaults to 75.
|
||||
-- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read.
|
||||
-- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )`
|
||||
function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce,Structured,Cinematic,Effect,Density)
|
||||
|
||||
function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce,Structured,Cinematic,Effect,Density,Resurrection,ResurrectPercentage,Healmin,Healmax)
|
||||
|
||||
local healmin = Healmin or 25
|
||||
local healmax = Healmax or 75
|
||||
local resurrection = (Resurrection == true) and true or false
|
||||
local resurrectpercentage = ResurrectPercentage or 25
|
||||
|
||||
local fires = {}
|
||||
|
||||
---
|
||||
-- @param Core.Point#COORDINATE coord
|
||||
local function Smokers(name,coord,effect,density)
|
||||
local eff = math.random(8)
|
||||
if type(effect) == "number" then eff = effect end
|
||||
coord:BigSmokeAndFire(eff,density,name)
|
||||
coord:BigSmokeAndFire( eff, Density, 300, 1, name )
|
||||
table.insert(fires,name)
|
||||
end
|
||||
|
||||
@@ -2924,7 +2958,16 @@ function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce,Structured,Cinema
|
||||
local name = _unit:GetName()
|
||||
Smokers(name,coordinate,Effect,Density)
|
||||
end
|
||||
_unit:Destroy(false)
|
||||
-- TODO Resurrection logic
|
||||
local resurectok = math.random(1,100)
|
||||
BASE:E(string.format("Load Group | Resurrection | Resurrect %s | Thresh %d | Random %d",tostring(resurrection),resurrectpercentage,resurectok))
|
||||
if resurrection == true and (resurectok < resurrectpercentage) then
|
||||
local heallife = math.random(healmin,healmax)
|
||||
BASE:E("Load Group | Resurrection | Life "..heallife)
|
||||
_unit:SetLife(heallife)
|
||||
else
|
||||
_unit:Destroy(false)
|
||||
end
|
||||
reduced = reduced + 1
|
||||
if reduced == anzahl then break end
|
||||
end
|
||||
@@ -4575,6 +4618,18 @@ function UTILS.Vec2toVec3(vec,y)
|
||||
end
|
||||
end
|
||||
|
||||
-- Converts a Vec3 to a Vec2
|
||||
-- @param vec3 the Vec3 to convert
|
||||
-- @return Vec2 The Vec2 output
|
||||
function UTILS.Vec3toVec2(Vec3)
|
||||
if Vec3 and type(Vec3)=="table" then
|
||||
local Vec2 = {}
|
||||
Vec2.x = Vec3.x or 0
|
||||
Vec2.y = Vec3.z or 0
|
||||
return Vec2
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the correction needed for true north in radians
|
||||
-- @param gPoint The map point vec2 or vec3
|
||||
-- @return number correction
|
||||
@@ -5456,3 +5511,97 @@ function UTILS.GetMinimumBoundingCircle(points)
|
||||
|
||||
return welzlHelper(pts, #pts, {})
|
||||
end
|
||||
|
||||
--- Calculated optimal intercepting course (Bearing)
|
||||
-- @param DCS#Vec3 A1 Position of flight one
|
||||
-- @param DCS#Vec3 V1 VelocityVector of flight one
|
||||
-- @param DCS#Vec3 A2 Position of flight two
|
||||
-- @param #number V2_speed Speed of A2 in m/s
|
||||
-- @return #number Bearing Bearing course for A2 to take for an intercept of A1 or nil if aspect is hot/cold.
|
||||
function UTILS.CalculateInterceptBearing(A1, V1, A2, V2_speed)
|
||||
|
||||
local function berechne_bearing(richtung)
|
||||
local bearing = math.deg(math.atan2(richtung.x, richtung.y))
|
||||
if bearing < 0 then
|
||||
bearing = bearing + 360
|
||||
end
|
||||
return bearing
|
||||
end
|
||||
|
||||
local function vec_normalize(v)
|
||||
local len = UTILS.Vec3Length(v)
|
||||
if len == 0 then return {x = 0, y = 0, z = 0} end
|
||||
return {x = v.x / len, y = v.y / len, z = v.z / len}
|
||||
end
|
||||
|
||||
|
||||
-- Relative Position von F1 zu F2
|
||||
local rel_pos = UTILS.Vec3Substract(A1, A2)
|
||||
local distance = UTILS.Vec3Length(rel_pos)
|
||||
|
||||
if distance == 0 then
|
||||
return nil -- Bereits am gleichen Ort
|
||||
end
|
||||
|
||||
-- Richtungsvektor von F2 zu F1 (normalisiert)
|
||||
local richtung_zu_f1 = vec_normalize(rel_pos)
|
||||
|
||||
-- Prüfe HOT: F1 fliegt direkt auf F2 zu
|
||||
-- Das ist der Fall wenn V1 in die entgegengesetzte Richtung von rel_pos zeigt
|
||||
local v1_normalisiert = vec_normalize(V1)
|
||||
local annaeherung = UTILS.VecDot(v1_normalisiert, richtung_zu_f1)
|
||||
|
||||
if annaeherung < -0.95 then -- F1 fliegt fast direkt auf F2 zu (Winkel > ~162°)
|
||||
return nil -- Hot
|
||||
end
|
||||
|
||||
-- Prüfe COLD: F1 fliegt parallel weg von F2
|
||||
-- Berechne die Geschwindigkeitsdifferenz
|
||||
local rel_velocity = UTILS.VecSubstract(V1, {x=0, y=0, z=0}) -- V1 relativ zu F2 (falls F2 stillsteht)
|
||||
local flucht_komponente = UTILS.VecDot(vec_normalize(rel_velocity), richtung_zu_f1)
|
||||
|
||||
if flucht_komponente > 0.95 then -- F1 fliegt fast parallel weg (Winkel < ~18°)
|
||||
return nil -- Cold
|
||||
end
|
||||
|
||||
-- Geschwindigkeiten
|
||||
local v1 = UTILS.Vec3Length(V1)
|
||||
local v2 = V2_speed
|
||||
|
||||
-- Löse quadratische Gleichung für Abfangzeit t
|
||||
local a = UTILS.VecDot(V1, V1) - v2 * v2
|
||||
local b = 2 * UTILS.VecDot(rel_pos, V1)
|
||||
local c = UTILS.VecDot(rel_pos, rel_pos)
|
||||
|
||||
local discriminant = b * b - 4 * a * c
|
||||
|
||||
if discriminant < 0 then
|
||||
return nil -- Keine Lösung möglich
|
||||
end
|
||||
|
||||
-- Wähle die positive, kleinste Lösung
|
||||
local t1 = (-b + math.sqrt(discriminant)) / (2 * a)
|
||||
local t2 = (-b - math.sqrt(discriminant)) / (2 * a)
|
||||
|
||||
local t = nil
|
||||
if t1 > 0 and t2 > 0 then
|
||||
t = math.min(t1, t2)
|
||||
elseif t1 > 0 then
|
||||
t = t1
|
||||
elseif t2 > 0 then
|
||||
t = t2
|
||||
else
|
||||
return nil -- Keine positive Lösung
|
||||
end
|
||||
|
||||
-- Berechne Treffpunkt
|
||||
local treffpunkt = UTILS.VecAdd(A1, UTILS.VecScale(V1, t))
|
||||
|
||||
-- Berechne Richtung zum Treffpunkt
|
||||
local richtung = UTILS.VecSubstract(treffpunkt, A2)
|
||||
|
||||
-- Berechne Bearing
|
||||
local bearing = berechne_bearing(richtung)
|
||||
|
||||
return UTILS.Round(bearing,0)
|
||||
end
|
||||
|
||||
@@ -718,62 +718,62 @@ AIRBASE.SouthAtlantic = {
|
||||
|
||||
--- Airbases of the Sinai map
|
||||
--
|
||||
-- * `AIRBASE.SinaiMap.Abu_Rudeis` Abu Rudeis
|
||||
-- * `AIRBASE.SinaiMap.Abu_Suwayr` Abu Suwayr
|
||||
-- * `AIRBASE.SinaiMap.Al_Bahr_al_Ahmar` Al Bahr al Ahmar
|
||||
-- * `AIRBASE.SinaiMap.Al_Ismailiyah` Al Ismailiyah
|
||||
-- * `AIRBASE.SinaiMap.Al_Khatatbah` Al Khatatbah
|
||||
-- * `AIRBASE.SinaiMap.Al_Mansurah` Al Mansurah
|
||||
-- * `AIRBASE.SinaiMap.Al_Rahmaniyah_Air_Base` Al Rahmaniyah Air Base
|
||||
-- * `AIRBASE.SinaiMap.As_Salihiyah` As Salihiyah
|
||||
-- * `AIRBASE.SinaiMap.AzZaqaziq` AzZaqaziq
|
||||
-- * `AIRBASE.SinaiMap.Baluza` Baluza
|
||||
-- * `AIRBASE.SinaiMap.Ben_Gurion` Ben-Gurion
|
||||
-- * `AIRBASE.SinaiMap.Beni_Suef` Beni Suef
|
||||
-- * `AIRBASE.SinaiMap.Bilbeis_Air_Base` Bilbeis Air Base
|
||||
-- * `AIRBASE.SinaiMap.Bir_Hasanah` Bir Hasanah
|
||||
-- * `AIRBASE.SinaiMap.Birma_Air_Base` Birma Air Base
|
||||
-- * `AIRBASE.SinaiMap.Borg_El_Arab_International_Airport` Borg El Arab International Airport
|
||||
-- * `AIRBASE.SinaiMap.Cairo_International_Airport` Cairo International Airport
|
||||
-- * `AIRBASE.SinaiMap.Cairo_West` Cairo West
|
||||
-- * `AIRBASE.SinaiMap.Damascus_Intl` Damascus Intl
|
||||
-- * `AIRBASE.SinaiMap.Difarsuwar_Airfield` Difarsuwar Airfield
|
||||
-- * `AIRBASE.SinaiMap.Ein_Shamer` Ein Shamer
|
||||
-- * `AIRBASE.SinaiMap.El_Arish` El Arish
|
||||
-- * `AIRBASE.SinaiMap.El_Gora` El Gora
|
||||
-- * `AIRBASE.SinaiMap.El_Minya` El Minya
|
||||
-- * `AIRBASE.SinaiMap.Fayed` Fayed
|
||||
-- * `AIRBASE.SinaiMap.Gebel_El_Basur_Air_Base` Gebel El Basur Air Base
|
||||
-- * `AIRBASE.SinaiMap.Hatzerim` Hatzerim
|
||||
-- * `AIRBASE.SinaiMap.Hatzor` Hatzor
|
||||
-- * `AIRBASE.SinaiMap.Hurghada_International_Airport` Hurghada International Airport
|
||||
-- * `AIRBASE.SinaiMap.Inshas_Airbase` Inshas Airbase
|
||||
-- * `AIRBASE.SinaiMap.Jiyanklis_Air_Base` Jiyanklis Air Base
|
||||
-- * `AIRBASE.SinaiMap.Kedem` Kedem
|
||||
-- * `AIRBASE.SinaiMap.Khalkhalah_Air_Base` Khalkhalah Air Base
|
||||
-- * `AIRBASE.SinaiMap.Kibrit_Air_Base` Kibrit Air Base
|
||||
-- * `AIRBASE.SinaiMap.King_Feisal_Air_Base` King Feisal Air Base
|
||||
-- * `AIRBASE.SinaiMap.Kom_Awshim` Kom Awshim
|
||||
-- * `AIRBASE.SinaiMap.Megiddo` Megiddo
|
||||
-- * `AIRBASE.SinaiMap.Melez` Melez
|
||||
-- * `AIRBASE.SinaiMap.Mezzeh_Air_Base` Mezzeh Air Base
|
||||
-- * `AIRBASE.SinaiMap.Nevatim` Nevatim
|
||||
-- * `AIRBASE.SinaiMap.Ovda` Ovda
|
||||
-- * `AIRBASE.SinaiMap.Palmachim` Palmachim
|
||||
-- * `AIRBASE.SinaiMap.Quwaysina` Quwaysina
|
||||
-- * `AIRBASE.SinaiMap.Rafic_Hariri_Intl` Rafic Hariri Intl
|
||||
-- * `AIRBASE.SinaiMap.Ramat_David` Ramat David
|
||||
-- * `AIRBASE.SinaiMap.Ramon_Airbase` Ramon Airbase
|
||||
-- * `AIRBASE.SinaiMap.Ramon_International_Airport` Ramon International Airport
|
||||
-- * `AIRBASE.SinaiMap.Sde_Dov` Sde Dov
|
||||
-- * `AIRBASE.SinaiMap.Sharm_El_Sheikh_International_Airport` Sharm El Sheikh International Airport
|
||||
-- * `AIRBASE.SinaiMap.St_Catherine` St Catherine
|
||||
-- * `AIRBASE.SinaiMap.Taba_International_Airport` Taba International Airport
|
||||
-- * `AIRBASE.SinaiMap.Tabuk` Tabuk
|
||||
-- * `AIRBASE.SinaiMap.TabukHeliBase` TabukHeliBase
|
||||
-- * `AIRBASE.SinaiMap.Tel_Nof` Tel Nof
|
||||
-- * `AIRBASE.SinaiMap.Wadi_Abu_Rish` Wadi Abu Rish
|
||||
-- * `AIRBASE.SinaiMap.Wadi_al_Jandali` Wadi al Jandali
|
||||
-- * `AIRBASE.Sinai.Abu_Rudeis` Abu Rudeis
|
||||
-- * `AIRBASE.Sinai.Abu_Suwayr` Abu Suwayr
|
||||
-- * `AIRBASE.Sinai.Al_Bahr_al_Ahmar` Al Bahr al Ahmar
|
||||
-- * `AIRBASE.Sinai.Al_Ismailiyah` Al Ismailiyah
|
||||
-- * `AIRBASE.Sinai.Al_Khatatbah` Al Khatatbah
|
||||
-- * `AIRBASE.Sinai.Al_Mansurah` Al Mansurah
|
||||
-- * `AIRBASE.Sinai.Al_Rahmaniyah_Air_Base` Al Rahmaniyah Air Base
|
||||
-- * `AIRBASE.Sinai.As_Salihiyah` As Salihiyah
|
||||
-- * `AIRBASE.Sinai.AzZaqaziq` AzZaqaziq
|
||||
-- * `AIRBASE.Sinai.Baluza` Baluza
|
||||
-- * `AIRBASE.Sinai.Ben_Gurion` Ben-Gurion
|
||||
-- * `AIRBASE.Sinai.Beni_Suef` Beni Suef
|
||||
-- * `AIRBASE.Sinai.Bilbeis_Air_Base` Bilbeis Air Base
|
||||
-- * `AIRBASE.Sinai.Bir_Hasanah` Bir Hasanah
|
||||
-- * `AIRBASE.Sinai.Birma_Air_Base` Birma Air Base
|
||||
-- * `AIRBASE.Sinai.Borg_El_Arab_International_Airport` Borg El Arab International Airport
|
||||
-- * `AIRBASE.Sinai.Cairo_International_Airport` Cairo International Airport
|
||||
-- * `AIRBASE.Sinai.Cairo_West` Cairo West
|
||||
-- * `AIRBASE.Sinai.Damascus_Intl` Damascus Intl
|
||||
-- * `AIRBASE.Sinai.Difarsuwar_Airfield` Difarsuwar Airfield
|
||||
-- * `AIRBASE.Sinai.Ein_Shamer` Ein Shamer
|
||||
-- * `AIRBASE.Sinai.El_Arish` El Arish
|
||||
-- * `AIRBASE.Sinai.El_Gora` El Gora
|
||||
-- * `AIRBASE.Sinai.El_Minya` El Minya
|
||||
-- * `AIRBASE.Sinai.Fayed` Fayed
|
||||
-- * `AIRBASE.Sinai.Gebel_El_Basur_Air_Base` Gebel El Basur Air Base
|
||||
-- * `AIRBASE.Sinai.Hatzerim` Hatzerim
|
||||
-- * `AIRBASE.Sinai.Hatzor` Hatzor
|
||||
-- * `AIRBASE.Sinai.Hurghada_International_Airport` Hurghada International Airport
|
||||
-- * `AIRBASE.Sinai.Inshas_Airbase` Inshas Airbase
|
||||
-- * `AIRBASE.Sinai.Jiyanklis_Air_Base` Jiyanklis Air Base
|
||||
-- * `AIRBASE.Sinai.Kedem` Kedem
|
||||
-- * `AIRBASE.Sinai.Khalkhalah_Air_Base` Khalkhalah Air Base
|
||||
-- * `AIRBASE.Sinai.Kibrit_Air_Base` Kibrit Air Base
|
||||
-- * `AIRBASE.Sinai.King_Feisal_Air_Base` King Feisal Air Base
|
||||
-- * `AIRBASE.Sinai.Kom_Awshim` Kom Awshim
|
||||
-- * `AIRBASE.Sinai.Megiddo` Megiddo
|
||||
-- * `AIRBASE.Sinai.Melez` Melez
|
||||
-- * `AIRBASE.Sinai.Mezzeh_Air_Base` Mezzeh Air Base
|
||||
-- * `AIRBASE.Sinai.Nevatim` Nevatim
|
||||
-- * `AIRBASE.Sinai.Ovda` Ovda
|
||||
-- * `AIRBASE.Sinai.Palmachim` Palmachim
|
||||
-- * `AIRBASE.Sinai.Quwaysina` Quwaysina
|
||||
-- * `AIRBASE.Sinai.Rafic_Hariri_Intl` Rafic Hariri Intl
|
||||
-- * `AIRBASE.Sinai.Ramat_David` Ramat David
|
||||
-- * `AIRBASE.Sinai.Ramon_Airbase` Ramon Airbase
|
||||
-- * `AIRBASE.Sinai.Ramon_International_Airport` Ramon International Airport
|
||||
-- * `AIRBASE.Sinai.Sde_Dov` Sde Dov
|
||||
-- * `AIRBASE.Sinai.Sharm_El_Sheikh_International_Airport` Sharm El Sheikh International Airport
|
||||
-- * `AIRBASE.Sinai.St_Catherine` St Catherine
|
||||
-- * `AIRBASE.Sinai.Taba_International_Airport` Taba International Airport
|
||||
-- * `AIRBASE.Sinai.Tabuk` Tabuk
|
||||
-- * `AIRBASE.Sinai.TabukHeliBase` TabukHeliBase
|
||||
-- * `AIRBASE.Sinai.Tel_Nof` Tel Nof
|
||||
-- * `AIRBASE.Sinai.Wadi_Abu_Rish` Wadi Abu Rish
|
||||
-- * `AIRBASE.Sinai.Wadi_al_Jandali` Wadi al Jandali
|
||||
--
|
||||
-- @field Sinai
|
||||
AIRBASE.Sinai = {
|
||||
@@ -834,6 +834,66 @@ AIRBASE.Sinai = {
|
||||
["Wadi_Abu_Rish"] = "Wadi Abu Rish",
|
||||
["Wadi_al_Jandali"] = "Wadi al Jandali",
|
||||
}
|
||||
---
|
||||
-- @field SinaiMap
|
||||
AIRBASE.SinaiMap = {
|
||||
["Abu_Rudeis"] = "Abu Rudeis",
|
||||
["Abu_Suwayr"] = "Abu Suwayr",
|
||||
["Al_Bahr_al_Ahmar"] = "Al Bahr al Ahmar",
|
||||
["Al_Ismailiyah"] = "Al Ismailiyah",
|
||||
["Al_Khatatbah"] = "Al Khatatbah",
|
||||
["Al_Mansurah"] = "Al Mansurah",
|
||||
["Al_Rahmaniyah_Air_Base"] = "Al Rahmaniyah Air Base",
|
||||
["As_Salihiyah"] = "As Salihiyah",
|
||||
["AzZaqaziq"] = "AzZaqaziq",
|
||||
["Baluza"] = "Baluza",
|
||||
["Ben_Gurion"] = "Ben-Gurion",
|
||||
["Beni_Suef"] = "Beni Suef",
|
||||
["Bilbeis_Air_Base"] = "Bilbeis Air Base",
|
||||
["Bir_Hasanah"] = "Bir Hasanah",
|
||||
["Birma_Air_Base"] = "Birma Air Base",
|
||||
["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport",
|
||||
["Cairo_International_Airport"] = "Cairo International Airport",
|
||||
["Cairo_West"] = "Cairo West",
|
||||
["Damascus_Intl"] = "Damascus Intl",
|
||||
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
||||
["Ein_Shamer"] = "Ein Shamer",
|
||||
["El_Arish"] = "El Arish",
|
||||
["El_Gora"] = "El Gora",
|
||||
["El_Minya"] = "El Minya",
|
||||
["Fayed"] = "Fayed",
|
||||
["Gebel_El_Basur_Air_Base"] = "Gebel El Basur Air Base",
|
||||
["Hatzerim"] = "Hatzerim",
|
||||
["Hatzor"] = "Hatzor",
|
||||
["Hurghada_International_Airport"] = "Hurghada International Airport",
|
||||
["Inshas_Airbase"] = "Inshas Airbase",
|
||||
["Jiyanklis_Air_Base"] = "Jiyanklis Air Base",
|
||||
["Kedem"] = "Kedem",
|
||||
["Khalkhalah_Air_Base"] = "Khalkhalah Air Base",
|
||||
["Kibrit_Air_Base"] = "Kibrit Air Base",
|
||||
["King_Feisal_Air_Base"] = "King Feisal Air Base",
|
||||
["Kom_Awshim"] = "Kom Awshim",
|
||||
["Megiddo"] = "Megiddo",
|
||||
["Melez"] = "Melez",
|
||||
["Mezzeh_Air_Base"] = "Mezzeh Air Base",
|
||||
["Nevatim"] = "Nevatim",
|
||||
["Ovda"] = "Ovda",
|
||||
["Palmachim"] = "Palmachim",
|
||||
["Quwaysina"] = "Quwaysina",
|
||||
["Rafic_Hariri_Intl"] = "Rafic Hariri Intl",
|
||||
["Ramat_David"] = "Ramat David",
|
||||
["Ramon_Airbase"] = "Ramon Airbase",
|
||||
["Ramon_International_Airport"] = "Ramon International Airport",
|
||||
["Sde_Dov"] = "Sde Dov",
|
||||
["Sharm_El_Sheikh_International_Airport"] = "Sharm El Sheikh International Airport",
|
||||
["St_Catherine"] = "St Catherine",
|
||||
["Taba_International_Airport"] = "Taba International Airport",
|
||||
["Tabuk"] = "Tabuk",
|
||||
["TabukHeliBase"] = "TabukHeliBase",
|
||||
["Tel_Nof"] = "Tel Nof",
|
||||
["Wadi_Abu_Rish"] = "Wadi Abu Rish",
|
||||
["Wadi_al_Jandali"] = "Wadi al Jandali",
|
||||
}
|
||||
|
||||
--- Airbases of the Kola map
|
||||
--
|
||||
@@ -2109,7 +2169,7 @@ end
|
||||
function AIRBASE:GetParkingSpotsNumber(termtype)
|
||||
|
||||
-- Get free parking spots data.
|
||||
local parkingdata=self:GetParkingData(false)
|
||||
local parkingdata=self:GetParkingData(false) or {}
|
||||
|
||||
local nspots=0
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
@@ -2129,7 +2189,7 @@ end
|
||||
function AIRBASE:GetFreeParkingSpotsNumber(termtype, allowTOAC)
|
||||
|
||||
-- Get free parking spots data.
|
||||
local parkingdata=self:GetParkingData(true)
|
||||
local parkingdata=self:GetParkingData(true) or {}
|
||||
|
||||
local nfree=0
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
@@ -2152,7 +2212,7 @@ end
|
||||
function AIRBASE:GetFreeParkingSpotsCoordinates(termtype, allowTOAC)
|
||||
|
||||
-- Get free parking spots data.
|
||||
local parkingdata=self:GetParkingData(true)
|
||||
local parkingdata=self:GetParkingData(true) or {}
|
||||
|
||||
-- Put coordinates of free spots into table.
|
||||
local spots={}
|
||||
@@ -2251,7 +2311,7 @@ end
|
||||
function AIRBASE:_InitParkingSpots()
|
||||
|
||||
-- Get parking data of all spots (free or occupied)
|
||||
local parkingdata=self:GetParkingData(false)
|
||||
local parkingdata=self:GetParkingData(false) or {}
|
||||
|
||||
-- Init table.
|
||||
self.parking={}
|
||||
@@ -2327,10 +2387,10 @@ end
|
||||
function AIRBASE:GetParkingSpotsTable(termtype)
|
||||
|
||||
-- Get parking data of all spots (free or occupied)
|
||||
local parkingdata=self:GetParkingData(false)
|
||||
local parkingdata=self:GetParkingData(false) or {}
|
||||
|
||||
-- Get parking data of all free spots.
|
||||
local parkingfree=self:GetParkingData(true)
|
||||
local parkingfree=self:GetParkingData(true) or {}
|
||||
|
||||
-- Function to ckeck if any parking spot is free.
|
||||
local function _isfree(_tocheck)
|
||||
@@ -2379,7 +2439,7 @@ end
|
||||
function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC)
|
||||
|
||||
-- Get parking data of all free spots.
|
||||
local parkingfree=self:GetParkingData(true)
|
||||
local parkingfree=self:GetParkingData(true) or {}
|
||||
|
||||
-- Put coordinates of free spots into table.
|
||||
local freespots={}
|
||||
@@ -2409,7 +2469,7 @@ end
|
||||
function AIRBASE:GetParkingSpotData(TerminalID)
|
||||
|
||||
-- Get parking data.
|
||||
local parkingdata=self:GetParkingSpotsTable()
|
||||
local parkingdata=self:GetParkingSpotsTable() or {}
|
||||
|
||||
for _,_spot in pairs(parkingdata) do
|
||||
local spot=_spot --#AIRBASE.ParkingSpot
|
||||
@@ -2435,7 +2495,7 @@ function AIRBASE:MarkParkingSpots(termtype, mark)
|
||||
end
|
||||
|
||||
-- Get parking data from getParking() wrapper function.
|
||||
local parkingdata=self:GetParkingSpotsTable(termtype)
|
||||
local parkingdata=self:GetParkingSpotsTable(termtype) or {}
|
||||
|
||||
-- Get airbase name.
|
||||
local airbasename=self:GetName()
|
||||
@@ -2550,7 +2610,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
||||
local markobstacles=false
|
||||
|
||||
-- Loop over all known parking spots
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
for _,parkingspot in pairs(parkingdata or {}) do
|
||||
|
||||
-- Coordinate of the parking spot.
|
||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||
|
||||
@@ -1352,9 +1352,7 @@ function UNIT:GetThreatLevel()
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel + 1]
|
||||
end
|
||||
|
||||
if self:IsAir() then
|
||||
elseif self:IsAir() then
|
||||
|
||||
local ThreatLevels = {
|
||||
[1] = "Unarmed",
|
||||
@@ -1397,9 +1395,7 @@ function UNIT:GetThreatLevel()
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel + 1]
|
||||
end
|
||||
|
||||
if self:IsShip() then
|
||||
elseif self:IsShip() then
|
||||
|
||||
--["Aircraft Carriers"] = {"Heavy armed ships",},
|
||||
--["Cruisers"] = {"Heavy armed ships",},
|
||||
@@ -1953,3 +1949,26 @@ end
|
||||
function UNIT:SetValidateAndRepositionGroundUnits(Enabled)
|
||||
self.ValidateAndRepositionGroundUnits = Enabled
|
||||
end
|
||||
|
||||
--- Get the max kgs of fuel this unit can hold in its *internal* tank(s) and overall (with external tanks) in kgs.
|
||||
-- @param #UNIT self
|
||||
-- @return #number InternalFuel Max internal fuel in kgs. Zero if it cannot be determined.
|
||||
-- @return #number Overall Fuel Overall max in case there are external tanks in kgs. Zero if it cannot be determined.
|
||||
function UNIT:GetFuelMassMax()
|
||||
local Desc = self:GetDesc() or {}
|
||||
local massFuelMax=Desc.fuelMassMax or 0
|
||||
local relFuel=math.min(self:GetFuel() or 1.0, 1.0) -- We take 1.0 as max in case of external fuel tanks.
|
||||
local massFuel=massFuelMax*relFuel
|
||||
return massFuel, massFuelMax
|
||||
end
|
||||
|
||||
--- Get the current kgs of fuel this unit holds in all of its tanks.
|
||||
-- @param #UNIT self
|
||||
-- @param #number Filling Fuel in kgs.
|
||||
function UNIT:GetCurrentFuelKgs()
|
||||
local fuel, maxfuel = self:GetFuelMassMax()
|
||||
local relfuel = self:GetFuel()
|
||||
local maxfilling = math.max(fuel,maxfuel)
|
||||
local mass = maxfilling*relfuel
|
||||
return mass
|
||||
end
|
||||
|
||||
@@ -350,7 +350,7 @@ end
|
||||
-- myweapon:SetFuncImpact(OnImpact)
|
||||
--
|
||||
-- -- Start tracking.
|
||||
-- myweapon:Track()
|
||||
-- myweapon:StartTrack()
|
||||
--
|
||||
function WEAPON:SetFuncImpact(FuncImpact, ...)
|
||||
self.impactFunc=FuncImpact
|
||||
|
||||
Reference in New Issue
Block a user