mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-07-20 22:03:25 +00:00
Merge branch 'FF/Ops' into FF/OpsDev
This commit is contained in:
@@ -79,6 +79,7 @@
|
||||
|
||||
do -- FSM
|
||||
|
||||
--- FSM class
|
||||
-- @type FSM
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field Core.Scheduler#SCHEDULER CallScheduler Call scheduler.
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
-- you specify in the draw panel.
|
||||
--
|
||||
-- # Mark on F10 map
|
||||
--
|
||||
-- The ponints of the PATHLINE can be marked on the F10 map with the @{#PATHLINE.MarkPoints}(`true`) function. The mark points contain information of the surface type, land height and
|
||||
--
|
||||
-- The points of the PATHLINE can be marked on the F10 map with the @{#PATHLINE.MarkPoints}(`true`) function. The mark points contain information of the surface type, land height and
|
||||
-- water depth.
|
||||
--
|
||||
-- To remove the marks, use @{#PATHLINE.MarkPoints}(`false`).
|
||||
@@ -76,17 +76,12 @@ PATHLINE = {
|
||||
-- @field #number landHeight Land height in meters.
|
||||
-- @field #number depth Water depth in meters.
|
||||
-- @field #number markerID Marker ID.
|
||||
-- @field #number lineID Marker of pathline ID.
|
||||
|
||||
--- Segment of line.
|
||||
-- @type PATHLINE.Segment
|
||||
-- @field #PATHLINE.Point p1 First point.
|
||||
-- @field #PATHLINE.Point p2 Second point.
|
||||
-- @field #number lineID Line marker ID.
|
||||
|
||||
|
||||
--- PATHLINE class version.
|
||||
-- @field #string version
|
||||
PATHLINE.version="0.3.0"
|
||||
PATHLINE.version="0.2.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -362,6 +357,30 @@ function PATHLINE:GetPoint2DFromIndex(n)
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Calculate the length of the line.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #boolean Project2D Calculate 2D distance between points.
|
||||
-- @return #number Length in meters.
|
||||
function PATHLINE:GetLength(Project2D)
|
||||
local l=0
|
||||
|
||||
local np=#self.points
|
||||
|
||||
for i=1,np-1 do
|
||||
local p1=self.points[i] --#PATHLINE.Point
|
||||
local p2=self.points[i+1] --#PATHLINE.Point
|
||||
|
||||
if Project2D then
|
||||
l=l+UTILS.VecDist2D(p1.vec2, p2.vec2)
|
||||
else
|
||||
l=l+UTILS.VecDist3D(p1.vec3, p2.vec3)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return l
|
||||
end
|
||||
|
||||
|
||||
--- Mark points on F10 map.
|
||||
-- @param #PATHLINE self
|
||||
@@ -373,7 +392,13 @@ function PATHLINE:MarkPoints(Switch)
|
||||
local point=_point --#PATHLINE.Point
|
||||
|
||||
if Switch==false then
|
||||
|
||||
|
||||
if point.markerID then
|
||||
UTILS.RemoveMark(point.markerID)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if point.markerID then
|
||||
UTILS.RemoveMark(point.markerID)
|
||||
end
|
||||
@@ -392,6 +417,54 @@ function PATHLINE:MarkPoints(Switch)
|
||||
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Draw line on F10 map.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #number Recipient Recipent of the line: -1=All.
|
||||
-- @param #table Color Color as RGB table plus alpha value. Default {1, 0, 0, 1.0}.
|
||||
-- @param #number LineType Line type: 1=Solid (default).
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:DrawLine(Recipient, Color, LineType)
|
||||
|
||||
-- Input
|
||||
Recipient= Recipient or -1
|
||||
Color= Color or {1,0,0, 1.0}
|
||||
LineType=LineType or 1
|
||||
local ReadOnly=false
|
||||
|
||||
|
||||
local np=#self.points
|
||||
|
||||
for i=1,np-1 do
|
||||
local p1=self.points[i] --#PATHLINE.Point
|
||||
local p2=self.points[i+1] --#PATHLINE.Point
|
||||
|
||||
p1.lineID = UTILS.GetMarkID()
|
||||
|
||||
trigger.action.lineToAll(Recipient, p1.lineID, p1.vec3, p2.vec3, Color, LineType, ReadOnly, "")
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove line on F10 map.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #number Delay Delay in seconds before line is removed.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:UnDrawLine(Delay)
|
||||
|
||||
|
||||
local np=#self.points
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local p=_point --#PATHLINE.Point
|
||||
if p.lineID then
|
||||
UTILS.RemoveMark(p.lineID, Delay)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1654,6 +1654,7 @@ do -- COORDINATE
|
||||
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
||||
RoutePoint.linkUnit = AirbaseID
|
||||
RoutePoint.helipadId = AirbaseID
|
||||
RoutePoint.airdromeId = airbase:IsAirdrome() and AirbaseID or nil
|
||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||
RoutePoint.airdromeId = AirbaseID
|
||||
else
|
||||
@@ -2076,6 +2077,40 @@ do -- COORDINATE
|
||||
|
||||
return Path, Way, GotPath
|
||||
end
|
||||
|
||||
--- Returns a table of coordinates to a destination using only roads or railroads.
|
||||
-- The first point is the closest point on road of the given coordinate.
|
||||
-- By default, the last point is the closest point on road of the ToCoord. Hence, the coordinate itself and the final ToCoord are not necessarily included in the path.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE ToCoord Coordinate of destination.
|
||||
-- @param #boolean IncludeEndpoints (Optional) Include the coordinate itself and the ToCoordinate in the path.
|
||||
-- @param #boolean Railroad (Optional) If true, path on railroad is returned. Default false.
|
||||
-- @return Core.Pathline#PATHLINE Pathline containing the points on road. If no path on road can be found, nil is returned or just the endpoints.
|
||||
function COORDINATE:GetPathlineOnRoad(ToCoord, IncludeEndpoints, Railroad)
|
||||
|
||||
-- Set road type.
|
||||
local RoadType="roads"
|
||||
if Railroad==true then
|
||||
RoadType="railroads"
|
||||
end
|
||||
|
||||
-- DCS API function returning a table of vec2.
|
||||
local path = land.findPathOnRoads(RoadType, self.x, self.z, ToCoord.x, ToCoord.z)
|
||||
|
||||
if IncludeEndpoints then
|
||||
path=path or {}
|
||||
table.insert(path, 1, self:GetVec2())
|
||||
table.insert(path, ToCoord:GetVec2())
|
||||
end
|
||||
|
||||
local pathline=nil
|
||||
if path then
|
||||
pathline=PATHLINE:NewFromVec2Array(RoadType, path)
|
||||
end
|
||||
|
||||
return pathline
|
||||
end
|
||||
|
||||
|
||||
--- Gets the surface type at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
|
||||
+1248
-1346
File diff suppressed because it is too large
Load Diff
@@ -133,7 +133,10 @@ VECTOR = {
|
||||
|
||||
--- VECTOR class version.
|
||||
-- @field #string version
|
||||
VECTOR.version="0.0.2"
|
||||
VECTOR.version="0.1.0"
|
||||
|
||||
--- VECTOR unique ID
|
||||
_VECTORID=0
|
||||
|
||||
--- VECTOR private index.
|
||||
-- @field #VECTOR __index
|
||||
@@ -144,7 +147,7 @@ VECTOR.__index = VECTOR
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: 3D rotation
|
||||
-- TODO: Markers
|
||||
-- DONE: Markers
|
||||
-- TODO: Documentation
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -168,6 +171,10 @@ function VECTOR:New(x, y, z)
|
||||
else
|
||||
self=setmetatable({x=x or 0, y=y or 0, z=z or 0}, VECTOR)
|
||||
end
|
||||
|
||||
_VECTORID=_VECTORID+1
|
||||
|
||||
self.uid=_VECTORID
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -275,7 +282,7 @@ end
|
||||
-- @param #VECTOR self
|
||||
-- @param #number Latitude Latitude in decimal degrees.
|
||||
-- @param #number Longitude Longitude in decimal degrees.
|
||||
-- @param #number altitude (Optional) Altitude in meters. Default is the land height at the 2D position.
|
||||
-- @param #number Altitude (Optional) Altitude in meters. Default is the land height at the 2D position.
|
||||
-- @return #VECTOR self
|
||||
function VECTOR:NewFromLLDD(Latitude, Longitude, Altitude)
|
||||
|
||||
@@ -284,13 +291,11 @@ function VECTOR:NewFromLLDD(Latitude, Longitude, Altitude)
|
||||
|
||||
-- Convert vec3 to coordinate object.
|
||||
self=VECTOR:NewFromVec(vec3)
|
||||
|
||||
-- -- Adjust height
|
||||
-- if Altitude==nil then
|
||||
-- self.y=self:GetSurfaceHeight()
|
||||
-- else
|
||||
-- self.y=Altitude
|
||||
-- end
|
||||
|
||||
-- Adjust height
|
||||
if Altitude then
|
||||
self.y=Altitude
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -526,18 +531,29 @@ function VECTOR:GetLatitudeLongitude()
|
||||
end
|
||||
|
||||
|
||||
--- Get MGRS coordinates of this vector.
|
||||
--- Get MGRS information of this vector.
|
||||
--
|
||||
-- `MGRS = {UTMZone = string, MGRSDigraph = string, Easting = number, Northing = number}`
|
||||
--
|
||||
-- @param #VECTOR self
|
||||
-- @param #VECTOR Vector Vector from which the heading is requested.
|
||||
-- @return #number Latitude
|
||||
-- @return #number Longitude
|
||||
-- @return #table MGRS table with `UTMZone`, `MGRSDiGraph`, `Easting` and `Northing` keys.
|
||||
function VECTOR:GetMGRS()
|
||||
|
||||
local lat, long=self:GetLatitudeLongitude()
|
||||
|
||||
local mrgs=coord.LLtoMGRS(lat, long)
|
||||
local mgrs=coord.LLtoMGRS(lat, long)
|
||||
|
||||
-- Example table returned by coord.LLtoMGRS
|
||||
--[[
|
||||
MGRS = {
|
||||
UTMZone = string,
|
||||
MGRSDigraph = string,
|
||||
Easting = number,
|
||||
Northing = number
|
||||
}
|
||||
]]
|
||||
|
||||
return mrgs.Easing, mrgs.Northing
|
||||
return mgrs
|
||||
end
|
||||
|
||||
--- Get the difference of the heading of this vector w.
|
||||
@@ -569,7 +585,7 @@ end
|
||||
-- @param #VECTOR Vector The destination vector.
|
||||
-- @param #number Fraction The fraction (0,1) where the new vector is created. Default 0.5, *i.e.* in the middle.
|
||||
-- @return #VECTOR Vector between this and the other vector.
|
||||
function VECTOR:GetIntermediateCoordinate(Vector, Fraction)
|
||||
function VECTOR:GetIntermediateVector(Vector, Fraction)
|
||||
|
||||
local f=Fraction or 0.5
|
||||
|
||||
@@ -581,13 +597,7 @@ function VECTOR:GetIntermediateCoordinate(Vector, Fraction)
|
||||
|
||||
-- Set/scale the length.
|
||||
vec:SetLength(f*length)
|
||||
|
||||
--TODO: Not sure what this was supposed to do?!
|
||||
-- if f>1 then
|
||||
-- local norm=UTILS.VecNorm(vec)
|
||||
-- f=Fraction/norm
|
||||
-- end
|
||||
|
||||
|
||||
-- Get to the desired position.
|
||||
vec=self+vec
|
||||
|
||||
@@ -638,14 +648,13 @@ end
|
||||
--- Set z-component of vector. The z-axis points to the East.
|
||||
-- @param #VECTOR self
|
||||
-- @param #number z Value of z. Default 0.
|
||||
-- @param #VECTOR self
|
||||
-- @return #VECTOR self
|
||||
function VECTOR:SetZ(z)
|
||||
self.z=z or 0
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Add a vector to this. This function works for DCS#Vec2, DCS#Vec3, VECTOR, COORDINATE objects.
|
||||
-- Note that if you want to add a VECTOR, you can also simply use the `+` operator.
|
||||
-- @param #VECTOR self
|
||||
@@ -666,8 +675,9 @@ function VECTOR:AddVec(Vec)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Substract a vector from this one. This function works for DCS#Vec2, DCS#Vec3, VECTOR, COORDINATE objects.
|
||||
-- Note that if you want to add a VECTOR, you can also simply use the `-` operator.
|
||||
--- Subtract a vector from this one. This function works for DCS#Vec2, DCS#Vec3, VECTOR, COORDINATE objects.
|
||||
--
|
||||
-- **Note** that if you want to add a VECTOR, you can also simply use the `-` operator.
|
||||
-- @param #VECTOR self
|
||||
-- @param DCS#Vec3 Vec Vector to substract. Can also be a DCS#Vec2, DCS#Vec3, COORDINATE or VECTOR object.
|
||||
-- @return #VECTOR self
|
||||
@@ -818,10 +828,14 @@ function VECTOR:Rotate2D(Angle, Copy)
|
||||
local x = X*sinPhi + Y*cosPhi
|
||||
|
||||
-- Create new vector.
|
||||
-- TODO: Copy argument
|
||||
local vector=VECTOR:New(x, self.y, z)
|
||||
|
||||
return vector
|
||||
if Copy then
|
||||
local vector=VECTOR:New(x, self.y, z)
|
||||
return vector
|
||||
else
|
||||
self:SetX(x)
|
||||
self:SetZ(z)
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -857,7 +871,7 @@ end
|
||||
-- * RUNWAY = 5
|
||||
--
|
||||
-- @param #VECTOR self
|
||||
-- @return #number Surface Type
|
||||
-- @return #number Surface type
|
||||
function VECTOR:GetSurfaceType()
|
||||
|
||||
local vec2=self:GetVec2()
|
||||
@@ -867,6 +881,32 @@ function VECTOR:GetSurfaceType()
|
||||
return s
|
||||
end
|
||||
|
||||
|
||||
--- Get the name of surface type at the vector.
|
||||
--
|
||||
-- * LAND = 1
|
||||
-- * SHALLOW_WATER = 2
|
||||
-- * WATER = 3
|
||||
-- * ROAD = 4
|
||||
-- * RUNWAY = 5
|
||||
--
|
||||
-- @param #VECTOR self
|
||||
-- @return #string Surface type name
|
||||
function VECTOR:GetSurfaceTypeName()
|
||||
|
||||
local vec2=self:GetVec2()
|
||||
|
||||
local s=land.getSurfaceType(vec2)
|
||||
|
||||
for name,id in land.SurfaceType() do
|
||||
if id==s then
|
||||
return name
|
||||
end
|
||||
end
|
||||
|
||||
return "unknown"
|
||||
end
|
||||
|
||||
--- Check if a given vector has line of sight with this vector.
|
||||
-- @param #VECTOR self
|
||||
-- @param #VECTOR Vec The other vector.
|
||||
@@ -884,8 +924,7 @@ end
|
||||
|
||||
--- Get a vector on the closest road.
|
||||
-- @param #VECTOR self
|
||||
-- @param #VECTOR Vec The other vector.
|
||||
-- @return #VECTOR Closest vector on a road.
|
||||
-- @return #VECTOR Closest vector to a road.
|
||||
function VECTOR:GetClosestRoad()
|
||||
|
||||
local vec2=self:GetVec2()
|
||||
@@ -900,19 +939,36 @@ function VECTOR:GetClosestRoad()
|
||||
return road
|
||||
end
|
||||
|
||||
--- Get a vector on the closest railroad.
|
||||
-- @param #VECTOR self
|
||||
-- @return #VECTOR Closest vector to a railroad.
|
||||
function VECTOR:GetClosestRailroad()
|
||||
|
||||
local vec2=self:GetVec2()
|
||||
|
||||
local x,y=land.getClosestPointOnRoads('railroads', vec2.x, vec2.y)
|
||||
|
||||
local road=nil
|
||||
if x and y then
|
||||
road=VECTOR:New(x, y)
|
||||
end
|
||||
|
||||
return road
|
||||
end
|
||||
|
||||
|
||||
--- Get the path on road from this vector to a given other vector.
|
||||
-- @param #VECTOR self
|
||||
-- @param #VECTOR Vec The destination vector.
|
||||
-- @return Core.Path#PATHLINE Pathline with points on road.
|
||||
-- @return Core.Pathline#PATHLINE Pathline with points on road.
|
||||
function VECTOR:GetPathOnRoad(Vec)
|
||||
|
||||
local vec2=self:GetVec2()
|
||||
local vec1=self:GetVec2()
|
||||
local vec2=Vec:GetVec2()
|
||||
|
||||
local path=nil
|
||||
|
||||
local vec2points=land.findPathOnRoads("roads", vec2.x , vec2.y, vec2.x, vec2.y)
|
||||
local vec2points=land.findPathOnRoads("roads", vec1.x , vec1.y, vec2.x, vec2.y)
|
||||
|
||||
local path=nil
|
||||
if vec2points then
|
||||
path=PATHLINE:NewFromVec2Array("Road", vec2points)
|
||||
end
|
||||
@@ -924,7 +980,7 @@ end
|
||||
--- Get profile of the land between the two passed points.
|
||||
-- @param #VECTOR self
|
||||
-- @param #VECTOR Vec3 The 3D destination vector. If a 2D vector is passed, `y` is set to the land height.
|
||||
-- @return Core.Path#PATHLINE Pathline with points of the profile.
|
||||
-- @return Core.Pathline#PATHLINE Pathline with points of the profile.
|
||||
function VECTOR:GetProfile(Vec3)
|
||||
|
||||
local vec3=self:GetVec3()
|
||||
@@ -1022,36 +1078,104 @@ function VECTOR:GetTemperaturAndPressure()
|
||||
return t,p
|
||||
end
|
||||
|
||||
--- Creates a smoke at this vector.
|
||||
-- @param #VECTOR self
|
||||
-- @param #number Color Color of the smoke: 0=Green, 1=Red, 2=White, 3=Orange, 4=Blue. Default 0.
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. Default nil.
|
||||
-- @return #string Name of the smoke object. Can be used to stop it.
|
||||
function VECTOR:Smoke(Color, Duration)
|
||||
|
||||
local vec3=self:GetVec3()
|
||||
|
||||
Color=Color or 0
|
||||
|
||||
-- Create a name for the smoke object
|
||||
local name=string.format("Vector-Smoke-%d", self.uid)
|
||||
|
||||
-- Create smoke at this position
|
||||
trigger.action.smoke(vec3, Color, name)
|
||||
|
||||
if Duration and Duration>0 then
|
||||
self:StopSmoke(name, Duration)
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
|
||||
--- Creates a large smoke and fire effect of a specified type and density at this vector.
|
||||
--
|
||||
-- * 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 #VECTOR self
|
||||
-- @param #number Preset Preset of smoke. Default `BIGSMOKEPRESET.LargeSmokeAndFire`.
|
||||
-- @param #number Density Density between [0,1]. Default 0.5.
|
||||
-- @return #string Name of the smoke. Can be used to stop it.
|
||||
function VECTOR:SmokeAndFire(Preset, Density)
|
||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
||||
-- @return #string Name of the smoke. Can be used to stop it.
|
||||
function VECTOR:SmokeAndFire(Preset, Density, Duration)
|
||||
|
||||
Preset=Preset or BIGSMOKEPRESET.LargeSmokeAndFire
|
||||
Density=Density or 0.5
|
||||
|
||||
local vec3=self:GetVec3()
|
||||
|
||||
--TODO: Get a unique name or pass name as parameter?
|
||||
-- Get a name of this smoke & fire object
|
||||
local name=string.format("Vector-Fire-%d", self.uid)
|
||||
|
||||
trigger.action.effectSmokeBig(vec3, Preset, Density, Name)
|
||||
trigger.action.effectSmokeBig(vec3, Preset, Density, name)
|
||||
|
||||
if Duration and Duration>0 then
|
||||
self:StopSmoke(name, Duration)
|
||||
end
|
||||
|
||||
return Name
|
||||
return name
|
||||
end
|
||||
|
||||
--- Stop smoke or fire effect.
|
||||
-- @param #VECTOR self
|
||||
-- @param #string Name Name of the smoke object.
|
||||
-- @param #number Delay Delay in seconds before the smoke is stopped.
|
||||
-- @return #VECTOR self
|
||||
function VECTOR:StopSmoke(Name, Delay)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
TIMER:New(VECTOR.StopSmoke, self, Name):Start(Delay)
|
||||
else
|
||||
if Name then
|
||||
trigger.action.effectSmokeStop(Name)
|
||||
else
|
||||
env.error(string.format("No name provided in VECTOR.StopSmoke function!"))
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates an illumination bomb at the specified point.
|
||||
-- @param #VECTOR self
|
||||
-- @param #number Power The power in Candela (cd). Should be between 1 and 1000000. Default 1000 cd.
|
||||
-- @param #number Altitude (Optional) Altitude [m] at which the illumination bomb is created.
|
||||
-- @return #VECTOR self
|
||||
function VECTOR:IlluminationBomb(Power)
|
||||
function VECTOR:IlluminationBomb(Power, Altitude)
|
||||
|
||||
local vec3=self:GetVec3()
|
||||
|
||||
if Altitude then
|
||||
vec3.y=Altitude
|
||||
end
|
||||
|
||||
-- Create an illumination bomb.
|
||||
trigger.action.illuminationBomb(vec3, Power or 1000)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates an explosion at a given point at the specified power.
|
||||
@@ -1085,16 +1209,73 @@ end
|
||||
--- Creates a arrow from this VECTOR to another vector on the F10 map.
|
||||
-- @param #VECTOR self
|
||||
-- @param #VECTOR Vector The vector defining the endpoint.
|
||||
-- @return #VECTOR self
|
||||
function VECTOR:ArrowToAll(Vector)
|
||||
-- @param #number Coalition Coalition Id: -1=All, 0=Neutral, 1=Red, 2=Blue. Default -1.
|
||||
-- @param #table Color RGB color with alpha {r, g, b, alpha}. Default {1, 0, 0, 0.7}.
|
||||
-- @param #table FillColor RGB color with alpha {r, g, b, alpha}. Default {1, 0, 0, 0.5}.
|
||||
-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot Dash, 5=Long Dash, 6=Two Dash. Default 1.
|
||||
-- @return #number Marker ID. Can be used to remove the drawing.
|
||||
function VECTOR:ArrowTo(Vector, Coalition, Color, FillColor, LineType)
|
||||
|
||||
local vec3Start=self:GetVec3()
|
||||
local vec3End=self:GetVec3()
|
||||
local vec3Start=Vector:GetVec3()
|
||||
|
||||
trigger.action.arrowToAll(coalition , id, vec3Start, vec3End, color, fillColor , lineType, readOnly, "")
|
||||
local id=UTILS.GetMarkID()
|
||||
|
||||
Coalition=Coalition or -1
|
||||
Color=Color or {1,0,0,0.7}
|
||||
FillColor=FillColor or {1,0,0,0.5}
|
||||
LineType=LineType or 1
|
||||
|
||||
local readOnly=false
|
||||
|
||||
trigger.action.arrowToAll(Coalition , id, vec3Start, vec3End, Color, FillColor , LineType, readOnly, "")
|
||||
|
||||
return self
|
||||
return id
|
||||
end
|
||||
|
||||
|
||||
--- Create mark on F10 map.
|
||||
-- @param #VECTOR self
|
||||
-- @param #string MarkText Free format text that shows the marking clarification.
|
||||
-- @param #number Recipient Recipient of the mark: -1=All (default), 0=Neutral, 1=Red, 2=Blue. Can also be a `GROUP` object.
|
||||
-- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false.
|
||||
-- @return #number Mark ID.
|
||||
function VECTOR:Mark(MarkText, Recipient, ReadOnly)
|
||||
|
||||
Recipient=Recipient or -1
|
||||
|
||||
if type(Recipient)=="number" then
|
||||
|
||||
local MarkID = UTILS.GetMarkID()
|
||||
|
||||
if Recipient==-1 then
|
||||
trigger.action.markToAll(MarkID, MarkText, self:GetVec3(), ReadOnly, "")
|
||||
elseif Recipient==0 then
|
||||
trigger.action.markToCoalition(MarkID, MarkText, self:GetVec3(), coalition.side.NEUTRAL, ReadOnly, "")
|
||||
elseif Recipient==1 then
|
||||
trigger.action.markToCoalition(MarkID, MarkText, self:GetVec3(), coalition.side.RED, ReadOnly, "")
|
||||
elseif Recipient==2 then
|
||||
trigger.action.markToCoalition(MarkID, MarkText, self:GetVec3(), coalition.side.BLUE, ReadOnly, "")
|
||||
end
|
||||
|
||||
return MarkID
|
||||
|
||||
elseif type(Recipient)=="table" then
|
||||
|
||||
local MarkID = UTILS.GetMarkID()
|
||||
|
||||
local group=Recipient --Wrapper.Group#GROUP
|
||||
|
||||
trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), group:GetID(), ReadOnly, "")
|
||||
|
||||
return MarkID
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1119,7 +1300,7 @@ function VECTOR.__add(a,b)
|
||||
return c
|
||||
end
|
||||
|
||||
--- Meta function to substract vectors.
|
||||
--- Meta function to subtract vectors.
|
||||
-- @param #VECTOR a Vector a.
|
||||
-- @param #VECTOR b Vector b.
|
||||
-- @return #VECTOR Returns a new VECTOR c with c[i]=a[i]-b[i] for i=x,y,z.
|
||||
@@ -1152,17 +1333,21 @@ function VECTOR.__mul(a, b)
|
||||
return c
|
||||
end
|
||||
|
||||
--- Meta function for dividing vectors by scalars.
|
||||
--- Meta function for dividing a vector by a scalar or by another vector.
|
||||
-- @param #VECTOR a Vector a.
|
||||
-- @param #number b Number by which the components of the vector are divided.
|
||||
-- @return #VECTOR Returns a new VECTOR c with c[i]=a[i]/b for i=x,y,z.
|
||||
-- @param #VECTOR b Vector b. Can also be a #number.
|
||||
-- @return #VECTOR Returns a new VECTOR c with c[i]=a[i]/b or c[i]=a[i]/b[i] for i=x,y,z.
|
||||
function VECTOR.__div(a, b)
|
||||
|
||||
assert(VECTOR._IsVector(a) and type(b) == "number", "div: wrong argument types (expected <vector> and <number>)")
|
||||
|
||||
env.info("FF __div")
|
||||
assert(VECTOR._IsVector(a) and (type(b) == "number" or VECTOR._IsVector(b)), "div: wrong argument types (expected <vector> and (<number> or <vector>))")
|
||||
|
||||
local c=VECTOR:New(a.x/b, a.y/b, a.z/b)
|
||||
local c=nil --#VECTOR
|
||||
|
||||
if type(b) == "number" then
|
||||
c=VECTOR:New(a.x/b, a.y/b, a.z/b)
|
||||
else
|
||||
c=VECTOR:New(a.x/b.x, a.y/b.y, a.z/b.z)
|
||||
end
|
||||
|
||||
return c
|
||||
end
|
||||
@@ -1179,10 +1364,6 @@ end
|
||||
-- @param #VECTOR b Vector b.
|
||||
-- @return #boolean If `true`, both vectors are equal
|
||||
function VECTOR.__eq(a, b)
|
||||
--assert(VECTOR._IsVector(a) and VECTOR._IsVector(b), "ERROR in VECTOR.__eq: wrong argument types: (expected <vector> and <vector>)")
|
||||
env.info("FF __eq",showMessageBox)
|
||||
BASE:I(a)
|
||||
BASE:I(b)
|
||||
return a.x==b.x and a.y==b.y and a.z==b.z
|
||||
end
|
||||
|
||||
@@ -1191,7 +1372,7 @@ end
|
||||
-- @param #VECTOR self
|
||||
-- @return #string String representation of vector.
|
||||
function VECTOR:__tostring()
|
||||
local text=string.format("(x=%.1f, y=%.1f, z=%.1f) |v|=%.1f Phi=%4.1f°", self.x, self.y, self.z, self:GetLength(), self:GetHeading(false))
|
||||
local text=string.format("VECTOR: x=%.1f, y=%.1f, z=%.1f |v|=%.1f Phi=%4.1f°", self.x, self.y, self.z, self:GetLength(), self:GetHeading(false))
|
||||
return text
|
||||
end
|
||||
|
||||
|
||||
@@ -320,8 +320,8 @@ function SCORING:New( GameName, SavePath, AutoSave )
|
||||
|
||||
-- Create the CSV file.
|
||||
self.AutoSavePath = SavePath
|
||||
self.AutoSave = AutoSave or true
|
||||
if self.AutoSave == true then
|
||||
self.AutoSave = (AutoSave == nil or AutoSave == true) and true or false
|
||||
if self.AutoSavePath and self.AutoSave == true then
|
||||
self:OpenCSV( GameName )
|
||||
end
|
||||
|
||||
|
||||
@@ -3340,7 +3340,6 @@ function WAREHOUSE:FindAssetInDB(group)
|
||||
if aid~=nil then
|
||||
|
||||
local asset=_WAREHOUSEDB.Assets[aid]
|
||||
self:T2({asset=asset})
|
||||
if asset==nil then
|
||||
self:_ErrorMessage(string.format("ERROR: Asset for group %s not found in the data base!", group:GetName()), 0)
|
||||
end
|
||||
@@ -3918,7 +3917,7 @@ end
|
||||
-- @param #string assignment A free to choose string specifying an assignment for the asset. This can be used with the @{#WAREHOUSE.OnAfterNewAsset} function.
|
||||
-- @param #table other (Optional) Table of other useful data. Can be collected via WAREHOUSE.OnAfterNewAsset() function for example
|
||||
function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribute, forcecargobay, forceweight, loadradius, skill, liveries, assignment, other)
|
||||
self:T({group=group, ngroups=ngroups, forceattribute=forceattribute, forcecargobay=forcecargobay, forceweight=forceweight})
|
||||
--self:T({group=group:GetName(), ngroups=ngroups, forceattribute=forceattribute, forcecargobay=forcecargobay, forceweight=forceweight})
|
||||
|
||||
-- Set default.
|
||||
local n=ngroups or 1
|
||||
@@ -4446,7 +4445,6 @@ end
|
||||
-- @param #WAREHOUSE.Queueitem Request Information table of the request.
|
||||
-- @return #boolean If true, request is granted.
|
||||
function WAREHOUSE:onbeforeRequest(From, Event, To, Request)
|
||||
self:T3({warehouse=self.alias, request=Request})
|
||||
|
||||
-- Distance from warehouse to requesting warehouse.
|
||||
local distance=self:GetCoordinate():Get2DDistance(Request.warehouse:GetCoordinate())
|
||||
@@ -6153,9 +6151,6 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
|
||||
-- Uncontrolled spawning.
|
||||
template.uncontrolled=uncontrolled
|
||||
|
||||
-- Debug info.
|
||||
self:T2({airtemplate=template})
|
||||
|
||||
-- Spawn group.
|
||||
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
||||
|
||||
@@ -8601,6 +8596,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
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,6 +20,13 @@ _DATABASE:_RegisterCargos()
|
||||
_DATABASE:_RegisterZones()
|
||||
_DATABASE:_RegisterAirbases()
|
||||
|
||||
--- Function that writes to DCS log file
|
||||
-- @param #string text Formatted text.
|
||||
-- @param ... Format passed to string.format().
|
||||
function printf(text, ...)
|
||||
env.info(string.format(text, ...))
|
||||
end
|
||||
|
||||
--- Check if os etc is available.
|
||||
BASE:I("Checking de-sanitization of os, io and lfs:")
|
||||
local __na = false
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
--
|
||||
-- # The BEACONS Concept
|
||||
--
|
||||
-- This class is desinged to make information about beacons of a map/theatre easier accessible. The information contains location, type and frequencies of all or specific beacons of the map.
|
||||
-- This class is designed to make information about beacons of a map/theatre easier accessible. The information contains location, type and frequencies of all or specific beacons of the map.
|
||||
--
|
||||
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `beacons.lua` that can be
|
||||
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
|
||||
@@ -90,7 +90,7 @@ BEACONS = {
|
||||
|
||||
--- BEACONS class version.
|
||||
-- @field #string version
|
||||
BEACONS.version="0.0.4"
|
||||
BEACONS.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
@@ -104,7 +104,7 @@ BEACONS.version="0.0.4"
|
||||
-- Constructor(s)
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new BECAONS class instance from a given table.
|
||||
--- Create a new BEACONS class instance from a given table.
|
||||
-- @param #BEACONS self
|
||||
-- @param #table BeaconTable Table with beacon info.
|
||||
-- @return #BEACONS self
|
||||
@@ -159,7 +159,7 @@ function BEACONS:NewFromTable(BeaconTable)
|
||||
end
|
||||
|
||||
|
||||
--- Create a new BECAONS class instance from a given file.
|
||||
--- Create a new BEACONS class instance from a given file.
|
||||
-- @param #BEACONS self
|
||||
-- @param #string FileName Full path to the file containing the map beacons.
|
||||
-- @return #BEACONS self
|
||||
@@ -238,18 +238,56 @@ function BEACONS:GetClosestBeacon(Coordinate, TypeID, DistMax, ExcludeList)
|
||||
return beacon
|
||||
end
|
||||
|
||||
--- Find closest beacons to a given coordinate.
|
||||
-- @param #BEACONS self
|
||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
||||
-- @param #number Nmax Max number of beacons. Default 5.
|
||||
-- @param #number TypeID (Optional) Only search for specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
||||
-- @param #number DistMax (Optional) Max search distance in meters.
|
||||
-- @return #table Table of #BEACONS.Beacon closest beacons.
|
||||
function BEACONS:GetClosestBeacons(Coordinate, Nmax, TypeID, DistMax)
|
||||
|
||||
Nmax=Nmax or 5
|
||||
|
||||
local closest={}
|
||||
for i=1,Nmax do
|
||||
|
||||
local beacon=self:GetClosestBeacon(Coordinate, TypeID, DistMax, closest)
|
||||
|
||||
if beacon then
|
||||
table.insert(closest, beacon)
|
||||
else
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
--- Get table of all beacons, optionally of a given type.
|
||||
-- @param #BEACONS self
|
||||
-- @param #number TypeID (Optional) Only return specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
||||
-- @param #number TypeID (Optional) Only return specific beacon types, *e.g.* `BEACON.Type.TACAN`. Can be handed in as tanle of beacon types.
|
||||
-- @return #table Table of beacons. Each element is of type #BEACON.Beacon.
|
||||
function BEACONS:GetBeacons(TypeID)
|
||||
|
||||
|
||||
local beacons={}
|
||||
local keys = {}
|
||||
|
||||
if TypeID~=nil and type(TypeID) ~= "table" then
|
||||
TypeID = {TypeID}
|
||||
end
|
||||
|
||||
for _,_typeid in pairs(TypeID or {}) do
|
||||
if _typeid ~= nil then
|
||||
keys[_typeid] = _typeid
|
||||
end
|
||||
end
|
||||
|
||||
for _,_beacon in pairs(self.beacons) do
|
||||
local bc=_beacon --#BEACONS.Beacon
|
||||
|
||||
if TypeID==nil or TypeID==bc.type then
|
||||
if TypeID==nil or keys[bc.type] ~= nil then
|
||||
table.insert(beacons, bc)
|
||||
end
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Stuff
|
||||
-- * More Stuff
|
||||
-- * Navigation Fixes
|
||||
-- * Navigation Aids
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -100,7 +100,7 @@ NAVFIX.Type={
|
||||
|
||||
--- NAVFIX class version.
|
||||
-- @field #string version
|
||||
NAVFIX.version="0.0.1"
|
||||
NAVFIX.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
@@ -231,6 +231,21 @@ function NAVFIX:NewFromNavFix(Name, Type, NavFix, Distance, Bearing, Reciprocal)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new NAVFIX class instance from BEACONS.Beacon data.
|
||||
-- @param #NAVFIX self
|
||||
-- @param Navigation.Beacons#BEACONS.Beacon Beacon The beacon data.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:NewFromBeacon(Beacon)
|
||||
local frequency, unit = BEACONS:_GetFrequency(Beacon.frequency)
|
||||
frequency = string.format("%.3f",frequency)
|
||||
if Beacon.typeName == "TACAN" then
|
||||
frequency = Beacon.channel
|
||||
unit = "X"
|
||||
end
|
||||
self = NAVFIX:NewFromVector(string.format("%s %s %s",Beacon.typeName,frequency,unit),Beacon.typeName,Beacon.vec3)
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -348,7 +363,7 @@ end
|
||||
|
||||
--- Set whether this fix is compulsory.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #boolean Compulsory If `true`, this is a compusory fix. If `false` or nil, it is non-compulsory.
|
||||
-- @param #boolean Compulsory If `true`, this is a compulsory fix. If `false` or nil, it is non-compulsory.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetCompulsory(Compulsory)
|
||||
self.isCompulsory=Compulsory
|
||||
@@ -492,7 +507,7 @@ NAVAID = {
|
||||
|
||||
--- NAVAID class version.
|
||||
-- @field #string version
|
||||
NAVAID.version="0.0.1"
|
||||
NAVAID.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Get radio frequencies of airbases
|
||||
-- * Find closest airbase radios
|
||||
-- * Mark radio frequencies on F10 map
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -37,7 +39,7 @@
|
||||
--
|
||||
-- # The RADIOS Concept
|
||||
--
|
||||
-- This class is desinged to make information about radios of a map/theatre easier accessible. The information contains mostly the frequencies of airbases of the map.
|
||||
-- This class is designed to make information about radios of a map/theatre easier accessible. The information contains mostly the frequencies of airbases of the map.
|
||||
--
|
||||
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `radio.lua` that can be
|
||||
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
|
||||
@@ -46,7 +48,7 @@
|
||||
--
|
||||
-- A new `RADIOS` object can be created with the @{#RADIOS.NewFromFile}(*radio_lua_file*) function.
|
||||
--
|
||||
-- local radios=RADIOS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\radios.lua")
|
||||
-- local radios=RADIOS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\radio.lua")
|
||||
-- radios:MarkerShow()
|
||||
--
|
||||
-- This will load the radios from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
|
||||
@@ -64,7 +66,7 @@
|
||||
-- @field #RADIOS
|
||||
RADIOS = {
|
||||
ClassName = "RADIOS",
|
||||
verbose = 0,
|
||||
verbose = 0,
|
||||
radios = {},
|
||||
}
|
||||
|
||||
@@ -78,6 +80,9 @@ RADIOS = {
|
||||
-- @field #table sceneObjects Scenery objects.
|
||||
-- @field #string name Name of the airbase.
|
||||
-- @field Wrapper.Airbase#AIRBASE airbase Airbase.
|
||||
-- @field Core.Point#COORDINATE coordinate The COORDINATE of the radio.
|
||||
-- @field DCS#Vec3 vec3 3D vector.
|
||||
-- @field #number markerID Marker ID.
|
||||
|
||||
--- Radio item data structure.
|
||||
-- @type RADIOS.Frequency
|
||||
@@ -87,7 +92,7 @@ RADIOS = {
|
||||
|
||||
--- RADIOS class version.
|
||||
-- @field #string version
|
||||
RADIOS.version="0.0.0"
|
||||
RADIOS.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
@@ -108,32 +113,41 @@ function RADIOS:NewFromTable(RadioTable)
|
||||
-- Inherit everything from BASE class.
|
||||
self=BASE:Inherit(self, BASE:New()) -- #RADIOS
|
||||
|
||||
local airbasenames=AIRBASE.GetAllAirbaseNames()
|
||||
--local airbasenames=AIRBASE.GetAllAirbaseNames()
|
||||
|
||||
-- Get all airdromes
|
||||
local airdromes=AIRBASE.GetAllAirbases(nil, Airbase.Category.AIRDROME)
|
||||
|
||||
for _,_radio in pairs(RadioTable) do
|
||||
local radio=_radio --#RADIOS.Radio
|
||||
|
||||
--UTILS.PrintTableToLog(radio)
|
||||
--UTILS.PrintTableToLog(radio.callsign)
|
||||
|
||||
|
||||
-- The table structure of callsign is a bit awkward. We need to get the airbase name.
|
||||
local cs=radio.callsign[1]
|
||||
if cs and cs.common then
|
||||
radio.name=cs.common[1]
|
||||
elseif cs and cs.nato then
|
||||
radio.name=cs.nato[1]
|
||||
else
|
||||
radio.name="Unknown"
|
||||
-- Note that unfortunately, the callsign does not always correspond to the airbase name.
|
||||
if false then
|
||||
local cs=radio.callsign[1]
|
||||
if cs and cs.common then
|
||||
radio.name=cs.common[1]
|
||||
elseif cs and cs.nato then
|
||||
radio.name=cs.nato[1]
|
||||
else
|
||||
radio.name="Unknown"
|
||||
end
|
||||
radio.name=self:_GetAirbaseName(airbasenames, radio.name)
|
||||
radio.airbase=AIRBASE:FindByName(radio.name)
|
||||
end
|
||||
|
||||
--UTILS.PrintTableToLog(radio.callsign)
|
||||
-- Each radio item has a key radioId = 'airfield106_0', where 106 is the UID of the airbase.
|
||||
-- So we can use that to get the airbase.
|
||||
local aid = tonumber(string.match(radio.radioId, "airfield(%d+)_"))
|
||||
|
||||
radio.name=self:_GetAirbaseName(airbasenames, radio.name)
|
||||
|
||||
radio.airbase=AIRBASE:FindByName(radio.name)
|
||||
-- Get airbase
|
||||
radio.airbase=self:_GetAirbaseByID(airdromes, aid)
|
||||
|
||||
-- Set other stuff
|
||||
if radio.airbase then
|
||||
radio.coordinate=radio.airbase:GetCoordinate()
|
||||
radio.vec3=radio.airbase:GetVec3()
|
||||
radio.name=radio.airbase:GetName()
|
||||
end
|
||||
|
||||
-- Add to table
|
||||
@@ -198,6 +212,66 @@ function RADIOS:GetCoordinate(radio)
|
||||
return radio.coordinate
|
||||
end
|
||||
|
||||
|
||||
--- Find closest radio to a given coordinate.
|
||||
-- @param #RADIOS self
|
||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
||||
-- @param #number DistMax (Optional) Max search distance in meters.
|
||||
-- @param #table ExcludeList (Optional) List of radios to exclude.
|
||||
-- @return #RADIOS.Radio The closest radio.
|
||||
function RADIOS:GetClosestRadio(Coordinate, DistMax, ExcludeList)
|
||||
|
||||
local radio=nil --#RADIOS.Radio
|
||||
local distmin=math.huge
|
||||
|
||||
ExcludeList=ExcludeList or {}
|
||||
|
||||
for _,_radio in pairs(self.radios) do
|
||||
local ra=_radio --#RADIOS.Radio
|
||||
|
||||
if (not UTILS.IsInTable(ExcludeList, ra, "radioId")) then
|
||||
|
||||
local dist=Coordinate:Get2DDistance(ra.coordinate)
|
||||
|
||||
if dist<distmin and (DistMax==nil or dist<=DistMax) then
|
||||
distmin=dist
|
||||
radio=ra
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return radio
|
||||
end
|
||||
|
||||
--- Find closest radios to a given coordinate.
|
||||
-- @param #RADIOS self
|
||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
||||
-- @param #number Nmax Max number of radios. Default 5.
|
||||
-- @param #number DistMax (Optional) Max search distance in meters.
|
||||
-- @return #table Table of #RADIOS.Radio closest radios.
|
||||
function RADIOS:GetClosestRadios(Coordinate, Nmax, DistMax)
|
||||
|
||||
Nmax=Nmax or 5
|
||||
|
||||
local closest={}
|
||||
for i=1,Nmax do
|
||||
|
||||
local radio=self:GetClosestRadio(Coordinate, DistMax, closest)
|
||||
|
||||
if radio then
|
||||
table.insert(closest, radio)
|
||||
else
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
|
||||
--- Add markers for all radios on the F10 map.
|
||||
-- @param #RADIOS self
|
||||
-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio.
|
||||
@@ -325,6 +399,24 @@ function RADIOS:_GetAirbaseName(airbasenames, name)
|
||||
return "Unknown"
|
||||
end
|
||||
|
||||
--- Get name of frequency band.
|
||||
-- @param #RADIOS self
|
||||
-- @param #table airbases Table of airbases.
|
||||
-- @param #number aid Airbase ID.
|
||||
-- @return Wrapper.Airbase#AIRBASE Airbase matching the ID or nil.
|
||||
function RADIOS:_GetAirbaseByID(airbases, aid)
|
||||
|
||||
for _,_airbase in pairs(airbases) do
|
||||
local airbase=_airbase --Wrapper.Airbase#AIRBASE
|
||||
local id=airbase:GetID(true)
|
||||
if id==aid then
|
||||
return airbase
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
--- **NAVIGATION** - Beacons of the map/theatre.
|
||||
--- **NAVIGATION** - Towns of the map/theatre.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Find towns of map
|
||||
-- * Road and rail connections
|
||||
-- * Find closest town to a given coordinate
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -38,7 +39,7 @@
|
||||
--
|
||||
-- # The TOWNS Concept
|
||||
--
|
||||
-- This class is desinged to make information about towns of a map/theatre easier accessible. The information contains location and road/rail connections of the towns.
|
||||
-- This class is designed to make information about towns of a map/theatre easier accessible. The information contains location and road/rail connections of the towns.
|
||||
--
|
||||
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `towns.lua` that can be
|
||||
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
|
||||
@@ -47,7 +48,7 @@
|
||||
--
|
||||
-- A new `TOWNS` object can be created with the @{#TOWNS.NewFromFile}(*towns_lua_file*) function.
|
||||
--
|
||||
-- local towns=TOWNS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\towns.lua")
|
||||
-- local towns=TOWNS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\map\towns.lua")
|
||||
-- towns:MarkerShow()
|
||||
--
|
||||
-- This will load the towns from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
|
||||
@@ -83,16 +84,16 @@ TOWNS = {
|
||||
|
||||
--- TOWNS class version.
|
||||
-- @field #string version
|
||||
TOWNS.version="0.0.1"
|
||||
TOWNS.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
-- TODO: Road connection
|
||||
-- TODO: Rail connection
|
||||
-- TODO: Connection between towns
|
||||
-- DONE: Road connection
|
||||
-- DONE: Rail connection
|
||||
-- DONE: Connection between towns
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor(s)
|
||||
@@ -193,14 +194,15 @@ function TOWNS:GetCoordRail(town)
|
||||
return town.coordRail
|
||||
end
|
||||
|
||||
--- Get road connection between two towns.
|
||||
--- Get road or rail connection between two towns.
|
||||
-- @param #TOWNS self
|
||||
-- @param #TOWNS.Town townA The town data structure.
|
||||
-- @param #TOWNS.Town townB The town data structure.
|
||||
-- @return #table Table containing path coordinates.
|
||||
function TOWNS:GetConnectionRoad(townA, townB)
|
||||
-- @param #boolean Railroad If `true`, find rail road connection
|
||||
-- @return Core.Pathline#PATHLINE Pathline connecting the two towns on road.
|
||||
function TOWNS:GetConnectionRoad(townA, townB, Railroad)
|
||||
|
||||
local path=townA.coordRoad:GetPathOnRoad(townB.coordRoad)
|
||||
local path=townA.coordRoad:GetPathlineOnRoad(townB.coordRoad, false, Railroad)
|
||||
|
||||
return path
|
||||
end
|
||||
@@ -208,26 +210,59 @@ end
|
||||
--- Find closest town to a given coordinate.
|
||||
-- @param #TOWNS self
|
||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
||||
-- @param #number DistMax (Optional) Max search distance in meters.
|
||||
-- @param #table ExcludeList (Optional) List of towns excluded from the search.
|
||||
-- @return #TOWNS.Town The closest town.
|
||||
function TOWNS:GetClosestTown(Coordinate)
|
||||
function TOWNS:GetClosestTown(Coordinate, DistMax, ExcludeList)
|
||||
|
||||
local Town=nil --#TOWNS.Town
|
||||
local distmin=math.huge
|
||||
ExcludeList=ExcludeList or {}
|
||||
|
||||
for _,_town in pairs(self.towns) do
|
||||
local town=_town --#TOWNS.Town
|
||||
|
||||
local dist=Coordinate:Get2DDistance(town.coordinate)
|
||||
if (not UTILS.IsInTable(ExcludeList, town, "name")) then
|
||||
|
||||
if dist<distmin then
|
||||
distmin=dist
|
||||
Town=town
|
||||
local dist=Coordinate:Get2DDistance(town.coordinate)
|
||||
|
||||
if dist<distmin then
|
||||
distmin=dist
|
||||
Town=town
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Town
|
||||
end
|
||||
|
||||
--- Find closest towns to a given coordinate.
|
||||
-- @param #TOWNS self
|
||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
||||
-- @param #number Nmax Max number of towns. Default 5.
|
||||
-- @param #number DistMax (Optional) Max search distance in meters.
|
||||
-- @return #table Table of #TOWNS.Town closest towns.
|
||||
function TOWNS:GetClosestTowns(Coordinate, Nmax, DistMax)
|
||||
|
||||
Nmax=Nmax or 5
|
||||
|
||||
local closest={}
|
||||
for i=1,Nmax do
|
||||
|
||||
local town=self:GetClosestTown(Coordinate, DistMax, closest)
|
||||
|
||||
if town then
|
||||
table.insert(closest, town)
|
||||
else
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
|
||||
--- Get table of all towns, optionally of a given type.
|
||||
-- @param #TOWNS self
|
||||
-- @return #table Table of towns. Each element is of type #TOWN.Town.
|
||||
|
||||
@@ -5498,15 +5498,15 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
||||
aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5
|
||||
aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14
|
||||
aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13
|
||||
elseif goshawk then
|
||||
elseif goshawk then --These parameters edited by CIRCUIT to support new VNAO flight model
|
||||
-- T-45C Goshawk parameters.
|
||||
aoa.SLOW = 8.00 -- 19
|
||||
aoa.Slow = 7.75 -- 18
|
||||
aoa.OnSpeedMax = 7.25 -- 17.5
|
||||
aoa.OnSpeed = 7.00 -- 17
|
||||
aoa.OnSpeedMin = 6.75 -- 16.5
|
||||
aoa.Fast = 6.25 -- 16
|
||||
aoa.FAST = 6.00 -- 15
|
||||
aoa.SLOW = 9.5 -- 8.00 -- 19
|
||||
aoa.Slow = 9.25 -- 7.75 -- 18
|
||||
aoa.OnSpeedMax = 9.0 --7.25 -- 17.5
|
||||
aoa.OnSpeed = 8.5 -- 7.00 -- 17
|
||||
aoa.OnSpeedMin = 8.25 -- 6.75 -- 16.5
|
||||
aoa.Fast = 7.75 -- 6.25 -- 16
|
||||
aoa.FAST = 5.5 -- 6.00 -- 15
|
||||
elseif skyhawk then
|
||||
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
|
||||
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
|
||||
@@ -8161,8 +8161,14 @@ function AIRBOSS:_CheckPlayerStatus()
|
||||
-- TODO: This might cause problems if the CCA is set to be very small!
|
||||
if unit:IsInZone( self.zoneCCA ) then
|
||||
|
||||
-- VNAO Edit - Added wrapped up call to LSO grading
|
||||
if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added
|
||||
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||
|
||||
-- VNAO Edit - Added wrapped up call to LSO grading Hornet
|
||||
if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added
|
||||
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
||||
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
||||
@@ -8186,6 +8192,30 @@ function AIRBOSS:_CheckPlayerStatus()
|
||||
end -- VNAO Edit - Added
|
||||
end-- VNAO Edit - Added
|
||||
|
||||
-- VNAO Edit - Added wrapped up call to LSO grading Tomcat
|
||||
if playerData.step==AIRBOSS.PatternStep.WAKE and tomcat then-- VNAO Edit - Added
|
||||
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
||||
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
||||
playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added
|
||||
playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||
playerData.AAatWakeLittle = true -- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||
playerData.AAatWakeFull = true -- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||
playerData.AAatWakeUnderline = true -- VNAO Edit - Added
|
||||
else -- VNAO Edit - Added
|
||||
end -- VNAO Edit - Added
|
||||
|
||||
if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added
|
||||
playerData.AFU = true -- VNAO Edit - Added
|
||||
elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added
|
||||
playerData.AFU = true -- VNAO Edit - Added
|
||||
else -- VNAO Edit - Added
|
||||
end -- VNAO Edit - Added
|
||||
end-- VNAO Edit - Added
|
||||
|
||||
-- Display aircraft attitude and other parameters as message text.
|
||||
if playerData.attitudemonitor then
|
||||
@@ -12229,8 +12259,8 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord )
|
||||
local magvar= magnetic and self.magvar or 0
|
||||
|
||||
-- Ship heading so cross wind is min for the given wind.
|
||||
-- local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 -- VNAO Edit: Using old heading into wind algorithm
|
||||
local intowind = self:GetHeadingIntoWind_old(vdeck,magnetic) -- VNAO Edit: Using old heading into wind algorithm
|
||||
local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360
|
||||
|
||||
|
||||
return intowind, v
|
||||
end
|
||||
@@ -12682,7 +12712,8 @@ function AIRBOSS:_LSOgrade( playerData )
|
||||
local nL=count(G, '_')/2
|
||||
local nS=count(G, '%(')
|
||||
local nN=N-nS-nL
|
||||
|
||||
|
||||
if TIG=="_OK_" then nL = nL -1 end --Circuit added to prevent grade deduction for perfect groove
|
||||
|
||||
-- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn.
|
||||
local Tgroove=playerData.Tgroove
|
||||
@@ -12712,7 +12743,6 @@ function AIRBOSS:_LSOgrade( playerData )
|
||||
else
|
||||
|
||||
if vtol then
|
||||
|
||||
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe.--Pene testing
|
||||
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
||||
|
||||
|
||||
@@ -839,8 +839,8 @@ function ARMYGROUP:Status()
|
||||
local ammo=self:GetAmmoElement(element)
|
||||
|
||||
-- Output text for element.
|
||||
text=text..string.format("\n[%d] %s: status=%s, life=%.1f/%.1f, guns=%d, rockets=%d, bombs=%d, missiles=%d, cargo=%d/%d kg",
|
||||
i, name, status, life, life0, ammo.Guns, ammo.Rockets, ammo.Bombs, ammo.Missiles, element.weightCargo, element.weightMaxCargo)
|
||||
text=text..string.format("\n[%d] %s: status=%s, life=%.1f/%.1f, guns=%d, cannons=%d, rockets=%d, missiles=%d, cargo=%d/%d kg",
|
||||
i, name, status, life, life0, ammo.Guns, ammo.Cannons, ammo.Rockets, ammo.Missiles, element.weightCargo, element.weightMaxCargo)
|
||||
end
|
||||
if #self.elements==0 then
|
||||
text=text.." none!"
|
||||
@@ -1571,7 +1571,7 @@ end
|
||||
-- @param Core.Zone#ZONE Zone The zone to return to.
|
||||
-- @param #number Formation Formation of the group.
|
||||
function ARMYGROUP:onafterRTZ(From, Event, To, Zone, Formation)
|
||||
self:T2(self.lid.."onafterRTZ")
|
||||
self:T(self.lid.."onafterRTZ")
|
||||
|
||||
-- Zone.
|
||||
local zone=Zone or self.homezone
|
||||
@@ -1841,8 +1841,6 @@ function ARMYGROUP:_UpdateEngageTarget()
|
||||
-- Check if target moved more than 100 meters or we do not have line of sight.
|
||||
if dist>100 or los==false then
|
||||
|
||||
--env.info("FF Update Engage Target Moved "..self.engage.Target:GetName())
|
||||
|
||||
-- Update new position.
|
||||
self.engage.Coordinate:UpdateFromVec3(vec3)
|
||||
|
||||
@@ -1852,13 +1850,14 @@ function ARMYGROUP:_UpdateEngageTarget()
|
||||
-- Remove current waypoint
|
||||
self:RemoveWaypointByID(self.engage.Waypoint.uid)
|
||||
|
||||
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.9)
|
||||
-- Get new coordinate where to go.
|
||||
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.95)
|
||||
|
||||
-- Add waypoint after current.
|
||||
self.engage.Waypoint=self:AddWaypoint(intercoord, self.engage.Speed, uid, self.engage.Formation, true)
|
||||
|
||||
-- Set if we want to resume route after reaching the detour waypoint.
|
||||
self.engage.Waypoint.detour=0
|
||||
self.engage.Waypoint.detour=1
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -324,6 +324,10 @@
|
||||
--
|
||||
-- A ground attack mission can be created with the @{#AUFTRAG.NewGROUNDATTACK}() function.
|
||||
--
|
||||
-- ## NAVALENGAGEMENT
|
||||
--
|
||||
-- A naval engagement mission can be created with the @{#AUFTRAG.NewNAVALENGAGEMENT}() function.
|
||||
--
|
||||
-- # Assigning Missions
|
||||
--
|
||||
-- An AUFTRAG can be assigned to groups (FLIGHTGROUP, ARMYGROUP, NAVYGROUP), legions (AIRWING, BRIGADE, FLEET) or to a COMMANDER.
|
||||
@@ -443,6 +447,7 @@ _AUFTRAGSNR=0
|
||||
-- @field #string HOVER Hover.
|
||||
-- @field #string LANDATCOORDINATE Land at coordinate.
|
||||
-- @field #string GROUNDATTACK Ground attack.
|
||||
-- @field #string NAVALENGAGEMENT Naval engagement (similar to GROUNDATTACK).
|
||||
-- @field #string CARGOTRANSPORT Cargo transport.
|
||||
-- @field #string RELOCATECOHORT Relocate a cohort from one legion to another.
|
||||
-- @field #string AIRDEFENSE Air defense.
|
||||
@@ -491,6 +496,7 @@ AUFTRAG.Type={
|
||||
HOVER="Hover",
|
||||
LANDATCOORDINATE="Land at Coordinate",
|
||||
GROUNDATTACK="Ground Attack",
|
||||
NAVALENGAGEMENT="Naval Engagement",
|
||||
CARGOTRANSPORT="Cargo Transport",
|
||||
RELOCATECOHORT="Relocate Cohort",
|
||||
AIRDEFENSE="Air Defence",
|
||||
@@ -515,6 +521,7 @@ AUFTRAG.Type={
|
||||
-- @field #string BARRAGE Barrage.
|
||||
-- @field #string HOVER Hover.
|
||||
-- @field #string GROUNDATTACK Ground attack.
|
||||
-- @field #string NAVALENGAGEMENT Naval engagement.
|
||||
-- @field #string FERRY Ferry mission.
|
||||
-- @field #string RELOCATECOHORT Relocate cohort.
|
||||
-- @field #string AIRDEFENSE Air defense.
|
||||
@@ -537,6 +544,7 @@ AUFTRAG.SpecialTask={
|
||||
ARMORATTACK="AmorAttack",
|
||||
HOVER="Hover",
|
||||
GROUNDATTACK="Ground Attack",
|
||||
NAVALENGAGEMENT="Naval Engagement",
|
||||
FERRY="Ferry",
|
||||
RELOCATECOHORT="Relocate Cohort",
|
||||
AIRDEFENSE="Air Defense",
|
||||
@@ -666,7 +674,7 @@ AUFTRAG.Category={
|
||||
|
||||
--- AUFTRAG class version.
|
||||
-- @field #string version
|
||||
AUFTRAG.version="1.2.1"
|
||||
AUFTRAG.version="1.3.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -2210,7 +2218,7 @@ end
|
||||
-- **Note** that it is recommended to set the weapon range via the `OPSGROUP:AddWeaponRange()` function as this cannot be retrieved from the DCS API.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE Target Center of the firing solution.
|
||||
-- @param #number Nshots Number of shots to be fired. Default `#nil`.
|
||||
-- @param #number Nshots Number of shots to be fired. Default `#nil`. If value is in (0,1), it is interpreted as per cent of available ammo.
|
||||
-- @param #number Radius Radius of the shells in meters. Default 100 meters.
|
||||
-- @param #number Altitude Altitude in meters. Can be used to setup a Barrage. Default `#nil`.
|
||||
-- @return #AUFTRAG self
|
||||
@@ -2382,11 +2390,13 @@ function AUFTRAG:NewARMORATTACK(Target, Speed, Formation)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[GROUND]** Create a GROUNDATTACK mission. Ground group(s) will go to a target object and attack.
|
||||
--- **[GROUND]** Create a GROUNDATTACK mission. Ground group(s) will go to a target object and attack at their own discretion.
|
||||
-- Unfortunately, the "Attack Group" and "Attack Unit" tasks do not work for ground and naval groups (only for aircraft).
|
||||
-- Therefore, we resort to this workaround, which guides the attacking group to the vicinity of the target. Then they start shooting on their own, once they detect the target.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP, UNIT or STATIC object.
|
||||
-- @param #number Speed Speed in knots. Default max.
|
||||
-- @param #string Formation The attack formation, e.g. "Wedge", "Vee" etc. Default `ENUMS.Formation.Vehicle.Vee`.
|
||||
-- @param #string Formation The attack formation, e.g. "Wedge", "Vee" etc. Default `ENUMS.Formation.Vehicle.Vee`. Only working for ground, not naval!
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewGROUNDATTACK(Target, Speed, Formation)
|
||||
|
||||
@@ -2413,6 +2423,38 @@ function AUFTRAG:NewGROUNDATTACK(Target, Speed, Formation)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[NAVAL]** Create a NAVALENGAGEMENT mission. Naval group(s) will go to a target object and attack at their own discretion.
|
||||
-- Unfortunately, the "Attack Group" and "Attack Unit" tasks do not work for ground and naval groups (only for aircraft).
|
||||
-- Therefore, we resort to this workaround, which guides the attacking group to the vicinity of the target. Then they start shooting on their own, once they detect the target.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP, UNIT or STATIC object.
|
||||
-- @param #number Speed Speed in knots. Default max.
|
||||
-- @param #number Depth The attack depth in meters. Only for submarines!
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewNAVALENGAGEMENT(Target, Speed, Depth)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.NAVALENGAGEMENT)
|
||||
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
mission.missionTask=mission:GetMissionTaskforMissionType(AUFTRAG.Type.NAVALENGAGEMENT)
|
||||
|
||||
-- Defaults.
|
||||
mission.optionROE=ENUMS.ROE.OpenFire
|
||||
mission.optionAlarm=ENUMS.AlarmState.Auto
|
||||
mission.missionFraction=0.70
|
||||
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
|
||||
mission.missionAltitude=Depth or 0
|
||||
|
||||
mission.categories={AUFTRAG.Category.NAVAL}
|
||||
|
||||
mission.DCStask=mission:GetDCSMissionTask()
|
||||
|
||||
mission.DCStask.params.speed=mission.missionSpeed and UTILS.KmphToMps(mission.missionSpeed) or nil
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR, GROUND, NAVAL]** Create a RECON mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Set#SET_ZONE ZoneSet The recon zones.
|
||||
@@ -2705,33 +2747,35 @@ function AUFTRAG:NewFromTarget(Target, MissionType)
|
||||
local mission=nil --#AUFTRAG
|
||||
|
||||
if MissionType==AUFTRAG.Type.ANTISHIP then
|
||||
mission=self:NewANTISHIP(Target, Altitude)
|
||||
mission=self:NewANTISHIP(Target)
|
||||
elseif MissionType==AUFTRAG.Type.ARTY then
|
||||
mission=self:NewARTY(Target, Nshots, Radius)
|
||||
mission=self:NewARTY(Target, 0.3) -- use 30% of the available ammo
|
||||
elseif MissionType==AUFTRAG.Type.BAI then
|
||||
mission=self:NewBAI(Target, Altitude)
|
||||
mission=self:NewBAI(Target)
|
||||
elseif MissionType==AUFTRAG.Type.BOMBCARPET then
|
||||
mission=self:NewBOMBCARPET(Target, Altitude, CarpetLength)
|
||||
mission=self:NewBOMBCARPET(Target)
|
||||
elseif MissionType==AUFTRAG.Type.BOMBING then
|
||||
mission=self:NewBOMBING(Target, Altitude)
|
||||
mission=self:NewBOMBING(Target)
|
||||
elseif MissionType==AUFTRAG.Type.BOMBRUNWAY then
|
||||
mission=self:NewBOMBRUNWAY(Target, Altitude)
|
||||
mission=self:NewBOMBRUNWAY(Target)
|
||||
elseif MissionType==AUFTRAG.Type.STRAFING then
|
||||
mission=self:NewSTRAFING(Target, Altitude)
|
||||
mission=self:NewSTRAFING(Target)
|
||||
elseif MissionType==AUFTRAG.Type.CAS then
|
||||
mission=self:NewCAS(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000), Altitude, Speed, Target:GetAverageCoordinate(), Heading, Leg, TargetTypes)
|
||||
mission=self:NewCAS(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000), nil, nil, Target:GetAverageCoordinate())
|
||||
elseif MissionType==AUFTRAG.Type.CASENHANCED then
|
||||
mission=self:NewCASENHANCED(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000), Altitude, Speed, RangeMax, NoEngageZoneSet, TargetTypes)
|
||||
mission=self:NewCASENHANCED(ZONE_RADIUS:New(Target:GetName(),Target:GetVec2(),1000))
|
||||
elseif MissionType==AUFTRAG.Type.INTERCEPT then
|
||||
mission=self:NewINTERCEPT(Target)
|
||||
elseif MissionType==AUFTRAG.Type.SEAD then
|
||||
mission=self:NewSEAD(Target, Altitude)
|
||||
mission=self:NewSEAD(Target)
|
||||
elseif MissionType==AUFTRAG.Type.STRIKE then
|
||||
mission=self:NewSTRIKE(Target, Altitude)
|
||||
mission=self:NewSTRIKE(Target)
|
||||
elseif MissionType==AUFTRAG.Type.ARMORATTACK then
|
||||
mission=self:NewARMORATTACK(Target, Speed)
|
||||
mission=self:NewARMORATTACK(Target)
|
||||
elseif MissionType==AUFTRAG.Type.GROUNDATTACK then
|
||||
mission=self:NewGROUNDATTACK(Target, Speed, Formation)
|
||||
mission=self:NewGROUNDATTACK(Target)
|
||||
elseif MissionType==AUFTRAG.Type.NAVALENGAGEMENT then
|
||||
mission=self:NewNAVALENGAGEMENT(Target)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@@ -2848,7 +2892,7 @@ function AUFTRAG:NewAUTO(EngageGroup)
|
||||
if auftrag==AUFTRAG.Type.ANTISHIP then
|
||||
mission=AUFTRAG:NewANTISHIP(Target)
|
||||
elseif auftrag==AUFTRAG.Type.ARTY then
|
||||
mission=AUFTRAG:NewARTY(Target)
|
||||
mission=AUFTRAG:NewARTY(Target, 0.2)
|
||||
elseif auftrag==AUFTRAG.Type.AWACS then
|
||||
mission=AUFTRAG:NewAWACS(Coordinate, Altitude,Speed,Heading,Leg)
|
||||
elseif auftrag==AUFTRAG.Type.BAI then
|
||||
@@ -4399,7 +4443,7 @@ function AUFTRAG:onafterStatus(From, Event, To)
|
||||
-- Group info.
|
||||
if self.verbose>=3 then
|
||||
-- Data on assigned groups.
|
||||
local text=string.format("Assets [N=%d,Nassigned=%s, Ndead=%s]:", self.Nassets or 0, self.Nassigned or 0, self.Ndead or 0)
|
||||
local text=string.format("Assets [N=%d, Nassigned=%s, Ndead=%s]:", self.Nassets or 0, self.Nassigned or 0, self.Ndead or 0)
|
||||
for i,_asset in pairs(self.assets or {}) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
text=text..string.format("\n[%d] %s: spawned=%s, requested=%s, reserved=%s", i, asset.spawngroupname, tostring(asset.spawned), tostring(asset.requested), tostring(asset.reserved))
|
||||
@@ -4440,7 +4484,7 @@ function AUFTRAG:Evaluate()
|
||||
local owndamage=self.Ncasualties/self.Nelements*100
|
||||
|
||||
-- Current number of mission targets.
|
||||
local Ntargets=self:CountMissionTargets()
|
||||
local Ntargets=self:CountMissionTargets(true)
|
||||
local Ntargets0=self:GetTargetInitialNumber()
|
||||
|
||||
local Life=self:GetTargetLife()
|
||||
@@ -4891,16 +4935,25 @@ function AUFTRAG:CheckGroupsDone()
|
||||
self:T2(self.lid..string.format("CheckGroupsDone: Mission is still in state %s [FSM=%s] and reinfoce=%d. Mission NOT DONE!", self.status, self:GetState(), self.reinforce))
|
||||
return false
|
||||
end
|
||||
|
||||
local NopsgroupsAlive=self:CountOpsGroups()
|
||||
local NopsgroupsDone=self:CountOpsGroupsInStatus(AUFTRAG.GroupStatus.DONE)+self:CountOpsGroupsInStatus(AUFTRAG.GroupStatus.CANCELLED)
|
||||
|
||||
-- It could be that all groups were destroyed on the way to the mission execution waypoint.
|
||||
-- TODO: would be better to check if everybody is dead by now.
|
||||
if self:IsStarted() and self:CountOpsGroups()==0 then
|
||||
if self:IsStarted() and NopsgroupsAlive==0 then
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] but count of alive OPSGROUP is zero. Mission DONE!", self.status, self:GetState()))
|
||||
return true
|
||||
end
|
||||
|
||||
if (self:IsStarted() or self:IsExecuting()) and (fsmState == AUFTRAG.Status.STARTED or fsmState == AUFTRAG.Status.EXECUTING) and self:CountOpsGroups()>0 then
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState()))
|
||||
-- Every group alive is done or cancelled
|
||||
if NopsgroupsAlive==NopsgroupsDone then
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is in state %s [FSM=%s] but all groups [=%d] are done or cancelled. Mission DONE!", self.status, self:GetState(), NopsgroupsAlive))
|
||||
return true
|
||||
end
|
||||
|
||||
if (self:IsStarted() or self:IsExecuting()) and (fsmState == AUFTRAG.Status.STARTED or fsmState == AUFTRAG.Status.EXECUTING) and NopsgroupsAlive>0 then
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is in state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState()))
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -5494,8 +5547,9 @@ end
|
||||
|
||||
--- Count alive mission targets.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #boolean OnlyReallyAlive (Optional) If `true`, count only really alive targets (units, groups) but not coordinates or zones.
|
||||
-- @return #number Number of alive target units.
|
||||
function AUFTRAG:CountMissionTargets()
|
||||
function AUFTRAG:CountMissionTargets(OnlyReallyAlive)
|
||||
|
||||
local N=0
|
||||
|
||||
@@ -5503,7 +5557,7 @@ function AUFTRAG:CountMissionTargets()
|
||||
local Coalitions=self.coalition and UTILS.GetCoalitionEnemy(self.coalition, true) or nil
|
||||
|
||||
if self.engageTarget then
|
||||
N=self.engageTarget:CountTargets(Coalitions)
|
||||
N=self.engageTarget:CountTargets(Coalitions, OnlyReallyAlive)
|
||||
end
|
||||
|
||||
return N
|
||||
@@ -6642,6 +6696,26 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.NAVALENGAGEMENT then
|
||||
|
||||
---------------------------
|
||||
-- NAVAL ENGAGEMENT Mission --
|
||||
---------------------------
|
||||
|
||||
local DCStask={}
|
||||
|
||||
DCStask.id=AUFTRAG.SpecialTask.NAVALENGAGEMENT
|
||||
|
||||
-- We create a "fake" DCS task and pass the parameters to the NAVYGROUP.
|
||||
local param={}
|
||||
param.target=self:GetTargetData()
|
||||
param.speed=self.missionSpeed and UTILS.KmphToMps(self.missionSpeed) or nil
|
||||
param.altitude=self.missionAltitude or 0
|
||||
|
||||
DCStask.params=param
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.AMMOSUPPLY then
|
||||
|
||||
-------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@
|
||||
-- @field #number Nsuccess Number of successful missions.
|
||||
-- @field #number Nfailure Number of failed mission.
|
||||
-- @field #table assetNumbers Asset numbers. Each entry is a table of data type `#CHIEF.AssetNumber`.
|
||||
-- @extends Ops.Intel#INTEL
|
||||
-- @extends Ops.Intelligence#INTEL
|
||||
|
||||
--- *In preparing for battle I have always found that plans are useless, but planning is indispensable* -- Dwight D Eisenhower
|
||||
--
|
||||
@@ -48,7 +48,7 @@
|
||||
--
|
||||
-- # Territory
|
||||
--
|
||||
-- The chief class allows you to define boarder zones, conflict zones and attack zones.
|
||||
-- The chief class allows you to define border zones, conflict zones and attack zones.
|
||||
--
|
||||
-- ## Border Zones
|
||||
--
|
||||
@@ -332,7 +332,7 @@ CHIEF.Strategy = {
|
||||
|
||||
--- CHIEF class version.
|
||||
-- @field #string version
|
||||
CHIEF.version="0.6.1"
|
||||
CHIEF.version="0.7.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -2897,6 +2897,8 @@ function CHIEF:_GetMissionPerformanceFromTarget(Target)
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
|
||||
|
||||
else
|
||||
|
||||
-- Everything else
|
||||
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.BAI, 100))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50))
|
||||
@@ -2912,6 +2914,8 @@ function CHIEF:_GetMissionPerformanceFromTarget(Target)
|
||||
---
|
||||
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ANTISHIP, 100))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.NAVALENGAGEMENT, 50))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
|
||||
|
||||
else
|
||||
self:E(self.lid.."ERROR: Unknown Group category!")
|
||||
|
||||
@@ -629,32 +629,42 @@ end
|
||||
--- Remove assets from pool. Not that assets must not be spawned or already reserved or requested.
|
||||
-- @param #COHORT self
|
||||
-- @param #number N Number of assets to be removed. Default 1.
|
||||
-- @param #number Delay Delay in seconds before assets are removed.
|
||||
-- @return #COHORT self
|
||||
function COHORT:RemoveAssets(N)
|
||||
function COHORT:RemoveAssets(N, Delay)
|
||||
self:T2(self.lid..string.format("Remove %d assets of Cohort", N))
|
||||
|
||||
N=N or 1
|
||||
|
||||
local n=0
|
||||
for i=#self.assets,1,-1 do
|
||||
local asset=self.assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
if Delay and Delay>0 then
|
||||
-- Delayed call
|
||||
self:ScheduleOnce(Delay, COHORT.RemoveAssets, self, N, 0)
|
||||
else
|
||||
|
||||
self:T2(self.lid..string.format("Checking removing asset %s", asset.spawngroupname))
|
||||
if not (asset.requested or asset.spawned or asset.isReserved) then
|
||||
self:T2(self.lid..string.format("Removing asset %s", asset.spawngroupname))
|
||||
table.remove(self.assets, i)
|
||||
n=n+1
|
||||
else
|
||||
self:T2(self.lid..string.format("Could NOT Remove asset %s", asset.spawngroupname))
|
||||
N=N or 1
|
||||
|
||||
local n=0
|
||||
for i=#self.assets,1,-1 do
|
||||
local asset=self.assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
|
||||
self:T2(self.lid..string.format("Checking removing asset %s", asset.spawngroupname))
|
||||
if not (asset.requested or asset.spawned or asset.isReserved) then
|
||||
self:T2(self.lid..string.format("Removing asset %s", asset.spawngroupname))
|
||||
-- Remove from warehouse and warehouse DB
|
||||
asset.legion:_DeleteStockItem(asset)
|
||||
table.remove(self.assets, i)
|
||||
n=n+1
|
||||
else
|
||||
self:T2(self.lid..string.format("Could NOT Remove asset %s", asset.spawngroupname))
|
||||
end
|
||||
|
||||
if n>=N then
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if n>=N then
|
||||
break
|
||||
end
|
||||
self:T(self.lid..string.format("Removed %d/%d assets. New asset count=%d", n, N, #self.assets))
|
||||
|
||||
end
|
||||
|
||||
self:T(self.lid..string.format("Removed %d/%d assets. New asset count=%d", n, N, #self.assets))
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1901,7 +1901,7 @@ function LEGION:_TacticalOverview()
|
||||
for _,mtype in pairs(AUFTRAG.Type) do
|
||||
local n=self:CountMissionsInQueue(mtype)
|
||||
if n>0 then
|
||||
local N=self:CountMissionsInQueue(mtype)
|
||||
local N=self:CountMissionsInQueue(mtype, true)
|
||||
text=text..string.format(" - %s: %d [Running=%d]\n", mtype, n, N)
|
||||
end
|
||||
end
|
||||
@@ -2057,18 +2057,23 @@ end
|
||||
--- Count missions in mission queue.
|
||||
-- @param #LEGION self
|
||||
-- @param #table MissionTypes Types on mission to be checked. Default *all* possible types `AUFTRAG.Type`.
|
||||
-- @param #boolean OnlyRunning If `true`, only count running missions.
|
||||
-- @return #number Number of missions that are not over yet.
|
||||
function LEGION:CountMissionsInQueue(MissionTypes)
|
||||
function LEGION:CountMissionsInQueue(MissionTypes, OnlyRunning)
|
||||
|
||||
MissionTypes=MissionTypes or AUFTRAG.Type
|
||||
|
||||
local N=0
|
||||
for _,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
|
||||
if (not OnlyRunning) or (mission.statusLegion~=AUFTRAG.Status.PLANNED) then
|
||||
|
||||
-- Check if this mission type is requested.
|
||||
if mission:IsNotOver() and AUFTRAG.CheckMissionType(mission.type, MissionTypes) then
|
||||
N=N+1
|
||||
-- Check if this mission type is requested.
|
||||
if mission:IsNotOver() and AUFTRAG.CheckMissionType(mission.type, MissionTypes) then
|
||||
N=N+1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -86,12 +86,14 @@ NAVYGROUP = {
|
||||
-- @field Ops.Target#TARGET Target The target.
|
||||
-- @field Core.Point#COORDINATE Coordinate Last known coordinate of the target.
|
||||
-- @field Ops.OpsGroup#OPSGROUP.Waypoint Waypoint the waypoint created to go to the target.
|
||||
-- @field #number Speed Speed in knots.
|
||||
-- @field #number Depth Depth of the engagement (submarines).
|
||||
-- @field #number roe ROE backup.
|
||||
-- @field #number alarmstate Alarm state backup.
|
||||
|
||||
--- NavyGroup version.
|
||||
-- @field #string version
|
||||
NAVYGROUP.version="1.0.3"
|
||||
NAVYGROUP.version="1.0.4"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -1081,7 +1083,7 @@ function NAVYGROUP:onafterSpawned(From, Event, To)
|
||||
text=text..string.format("Elements = %d\n", #self.elements)
|
||||
text=text..string.format("Waypoints = %d\n", #self.waypoints)
|
||||
text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On))
|
||||
text=text..string.format("Ammo = %d (G=%d/R=%d/M=%d/T=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles, self.ammo.Torpedos)
|
||||
text=text..string.format("Ammo = %d (G=%d/C=%d/R=%d/M=%d/T=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Cannons, self.ammo.Rockets, self.ammo.Missiles, self.ammo.Torpedos)
|
||||
text=text..string.format("FSM state = %s\n", self:GetState())
|
||||
text=text..string.format("Is alive = %s\n", tostring(self:IsAlive()))
|
||||
text=text..string.format("LateActivate = %s\n", tostring(self:IsLateActivated()))
|
||||
@@ -1602,8 +1604,10 @@ end
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Wrapper.Group#GROUP Group the group to be engaged.
|
||||
function NAVYGROUP:onafterEngageTarget(From, Event, To, Target)
|
||||
-- @param Ops.Target#TARGET Target The target to be engaged. Can also be a GROUP or UNIT object.
|
||||
-- @param #number Speed Attack speed in knots.
|
||||
-- @param #number Depth The depth in meters. Only for submarins.
|
||||
function NAVYGROUP:onafterEngageTarget(From, Event, To, Target, Speed, Depth)
|
||||
self:T(self.lid.."Engaging Target")
|
||||
|
||||
if Target:IsInstanceOf("TARGET") then
|
||||
@@ -1615,11 +1619,9 @@ function NAVYGROUP:onafterEngageTarget(From, Event, To, Target)
|
||||
-- Target coordinate.
|
||||
self.engage.Coordinate=UTILS.DeepCopy(self.engage.Target:GetCoordinate())
|
||||
|
||||
|
||||
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.9)
|
||||
-- Get a coordinate close to the target.
|
||||
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.8)
|
||||
|
||||
|
||||
|
||||
-- Backup ROE and alarm state.
|
||||
self.engage.roe=self:GetROE()
|
||||
self.engage.alarmstate=self:GetAlarmstate()
|
||||
@@ -1629,11 +1631,17 @@ function NAVYGROUP:onafterEngageTarget(From, Event, To, Target)
|
||||
self:SwitchROE(ENUMS.ROE.OpenFire)
|
||||
|
||||
-- ID of current waypoint.
|
||||
local uid=self:GetWaypointCurrent().uid
|
||||
local uid=self:GetWaypointCurrentUID()
|
||||
|
||||
-- Set formation.
|
||||
self.engage.Depth=Depth or 0
|
||||
|
||||
-- Set speed.
|
||||
self.engage.Speed=Speed
|
||||
|
||||
-- Add waypoint after current.
|
||||
self.engage.Waypoint=self:AddWaypoint(intercoord, nil, uid, Formation, true)
|
||||
|
||||
self.engage.Waypoint=self:AddWaypoint(intercoord, Speed, uid, Depth, true)
|
||||
|
||||
-- Set if we want to resume route after reaching the detour waypoint.
|
||||
self.engage.Waypoint.detour=1
|
||||
|
||||
@@ -1656,24 +1664,22 @@ function NAVYGROUP:_UpdateEngageTarget()
|
||||
-- Check if target moved more than 100 meters.
|
||||
if dist>100 then
|
||||
|
||||
--env.info("FF Update Engage Target Moved "..self.engage.Target:GetName())
|
||||
|
||||
-- Update new position.
|
||||
self.engage.Coordinate:UpdateFromVec3(vec3)
|
||||
|
||||
-- ID of current waypoint.
|
||||
local uid=self:GetWaypointCurrent().uid
|
||||
local uid=self:GetWaypointCurrentUID()
|
||||
|
||||
-- Remove current waypoint
|
||||
self:RemoveWaypointByID(self.engage.Waypoint.uid)
|
||||
|
||||
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.9)
|
||||
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.8)
|
||||
|
||||
-- Add waypoint after current.
|
||||
self.engage.Waypoint=self:AddWaypoint(intercoord, nil, uid, Formation, true)
|
||||
self.engage.Waypoint=self:AddWaypoint(intercoord, self.engage.Speed, uid, self.engage.Depth, true)
|
||||
|
||||
-- Set if we want to resume route after reaching the detour waypoint.
|
||||
self.engage.Waypoint.detour=0
|
||||
self.engage.Waypoint.detour=1
|
||||
|
||||
end
|
||||
|
||||
@@ -1709,8 +1715,8 @@ function NAVYGROUP:onafterDisengage(From, Event, To)
|
||||
local task=self:GetTaskCurrent()
|
||||
|
||||
-- Get if current task is ground attack.
|
||||
if task and task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK then
|
||||
self:T(self.lid.."Disengage with current task GROUNDATTACK ==> Task Done!")
|
||||
if task and (task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK or task.dcstask.id==AUFTRAG.SpecialTask.NAVALENGAGEMENT) then
|
||||
self:T(self.lid.."Disengage with current task GROUNDATTACK/NAVALENGAGEMENT ==> Task Done!")
|
||||
self:TaskDone(task)
|
||||
end
|
||||
|
||||
|
||||
@@ -405,7 +405,9 @@ OPSGROUP.TaskType={
|
||||
--- Ammo data.
|
||||
-- @type OPSGROUP.Ammo
|
||||
-- @field #number Total Total amount of ammo.
|
||||
-- @field #number Guns Amount of gun shells.
|
||||
-- @field #number Shells Amount of shells (guns + cannons).
|
||||
-- @field #number Guns Amount of gun shells (caliber < 25).
|
||||
-- @field #number Cannons Amount of cannon shells (caliber >= 25).
|
||||
-- @field #number Bombs Amount of bombs.
|
||||
-- @field #number Rockets Amount of rockets.
|
||||
-- @field #number Torpedos Amount of torpedos.
|
||||
@@ -1195,8 +1197,8 @@ function OPSGROUP:GetDCSObject()
|
||||
return self.dcsgroup
|
||||
end
|
||||
|
||||
--- Set detection on or off.
|
||||
-- If detection is on, detected targets of the group will be evaluated and FSM events triggered.
|
||||
--- Make a target (unit, group, opsgroup) known to this group.
|
||||
-- This is useing the DCS function `controller.knowTarget`.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE TargetObject The target object.
|
||||
-- @param #boolean KnowType Make type known.
|
||||
@@ -4519,6 +4521,25 @@ function OPSGROUP:_UpdateTask(Task, Mission)
|
||||
if target then
|
||||
self:EngageTarget(target, speed, Task.dcstask.params.formation)
|
||||
end
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.NAVALENGAGEMENT then
|
||||
|
||||
---
|
||||
-- Task "Naval Engagement" Mission.
|
||||
---
|
||||
|
||||
-- Engage target.
|
||||
local target=Task.dcstask.params.target --Ops.Target#TARGET
|
||||
|
||||
-- Set speed. Default max.
|
||||
local speed=self.speedMax and UTILS.KmphToKnots(self.speedMax) or nil
|
||||
if Task.dcstask.params.speed then
|
||||
speed=UTILS.MpsToKnots(Task.dcstask.params.speed)
|
||||
end
|
||||
|
||||
if target then
|
||||
self:EngageTarget(target, speed, Task.dcstask.params.altitude)
|
||||
end
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.PATROLRACETRACK then
|
||||
|
||||
@@ -4745,7 +4766,7 @@ function OPSGROUP:_UpdateTask(Task, Mission)
|
||||
elseif weaponType==ENUMS.WeaponFlag.AnyRocket then
|
||||
nAmmo=ammo.Rockets
|
||||
elseif weaponType==ENUMS.WeaponFlag.Cannons then
|
||||
nAmmo=ammo.Guns
|
||||
nAmmo=ammo.Cannons
|
||||
end
|
||||
|
||||
--TODO: Update target location while we're at it anyway.
|
||||
@@ -4892,7 +4913,7 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ONGUARD or Task.dcstask.id==AUFTRAG.SpecialTask.ARMOREDGUARD then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK or Task.dcstask.id==AUFTRAG.SpecialTask.ARMORATTACK then
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK or Task.dcstask.id==AUFTRAG.SpecialTask.ARMORATTACK or Task.dcstask.id==AUFTRAG.SpecialTask.NAVALENGAGEMENT then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.NOTHING then
|
||||
done=true
|
||||
@@ -5724,7 +5745,7 @@ end
|
||||
function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
|
||||
|
||||
-- Debug info.
|
||||
local text=string.format("Mission %s DONE!", Mission.name)
|
||||
local text=string.format("Mission DONE %s!", Mission.name)
|
||||
self:T(self.lid..text)
|
||||
|
||||
-- Set group status.
|
||||
@@ -6237,11 +6258,12 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
self:T(self.lid.."Already in mission zone ==> TaskExecute()")
|
||||
self:TaskExecute(waypointtask)
|
||||
-- TODO: Calling PassingWaypoint here is probably better as it marks the mission waypoint as passed!
|
||||
--self:PassingWaypoint(waypoint)
|
||||
self:PassingWaypoint(waypoint)
|
||||
return
|
||||
elseif d<25 then
|
||||
self:T(self.lid.."Already within 25 meters of mission waypoint ==> TaskExecute()")
|
||||
self:TaskExecute(waypointtask)
|
||||
self:PassingWaypoint(waypoint)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -7856,7 +7878,7 @@ function OPSGROUP:_Spawn(Delay, Template)
|
||||
self:ScheduleOnce(Delay, OPSGROUP._Spawn, self, 0, Template)
|
||||
else
|
||||
-- Debug output.
|
||||
self:T2({Template=Template})
|
||||
--self:T2({Template=Template})
|
||||
|
||||
if self:IsArmygroup() and self.ValidateAndRepositionGroundUnits then
|
||||
UTILS.ValidateAndRepositionGroundUnits(Template.units)
|
||||
@@ -11196,11 +11218,11 @@ function OPSGROUP:_CheckAmmoStatus()
|
||||
self:OutOfAmmo()
|
||||
end
|
||||
|
||||
-- Guns.
|
||||
if self.outofGuns and ammo.Guns>0 then
|
||||
-- Guns (changed to shells)
|
||||
if self.outofGuns and ammo.Shells>0 then
|
||||
self.outofGuns=false
|
||||
end
|
||||
if ammo.Guns==0 and self.ammo.Guns>0 and not self.outofGuns then
|
||||
if ammo.Shells==0 and self.ammo.Shells>0 and not self.outofGuns then
|
||||
self.outofGuns=true
|
||||
self:OutOfGuns()
|
||||
end
|
||||
@@ -13376,7 +13398,9 @@ function OPSGROUP:GetAmmoTot()
|
||||
|
||||
local Ammo={} --#OPSGROUP.Ammo
|
||||
Ammo.Total=0
|
||||
Ammo.Shells=0
|
||||
Ammo.Guns=0
|
||||
Ammo.Cannons=0
|
||||
Ammo.Rockets=0
|
||||
Ammo.Bombs=0
|
||||
Ammo.Torpedos=0
|
||||
@@ -13397,7 +13421,9 @@ function OPSGROUP:GetAmmoTot()
|
||||
|
||||
-- Add up total.
|
||||
Ammo.Total=Ammo.Total+ammo.Total
|
||||
Ammo.Shells=Ammo.Shells+ammo.Shells
|
||||
Ammo.Guns=Ammo.Guns+ammo.Guns
|
||||
Ammo.Cannons=Ammo.Cannons+ammo.Cannons
|
||||
Ammo.Rockets=Ammo.Rockets+ammo.Rockets
|
||||
Ammo.Bombs=Ammo.Bombs+ammo.Bombs
|
||||
Ammo.Torpedos=Ammo.Torpedos+ammo.Torpedos
|
||||
@@ -13430,6 +13456,8 @@ function OPSGROUP:GetAmmoUnit(unit, display)
|
||||
-- Init counter.
|
||||
local nammo=0
|
||||
local nshells=0
|
||||
local nguns=0
|
||||
local ncannons=0
|
||||
local nrockets=0
|
||||
local nmissiles=0
|
||||
local nmissilesAA=0
|
||||
@@ -13452,10 +13480,10 @@ function OPSGROUP:GetAmmoUnit(unit, display)
|
||||
local ammotable=unit:GetAmmo()
|
||||
|
||||
if ammotable then
|
||||
|
||||
local weapons=#ammotable
|
||||
|
||||
--self:I(ammotable)
|
||||
--self:I(ammotable)
|
||||
--UTILS.PrintTableToLog(ammotable)
|
||||
|
||||
-- Loop over all weapons.
|
||||
for w=1,weapons do
|
||||
@@ -13463,9 +13491,9 @@ function OPSGROUP:GetAmmoUnit(unit, display)
|
||||
-- Number of current weapon.
|
||||
local Nammo=ammotable[w]["count"]
|
||||
|
||||
-- Range in meters. Seems only to exist for missiles (not shells).
|
||||
local rmin=ammotable[w]["desc"]["rangeMin"] or 0
|
||||
local rmax=ammotable[w]["desc"]["rangeMaxAltMin"] or 0
|
||||
-- Range in meters. Seems only to exist for missiles (not shells).
|
||||
local rmin=ammotable[w]["desc"]["rangeMin"] or 0
|
||||
local rmax=ammotable[w]["desc"]["rangeMaxAltMin"] or 0
|
||||
|
||||
-- Type name of current weapon.
|
||||
local Tammo=ammotable[w]["desc"]["typeName"]
|
||||
@@ -13487,6 +13515,16 @@ function OPSGROUP:GetAmmoUnit(unit, display)
|
||||
|
||||
-- Add up all shells.
|
||||
nshells=nshells+Nammo
|
||||
|
||||
-- Add small and large caliber shells for guns and cannons
|
||||
if ammotable[w]["desc"]["warhead"] and ammotable[w]["desc"]["warhead"]["caliber"] then
|
||||
local caliber=ammotable[w]["desc"]["warhead"]["caliber"]
|
||||
if caliber<25 then
|
||||
nguns=nguns+Nammo
|
||||
else
|
||||
ncannons=ncannons+Nammo
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug info.
|
||||
text=text..string.format("- %d shells of type %s, range=%d - %d meters\n", Nammo, _weaponName, rmin, rmax)
|
||||
@@ -13565,7 +13603,9 @@ function OPSGROUP:GetAmmoUnit(unit, display)
|
||||
|
||||
local ammo={} --#OPSGROUP.Ammo
|
||||
ammo.Total=nammo
|
||||
ammo.Guns=nshells
|
||||
ammo.Shells=nshells
|
||||
ammo.Guns=nguns
|
||||
ammo.Cannons=ncannons
|
||||
ammo.Rockets=nrockets
|
||||
ammo.Bombs=nbombs
|
||||
ammo.Torpedos=ntorps
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-- ===
|
||||
-- @module Ops.PlayerTask
|
||||
-- @image OPS_PlayerTask.jpg
|
||||
-- @date Last Update May 2025
|
||||
-- @date Last Update Oct 2025
|
||||
|
||||
|
||||
do
|
||||
@@ -59,6 +59,8 @@ do
|
||||
-- @field #string FinalState
|
||||
-- @field #string TypeName
|
||||
-- @field #number PreviousCount
|
||||
-- @field #boolean CanSmoke
|
||||
-- @field #boolean ShowThreatDetails
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
@@ -94,11 +96,13 @@ PLAYERTASK = {
|
||||
NextTaskFailure = {},
|
||||
FinalState = "none",
|
||||
PreviousCount = 0,
|
||||
CanSmoke = true,
|
||||
ShowThreatDetails = true,
|
||||
}
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASK.version="0.1.28"
|
||||
PLAYERTASK.version="0.1.29"
|
||||
|
||||
--- Generic task condition.
|
||||
-- @type PLAYERTASK.Condition
|
||||
@@ -231,6 +235,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.
|
||||
|
||||
--- On After "Planned" event. Task has been planned.
|
||||
-- @function [parent=#PLAYERTASK] OnAfterPilotPlanned
|
||||
@@ -468,6 +473,26 @@ function PLAYERTASK:SetSubType(Type)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [USER] Set if a task can have a smoke marker.
|
||||
-- @param #PLAYERTASK self
|
||||
-- @param #boolean OnOff If true (default) it can be smoke, false if not.
|
||||
-- @return #PLAYERTASK self
|
||||
function PLAYERTASK:SetCanSmoke(OnOff)
|
||||
self:T(self.lid.."AddSSetCanSmokeubType")
|
||||
self.CanSmoke = OnOff
|
||||
return self
|
||||
end
|
||||
|
||||
--- [USER] Set if a task can show threat details.
|
||||
-- @param #PLAYERTASK self
|
||||
-- @param #boolean OnOff If true (default) it can be shown, false if not.
|
||||
-- @return #PLAYERTASK self
|
||||
function PLAYERTASK:SetShowThreatDetails(OnOff)
|
||||
self:T(self.lid.."SetShowThreatDetails")
|
||||
self.ShowThreatDetails = OnOff
|
||||
return self
|
||||
end
|
||||
|
||||
--- [USER] Get task sub type description from this task.
|
||||
-- @param #PLAYERTASK self
|
||||
-- @return #string Type or nil
|
||||
@@ -1173,11 +1198,12 @@ end
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param #boolean Silent
|
||||
-- @return #PLAYERTASK self
|
||||
function PLAYERTASK:onafterCancel(From, Event, To)
|
||||
function PLAYERTASK:onafterCancel(From, Event, To, Silent)
|
||||
self:T({From, Event, To})
|
||||
if self.TaskController then
|
||||
self.TaskController:__TaskCancelled(-1,self)
|
||||
self.TaskController:__TaskCancelled(-1,self, Silent)
|
||||
end
|
||||
self.timestamp = timer.getAbsTime()
|
||||
self.FinalState = "Cancelled"
|
||||
@@ -1606,7 +1632,7 @@ do
|
||||
--
|
||||
-- The event is triggered when a task was cancelled manually. Use @{#PLAYERTASKCONTROLLER.OnAfterTaskCancelled}()` to link into this event:
|
||||
--
|
||||
-- function taskmanager:OnAfterTaskCancelled(From, Event, To, Task)
|
||||
-- function taskmanager:OnAfterTaskCancelled(From, Event, To, Task, Silent)
|
||||
-- ... your code here ...
|
||||
-- end
|
||||
--
|
||||
@@ -1770,12 +1796,15 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
THREATMEDIUM = "medium",
|
||||
THREATLOW = "low",
|
||||
THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
||||
NOTHREATTEXT = "%s\nNo target information available.",
|
||||
ELEVATION = "\nTarget Elevation: %s %s",
|
||||
METER = "meter",
|
||||
FEET = "feet",
|
||||
THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
||||
NOTHREATTEXTTTS = "%s, %s. No target information available.",
|
||||
MARKTASK = "%s, %s, copy, task %03d location marked on map!",
|
||||
SMOKETASK = "%s, %s, copy, task %03d location smoked!",
|
||||
NOSMOKETASK = "%s, %s, negative, task %03d location cannot be smoked!",
|
||||
FLARETASK = "%s, %s, copy, task %03d location illuminated!",
|
||||
ABORTTASK = "All stations, %s, %s has aborted %s task %03d!",
|
||||
UNKNOWN = "Unknown",
|
||||
@@ -1854,12 +1883,15 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
THREATMEDIUM = "mittel",
|
||||
THREATLOW = "niedrig",
|
||||
THREATTEXT = "%s\nGefahrstufe: %s\nZiele: %d\nKoord: %s",
|
||||
NOTHREATTEXT = "%s\nKeine Zielinformation verfügbar.",
|
||||
ELEVATION = "\nZiel Höhe: %s %s",
|
||||
METER = "Meter",
|
||||
FEET = "Fuss",
|
||||
THREATTEXTTTS = "%s, %s. Zielinformation zu %s. Gefahrstufe %s. Ziele %d. Zielposition %s.",
|
||||
NOTHREATTEXTTTS = "%s, %s. Keine Zielinformation verfügbar.",
|
||||
MARKTASK = "%s, %s, verstanden, Zielposition %03d auf der Karte markiert!",
|
||||
SMOKETASK = "%s, %s, verstanden, Zielposition %03d mit Rauch markiert!",
|
||||
NOSMOKETASK = "%s, %s, negativ, Zielposition %03d kann nicht markiert werden!",
|
||||
FLARETASK = "%s, %s, verstanden, Zielposition %03d beleuchtet!",
|
||||
ABORTTASK = "%s, an alle, %s hat Auftrag %s %03d abgebrochen!",
|
||||
UNKNOWN = "Unbekannt",
|
||||
@@ -1920,7 +1952,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASKCONTROLLER.version="0.1.70"
|
||||
PLAYERTASKCONTROLLER.version="0.1.71"
|
||||
|
||||
--- Create and run a new TASKCONTROLLER instance.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
@@ -2061,6 +2093,7 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter)
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Ops.PlayerTask#PLAYERTASK Task
|
||||
-- @param #boolean Silent If true suppress message output.
|
||||
|
||||
--- On After "TaskFailed" event. Task has failed.
|
||||
-- @function [parent=#PLAYERTASKCONTROLLER] OnAfterTaskFailed
|
||||
@@ -2741,11 +2774,12 @@ end
|
||||
|
||||
--- [User] Manually cancel a specific task
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Ops.PlayerTask#PLAYERTASK Task The task to be cancelled
|
||||
-- @param Ops.PlayerTask#PLAYERTASK Task The task to be cancelled.
|
||||
-- @param #boolean Silent If true suppress message output.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
function PLAYERTASKCONTROLLER:CancelTask(Task)
|
||||
function PLAYERTASKCONTROLLER:CancelTask(Task,Silent)
|
||||
self:T(self.lid.."CancelTask")
|
||||
Task:__Cancel(-1)
|
||||
Task:__Cancel(-1,Silent)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -3734,6 +3768,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
local Elevation = Coordinate:GetLandHeight() or 0 -- meters
|
||||
local CoordText = ""
|
||||
local CoordTextLLDM = nil
|
||||
local ShowThreatInfo = task.ShowThreatDetails
|
||||
local LasingDrone = self:_FindLasingDroneForTaskID(task.PlayerTaskNr)
|
||||
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
||||
CoordText = Coordinate:ToStringA2G(Client,nil,self.ShowMagnetic)
|
||||
@@ -3757,7 +3792,12 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
local clientlist, clientcount = task:GetClients()
|
||||
local ThreatGraph = "[" .. string.rep( "■", ThreatLevel ) .. string.rep( "□", 10 - ThreatLevel ) .. "]: "..ThreatLevel
|
||||
local ThreatLocaleText = self.gettext:GetEntry("THREATTEXT",self.locale)
|
||||
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
|
||||
if ShowThreatInfo == true then
|
||||
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
|
||||
else
|
||||
ThreatLocaleText = self.gettext:GetEntry("NOTHREATTEXT",self.locale)
|
||||
text = string.format(ThreatLocaleText, taskname)
|
||||
end
|
||||
local settings = _DATABASE:GetPlayerSettings(playername) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
local elevationmeasure = self.gettext:GetEntry("FEET",self.locale)
|
||||
if settings:IsMetric() then
|
||||
@@ -3880,9 +3920,19 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
end
|
||||
--self:I(self.lid.." | ".. CoordText)
|
||||
end
|
||||
local ttstext
|
||||
local ThreatLocaleTextTTS = self.gettext:GetEntry("THREATTEXTTTS",self.locale)
|
||||
local ttstext = string.format(ThreatLocaleTextTTS,ttsplayername,self.MenuName or self.Name,ttstaskname,ThreatLevelText, targets, CoordText)
|
||||
-- THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
||||
-- THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
||||
if ShowThreatInfo == true then
|
||||
ttstext = string.format(ThreatLocaleTextTTS,ttsplayername,self.MenuName or self.Name,ttstaskname,ThreatLevelText, targets, CoordText)
|
||||
else
|
||||
ThreatLocaleTextTTS = self.gettext:GetEntry("NOTHREATTEXTTTS",self.locale)
|
||||
ttstext = string.format(ThreatLocaleTextTTS,ttsplayername,self.MenuName or self.Name)
|
||||
end
|
||||
|
||||
-- POINTERTARGETLASINGTTS = ". Pointer over target and lasing."
|
||||
|
||||
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
|
||||
if LasingDrone and LasingDrone.playertask.inreach and LasingDrone:IsLasing() then
|
||||
local lasingtext = self.gettext:GetEntry("POINTERTARGETLASINGTTS",self.locale)
|
||||
@@ -3951,15 +4001,25 @@ function PLAYERTASKCONTROLLER:_SmokeTask(Group, Client)
|
||||
local text = ""
|
||||
if self.TasksPerPlayer:HasUniqueID(playername) then
|
||||
local task = self.TasksPerPlayer:ReadByID(playername) -- Ops.PlayerTask#PLAYERTASK
|
||||
task:SmokeTarget()
|
||||
local textmark = self.gettext:GetEntry("SMOKETASK",self.locale)
|
||||
text = string.format(textmark, ttsplayername, self.MenuName or self.Name, task.PlayerTaskNr)
|
||||
self:T(self.lid..text)
|
||||
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
|
||||
if self.UseSRS then
|
||||
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
|
||||
if task.CanSmoke == true then
|
||||
task:SmokeTarget()
|
||||
local textmark = self.gettext:GetEntry("SMOKETASK",self.locale)
|
||||
text = string.format(textmark, ttsplayername, self.MenuName or self.Name, task.PlayerTaskNr)
|
||||
self:T(self.lid..text)
|
||||
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
|
||||
if self.UseSRS then
|
||||
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
|
||||
end
|
||||
self:__TaskTargetSmoked(5,task)
|
||||
else
|
||||
local textmark = self.gettext:GetEntry("NOSMOKETASK",self.locale)
|
||||
text = string.format(textmark, ttsplayername, self.MenuName or self.Name, task.PlayerTaskNr)
|
||||
self:T(self.lid..text)
|
||||
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
|
||||
if self.UseSRS then
|
||||
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
|
||||
end
|
||||
end
|
||||
self:__TaskTargetSmoked(5,task)
|
||||
else
|
||||
text = self.gettext:GetEntry("NOACTIVETASK",self.locale)
|
||||
end
|
||||
@@ -4793,22 +4853,27 @@ end
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Ops.PlayerTask#PLAYERTASK Task
|
||||
-- @param #boolean Silent If true, suppress message output on cancel.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
function PLAYERTASKCONTROLLER:onafterTaskCancelled(From, Event, To, Task)
|
||||
function PLAYERTASKCONTROLLER:onafterTaskCancelled(From, Event, To, Task, Silent)
|
||||
self:T({From, Event, To})
|
||||
self:T(self.lid.."TaskCancelled")
|
||||
local canceltxt = self.gettext:GetEntry("TASKCANCELLED",self.locale)
|
||||
local canceltxttts = self.gettext:GetEntry("TASKCANCELLEDTTS",self.locale)
|
||||
local taskname = string.format(canceltxt, Task.PlayerTaskNr, tostring(Task.Type))
|
||||
if not self.NoScreenOutput then
|
||||
self:_SendMessageToClients(taskname,15)
|
||||
--local m = MESSAGE:New(taskname,15,"Tasking"):ToCoalition(self.Coalition)
|
||||
if Silent ~= true then
|
||||
local canceltxt = self.gettext:GetEntry("TASKCANCELLED",self.locale)
|
||||
local canceltxttts = self.gettext:GetEntry("TASKCANCELLEDTTS",self.locale)
|
||||
local taskname = string.format(canceltxt, Task.PlayerTaskNr, tostring(Task.Type))
|
||||
|
||||
if self.NoScreenOutput ~= true then
|
||||
self:_SendMessageToClients(taskname,15)
|
||||
--local m = MESSAGE:New(taskname,15,"Tasking"):ToCoalition(self.Coalition)
|
||||
end
|
||||
|
||||
if self.UseSRS then
|
||||
taskname = string.format(canceltxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType))
|
||||
self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2)
|
||||
end
|
||||
|
||||
end
|
||||
if self.UseSRS then
|
||||
taskname = string.format(canceltxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType))
|
||||
self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2)
|
||||
end
|
||||
|
||||
local clients=Task:GetClientObjects()
|
||||
for _,client in pairs(clients) do
|
||||
self:_RemoveMenuEntriesForTask(Task,client)
|
||||
|
||||
@@ -2006,9 +2006,10 @@ end
|
||||
--- Count alive objects.
|
||||
-- @param #TARGET self
|
||||
-- @param #TARGET.Object Target Target objective.
|
||||
-- @param #table Coalitions (Optional) Only count targets of the given coalition(s).
|
||||
-- @param #table Coalitions (Optional) Only count targets of the given coalition(s).
|
||||
-- @param #boolean OnlyReallyAlive (Optional) If `true`, count only really alive targets (units, groups) but not coordinates or zones.
|
||||
-- @return #number Number of alive target objects.
|
||||
function TARGET:CountObjectives(Target, Coalitions)
|
||||
function TARGET:CountObjectives(Target, Coalitions, OnlyReallyAlive)
|
||||
|
||||
local N=0
|
||||
|
||||
@@ -2067,13 +2068,17 @@ function TARGET:CountObjectives(Target, Coalitions)
|
||||
|
||||
-- No target, where we can check the alive status, so we assume it is alive. Changed this because otherwise target count is 0 if we pass a coordinate.
|
||||
-- This is also more consitent with the life and is alive status.
|
||||
N=N+1
|
||||
if not OnlyReallyAlive then
|
||||
N=N+1
|
||||
end
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.ZONE then
|
||||
|
||||
-- No target, where we can check the alive status, so we assume it is alive. Changed this because otherwise target count is 0 if we pass a coordinate.
|
||||
-- This is also more consitent with the life and is alive status.
|
||||
N=N+1
|
||||
if not OnlyReallyAlive then
|
||||
N=N+1
|
||||
end
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.OPSZONE then
|
||||
|
||||
@@ -2093,15 +2098,16 @@ end
|
||||
--- Count alive targets.
|
||||
-- @param #TARGET self
|
||||
-- @param #table Coalitions (Optional) Only count targets of the given coalition(s).
|
||||
-- @param #boolean OnlyReallyAlive (Optional) If `true`, count only really alive targets (units, groups) but not coordinates or zones.
|
||||
-- @return #number Number of alive target objects.
|
||||
function TARGET:CountTargets(Coalitions)
|
||||
function TARGET:CountTargets(Coalitions, OnlyReallyAlive)
|
||||
|
||||
local N=0
|
||||
|
||||
for _,_target in pairs(self.targets) do
|
||||
local Target=_target --#TARGET.Object
|
||||
|
||||
N=N+self:CountObjectives(Target, Coalitions)
|
||||
N=N+self:CountObjectives(Target, Coalitions, OnlyReallyAlive)
|
||||
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3318,48 +3318,6 @@ function UTILS.AdjustHeading360(Heading)
|
||||
return Heading
|
||||
end
|
||||
|
||||
--- Transfroms a given 2D vector 3D.
|
||||
-- This takes care of ED's different conventions for 2D and 3D coordinate systems.
|
||||
-- @param DCS#Vec2 Vec Vector to be transformed. Can be any table/object that has at least x and y and optionally a z component.
|
||||
-- @param #boolean OnSurface If `true`, new vector's y-component (alt) is at surface height. Otherwise, it is set to 0.
|
||||
-- @return DCS#Vec3 Vector in 3D with x-, y- and z-components.
|
||||
function UTILS.VecTo3D(Vec, OnSurface)
|
||||
|
||||
local vec={x=0, y=0, z=0} --DCS#Vec3
|
||||
if Vec.z then
|
||||
-- Vector is 3D already ==> Nothing to do.
|
||||
vec.x=Vec.x
|
||||
vec.y=Vec.y
|
||||
vec.z=Vec.z
|
||||
else
|
||||
-- Vector is 2D
|
||||
vec.x=Vec.x
|
||||
vec.y=OnSurface and land.getHeight({x=Vec.x, y=Vec.y}) or 0
|
||||
vec.z=Vec.y
|
||||
end
|
||||
|
||||
return vec
|
||||
end
|
||||
|
||||
--- Transfroms a given 3D (or 2D) vector to 2D.
|
||||
-- This takes care of ED's different conventions for 2D and 3D coordinate systems.
|
||||
-- @param DCS#Vec3 Vec Vector to be transformed. Can be any table/object that has at least x and y and optionally a z component.
|
||||
-- @return DCS#Vec2 Vector in 2D with x- and y-components.
|
||||
function UTILS.VecTo2D(Vec)
|
||||
|
||||
local vec={x=0, y=0} --DCS#Vec2
|
||||
|
||||
if Vec.z then
|
||||
vec.x=Vec.x
|
||||
vec.y=Vec.z
|
||||
else
|
||||
vec.x=Vec.x
|
||||
vec.y=Vec.y
|
||||
end
|
||||
|
||||
return vec
|
||||
end
|
||||
|
||||
--- Create a BRAA NATO call string BRAA between two GROUP objects
|
||||
-- @param Wrapper.Group#GROUP FromGrp GROUP object
|
||||
-- @param Wrapper.Group#GROUP ToGrp GROUP object
|
||||
@@ -4388,18 +4346,56 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
||||
local FarpVec2 = Coordinate:GetVec2()
|
||||
|
||||
if NumberPads > 1 then
|
||||
local Grid = UTILS.GenerateGridPoints(FarpVec2, NumberPads, SpacingX, SpacingY)
|
||||
local Grid = UTILS.GenerateGridPoints(FarpVec2, NumberPads, SpacingX, SpacingY)
|
||||
local groupData = {
|
||||
["visible"] = true,
|
||||
["hidden"] = false,
|
||||
["units"] = {},
|
||||
["y"] = 0, -- Group center latitude
|
||||
["x"] = 0, -- Group center longitude
|
||||
["name"] = Name,
|
||||
}
|
||||
local unitData = {
|
||||
["category"] = "Heliports",
|
||||
["type"] = STypeName, -- FARP type
|
||||
["y"] = 0, -- Latitude coordinate (meters)
|
||||
["x"] = 0, -- Longitude coordinate (meters)
|
||||
["name"] = Name,
|
||||
["heading"] = 0, -- Heading in radians
|
||||
["heliport_modulation"] = mod, -- 0 = AM, 1 = FM
|
||||
["heliport_frequency"] = freq, -- Radio frequency in MHz
|
||||
["heliport_callsign_id"] = callsign, -- Callsign ID
|
||||
["dead"] = false,
|
||||
["shape_name"] = SShapeName,
|
||||
["dynamicSpawn"] = DynamicSpawns,
|
||||
["allowHotStart"] = HotStart,
|
||||
}
|
||||
for id,gridpoint in ipairs(Grid) do
|
||||
-- Spawn FARP
|
||||
local location = COORDINATE:NewFromVec2(gridpoint)
|
||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
||||
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
||||
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
||||
local spawnedfarp = newfarp:SpawnFromCoordinate(location,0,Name.."-"..id)
|
||||
table.insert(ReturnObjects,spawnedfarp)
|
||||
|
||||
PopulateStorage(Name.."-"..id,liquids,equip,airframes)
|
||||
end
|
||||
local UnitTemplate = UTILS.DeepCopy(unitData)
|
||||
UnitTemplate.x = gridpoint.x
|
||||
UnitTemplate.y = gridpoint.y
|
||||
if id > 1 then UnitTemplate.name = Name.."-"..id end
|
||||
table.insert(groupData.units,UnitTemplate)
|
||||
if id==1 then
|
||||
groupData.x = gridpoint.x
|
||||
groupData.y = gridpoint.y
|
||||
end
|
||||
end
|
||||
--BASE:I("Spawning FARP")
|
||||
--UTILS.PrintTableToLog(groupData,1)
|
||||
local Static=coalition.addGroup(Country, -1, groupData)
|
||||
-- Currently DCS >= 2.8 does not trigger birth events if FARPS are spawned!
|
||||
-- We create such an event. The airbase is registered in Core.Event
|
||||
local Event = {
|
||||
id = EVENTS.Birth,
|
||||
time = timer.getTime(),
|
||||
initiator = Static
|
||||
}
|
||||
-- Create BIRTH event.
|
||||
world.onEvent(Event)
|
||||
|
||||
PopulateStorage(Name.."-1",liquids,equip,airframes)
|
||||
else
|
||||
-- Spawn FARP
|
||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
||||
|
||||
@@ -2855,7 +2855,7 @@ do -- Route methods
|
||||
-- @param Core.Zone#ZONE Zone The zone where to route to.
|
||||
-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone.
|
||||
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
||||
-- @param Core.Base#FORMATION Formation The formation string.
|
||||
-- @param DCS#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
|
||||
self:F2( Zone )
|
||||
|
||||
@@ -2915,7 +2915,7 @@ do -- Route methods
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param DCS#Vec2 Vec2 The Vec2 where to route to.
|
||||
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
||||
-- @param Core.Base#FORMATION Formation The formation string.
|
||||
-- @param DCS#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
@@ -108,8 +108,9 @@ DYNAMICCARGO.State = {
|
||||
-- @type DYNAMICCARGO.AircraftTypes
|
||||
DYNAMICCARGO.AircraftTypes = {
|
||||
["CH-47Fbl1"] = "CH-47Fbl1",
|
||||
["Mi-8MTV2"] = "CH-47Fbl1",
|
||||
["Mi-8MT"] = "CH-47Fbl1",
|
||||
["Mi-8MTV2"] = "Mi-8MTV2",
|
||||
["Mi-8MT"] = "Mi-8MT",
|
||||
["C-130J-30"] = "C-130J-30",
|
||||
}
|
||||
|
||||
--- Helo types possible.
|
||||
@@ -122,23 +123,29 @@ DYNAMICCARGO.AircraftDimensions = {
|
||||
["length"] = 11,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
["Mi-8MTV2"] = {
|
||||
["Mi-8MTV2"] = {
|
||||
["width"] = 6,
|
||||
["height"] = 6,
|
||||
["length"] = 15,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
["Mi-8MT"] = {
|
||||
["Mi-8MT"] = {
|
||||
["width"] = 6,
|
||||
["height"] = 6,
|
||||
["length"] = 15,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
["C-130J-30"] = {
|
||||
["width"] = 4,
|
||||
["height"] = 12,
|
||||
["length"] = 35,
|
||||
["ropelength"] = 0,
|
||||
},
|
||||
}
|
||||
|
||||
--- DYNAMICCARGO class version.
|
||||
-- @field #string version
|
||||
DYNAMICCARGO.version="0.0.9"
|
||||
DYNAMICCARGO.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -527,7 +534,10 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
---------------
|
||||
-- REMOVED Cargo
|
||||
---------------
|
||||
if self.timer and self.timer:IsRunning() then self.timer:Stop() end
|
||||
if self.timer and self.timer:IsRunning() then
|
||||
self.timer:Stop()
|
||||
self.timer=nil
|
||||
end
|
||||
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
|
||||
self.CargoState = DYNAMICCARGO.State.REMOVED
|
||||
_DATABASE:CreateEventDynamicCargoRemoved(self)
|
||||
@@ -535,6 +545,24 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
return self
|
||||
end
|
||||
|
||||
--- [USER] Destroy a DYNAMICCARGO object.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param #boolean GenerateEvent Set to false to remove an item silently. Defaults to true.
|
||||
-- @return #boolean Return Returns nil if the object could not be found, else returns true.
|
||||
function DYNAMICCARGO:Destroy(GenerateEvent)
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
local GenerateEvent = (GenerateEvent ~= nil and GenerateEvent == false) and false or true
|
||||
if GenerateEvent and GenerateEvent == true then
|
||||
self:CreateEventDead( timer.getTime(), DCSObject )
|
||||
end
|
||||
DCSObject:destroy()
|
||||
self:_UpdatePosition()
|
||||
return true
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [Internal] Track helos for loaded/unloaded decision making.
|
||||
-- @param Wrapper.Client#CLIENT client
|
||||
-- @return #boolean IsIn
|
||||
|
||||
@@ -1058,9 +1058,12 @@ function GROUP:GetTypeName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return( GroupTypeName )
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupTypeName = unit:getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return( GroupTypeName )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1075,9 +1078,12 @@ function GROUP:GetNatoReportingName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return UTILS.GetReportingName(GroupTypeName)
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupTypeName = unit:getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return UTILS.GetReportingName(GroupTypeName)
|
||||
end
|
||||
end
|
||||
|
||||
return "Bogey"
|
||||
@@ -1093,9 +1099,12 @@ function GROUP:GetPlayerName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local PlayerName = DCSGroup:getUnit(1):getPlayerName()
|
||||
--self:T3( PlayerName )
|
||||
return( PlayerName )
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local PlayerName = unit:getPlayerName()
|
||||
--self:T3( PlayerName )
|
||||
return( PlayerName )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1111,9 +1120,12 @@ function GROUP:GetCallsign()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupCallSign = DCSGroup:getUnit(1):getCallsign()
|
||||
--self:T3( GroupCallSign )
|
||||
return GroupCallSign
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupCallSign = unit:getCallsign()
|
||||
--self:T3( GroupCallSign )
|
||||
return GroupCallSign
|
||||
end
|
||||
end
|
||||
|
||||
BASE:E( { "Cannot GetCallsign", Positionable = self, Alive = self:IsAlive() } )
|
||||
@@ -1152,6 +1164,23 @@ function GROUP:GetVec3()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the current {@Core.Vector#VECTOR} of the first Unit in the GROUP.
|
||||
-- @param #GROUP self
|
||||
-- @return Core.Vector#VECTOR Vector of the first Unit of the GROUP or nil if cannot be found.
|
||||
function GROUP:GetVector()
|
||||
|
||||
-- Get first unit.
|
||||
local unit=self:GetUnit(1)
|
||||
|
||||
if unit then
|
||||
local vector=unit:GetVector()
|
||||
return vector
|
||||
end
|
||||
|
||||
self:E("ERROR: Cannot get Vector of group "..tostring(self.GroupName))
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the average Vec3 vector of the Units in the GROUP.
|
||||
-- @param #GROUP self
|
||||
-- @return DCS#Vec3 Current Vec3 of the GROUP or nil if cannot be found.
|
||||
|
||||
@@ -170,6 +170,27 @@ function IDENTIFIABLE:GetCoalition()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns true if identifiable is of RED coalition.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #boolean If the identifiable is red.
|
||||
function IDENTIFIABLE:IsRed()
|
||||
return self:GetCoalition() == coalition.side.RED
|
||||
end
|
||||
|
||||
--- Returns true if identifiable is of BLUE coalition.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #boolean If the identifiable is blue.
|
||||
function IDENTIFIABLE:IsBlue()
|
||||
return self:GetCoalition() == coalition.side.BLUE
|
||||
end
|
||||
|
||||
--- Returns true if identifiable is of NEUTRAL coalition.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #boolean If the identifiable is neutral.
|
||||
function IDENTIFIABLE:IsNeutral()
|
||||
return self:GetCoalition() == coalition.side.NEUTRAL
|
||||
end
|
||||
|
||||
--- Returns the name of the coalition of the Identifiable.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #string The name of the coalition.
|
||||
|
||||
@@ -219,6 +219,25 @@ function POSITIONABLE:GetOrientationZ()
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns the vectors of the orientation of the object:
|
||||
-- X is the orientation parallel to the movement of the object, Z perpendicular and Y vertical orientation.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Vector#VECTOR X orientation, i.e. parallel to the direction of movement.
|
||||
-- @return Core.Vector#VECTOR Y orientation, i.e. vertical.
|
||||
-- @return Core.Vector#VECTOR Z orientation, i.e. perpendicular to the direction of movement.
|
||||
function POSITIONABLE:GetOrientationVectors()
|
||||
local position = self:GetPosition()
|
||||
if position then
|
||||
local vecx=VECTOR:NewFromVec(position.x)
|
||||
local vecy=VECTOR:NewFromVec(position.y)
|
||||
local vecz=VECTOR:NewFromVec(position.z)
|
||||
return vecx, vecy, vecz
|
||||
else
|
||||
BASE:E( { "Cannot GetOrientation", Positionable = self, Alive = self:IsAlive() } )
|
||||
return nil, nil, nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return DCS#Position The 3D position vectors of the POSITIONABLE.
|
||||
@@ -286,6 +305,27 @@ function POSITIONABLE:GetVec2()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the @{Core.Vector#VECTOR} indicating the 3D position of the object on the map.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Vector#VECTOR The 3D vector.
|
||||
function POSITIONABLE:GetVector()
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
|
||||
local Vec3 = DCSPositionable:getPoint() -- DCS#Vec3
|
||||
|
||||
local vector=VECTOR:NewFromVec(Vec3)
|
||||
|
||||
return vector
|
||||
end
|
||||
|
||||
self:E( { "Cannot GetVec2", Positionable = self, Alive = self:IsAlive() } )
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a COORDINATE object indicating the point in 2D of the POSITIONABLE within the mission.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Point#COORDINATE The 3D point vector of the POSITIONABLE.
|
||||
@@ -914,6 +954,24 @@ function POSITIONABLE:GetVelocityVec3()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the velocity vector.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Vector#VECTOR The velocity vector or `nil` if the object does not exist.
|
||||
function POSITIONABLE:GetVelocityVector()
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable and DCSPositionable:isExist() then
|
||||
local vec3 = DCSPositionable:getVelocity()
|
||||
local vector=VECTOR:NewFromVec(vec3)
|
||||
return vector
|
||||
end
|
||||
|
||||
BASE:E( { "Cannot GetVelocityVector", Positionable = self, Alive = self:IsAlive() } )
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get relative velocity with respect to another POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param #POSITIONABLE Positionable Other POSITIONABLE.
|
||||
@@ -1865,6 +1923,7 @@ do -- Cargo
|
||||
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
||||
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
||||
["Sd_Kfz_251"] = 10*POSITIONABLE.DefaultInfantryWeight,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ function STATIC:Register( StaticName )
|
||||
else
|
||||
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
||||
end
|
||||
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -86,6 +89,30 @@ function STATIC:GetLife()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get the position of the STATIC even if it is not alive.
|
||||
-- @param #STATIC self
|
||||
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE.
|
||||
-- @return #nil The position was not cached.
|
||||
function STATIC:GetVec2Cached()
|
||||
local vec2 = self:GetVec2()
|
||||
if not vec2 and self._vec3 then
|
||||
vec2 = {x = self._vec3.x, y = self._vec3.z }
|
||||
end
|
||||
return vec2
|
||||
end
|
||||
|
||||
--- Get the position of the STATIC even if it is not alive.
|
||||
-- @param #STATIC self
|
||||
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE.
|
||||
-- @return #nil The position was not cached.
|
||||
function STATIC:GetVec3Cached()
|
||||
local vec3 = self:GetVec3()
|
||||
if not vec3 and self._vec3 then
|
||||
vec3 = self._vec3
|
||||
end
|
||||
return vec3
|
||||
end
|
||||
|
||||
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
||||
-- @param #STATIC self
|
||||
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
||||
@@ -232,6 +259,8 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
|
||||
|
||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
@@ -255,6 +284,8 @@ function STATIC:ReSpawn(CountryID, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||
|
||||
SpawnStatic:Spawn(nil, self.StaticName)
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
@@ -278,6 +309,8 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||
|
||||
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user